Changeset 152


Ignore:
Timestamp:
06/02/09 16:00:38 (16 years ago)
Author:
tim
Message:

preliminary support for big data records

switched to using key flags rather than incorrect key types

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/regfi.h

    r151 r152  
    9696#define REGFI_REGF_MAGIC_SIZE      4
    9797#define REGFI_REGF_NAME_SIZE       64
    98 
    9998#define REGFI_REGF_RESERVED1_SIZE  340
    10099#define REGFI_REGF_RESERVED2_SIZE  3528
    101 
    102100#define REGFI_HBIN_MAGIC_SIZE      4
    103101#define REGFI_CELL_MAGIC_SIZE      2
     
    127125
    128126/* Flags for the vk records */
     127/* XXX: This next flag may be incorrect.  According to Jeffrey Muir,
     128*       this may actually indicate that the value name is stored in
     129*       UTF-16LE.
     130*/
    129131#define REGFI_VK_FLAG_NAME_PRESENT 0x0001
    130132#define REGFI_VK_DATA_IN_OFFSET    0x80000000
    131 #define REGFI_VK_MAX_DATA_LENGTH   1024*1024
    132 
    133 
    134 /* NK record types */
    135 /* XXX: This is starting to look like this is a flags field. 
    136  *      Need to decipher the meaning of each flag.
    137  */
    138 #define REGFI_NK_TYPE_LINKKEY      0x0010
    139 #define REGFI_NK_TYPE_NORMALKEY    0x0020
    140  /* XXX: Unknown key type that shows up in Vista registries */
    141 #define REGFI_NK_TYPE_UNKNOWN1     0x1020
    142  /* XXX: Unknown key types that shows up in W2K3 registries */
    143 #define REGFI_NK_TYPE_UNKNOWN2     0x4020
    144 #define REGFI_NK_TYPE_UNKNOWN3     0x0000  /* XXX: This type seems to have UTF-16 names!!! */
    145 #define REGFI_NK_TYPE_ROOTKEY1     0x002c
    146  /* XXX: Unknown root key type that shows up in Vista registries */
    147 #define REGFI_NK_TYPE_ROOTKEY2     0x00ac
    148 
    149 #if 0
    150 /* Initial hypothesis of NK flags: */
    151 /***********************************/
    152 #define REGFI_NK_FLAG_LINK         0x0010
    153 /* The name will be in ASCII if this next bit is set, otherwise UTF-16LE */
    154 #define REGFI_NK_FLAG_ASCIINAME    0x0020
    155 /* These next two combine to form the "c" on both known root key types */
    156 #define REGFI_NK_FLAG_ROOT1        0x0008
    157 #define REGFI_NK_FLAG_ROOT2        0x0004
     133#define REGFI_VK_MAX_DATA_LENGTH   1024*1024  /* XXX: This is arbitrary */
     134
     135
     136/* Known key flags */
     137/*******************/
    158138/* These next two show up on normal-seeming keys in Vista and W2K3 registries */
    159139#define REGFI_NK_FLAG_UNKNOWN1     0x4000
    160140#define REGFI_NK_FLAG_UNKNOWN2     0x1000
     141
    161142/* This next one shows up on root keys in some Vista "software" registries */
    162143#define REGFI_NK_FLAG_UNKNOWN3     0x0080
    163 #endif
    164 
     144
     145/* Predefined handle.  Rumor has it that the valuelist count for this key is
     146 * where the handle is stored.
     147 * http://msdn.microsoft.com/en-us/library/ms724836(VS.85).aspx
     148 */
     149#define REGFI_NK_FLAG_PREDEF_KEY   0x0040
     150
     151/* The name will be in ASCII if this next bit is set, otherwise UTF-16LE */
     152#define REGFI_NK_FLAG_ASCIINAME    0x0020
     153
     154/* Symlink key. 
     155 * See: http://www.codeproject.com/KB/system/regsymlink.aspx
     156 */
     157#define REGFI_NK_FLAG_LINK         0x0010
     158
     159/* This key cannot be deleted */
     160#define REGFI_NK_FLAG_NO_RM        0x0008
     161
     162/* Root of a hive */
     163#define REGFI_NK_FLAG_ROOT         0x0004
     164
     165/* Mount point of another hive.  NULL/(default) value indicates which hive
     166 * and where in the hive it points to.
     167 */
     168#define REGFI_NK_FLAG_HIVE_LINK    0x0002
     169
     170/* These keys shouldn't be stored on disk, according to:
     171 * http://geekswithblogs.net/sdorman/archive/2007/12/24/volatile-registry-keys.aspx
     172 */
     173#define REGFI_NK_FLAG_VOLATILE     0x0001
     174
     175/* Useful for identifying unknown flag types */
     176#define REGFI_NK_KNOWN_FLAGS       (REGFI_NK_FLAG_PREDEF_KEY\
     177                                    | REGFI_NK_FLAG_ASCIINAME\
     178                                    | REGFI_NK_FLAG_LINK\
     179                                    | REGFI_NK_FLAG_NO_RM\
     180                                    | REGFI_NK_FLAG_ROOT\
     181                                    | REGFI_NK_FLAG_HIVE_LINK\
     182                                    | REGFI_NK_FLAG_VOLATILE\
     183                                    | REGFI_NK_FLAG_UNKNOWN1\
     184                                    | REGFI_NK_FLAG_UNKNOWN2)
    165185
    166186/* HBIN block */
     
    350370
    351371  NTTIME mtime;
    352   uint32 major_version;  /* XXX: Unverified. Set to 1 in all known hives */
    353   uint32 minor_version;  /* XXX: Unverified. Set to 3 or 5 in all known hives */
     372  uint32 major_version;  /* Set to 1 in all known hives */
     373  uint32 minor_version;  /* Set to 3 or 5 in all known hives */
    354374  uint32 type;           /* XXX: Unverified.  Set to 0 in all known hives */
    355375  uint32 format;         /* XXX: Unverified.  Set to 1 in all known hives */
    356376
    357377  uint32 root_cell;  /* Offset to root cell in the first (or any?) hbin block */
    358   uint32 last_block; /* Offset to last hbin block in file
    359                       * (or length of file minus header?) */
     378  uint32 last_block; /* Offset to last hbin block in file */
    360379
    361380  uint32 cluster;    /* XXX: Unverified. Set to 1 in all known hives */
     
    516535                                     uint32 max_size, bool strict);
    517536
    518 REGFI_BUFFER          regfi_parse_data(REGFI_FILE* file,
    519                                        uint32 data_type, uint32 offset,
    520                                        uint32 length, uint32 max_size,
    521                                        bool data_in_offset, bool strict);
     537REGFI_BUFFER          regfi_load_data(REGFI_FILE* file,
     538                                      uint32 data_type, uint32 offset,
     539                                      uint32 length, uint32 max_size,
     540                                      bool data_in_offset, bool strict);
     541
     542REGFI_BUFFER          regfi_load_big_data(REGFI_FILE* file,
     543                                          uint32 offset, uint32 data_length,
     544                                          uint32 cell_length, bool strict);
    522545
    523546REGFI_SK_REC*         regfi_parse_sk(REGFI_FILE* file, uint32 offset,
  • trunk/lib/regfi.c

    r151 r152  
    966966    if(ret_val->data_in_offset)
    967967    {
    968       data = regfi_parse_data(file, ret_val->type, ret_val->data_off,
     968      data = regfi_load_data(file, ret_val->type, ret_val->data_off,
    969969                              ret_val->data_size, 4,
    970970                              ret_val->data_in_offset, strict);
     
    979979        data_offset = ret_val->data_off+REGFI_REGF_SIZE;
    980980        data_maxsize = hbin->block_size + hbin->file_off - data_offset;
    981         data = regfi_parse_data(file, ret_val->type, data_offset,
     981        data = regfi_load_data(file, ret_val->type, data_offset,
    982982                                ret_val->data_size, data_maxsize,
    983983                                ret_val->data_in_offset, strict);
     
    999999      regfi_add_message(file, REGFI_MSG_WARN, "Could not parse data record"
    10001000                        " while parsing VK record at offset 0x%.8X.",
    1001                         ret_val->offset);
     1001                        ret_val->offset, ret_val->valuename);
    10021002    }
    10031003    else
     
    12041204      if(nk != NULL)
    12051205      {
    1206         if((nk->key_type == REGFI_NK_TYPE_ROOTKEY1)
    1207            || (nk->key_type == REGFI_NK_TYPE_ROOTKEY2))
     1206        if(nk->key_type & REGFI_NK_FLAG_ROOT)
    12081207        {
    12091208          found = true;
     
    17771776  ret_val->thaw_rm_id = winsec_parse_uuid(ret_val, file_header+0xFD8, 16);
    17781777  ret_val->thaw_log_id = winsec_parse_uuid(ret_val, file_header+0xFE8, 16);
    1779   ret_val->boot_type = IVAL(file_header, 0x90);
    1780   ret_val->boot_recover = IVAL(file_header, 0x90);
     1778  ret_val->boot_type = IVAL(file_header, 0xFF8);
     1779  ret_val->boot_recover = IVAL(file_header, 0xFFC);
    17811780
    17821781  return ret_val;
     
    19181917  ret_val->magic[1] = nk_header[0x1];
    19191918  ret_val->key_type = SVAL(nk_header, 0x2);
    1920   if((ret_val->key_type != REGFI_NK_TYPE_NORMALKEY)
    1921      && (ret_val->key_type != REGFI_NK_TYPE_ROOTKEY1)
    1922      && (ret_val->key_type != REGFI_NK_TYPE_ROOTKEY2)
    1923      && (ret_val->key_type != REGFI_NK_TYPE_LINKKEY)
    1924      && (ret_val->key_type != REGFI_NK_TYPE_UNKNOWN1)
    1925      && (ret_val->key_type != REGFI_NK_TYPE_UNKNOWN2)
    1926      && (ret_val->key_type != REGFI_NK_TYPE_UNKNOWN3))
    1927   {
    1928     regfi_add_message(file, REGFI_MSG_WARN, "Unknown key type (0x%.4X) while"
     1919 
     1920  if((ret_val->key_type & ~REGFI_NK_KNOWN_FLAGS) != 0)
     1921  {
     1922    regfi_add_message(file, REGFI_MSG_WARN, "Unknown key flags (0x%.4X) while"
    19291923                      " parsing NK record at offset 0x%.8X.",
    1930                       ret_val->key_type, offset);
     1924                      (ret_val->key_type & ~REGFI_NK_KNOWN_FLAGS), offset);
    19311925  }
    19321926
     
    19641958  ret_val->classname_length = SVAL(nk_header, 0x4A);
    19651959
    1966 
    19671960  if(ret_val->name_length + REGFI_NK_MIN_LENGTH > ret_val->cell_size)
    19681961  {
     
    21062099
    21072100
    2108 /*******************************************************************
    2109  *******************************************************************/
     2101/******************************************************************************
     2102*******************************************************************************/
    21102103REGFI_VK_REC* regfi_parse_vk(REGFI_FILE* file, uint32 offset,
    21112104                             uint32 max_size, bool strict)
     
    22212214
    22222215
    2223 REGFI_BUFFER regfi_parse_data(REGFI_FILE* file,
    2224                               uint32 data_type, uint32 offset,
    2225                               uint32 length, uint32 max_size,
    2226                               bool data_in_offset, bool strict)
     2216/******************************************************************************
     2217*******************************************************************************/
     2218REGFI_BUFFER regfi_load_data(REGFI_FILE* file,
     2219                             uint32 data_type, uint32 offset,
     2220                             uint32 length, uint32 max_size,
     2221                             bool data_in_offset, bool strict)
    22272222{
    22282223  REGFI_BUFFER ret_val;
     
    22802275    if(cell_length - 4 < length)
    22812276    {
    2282       /* XXX: This strict condition has been triggered in multiple registries.
    2283        *      Not sure the cause, but the data length values are very large,
    2284        *      such as 53392.  For now, we're truncating the size and returning
    2285        *      what we can, since this issue is so common.
    2286        */
    2287       regfi_add_message(file, REGFI_MSG_WARN, "Data length (0x%.8X) larger than"
    2288                         " remaining cell length (0x%.8X)"
    2289                         " while parsing data record at offset 0x%.8X.",
    2290                         length, cell_length - 4, offset);
    2291       /*
    2292       if(strict)
    2293         goto fail;
     2277      if (file->major_version >= 1 && file->minor_version >= 5)
     2278      {
     2279        /* Attempt to parse a big data record */
     2280        return regfi_load_big_data(file, offset, length, cell_length, strict);
     2281      }
    22942282      else
    2295       */
    2296       length = cell_length - 4;
     2283      {
     2284        regfi_add_message(file, REGFI_MSG_WARN, "Data length (0x%.8X) larger than"
     2285                          " remaining cell length (0x%.8X)"
     2286                          " while parsing data record at offset 0x%.8X.",
     2287                          length, cell_length - 4, offset);
     2288        if(strict)
     2289          goto fail;
     2290        else
     2291          length = cell_length - 4;
     2292      }
    22972293    }
    22982294
     
    23142310  return ret_val;
    23152311
     2312 fail:
     2313  ret_val.buf = NULL;
     2314  ret_val.len = 0;
     2315  return ret_val;
     2316}
     2317
     2318
     2319/******************************************************************************
     2320*******************************************************************************/
     2321REGFI_BUFFER regfi_load_big_data(REGFI_FILE* file,
     2322                                 uint32 offset, uint32 data_length,
     2323                                 uint32 cell_length, bool strict)
     2324{
     2325  REGFI_BUFFER ret_val;
     2326  uint16 num_chunks, i;
     2327  uint32 indirect_offset, indirect_length, chunk_length, chunk_offset;
     2328  uint32 read_length, data_left;
     2329  bool unalloc;
     2330  uint32* indirect_ptrs;
     2331  uint8* big_data_cell = (uint8*)malloc(cell_length*sizeof(uint8));
     2332  if(big_data_cell == NULL)
     2333    goto fail;
     2334
     2335  if(!regfi_parse_cell(file->fd, offset, big_data_cell, cell_length-4,
     2336                       &cell_length, &unalloc))
     2337  {
     2338    regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while"
     2339                      " parsing big data record at offset 0x%.8X.", offset);
     2340    free(big_data_cell);
     2341    goto fail;
     2342  }
     2343 
     2344  if((big_data_cell[0] != 'd') || (big_data_cell[1] != 'b'))
     2345  {
     2346    regfi_add_message(file, REGFI_MSG_WARN, "Unknown magic number"
     2347                      " (0x%.2X, 0x%.2X) encountered while parsing"
     2348                      " big data record at offset 0x%.8X.",
     2349                      big_data_cell[0], big_data_cell[1], offset);
     2350    free(big_data_cell);
     2351    goto fail;
     2352  }
     2353  num_chunks = SVAL(big_data_cell, 0x2);
     2354  /* XXX: Should check sanity of pointers here and in the indirect
     2355   *      block.  At least ensure they are a multiple of 8.
     2356   */
     2357  indirect_offset = IVAL(big_data_cell, 0x4) + REGFI_REGF_SIZE;
     2358  free(big_data_cell);
     2359
     2360  indirect_ptrs = (uint32*)malloc(num_chunks*sizeof(uint32));
     2361  if(indirect_ptrs == NULL)
     2362    goto fail;
     2363
     2364  if(!regfi_parse_cell(file->fd, indirect_offset, (uint8*)indirect_ptrs,
     2365                       num_chunks*sizeof(uint32),
     2366                       &indirect_length, &unalloc))
     2367  {
     2368    regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while"
     2369                      " parsing big data indirect record at offset 0x%.8X.",
     2370                      offset);
     2371    free(indirect_ptrs);
     2372    goto fail;
     2373  }
     2374 
     2375  if((ret_val.buf = talloc_array(NULL, uint8_t, data_length)) == NULL)
     2376  {
     2377    free(indirect_ptrs);
     2378    goto fail;
     2379  }
     2380  data_left = data_length;
     2381
     2382  for(i=0; (i<num_chunks) && (data_left>0); i++)
     2383  {
     2384    /* Fix endianness of pointer and convert to physical offset */
     2385    chunk_offset = IVAL(indirect_ptrs, i*4) + REGFI_REGF_SIZE;
     2386    if(!regfi_parse_cell(file->fd, chunk_offset, NULL, 0,
     2387                         &chunk_length, &unalloc))
     2388    {
     2389      regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while"
     2390                        " parsing big data chunk at offset 0x%.8X.",
     2391                        chunk_offset);
     2392      if(strict)
     2393        goto chunk_fail;
     2394      else
     2395        break;
     2396    }
     2397
     2398    if(chunk_length-4 > data_left)
     2399      read_length = data_left;
     2400    else
     2401      read_length = chunk_length-4;
     2402
     2403    if(regfi_read(file->fd, ret_val.buf+(data_length-data_left),
     2404                  &read_length) != 0)
     2405    {
     2406      regfi_add_message(file, REGFI_MSG_WARN, "Could not read data chunk while"
     2407                        " constructing big data at offset 0x%.8X.",
     2408                        chunk_offset);
     2409      if(strict)
     2410        goto chunk_fail;
     2411      else
     2412        break;
     2413    }
     2414
     2415    data_left -= read_length;
     2416  }
     2417
     2418  free(indirect_ptrs);
     2419  ret_val.len = data_length-data_left;
     2420  return ret_val;
     2421
     2422 chunk_fail:
     2423  free(indirect_ptrs);
     2424  talloc_free(ret_val.buf);
    23162425 fail:
    23172426  ret_val.buf = NULL;
  • trunk/src/reglookup-recover.c

    r151 r152  
    285285      else
    286286      {
    287         if((cur_ancestor->key_type == REGFI_NK_TYPE_ROOTKEY1)
    288            || (cur_ancestor->key_type == REGFI_NK_TYPE_ROOTKEY2))
     287        if(cur_ancestor->key_type & REGFI_NK_FLAG_ROOT)
    289288          virt_offset = REGFI_OFFSET_NONE;
    290289        else
     
    482481      if(vk->data_in_offset)
    483482      {
    484         data = regfi_parse_data(f, vk->type, vk->data_off,
    485                                 vk->data_size, 4,
    486                                 vk->data_in_offset, false);
     483        data = regfi_load_data(f, vk->type, vk->data_off,
     484                               vk->data_size, 4,
     485                               vk->data_in_offset, false);
    487486        vk->data = data.buf;
    488487        vk->data_size = data.len;
     
    495494          data_offset = vk->data_off+REGFI_REGF_SIZE;
    496495          data_maxsize = hbin->block_size + hbin->file_off - data_offset;
    497           data = regfi_parse_data(f, vk->type, data_offset,
    498                                   vk->data_size, data_maxsize,
    499                                   vk->data_in_offset, false);
     496          data = regfi_load_data(f, vk->type, data_offset,
     497                                 vk->data_size, data_maxsize,
     498                                 vk->data_in_offset, false);
    500499          vk->data = data.buf;
    501500          vk->data_size = data.len;
     
    503502          if(vk->data != NULL)
    504503          {
     504            /* XXX: The following may not make sense now in light of big data
     505             *      records.
     506             */
    505507            /* XXX: This strict checking prevents partial recovery of data
    506              *      cells.  Also, see code for regfi_parse_data and note that
     508             *      cells.  Also, see code for regfi_load_data and note that
    507509             *      lengths indicated in VK records are sometimes just plain
    508510             *      wrong.  Need a feedback mechanism to be more fuzzy with
    509511             *      data cell lengths and the ranges removed.
    510512             *
    511              *      The introduction of REGFI_BUFFER in regfi_parse_data has
     513             *      The introduction of REGFI_BUFFER in regfi_load_data has
    512514             *      fixed some of this.  Should review again with respect to
    513515             *      the other issues mentioned above though.
Note: See TracChangeset for help on using the changeset viewer.