Changeset 97


Ignore:
Timestamp:
02/26/08 20:04:14 (17 years ago)
Author:
tim
Message:

begun the work of rewriting the lowest layer parsing routines

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/doc/devel/winntreg.txt

    r26 r97  
    1101100x0002      Word      for the root-key: 0x2C, otherwise 0x20  //key symbolic links 0x10. Nigel
    1111110x0004      Q-Word      write-date/time in windows nt notation
     1120x000C      D-Word      UNKNOWN // added by TDM
    1121130x0010      D-Word      Offset of Owner/Parent key
    1131140x0014      D-Word      number of sub-Keys
     1150x0018      D-Word      UNKNOWN // added by TDM
    1141160x001C      D-Word      Offset of the sub-key lf-Records
     1170x0020      D-Word      UNKNOWN // added by TDM
    1151180x0024      D-Word      number of values
    1161190x0028      D-Word      Offset of the Value-List
  • trunk/include/regfi.h

    r84 r97  
    7272
    7373#define REGF_BLOCKSIZE          0x1000
    74 #define REGF_ALLOC_BLOCK        0x1000
     74#define REGF_ALLOC_BLOCK        0x1000  /* Minimum allocation unit for hbins */
    7575#define REGF_MAX_DEPTH          512
    7676
    7777/* header sizes for various records */
    7878
    79 #define REGF_HDR_SIZE           4
    80 #define HBIN_HDR_SIZE           4
    81 #define HBIN_HEADER_REC_SIZE    0x24
     79#define REGF_MAGIC_SIZE         4
     80#define HBIN_MAGIC_SIZE         4
     81#define HBIN_HEADER_REC_SIZE    0x20
    8282#define REC_HDR_SIZE            2
    8383
     
    103103/* HBIN block */
    104104struct regf_hbin;
    105 typedef struct regf_hbin {
     105typedef struct regf_hbin
     106{
    106107  struct regf_hbin* prev;
    107108  struct regf_hbin* next;
    108109  uint32 file_off;       /* my offset in the registry file */
    109   uint32 free_off;       /* offset to free space within the hbin record */
    110   uint32 free_size;      /* amount of data left in the block */
    111110  uint32 ref_count;      /* how many active records are pointing to this
    112111                          * block (not used currently)
     
    114113 
    115114  uint32 first_hbin_off; /* offset from first hbin block */
    116   uint32 block_size;     /* block size of this block is
    117                           * usually a multiple of 4096Kb
     115  uint32 block_size;     /* block size of this block
     116                          * Should be a multiple of 4096 (0x1000)
    118117                          */
    119   uint8  header[HBIN_HDR_SIZE]; /* "hbin" */
     118  uint32 next_block;     /* relative offset to next block.  Should be
     119                          * exactly the same as block_size.  Stored just
     120                          * in case this is found to be different in the
     121                          * future.
     122                          */
     123
     124  uint8 magic[HBIN_MAGIC_SIZE]; /* "hbin" */
    120125  prs_struct ps;         /* data */
    121   bool dirty;            /* has this hbin block been modified? */
    122126} REGF_HBIN;
    123127
    124 /* ??? List -- list of key offsets and hashed names for consistency */
    125 typedef struct {
     128
     129/* Hash List -- list of key offsets and hashed names for consistency */
     130typedef struct
     131{
    126132  uint32 nk_off;
    127   uint8 keycheck[sizeof(uint32)];
     133  uint8 keycheck[4];
    128134} REGF_HASH_REC;
    129135
    130 typedef struct {
     136
     137typedef struct
     138{
    131139  REGF_HBIN* hbin;       /* pointer to HBIN record (in memory) containing
    132140                          * this nk record
     
    140148} REGF_LF_REC;
    141149
     150
    142151/* Key Value */
    143 
    144 typedef struct {
     152typedef struct
     153{
    145154  REGF_HBIN* hbin;      /* pointer to HBIN record (in memory) containing
    146155                         * this nk record
     
    163172struct _regf_sk_rec;
    164173
    165 typedef struct _regf_sk_rec {
     174typedef struct _regf_sk_rec
     175{
    166176  struct _regf_sk_rec* next;
    167177  struct _regf_sk_rec* prev;
     
    186196
    187197/* Key Name */
    188 typedef struct {
     198typedef struct
     199{
    189200  uint32 hbin_off;      /* offset from beginning of this hbin block */
    190201  uint32 rec_size;      /* ((start_offset - end_offset) & 0xfffffff8) */
     
    221232  uint32 num_values;
    222233  uint32 values_off;    /* value lists which point to VK records */
    223   uint32 sk_off;        /* offset to SK record */
    224  
     234  uint32 sk_off;        /* offset to SK record */ 
    225235} REGF_NK_REC;
    226236
    227237
     238
    228239/* REGF block */
    229 typedef struct {
     240typedef struct
     241{
    230242  /* run time information */
    231243  int fd;         /* file descriptor */
    232   int open_flags; /* flags passed to the open() call */
     244  /* For sanity checking (not part of the registry header) */
     245  uint32 file_length;
    233246  void* mem_ctx;  /* memory context for run-time file access information */
    234247  REGF_HBIN* block_list; /* list of open hbin blocks */
     
    239252                                 */
    240253 
    241   uint8  header[REGF_HDR_SIZE]; /* "regf" */
     254  uint8  magic[REGF_MAGIC_SIZE];/* "regf" */
    242255  NTTIME mtime;
    243256  uint32 data_offset;           /* offset to record in the first (or any?)
     
    245258                                 */
    246259  uint32 last_block;            /* offset to last hbin block in file */
    247   uint32 checksum;              /* XOR of bytes 0x0000 - 0x01FB */
    248  
    249   /* unknowns */
     260
     261  uint32 checksum;              /* Stored checksum. */
     262  uint32 computed_checksum;     /* Our own calculation of the checksum.
     263                                 * (XOR of bytes 0x0000 - 0x01FB)
     264                                 */
     265 
     266  /* unknown data structure values */
    250267  uint32 unknown1;
    251268  uint32 unknown2;
     
    254271  uint32 unknown5;
    255272  uint32 unknown6;
     273  uint32 unknown7;
    256274} REGF_FILE;
    257275
    258276
    259 typedef struct {
     277
     278typedef struct
     279{
    260280  REGF_FILE* f;
    261281  void_stack* key_positions;
     
    266286
    267287
    268 typedef struct {
     288typedef struct
     289{
    269290  REGF_NK_REC* nk;
    270291  uint32 cur_subkey;
     
    316337
    317338
     339
     340/****************/
     341/* Experimental */
     342/****************/
     343typedef struct
     344{
     345  uint32 offset;
     346  uint32 size;
     347} REGFI_CELL_INFO;
     348
     349typedef struct
     350{
     351  uint32 count;
     352  REGFI_CELL_INFO** cells;
     353} REGFI_CELL_LIST;
     354
     355
     356REGF_FILE* regfi_parse_regf(int fd, bool strict);
     357REGFI_CELL_LIST* regfi_get_unallocated_cells(REGF_FILE* file);
     358REGF_HBIN* regfi_parse_hbin(REGF_FILE* file, uint32 offset,
     359                            bool strict, bool save_unalloc);
     360REGF_NK_REC* regfi_parse_nk(REGF_FILE* f, uint32);
     361uint32 regfi_read(int fd, uint8* buf, uint32* length);
     362
    318363#endif  /* _REGFI_H */
  • trunk/lib/regfi.c

    r95 r97  
    66 * Windows NT registry I/O library
    77 *
    8  * Copyright (C) 2005-2007 Timothy D. Morgan
     8 * Copyright (C) 2005-2008 Timothy D. Morgan
    99 * Copyright (C) 2005 Gerald (Jerry) Carter
    1010 *
     
    340340/*******************************************************************
    341341 *******************************************************************/
    342 static int read_block( REGF_FILE *file, prs_struct *ps, uint32 file_offset,
    343                        uint32 block_size )
    344 {
    345   const int hdr_size = 0x20;
    346   int bytes_read, returned;
    347   char *buffer;
    348   SMB_STRUCT_STAT sbuf;
    349 
    350   /* check for end of file */
    351 
    352   if ( fstat( file->fd, &sbuf ) ) {
    353     /*DEBUG(0,("read_block: stat() failed! (%s)\n", strerror(errno)));*/
    354     return -1;
    355   }
    356 
    357   if ( (size_t)file_offset >= sbuf.st_size )
    358     return -1;
    359        
    360   /* if block_size == 0, we are parsnig HBIN records and need
    361      to read some of the header to get the block_size from there */
    362            
    363   if ( block_size == 0 ) {
    364     uint8 hdr[0x20];
    365 
    366     if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) {
    367       /*DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) ));*/
    368       return -1;
    369     }
    370 
    371     bytes_read = returned = 0;
    372     while (bytes_read < hdr_size)
    373     {
    374       returned = read(file->fd, hdr + bytes_read, hdr_size - bytes_read);
    375       if(returned == -1 && errno != EINTR && errno != EAGAIN)
    376       {
    377         /*DEBUG(0,("read_block: read of hdr failed (%s)\n",strerror(errno)));*/
    378         return -1;
    379       }
    380 
    381       if(returned == 0)
    382         return -1;
    383 
    384       bytes_read += returned;
    385     }
    386 
    387     /* make sure this is an hbin header */
    388 
    389     if ( strncmp( (char*)hdr, "hbin", HBIN_HDR_SIZE ) != 0 ) {
    390       /*DEBUG(0,("read_block: invalid block header!\n"));*/
    391       return -1;
    392     }
    393 
    394     block_size = IVAL( hdr, 0x08 );
    395   }
    396 
    397   /*DEBUG(10,("read_block: block_size == 0x%x\n", block_size ));*/
    398 
    399   /* set the offset, initialize the buffer, and read the block from disk */
    400 
    401   if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) {
    402     /*DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) ));*/
    403     return -1;
    404   }
    405        
    406   prs_init( ps, block_size, file->mem_ctx, UNMARSHALL );
    407   buffer = ps->data_p;
    408   bytes_read = returned = 0;
    409 
    410   while ( bytes_read < block_size )
    411   {
    412     returned = read(file->fd, buffer+bytes_read, block_size-bytes_read);
    413     if(returned == -1 && errno != EINTR && errno != EAGAIN)
    414     {
    415       /*DEBUG(0,("read_block: read() failed (%s)\n", strerror(errno) ));*/
    416       return -1;
    417     }
    418 
    419     if ((returned == 0) && (bytes_read < block_size))
    420     {
    421       /*DEBUG(0,("read_block: not a vald registry file ?\n" ));*/
    422       return -1;
    423     }   
    424 
    425     bytes_read += returned;
    426   }
    427        
    428   return bytes_read;
    429 }
    430 
    431 
    432 /*******************************************************************
    433  *******************************************************************/
    434 static bool prs_regf_block(const char *desc, prs_struct *ps,
    435                            int depth, REGF_FILE *file)
    436 {
    437   depth++;
    438        
    439   if(!prs_uint8s("header", ps, depth, file->header, sizeof(file->header)))
    440     return false;
    441        
    442   /* yes, these values are always identical so store them only once */
    443        
    444   if ( !prs_uint32( "unknown1", ps, depth, &file->unknown1 ))
    445     return false;
    446   if ( !prs_uint32( "unknown1 (again)", ps, depth, &file->unknown1 ))
    447     return false;
    448 
    449   /* get the modtime */
    450        
    451   if ( !prs_set_offset( ps, 0x0c ) )
    452     return false;
    453   if ( !smb_io_time( "modtime", &file->mtime, ps, depth ) )
    454     return false;
    455 
    456   /* constants */
    457        
    458   if ( !prs_uint32( "unknown2", ps, depth, &file->unknown2 ))
    459     return false;
    460   if ( !prs_uint32( "unknown3", ps, depth, &file->unknown3 ))
    461     return false;
    462   if ( !prs_uint32( "unknown4", ps, depth, &file->unknown4 ))
    463     return false;
    464   if ( !prs_uint32( "unknown5", ps, depth, &file->unknown5 ))
    465     return false;
    466 
    467   /* get file offsets */
    468        
    469   if ( !prs_set_offset( ps, 0x24 ) )
    470     return false;
    471   if ( !prs_uint32( "data_offset", ps, depth, &file->data_offset ))
    472     return false;
    473   if ( !prs_uint32( "last_block", ps, depth, &file->last_block ))
    474     return false;
    475                
    476   /* one more constant */
    477        
    478   if ( !prs_uint32( "unknown6", ps, depth, &file->unknown6 ))
    479     return false;
    480                
    481   /* get the checksum */
    482        
    483   if ( !prs_set_offset( ps, 0x01fc ) )
    484     return false;
    485   if ( !prs_uint32( "checksum", ps, depth, &file->checksum ))
    486     return false;
    487        
    488   return true;
    489 }
    490 
    491 
    492 /*******************************************************************
    493  *******************************************************************/
    494 static bool prs_hbin_block(const char *desc, prs_struct *ps,
    495                            int depth, REGF_HBIN *hbin)
    496 {
    497   uint32 block_size2;
    498 
    499   depth++;
    500        
    501   if(!prs_uint8s("header", ps, depth, hbin->header, sizeof(hbin->header)))
    502     return false;
    503 
    504   if ( !prs_uint32( "first_hbin_off", ps, depth, &hbin->first_hbin_off ))
    505     return false;
    506 
    507   /* The dosreg.cpp comments say that the block size is at 0x1c.
    508      According to a WINXP NTUSER.dat file, this is wrong.  The block_size
    509      is at 0x08 */
    510 
    511   if ( !prs_uint32( "block_size", ps, depth, &hbin->block_size ))
    512     return false;
    513 
    514   block_size2 = hbin->block_size;
    515   prs_set_offset( ps, 0x1c );
    516   if ( !prs_uint32( "block_size2", ps, depth, &block_size2 ))
    517     return false;
    518 
    519   if ( !ps->io )
    520     hbin->dirty = true;
    521        
    522 
    523   return true;
    524 }
    525 
    526 
    527 /*******************************************************************
    528  *******************************************************************/
    529342static bool prs_nk_rec( const char *desc, prs_struct *ps,
    530343                        int depth, REGF_NK_REC *nk )
     
    626439      DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, nk->rec_size));*/
    627440
    628   if ( !ps->io )
    629     nk->hbin->dirty = true;
    630  
    631441  return true;
    632 }
    633 
    634 
    635 /*******************************************************************
    636  *******************************************************************/
    637 static uint32 regf_block_checksum( prs_struct *ps )
    638 {
    639   char *buffer = ps->data_p;
    640   uint32 checksum, x;
    641   int i;
    642 
    643   /* XOR of all bytes 0x0000 - 0x01FB */
    644                
    645   checksum = x = 0;
    646        
    647   for ( i=0; i<0x01FB; i+=4 ) {
    648     x = IVAL(buffer, i );
    649     checksum ^= x;
    650   }
    651        
    652   return checksum;
    653 }
    654 
    655 
    656 /*******************************************************************
    657  *******************************************************************/
    658 static bool read_regf_block( REGF_FILE *file )
    659 {
    660   prs_struct ps;
    661   uint32 checksum;
    662        
    663   /* grab the first block from the file */
    664                
    665   if ( read_block( file, &ps, 0, REGF_BLOCKSIZE ) == -1 )
    666     return false;
    667        
    668   /* parse the block and verify the checksum */
    669        
    670   if ( !prs_regf_block( "regf_header", &ps, 0, file ) )
    671     return false;       
    672                
    673   checksum = regf_block_checksum( &ps );
    674        
    675   if(ps.is_dynamic)
    676     SAFE_FREE(ps.data_p);
    677   ps.is_dynamic = false;
    678   ps.buffer_size = 0;
    679   ps.data_offset = 0;
    680 
    681   if ( file->checksum !=  checksum ) {
    682     /*DEBUG(0,("read_regf_block: invalid checksum\n" ));*/
    683     return false;
    684   }
    685 
    686   return true;
    687 }
    688 
    689 
    690 /*******************************************************************
    691  *******************************************************************/
    692 static REGF_HBIN* read_hbin_block( REGF_FILE *file, off_t offset )
    693 {
    694   REGF_HBIN *hbin;
    695   uint32 record_size, curr_off, block_size, header;
    696        
    697   if ( !(hbin = (REGF_HBIN*)zalloc(sizeof(REGF_HBIN))) )
    698     return NULL;
    699   hbin->file_off = offset;
    700   hbin->free_off = -1;
    701                
    702   if ( read_block( file, &hbin->ps, offset, 0 ) == -1 )
    703     return NULL;
    704        
    705   if ( !prs_hbin_block( "hbin", &hbin->ps, 0, hbin ) )
    706     return NULL;       
    707 
    708   /* this should be the same thing as hbin->block_size but just in case */
    709 
    710   block_size = hbin->ps.buffer_size;
    711 
    712   /* Find the available free space offset.  Always at the end,
    713      so walk the record list and stop when you get to the end.
    714      The end is defined by a record header of 0xffffffff.  The
    715      previous 4 bytes contains the amount of free space remaining
    716      in the hbin block. */
    717 
    718   /* remember that the record_size is in the 4 bytes preceeding the record itself */
    719 
    720   if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE-sizeof(uint32) ) )
    721     return false;
    722 
    723   record_size = 0;
    724   curr_off = hbin->ps.data_offset;
    725   while ( header != 0xffffffff ) {
    726     /* not done yet so reset the current offset to the
    727        next record_size field */
    728 
    729     curr_off = curr_off+record_size;
    730 
    731     /* for some reason the record_size of the last record in
    732        an hbin block can extend past the end of the block
    733        even though the record fits within the remaining
    734        space....aaarrrgggghhhhhh */
    735 
    736     if ( curr_off >= block_size ) {
    737       record_size = -1;
    738       curr_off = -1;
    739       break;
    740     }
    741 
    742     if ( !prs_set_offset( &hbin->ps, curr_off) )
    743       return false;
    744 
    745     if ( !prs_uint32( "rec_size", &hbin->ps, 0, &record_size ) )
    746       return false;
    747     if ( !prs_uint32( "header", &hbin->ps, 0, &header ) )
    748       return false;
    749                
    750     assert( record_size != 0 );
    751 
    752     if ( record_size & 0x80000000 ) {
    753       /* absolute_value(record_size) */
    754       record_size = (record_size ^ 0xffffffff) + 1;
    755     }
    756   }
    757 
    758   /* save the free space offset */
    759 
    760   if ( header == 0xffffffff ) {
    761 
    762     /* account for the fact that the curr_off is 4 bytes behind the actual
    763        record header */
    764 
    765     hbin->free_off = curr_off + sizeof(uint32);
    766     hbin->free_size = record_size;
    767   }
    768 
    769   /*DEBUG(10,("read_hbin_block: free space offset == 0x%x\n", hbin->free_off));*/
    770 
    771   if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE )  )
    772     return false;
    773        
    774   return hbin;
    775442}
    776443
     
    824491      }
    825492
    826       hbin = read_hbin_block( file, block_off );
     493      hbin = regfi_parse_hbin(file, block_off, true, false);
    827494
    828495      if ( hbin )
     
    873540  /* move to the LF record */
    874541
    875   if ( !prs_set_offset( &hbin->ps, nk->subkeys_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
     542  if ( !prs_set_offset( &hbin->ps, nk->subkeys_off + HBIN_MAGIC_SIZE - hbin->first_hbin_off ) )
    876543    return false;
    877544
     
    909576    /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, lf->rec_size));*/
    910577
    911   if ( !hbin->ps.io )
    912     hbin->dirty = true;
    913 
    914578  return true;
    915579}
     
    927591  depth++;
    928592
    929   if ( !prs_set_offset( &hbin->ps, sk->sk_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
     593  if ( !prs_set_offset( &hbin->ps, sk->sk_off + HBIN_MAGIC_SIZE - hbin->first_hbin_off ) )
    930594    return false;
    931595
     
    962626  /*  if ( data_size > sk->rec_size )*/
    963627    /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, sk->rec_size));*/
    964 
    965   if ( !hbin->ps.io )
    966     hbin->dirty = true;
    967628
    968629  return true;
     
    1050711      if (!(prs_set_offset(&hblock->ps,
    1051712                           (vk->data_off
    1052                             + HBIN_HDR_SIZE
     713                            + HBIN_MAGIC_SIZE
    1053714                            - hblock->first_hbin_off)
    1054715                           - sizeof(uint32))))
     
    1066727        return false;
    1067728
    1068       if ( !hblock->ps.io )
    1069         hblock->dirty = true;
    1070729    }
    1071730    else
     
    1085744    DEBUG(10,("prs_vk_rec: data_size check failed (0x%x < 0x%x)\n", data_size, vk->rec_size));*/
    1086745
    1087   if ( !hbin->ps.io )
    1088     hbin->dirty = true;
    1089 
    1090746  return true;
    1091747}
     
    1118774  if (!prs_set_offset(&hbin->ps,
    1119775                      nk->values_off
    1120                       + HBIN_HDR_SIZE
     776                      + HBIN_MAGIC_SIZE
    1121777                      - hbin->first_hbin_off
    1122778                      - sizeof(uint32)))
     
    1155811       
    1156812    new_offset = nk->values[i].rec_off
    1157       + HBIN_HDR_SIZE
     813      + HBIN_MAGIC_SIZE
    1158814      - sub_hbin->first_hbin_off;
    1159815
     
    1163819      return false;
    1164820  }
    1165 
    1166   if ( !hbin->ps.io )
    1167     hbin->dirty = true;
    1168821
    1169822  return true;
     
    1299952  curr_off = ps->data_offset;
    1300953  if ( curr_off == 0 )
    1301     prs_set_offset( ps, HBIN_HEADER_REC_SIZE );
     954    prs_set_offset( ps, HBIN_HEADER_REC_SIZE+4 );
    1302955
    1303956  /* assume that the current offset is at the reacord header
     
    13621015
    13631016/*******************************************************************
    1364  Open the registry file and then read in the REGF block to get the
    1365  first hbin offset.
    1366 *******************************************************************/
    1367 REGF_FILE* regfi_open( const char *filename )
    1368 {
    1369   REGF_FILE *rb;
     1017 * Open the registry file and then read in the REGF block to get the
     1018 * first hbin offset.
     1019 *******************************************************************/
     1020REGF_FILE* regfi_open(const char* filename)
     1021{
     1022  REGF_FILE* rb;
     1023  int fd;
    13701024  int flags = O_RDONLY;
    13711025
    1372   if ( !(rb = (REGF_FILE*)malloc(sizeof(REGF_FILE))) ) {
    1373     /* DEBUG(0,("ERROR allocating memory\n")); */
    1374     return NULL;
    1375   }
    1376   memset(rb, 0, sizeof(REGF_FILE));
    1377   rb->fd = -1;
    1378        
    1379   /*    if ( !(rb->mem_ctx = talloc_init( "read_regf_block" )) )
    1380     {
    1381     regfi_close( rb );
    1382     return NULL;
    1383     }
    1384   */
    1385   rb->open_flags = flags;
    1386        
    1387   /* open and existing file */
    1388 
    1389   if ( (rb->fd = open(filename, flags)) == -1 ) {
     1026  /* open an existing file */
     1027  if ((fd = open(filename, flags)) == -1)
     1028  {
    13901029    /* DEBUG(0,("regfi_open: failure to open %s (%s)\n", filename, strerror(errno)));*/
    1391     regfi_close( rb );
    13921030    return NULL;
    13931031  }
    13941032       
    13951033  /* read in an existing file */
    1396        
    1397   if ( !read_regf_block( rb ) ) {
     1034  if ((rb = regfi_parse_regf(fd, true)) == NULL)
     1035  {
    13981036    /* DEBUG(0,("regfi_open: Failed to read initial REGF block\n"));*/
    1399     regfi_close( rb );
     1037    close(fd);
    14001038    return NULL;
    14011039  }
    14021040       
    14031041  /* success */
    1404        
    14051042  return rb;
    14061043}
     
    14661103     block (but I'm not assuming that for now) */
    14671104       
    1468   while ( (hbin = read_hbin_block( file, offset )) ) {
     1105  while ( (hbin = regfi_parse_hbin(file, offset, true, false)) ) {
    14691106    eob = false;
    14701107
     
    17541391 
    17551392  if(!prs_set_offset(&hbin->ps,
    1756                      HBIN_HDR_SIZE + nk_offset - hbin->first_hbin_off))
     1393                     HBIN_MAGIC_SIZE + nk_offset - hbin->first_hbin_off))
    17571394    return NULL;
    17581395               
     
    18481485  return ret_val;
    18491486}
     1487
     1488
     1489
     1490/****************/
     1491/* Experimental */
     1492/****************/
     1493/*
     1494typedef struct {
     1495  uint32 offset;
     1496  uint32 size;
     1497} REGFI_CELL_INFO;
     1498
     1499typedef struct {
     1500  uint32 count
     1501  REGFI_CELL_INFO** cells;
     1502} REGFI_CELL_LIST;
     1503*/
     1504
     1505
     1506/*******************************************************************
     1507 * Computes the checksum of the registry file header.
     1508 * buffer must be at least the size of an regf header (4096 bytes).
     1509 *******************************************************************/
     1510static uint32 regfi_compute_header_checksum(uint8* buffer)
     1511{
     1512  uint32 checksum, x;
     1513  int i;
     1514
     1515  /* XOR of all bytes 0x0000 - 0x01FB */
     1516
     1517  checksum = x = 0;
     1518 
     1519  for ( i=0; i<0x01FB; i+=4 ) {
     1520    x = IVAL(buffer, i );
     1521    checksum ^= x;
     1522  }
     1523 
     1524  return checksum;
     1525}
     1526
     1527
     1528/*******************************************************************
     1529 * TODO: add way to return more detailed error information.
     1530 *******************************************************************/
     1531REGF_FILE* regfi_parse_regf(int fd, bool strict)
     1532{
     1533  uint8 file_header[REGF_BLOCKSIZE];
     1534  uint32 ret, length;
     1535  uint32 file_length;
     1536  struct stat sbuf;
     1537  REGF_FILE* ret_val;
     1538
     1539  /* Determine file length.  Must be at least big enough
     1540   * for the header and one hbin.
     1541   */
     1542  if (fstat(fd, &sbuf) == -1)
     1543    return NULL;
     1544  file_length = sbuf.st_size;
     1545  if(file_length < REGF_BLOCKSIZE+REGF_ALLOC_BLOCK)
     1546    return NULL;
     1547
     1548  ret_val = (REGF_FILE*)zalloc(sizeof(REGF_FILE));
     1549  if(ret_val == NULL)
     1550    return NULL;
     1551
     1552  ret_val->fd = fd;
     1553  ret_val->file_length = file_length;
     1554
     1555  length = REGF_BLOCKSIZE;
     1556  if((ret = regfi_read(fd, file_header, &length)) != 0
     1557     || length != REGF_BLOCKSIZE)
     1558  {
     1559    free(ret_val);
     1560    return NULL;
     1561  }
     1562
     1563  ret_val->checksum = IVAL(file_header, 0x1FC);
     1564  ret_val->computed_checksum = regfi_compute_header_checksum(file_header);
     1565  if (strict && (ret_val->checksum != ret_val->computed_checksum))
     1566  {
     1567    free(ret_val);
     1568    return NULL;
     1569  }
     1570
     1571  memcpy(ret_val->magic, file_header, 4);
     1572  if(strict && (memcmp(ret_val->magic, "regf", 4) != 0))
     1573  {
     1574    free(ret_val);
     1575    return NULL;
     1576  }
     1577 
     1578  ret_val->unknown1 = IVAL(file_header, 0x4);
     1579  ret_val->unknown2 = IVAL(file_header, 0x8);
     1580
     1581  ret_val->mtime.low = IVAL(file_header, 0xC);
     1582  ret_val->mtime.high = IVAL(file_header, 0x10);
     1583
     1584  ret_val->unknown3 = IVAL(file_header, 0x14);
     1585  ret_val->unknown4 = IVAL(file_header, 0x18);
     1586  ret_val->unknown5 = IVAL(file_header, 0x1C);
     1587  ret_val->unknown6 = IVAL(file_header, 0x20);
     1588 
     1589  ret_val->data_offset = IVAL(file_header, 0x24);
     1590  ret_val->last_block = IVAL(file_header, 0x28);
     1591
     1592  ret_val->unknown7 = IVAL(file_header, 0x2C);
     1593
     1594  return ret_val;
     1595}
     1596
     1597
     1598
     1599/*******************************************************************
     1600 * Given real file offset, read and parse the hbin at that location
     1601 * along with it's associated cells.  If save_unalloc is true, a list
     1602 * of unallocated cell offsets will be stored in TODO.
     1603 *******************************************************************/
     1604/* TODO: Need a way to return types of errors.  Also need to free
     1605 *       the hbin/ps when an error occurs.
     1606 */
     1607REGF_HBIN* regfi_parse_hbin(REGF_FILE* file, uint32 offset,
     1608                            bool strict, bool save_unalloc)
     1609{
     1610  REGF_HBIN *hbin;
     1611  uint8 hbin_header[HBIN_HEADER_REC_SIZE];
     1612  uint32 length, curr_off;
     1613  int32 cell_len;
     1614  bool is_unalloc;
     1615
     1616  if(!(hbin = (REGF_HBIN*)zalloc(sizeof(REGF_HBIN))))
     1617    return NULL;
     1618  hbin->file_off = offset;
     1619 
     1620  if(lseek(file->fd, offset, SEEK_SET) == -1)
     1621    return NULL;
     1622
     1623  length = HBIN_HEADER_REC_SIZE;
     1624  if((regfi_read(file->fd, hbin_header, &length) != 0)
     1625     || length != HBIN_HEADER_REC_SIZE)
     1626    return NULL;
     1627
     1628  if(lseek(file->fd, offset, SEEK_SET) == -1)
     1629    return NULL;
     1630
     1631  memcpy(hbin->magic, hbin_header, 4);
     1632  if(strict && (memcmp(hbin->magic, "hbin", 4) != 0))
     1633    return NULL;
     1634
     1635  hbin->first_hbin_off = IVAL(hbin_header, 0x4);
     1636  hbin->block_size = IVAL(hbin_header, 0x8);
     1637  /* this should be the same thing as hbin->block_size but just in case */
     1638  hbin->next_block = IVAL(hbin_header, 0x1C);
     1639
     1640
     1641  /* TODO: This check is this more of a way to determine if they are ever
     1642   *       not the same than to really do sanity checking.  This may need
     1643   *       to be changed or removed once these fields are better understood. */
     1644  if(strict && (hbin->block_size != hbin->next_block))
     1645  {
     1646    fprintf(stderr, "DEBUG: hbin->block_size != hbin->next_block\n");
     1647    return NULL;
     1648  }
     1649
     1650
     1651  /* Ensure the block size is a multiple of 0x1000 and doesn't run off
     1652   * the end of the file.
     1653   */
     1654  /* TODO: This may need to be relaxed for dealing with
     1655   *       partial or corrupt files. */
     1656  if((offset + hbin->block_size > file->file_length)
     1657     || (hbin->block_size & 0xFFFFF000) != hbin->block_size)
     1658    return NULL;
     1659
     1660
     1661  /* TODO: need to get rid of this, but currently lots depends on the
     1662   * ps structure.
     1663   */
     1664  if(!prs_init(&hbin->ps, hbin->block_size, file->mem_ctx, UNMARSHALL))
     1665    return NULL;
     1666  length = hbin->block_size;
     1667  if((regfi_read(file->fd, (uint8*)hbin->ps.data_p, &length) != 0)
     1668     || length != hbin->block_size)
     1669    return NULL;
     1670
     1671
     1672  if(save_unalloc)
     1673  {
     1674    is_unalloc = false;
     1675    cell_len = 0;
     1676    curr_off = HBIN_HEADER_REC_SIZE;
     1677    while ( curr_off < hbin->block_size )
     1678    {
     1679      cell_len = IVALS(hbin->ps.data_p, curr_off);
     1680     
     1681      if(cell_len > 0)
     1682        is_unalloc = true;
     1683      else
     1684        cell_len = -1*cell_len;
     1685
     1686      if((cell_len == 0) || ((cell_len & 0xFFFFFFFC) != cell_len))
     1687        /* TODO: should report an error here. */
     1688        break;
     1689
     1690      /* for some reason the record_size of the last record in
     1691         an hbin block can extend past the end of the block
     1692         even though the record fits within the remaining
     1693         space....aaarrrgggghhhhhh */ 
     1694      if(curr_off + cell_len >= hbin->block_size)
     1695        cell_len = hbin->block_size - curr_off;
     1696
     1697      if(is_unalloc)
     1698        /* TODO: save cell info */
     1699
     1700      curr_off = curr_off+cell_len;
     1701    }
     1702  }
     1703
     1704  /* TODO: need to get rid of this, but currently lots depends on the
     1705   * ps structure.
     1706   */
     1707  if(!prs_set_offset(&hbin->ps, file->data_offset+HBIN_MAGIC_SIZE))
     1708    return NULL;
     1709
     1710  return hbin;
     1711}
     1712
     1713
     1714/*****************************************************************************
     1715 * This function is just like read(2), except that it continues to
     1716 * re-try reading from the file descriptor if EINTR or EAGAIN is received. 
     1717 * regfi_read will attempt to read length bytes from fd and write them to buf.
     1718 *
     1719 * On success, 0 is returned.  Upon failure, an errno code is returned.
     1720 *
     1721 * The number of bytes successfully read is returned through the length
     1722 * parameter by reference.  If both the return value and length parameter are
     1723 * returned as 0, then EOF was encountered immediately
     1724 *****************************************************************************/
     1725uint32 regfi_read(int fd, uint8* buf, uint32* length)
     1726{
     1727  uint32 rsize = 0;
     1728  uint32 rret = 0;
     1729
     1730  do
     1731  {
     1732    rret = read(fd, buf + rsize, *length - rsize);
     1733    if(rret > 0)
     1734      rsize += rret;
     1735  }while(*length - rsize > 0
     1736         && (rret > 0 || (rret == -1 && (errno == EAGAIN || errno == EINTR))));
     1737 
     1738  *length = rsize;
     1739  if (rret == -1 && errno != EINTR && errno != EAGAIN)
     1740    return errno;
     1741
     1742  return 0;
     1743}
  • trunk/src/reglookup.c

    r93 r97  
    754754
    755755
     756/* XXX: what if there is BOTH a value AND a key with that name?? */
    756757/*
    757758 * Returns 0 if path was not found.
Note: See TracChangeset for help on using the changeset viewer.