Changeset 139


Ignore:
Timestamp:
02/08/09 22:06:16 (16 years ago)
Author:
tim
Message:

rewrote subkey list parsing code to include more organized recursion and parsing as well as improved sanity checking

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/regfi.h

    r138 r139  
    8282#define REGFI_OFFSET_NONE          0xffffffff
    8383
     84/* XXX: This is totally arbitrary right now. */
     85#define REGFI_MAX_SUBKEY_DEPTH     255   
     86
    8487/* Header sizes and magic number lengths for various records */
    8588#define REGFI_REGF_MAGIC_SIZE      4
     
    171174typedef struct
    172175{
    173   uint32 nk_off;
     176  /* Virtual offset of NK record or additional subkey list,
     177   * depending on this list's type.
     178   */
     179  uint32 offset;
     180
    174181  uint32 hash;
    175182} REGFI_SUBKEY_LIST_ELEM;
     
    178185typedef struct
    179186{
    180   uint32 offset;        /* Real offset of this record's cell in the file */
    181   uint32 cell_size;      /* ((start_offset - end_offset) & 0xfffffff8) */
    182   uint32 num_keys;
     187  /* Real offset of this record's cell in the file */
     188  uint32 offset;
     189
     190  uint32 cell_size;
     191 
     192  /* Number of immediate children */
     193  uint32 num_children; 
     194
     195  /* Total number of keys referenced by this list and it's children */
     196  uint32 num_keys;     
     197
    183198  REGFI_SUBKEY_LIST_ELEM* elements;
    184  
    185199  uint8 magic[REGFI_CELL_MAGIC_SIZE];
     200
     201  /* Set if the magic indicates this subkey list points to child subkey lists */
     202  bool recursive_type; 
    186203} REGFI_SUBKEY_LIST;
    187204
     
    427444                                     uint32 max_size, bool strict);
    428445
     446REGFI_SUBKEY_LIST*    regfi_parse_subkeylist(REGFI_FILE* file, uint32 offset,
     447                                             uint32 max_size, bool strict);
     448
    429449REGFI_VK_REC*         regfi_parse_vk(REGFI_FILE* file, uint32 offset,
    430450                                     uint32 max_size, bool strict);
     
    467487                                              REGFI_SUBKEY_LIST** lists,
    468488                                              bool strict);
     489REGFI_SUBKEY_LIST*    regfi_load_subkeylist_aux(REGFI_FILE* file, uint32 offset,
     490                                                uint32 max_size, bool strict,
     491                                                uint8 depth_left);
    469492void                  regfi_add_message(REGFI_FILE* file, uint16 msg_type,
    470493                                        const char* fmt, ...);
  • trunk/lib/regfi.c

    r138 r139  
    508508
    509509
     510
     511/******************************************************************************
     512 ******************************************************************************/
     513REGFI_SUBKEY_LIST* regfi_load_subkeylist(REGFI_FILE* file, uint32 offset,
     514                                         uint32 num_keys, uint32 max_size,
     515                                         bool strict)
     516{
     517  REGFI_SUBKEY_LIST* ret_val;
     518
     519  ret_val = regfi_load_subkeylist_aux(file, offset, max_size, strict,
     520                                      REGFI_MAX_SUBKEY_DEPTH);
     521
     522  if(num_keys != ret_val->num_keys)
     523  {
     524    /*  Not sure which should be authoritative, the number from the
     525     *  NK record, or the number in the subkey list.  Just emit a warning for
     526     *  now if they don't match.
     527     */
     528    regfi_add_message(file, REGFI_MSG_WARN, "Number of subkeys listed in parent"
     529                      " (%d) did not match number found in subkey list/tree (%d)"
     530                      " while parsing subkey list/tree at offset 0x%.8X.",
     531                      num_keys, ret_val->num_keys, offset);
     532  }
     533
     534  return ret_val;
     535}
     536
     537
     538/******************************************************************************
     539 ******************************************************************************/
     540REGFI_SUBKEY_LIST* regfi_load_subkeylist_aux(REGFI_FILE* file, uint32 offset,
     541                                             uint32 max_size, bool strict,
     542                                             uint8 depth_left)
     543{
     544  REGFI_SUBKEY_LIST* ret_val;
     545  REGFI_SUBKEY_LIST** sublists;
     546  REGFI_HBIN* sublist_hbin;
     547  uint32 i, num_sublists, off, max_length;
     548
     549  if(depth_left == 0)
     550  {
     551    regfi_add_message(file, REGFI_MSG_WARN, "Maximum depth reached"
     552                      " while parsing subkey list/tree at offset 0x%.8X.",
     553                      offset);
     554    return NULL;
     555  }
     556
     557  ret_val = regfi_parse_subkeylist(file, offset, max_size, strict);
     558  if(ret_val == NULL)
     559    return NULL;
     560
     561  if(ret_val->recursive_type)
     562  {
     563    num_sublists = ret_val->num_children;
     564    sublists = (REGFI_SUBKEY_LIST**)zalloc(num_sublists
     565                                           * sizeof(REGFI_SUBKEY_LIST*));
     566    for(i=0; i < num_sublists; i++)
     567    {
     568      off = ret_val->elements[i].offset + REGFI_REGF_SIZE;
     569      sublist_hbin = regfi_lookup_hbin(file, ret_val->elements[i].offset);
     570      if(sublist_hbin == NULL)
     571        sublists[i] = NULL;
     572      else
     573      {
     574        max_length = sublist_hbin->block_size + sublist_hbin->file_off - off;
     575        sublists[i] = regfi_load_subkeylist_aux(file, off, max_length, strict,
     576                                                depth_left-1);
     577      }
     578    }
     579    free(ret_val);
     580
     581    return regfi_merge_subkeylists(num_sublists, sublists, strict);
     582  }
     583
     584  return ret_val;
     585}
     586
     587
     588/******************************************************************************
     589 ******************************************************************************/
     590REGFI_SUBKEY_LIST* regfi_parse_subkeylist(REGFI_FILE* file, uint32 offset,
     591                                          uint32 max_size, bool strict)
     592{
     593  REGFI_SUBKEY_LIST* ret_val;
     594  uint32 i, cell_length, length, elem_size;
     595  uint8* elements;
     596  uint8 buf[REGFI_SUBKEY_LIST_MIN_LEN];
     597  bool unalloc;
     598  bool recursive_type;
     599
     600  if(!regfi_parse_cell(file->fd, offset, buf, REGFI_SUBKEY_LIST_MIN_LEN,
     601                       &cell_length, &unalloc))
     602  {
     603    regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while "
     604                      "parsing subkey-list at offset 0x%.8X.", offset);
     605    return NULL;
     606  }
     607
     608  if(cell_length > max_size)
     609  {
     610    regfi_add_message(file, REGFI_MSG_WARN, "Cell size longer than max_size"
     611                      " while parsing subkey-list at offset 0x%.8X.", offset);
     612    if(strict)
     613      return NULL;
     614    cell_length = max_size & 0xFFFFFFF8;
     615  }
     616
     617  recursive_type = false;
     618  if(buf[0] == 'r' && buf[1] == 'i')
     619  {
     620    recursive_type = true;
     621    elem_size = sizeof(uint32);
     622  }
     623  else if(buf[0] == 'l' && buf[1] == 'i')
     624    elem_size = sizeof(uint32);
     625  else if((buf[0] == 'l') && (buf[1] == 'f' || buf[1] == 'h'))
     626    elem_size = sizeof(REGFI_SUBKEY_LIST_ELEM);
     627  else
     628  {
     629    regfi_add_message(file, REGFI_MSG_ERROR, "Unknown magic number"
     630                      " (0x%.2X, 0x%.2X) encountered while parsing"
     631                      " subkey-list at offset 0x%.8X.", buf[0], buf[1], offset);
     632    return NULL;
     633  }
     634
     635  ret_val = (REGFI_SUBKEY_LIST*)zalloc(sizeof(REGFI_SUBKEY_LIST));
     636  if(ret_val == NULL)
     637    return NULL;
     638
     639  ret_val->offset = offset;
     640  ret_val->cell_size = cell_length;
     641  ret_val->magic[0] = buf[0];
     642  ret_val->magic[1] = buf[1];
     643  ret_val->recursive_type = recursive_type;
     644  ret_val->num_children = SVAL(buf, 0x2);
     645
     646  if(!recursive_type)
     647    ret_val->num_keys = ret_val->num_children;
     648
     649  length = elem_size*ret_val->num_children;
     650  if(cell_length - REGFI_SUBKEY_LIST_MIN_LEN - sizeof(uint32) < length)
     651  {
     652    regfi_add_message(file, REGFI_MSG_WARN, "Number of elements too large for"
     653                      " cell while parsing subkey-list at offset 0x%.8X.",
     654                      offset);
     655    if(strict)
     656    {
     657      free(ret_val);
     658      return NULL;
     659    }
     660    length = cell_length - REGFI_SUBKEY_LIST_MIN_LEN - sizeof(uint32);
     661  }
     662
     663  ret_val->elements
     664    = (REGFI_SUBKEY_LIST_ELEM*)zalloc(ret_val->num_children
     665                                      * sizeof(REGFI_SUBKEY_LIST_ELEM));
     666  if(ret_val->elements == NULL)
     667  {
     668    free(ret_val);
     669    return NULL;
     670  }
     671
     672  elements = (uint8*)zalloc(length);
     673  if(elements == NULL)
     674  {
     675    free(ret_val->elements);
     676    free(ret_val);
     677    return NULL;
     678  }
     679
     680  if(regfi_read(file->fd, elements, &length) != 0
     681     || length != elem_size*ret_val->num_children)
     682  {
     683    free(ret_val->elements);
     684    free(ret_val);
     685    return NULL;
     686  }
     687
     688  if(elem_size == sizeof(uint32))
     689  {
     690    for (i=0; i < ret_val->num_children; i++)
     691    {
     692      ret_val->elements[i].offset = IVAL(elements, i*elem_size);
     693      ret_val->elements[i].hash = 0;
     694    }
     695  }
     696  else
     697  {
     698    for (i=0; i < ret_val->num_children; i++)
     699    {
     700      ret_val->elements[i].offset = IVAL(elements, i*elem_size);
     701      ret_val->elements[i].hash = IVAL(elements, i*elem_size+4);
     702    }
     703  }
     704  free(elements);
     705
     706  return ret_val;
     707}
     708
     709
    510710/*******************************************************************
    511711 *******************************************************************/
    512712REGFI_SUBKEY_LIST* regfi_merge_subkeylists(uint16 num_lists,
    513                                           REGFI_SUBKEY_LIST** lists,
    514                                           bool strict)
     713                                           REGFI_SUBKEY_LIST** lists,
     714                                           bool strict)
    515715{
    516716  uint32 i,j,k;
     
    528728  for(i=0; i < num_lists; i++)
    529729  {
    530     if(lists[i] == NULL)
    531     {
    532       free(ret_val);
    533       free(lists);
    534       return NULL;
    535     }
    536     ret_val->num_keys += lists[i]->num_keys;
    537   }
    538  
     730    if(lists[i] != NULL)
     731      ret_val->num_keys += lists[i]->num_children;
     732  }
     733  ret_val->num_children = ret_val->num_keys;
     734
    539735  if(ret_val->num_keys > 0)
    540736  {
     
    546742    if(ret_val->elements != NULL)
    547743    {
    548       for(i=0; i<num_lists; i++)
    549         for(j=0; j<lists[i]->num_keys; j++)
     744      for(i=0; i < num_lists; i++)
     745      {
     746        if(lists[i] != NULL)
    550747        {
    551           ret_val->elements[k].hash=lists[i]->elements[j].hash;
    552           ret_val->elements[k++].nk_off=lists[i]->elements[j].nk_off;
     748          for(j=0; j < lists[i]->num_keys; j++)
     749          {
     750            ret_val->elements[k].hash=lists[i]->elements[j].hash;
     751            ret_val->elements[k++].offset=lists[i]->elements[j].offset;
     752          }
    553753        }
     754      }
    554755    }
    555756  }
     
    561762  return ret_val;
    562763}
    563 
    564 
    565 
    566 /*******************************************************************
    567  *******************************************************************/
    568 REGFI_SUBKEY_LIST* regfi_load_subkeylist(REGFI_FILE* file, uint32 offset,
    569                                         uint32 num_keys, uint32 max_size,
    570                                         bool strict)
    571 {
    572   REGFI_SUBKEY_LIST* ret_val;
    573   REGFI_SUBKEY_LIST** sublists;
    574   REGFI_HBIN* sublist_hbin;
    575   uint32 i, cell_length, length, num_sublists, off, max_length, elem_size;
    576   uint8* hashes;
    577   uint8 buf[REGFI_SUBKEY_LIST_MIN_LEN];
    578   bool unalloc;
    579 
    580   if(!regfi_parse_cell(file->fd, offset, buf, REGFI_SUBKEY_LIST_MIN_LEN,
    581                        &cell_length, &unalloc))
    582     return NULL;
    583 
    584   if(cell_length > max_size)
    585   {
    586     if(strict)
    587       return NULL;
    588     cell_length = max_size & 0xFFFFFFF8;
    589   }
    590 
    591   if(buf[0] == 'r' && buf[1] == 'i')
    592   {
    593     num_sublists = SVAL(buf, 0x2);
    594 
    595     /* XXX: check cell_length vs num_sublists vs max_length */
    596     length = num_sublists*sizeof(uint32);
    597     hashes = (uint8*)zalloc(length);
    598     if(hashes == NULL)
    599       return NULL;
    600 
    601     if(regfi_read(file->fd, hashes, &length) != 0
    602        || length != num_sublists*sizeof(uint32))
    603     {
    604       free(hashes);
    605       return NULL;
    606     }
    607 
    608     sublists = (REGFI_SUBKEY_LIST**)zalloc(num_sublists*sizeof(REGFI_SUBKEY_LIST*));   
    609     for(i=0; i < num_sublists; i++)
    610     {
    611       off = IVAL(hashes, i*4)+REGFI_REGF_SIZE;
    612       sublist_hbin = regfi_lookup_hbin(file, IVAL(hashes, i*4));
    613       max_length = sublist_hbin->block_size + sublist_hbin->file_off - off;
    614 
    615       /* XXX: Need to add a recursion depth limit of some kind. */
    616       sublists[i] = regfi_load_subkeylist(file, off, 0, max_length, strict);
    617     }
    618     free(hashes);
    619 
    620     return regfi_merge_subkeylists(num_sublists, sublists, strict);
    621   }
    622 
    623   if(buf[0] == 'l' && buf[1] == 'i')
    624     elem_size = sizeof(uint32);
    625   else if((buf[0] == 'l') && (buf[1] == 'f' || buf[1] == 'h'))
    626     elem_size = sizeof(REGFI_SUBKEY_LIST_ELEM);
    627   else
    628   {
    629     /* fprintf(stderr, "DEBUG: lf->header=%c%c\n", buf[0], buf[1]);*/
    630     return NULL;
    631   }
    632 
    633   ret_val = (REGFI_SUBKEY_LIST*)zalloc(sizeof(REGFI_SUBKEY_LIST));
    634   if(ret_val == NULL)
    635     return NULL;
    636 
    637   ret_val->offset = offset;
    638   ret_val->cell_size = cell_length;
    639   ret_val->magic[0] = buf[0];
    640   ret_val->magic[1] = buf[1];
    641 
    642   ret_val->num_keys = SVAL(buf, 0x2);
    643   if(num_keys != ret_val->num_keys)
    644   {
    645     /*  Not sure which should be authoritative, the number from the
    646      *  NK record, or the number in the subkey list.  Go with the larger
    647      *  of the two to ensure all keys are found, since in 'ri' records,
    648      *  there is no authoritative parent count for a leaf subkey list. 
    649      *  Note the length checks on the cell later ensure that there won't
    650      *  be any critical errors.
    651      */
    652     if(num_keys < ret_val->num_keys)
    653       num_keys = ret_val->num_keys;
    654     else
    655       ret_val->num_keys = num_keys;
    656   }
    657 
    658   if(cell_length - REGFI_SUBKEY_LIST_MIN_LEN - sizeof(uint32)
    659      < ret_val->num_keys*elem_size)
    660   {
    661     free(ret_val);
    662     return NULL;
    663   }
    664 
    665   length = elem_size*ret_val->num_keys;
    666   ret_val->elements
    667     = (REGFI_SUBKEY_LIST_ELEM*)zalloc(ret_val->num_keys
    668                                      * sizeof(REGFI_SUBKEY_LIST_ELEM));
    669   if(ret_val->elements == NULL)
    670   {
    671     free(ret_val);
    672     return NULL;
    673   }
    674 
    675   hashes = (uint8*)zalloc(length);
    676   if(hashes == NULL)
    677   {
    678     free(ret_val->elements);
    679     free(ret_val);
    680     return NULL;
    681   }
    682 
    683   if(regfi_read(file->fd, hashes, &length) != 0
    684      || length != elem_size*ret_val->num_keys)
    685   {
    686     free(ret_val->elements);
    687     free(ret_val);
    688     return NULL;
    689   }
    690 
    691   if(buf[0] == 'l' && buf[1] == 'i')
    692   {
    693     for (i=0; i < ret_val->num_keys; i++)
    694     {
    695       ret_val->elements[i].nk_off = IVAL(hashes, i*elem_size);
    696       ret_val->elements[i].hash = 0;
    697     }
    698   }
    699   else
    700   {
    701     for (i=0; i < ret_val->num_keys; i++)
    702     {
    703       ret_val->elements[i].nk_off = IVAL(hashes, i*elem_size);
    704       ret_val->elements[i].hash = IVAL(hashes, i*elem_size+4);
    705     }
    706   }
    707   free(hashes);
    708 
    709   return ret_val;
    710 }
    711 
    712764
    713765
     
    15041556    return NULL;
    15051557
    1506   nk_offset = i->cur_key->subkeys->elements[i->cur_subkey].nk_off;
     1558  nk_offset = i->cur_key->subkeys->elements[i->cur_subkey].offset;
    15071559
    15081560  return regfi_load_key(i->f, nk_offset+REGFI_REGF_SIZE, true);
Note: See TracChangeset for help on using the changeset viewer.