Changeset 116


Ignore:
Timestamp:
08/03/08 15:34:27 (16 years ago)
Author:
tim
Message:

fixed major bug in reglookup-recover; now recovers much more data
rolled back release version to 0.9.0
added date range checking in regfi's NK parsing for deleted records

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/regfi.h

    r112 r116  
    7272#define REG_KEY                        0x7FFFFFFF
    7373
    74 #define REGF_BLOCKSIZE          0x1000
    75 #define REGF_ALLOC_BLOCK        0x1000  /* Minimum allocation unit for hbins */
    76 #define REGF_MAX_DEPTH          512
     74#define REGF_BLOCKSIZE             0x1000
     75#define REGF_ALLOC_BLOCK           0x1000 /* Minimum allocation unit for HBINs */
     76#define REGF_MAX_DEPTH             512
    7777
    7878/* header sizes for various records */
    79 
    80 #define REGF_MAGIC_SIZE         4
    81 #define HBIN_MAGIC_SIZE         4
    82 #define HBIN_HEADER_REC_SIZE    0x20
    83 #define REC_HDR_SIZE            2
    84 
    85 #define REGF_OFFSET_NONE        0xffffffff
    86 #define REGFI_NK_MIN_LENGTH     0x4C
    87 #define REGFI_VK_MIN_LENGTH     0x14
    88 #define REGFI_SK_MIN_LENGTH     0x14
    89 #define REGFI_HASH_LIST_MIN_LENGTH     0x4
     79#define REGF_MAGIC_SIZE            4
     80#define HBIN_MAGIC_SIZE            4
     81#define HBIN_HEADER_REC_SIZE       0x20
     82#define REC_HDR_SIZE               2
     83
     84#define REGF_OFFSET_NONE           0xffffffff
     85#define REGFI_NK_MIN_LENGTH        0x4C
     86#define REGFI_VK_MIN_LENGTH        0x14
     87#define REGFI_SK_MIN_LENGTH        0x14
     88#define REGFI_HASH_LIST_MIN_LENGTH 0x4
     89
     90/* Constants used for validation */
     91 /* Minimum time is Jan 1, 1990 00:00:00 */
     92#define REGFI_MTIME_MIN_HIGH       0x01B41E6D
     93#define REGFI_MTIME_MIN_LOW        0x26F98000
     94 /* Maximum time is Jan 1, 2290 00:00:00
     95  * (We hope no one is using Windows by then...)
     96  */
     97#define REGFI_MTIME_MAX_HIGH       0x03047543
     98#define REGFI_MTIME_MAX_LOW        0xC80A4000
     99
    90100
    91101/* Flags for the vk records */
    92 
    93 #define VK_FLAG_NAME_PRESENT    0x0001
    94 #define VK_DATA_IN_OFFSET       0x80000000
    95 #define VK_MAX_DATA_LENGTH      1024*1024
    96 
    97 /* NK record macros */
    98 
    99 #define NK_TYPE_LINKKEY         0x0010
    100 #define NK_TYPE_NORMALKEY       0x0020
    101 #define NK_TYPE_ROOTKEY         0x002c
    102   /* TODO: Unknown type that shows up in Vista registries */
    103 #define NK_TYPE_UNKNOWN1         0x1020
    104 
    105 #define HBIN_STORE_REF(x, y) { x->hbin = y; y->ref_count++ };
    106 /* if the count == 0; we can clean up */
    107 #define HBIN_REMOVE_REF(x, y){ x->hbin = NULL; y->ref_count-- };
     102#define VK_FLAG_NAME_PRESENT       0x0001
     103#define VK_DATA_IN_OFFSET          0x80000000
     104#define VK_MAX_DATA_LENGTH         1024*1024
     105
     106/* NK record types */
     107#define NK_TYPE_LINKKEY            0x0010
     108#define NK_TYPE_NORMALKEY          0x0020
     109#define NK_TYPE_ROOTKEY            0x002c
     110 /* TODO: Unknown type that shows up in Vista registries */
     111#define NK_TYPE_UNKNOWN1           0x1020
    108112
    109113
  • trunk/lib/range_list.c

    r113 r116  
    1818 */
    1919
    20 #include <stdio.h>
    2120#include <math.h>
    2221#include "../include/range_list.h"
     
    2928
    3029#if 0
     30#include <stdio.h>
    3131static void range_list_print(const range_list* rl)
    3232{
  • trunk/lib/regfi.c

    r113 r116  
    442442
    443443/*******************************************************************
    444  TODO: not currently validating against max_size
    445444 *******************************************************************/
    446445REGF_HASH_LIST* regfi_load_hashlist(REGF_FILE* file, uint32 offset,
     
    463462
    464463  ret_val->offset = offset;
     464  if(cell_length > max_size)
     465  {
     466    if(strict)
     467      return NULL;
     468    cell_length = max_size & 0xFFFFFFF8;
     469  }
    465470  ret_val->cell_size = cell_length;
    466471
     
    491496      return NULL;
    492497    }
    493     /* TODO: Not sure which should be authoritative, the number from the
    494      *       NK record, or the number in the hash list.  Go with the larger
    495      *       of the two to ensure all keys are found.  Note the length checks
    496      *       on the cell later ensure that there won't be any critical errors.
     498    /* XXX: Not sure which should be authoritative, the number from the
     499     *      NK record, or the number in the hash list.  Go with the larger
     500     *      of the two to ensure all keys are found.  Note the length checks
     501     *      on the cell later ensure that there won't be any critical errors.
    497502     */
    498503    if(num_keys < ret_val->num_keys)
     
    565570
    566571  ret_val->offset = offset;
    567   /* TODO: is there a way to be more conservative (shorter) with
    568    *       cell length when cell is unallocated?
     572  /* XXX: Is there a way to be more conservative (shorter) with
     573   *      cell length when cell is unallocated?
    569574   */
    570575  ret_val->cell_size = cell_length;
     
    582587  ret_val->magic[1] = sk_header[1];
    583588
    584   /* TODO: can additional validation be added here? */
     589  /* XXX: Can additional validation be added here? */
    585590  ret_val->unknown_tag = SVAL(sk_header, 0x2);
    586591  ret_val->prev_sk_off = IVAL(sk_header, 0x4);
     
    595600  }
    596601
    597   /* TODO: need to get rid of this, but currently the security descriptor
     602  /* XXX: need to get rid of this, but currently the security descriptor
    598603   * code depends on the ps structure.
    599604   */
     
    678683
    679684/******************************************************************************
    680  * If !strict, the list may contain NULLs and VK records may point to NULL data.
     685 * If !strict, the list may contain NULLs, VK records may point to NULL.
    681686 ******************************************************************************/
    682687REGF_VK_REC** regfi_load_valuelist(REGF_FILE* file, uint32 offset,
     
    686691  REGF_VK_REC** ret_val;
    687692  REGF_HBIN* hbin;
    688   uint32 i, vk_offset, vk_max_length;
     693  uint32 i, vk_offset, vk_max_length, usable_num_values;
    689694  uint32* voffsets;
    690695
    691696  if((num_values+1) * sizeof(uint32) > max_size)
    692     return NULL;
    693 
    694   /* TODO: For now, everything strict seems to make sense on this call.
    695    *       Maybe remove the parameter or use it for other things.
    696    */
    697   voffsets = regfi_parse_valuelist(file, offset, num_values, true);
     697  {
     698    if(strict)
     699      return NULL;
     700    usable_num_values = max_size/sizeof(uint32) - sizeof(uint32);
     701  }
     702  else
     703    usable_num_values = num_values;
     704
     705  voffsets = regfi_parse_valuelist(file, offset, usable_num_values, strict);
    698706  if(voffsets == NULL)
    699707    return NULL;
     
    706714  }
    707715 
    708   for(i=0; i < num_values; i++)
     716  for(i=0; i < usable_num_values; i++)
    709717  {
    710718    hbin = regfi_lookup_hbin(file, voffsets[i]);
     
    739747
    740748/*******************************************************************
    741  * TODO: Need to add full key caching using a
    742  *       custom cache structure.
     749 * XXX: Need to add full key caching using a
     750 *      custom cache structure.
    743751 *******************************************************************/
    744752REGF_NK_REC* regfi_load_key(REGF_FILE* file, uint32 offset, bool strict)
     
    800808      if(strict)
    801809      {
    802         free(nk);
    803         /* TODO: need convenient way to free nk->values deeply in all cases. */
     810        regfi_key_free(nk);
    804811        return NULL;
    805812      }
     
    815822      if(nk->subkeys == NULL)
    816823      {
    817         /* TODO: temporary hack to get around 'ri' records */
     824        /* XXX: Temporary hack to get around 'ri' records */
    818825        nk->num_subkeys = 0;
    819826      }
     
    10311038  }
    10321039
    1033   /* TODO: come up with a better secret. */
    1034   ret_val->sk_recs = lru_cache_create(127, 0xDEADBEEF, true);
     1040  /* This secret isn't very secret, but we don't need a good one.  This
     1041   * secret is just designed to prevent someone from trying to blow our
     1042   * caching and make things slow.
     1043   */
     1044  ret_val->sk_recs = lru_cache_create(127, 0x15DEAD05^time(NULL)
     1045                                           ^(getpid()<<16)^(getppid()<<8),
     1046                                      true);
    10351047
    10361048  ret_val->f = fh;
     
    13671379
    13681380/*******************************************************************
    1369  * TODO: add way to return more detailed error information.
     1381 * XXX: Add way to return more detailed error information.
    13701382 *******************************************************************/
    13711383REGF_FILE* regfi_parse_regf(int fd, bool strict)
     
    14411453 * along with it's associated cells.
    14421454 *******************************************************************/
    1443 /* TODO: Need a way to return types of errors.  Also need to free
    1444  *       the hbin/ps when an error occurs.
     1455/* XXX: Need a way to return types of errors.
    14451456 */
    14461457REGF_HBIN* regfi_parse_hbin(REGF_FILE* file, uint32 offset, bool strict)
     
    14851496   * the end of the file.
    14861497   */
    1487   /* TODO: This may need to be relaxed for dealing with
    1488    *       partial or corrupt files. */
     1498  /* XXX: This may need to be relaxed for dealing with
     1499   *      partial or corrupt files.
     1500   */
    14891501  if((offset + hbin->block_size > file->file_length)
    14901502     || (hbin->block_size & 0xFFFFF000) != hbin->block_size)
     
    15151527  if((nk_header[0x0] != 'n') || (nk_header[0x1] != 'k'))
    15161528  {
    1517     /* TODO: deal with subkey-lists that reference other subkey-lists. */
     1529    /* XXX: Deal with subkey-lists that reference other subkey-lists
     1530     *      (e.g. 'ri' records).
     1531     */
    15181532    return NULL;
    15191533  }
     
    15491563  ret_val->mtime.low = IVAL(nk_header, 0x4);
    15501564  ret_val->mtime.high = IVAL(nk_header, 0x8);
    1551  
     1565  /* If the key is unallocated and the MTIME is earlier than Jan 1, 1990
     1566   * or later than Jan 1, 2290, we consider this a bad key.  This helps
     1567   * weed out some false positives during deleted data recovery.
     1568   */
     1569  if(unalloc
     1570     && ((ret_val->mtime.high < REGFI_MTIME_MIN_HIGH
     1571          && ret_val->mtime.low < REGFI_MTIME_MIN_LOW)
     1572         || (ret_val->mtime.high > REGFI_MTIME_MAX_HIGH
     1573             && ret_val->mtime.low > REGFI_MTIME_MAX_LOW)))
     1574    return NULL;
     1575
    15521576  ret_val->unknown1 = IVAL(nk_header, 0xC);
    15531577  ret_val->parent_off = IVAL(nk_header, 0x10);
     
    15591583  ret_val->values_off = IVAL(nk_header, 0x28);
    15601584  ret_val->sk_off = IVAL(nk_header, 0x2C);
    1561   /* TODO: currently we do nothing with class names.  Need to investigate. */
     1585  /* XXX: currently we do nothing with class names.  Need to investigate. */
    15621586  ret_val->classname_off = IVAL(nk_header, 0x30);
    15631587
     
    17581782    if(cell_length - 4 < length)
    17591783    {
    1760       /* TODO: This strict condition has been triggered in multiple registries.
    1761        *       Not sure the cause, but the data length values are very large,
    1762        *       such as 53392.
     1784      /* XXX: This strict condition has been triggered in multiple registries.
     1785       *      Not sure the cause, but the data length values are very large,
     1786       *      such as 53392.
    17631787       */
    17641788      if(strict)
     
    17681792    }
    17691793
    1770     /* TODO: There is currently no check to ensure the data
    1771      *       cell doesn't cross HBIN boundary.
     1794    /* XXX: There is currently no check to ensure the data
     1795     *      cell doesn't cross HBIN boundary.
    17721796     */
    17731797
     
    18161840     
    18171841      if((cell_len == 0) || ((cell_len & 0xFFFFFFF8) != cell_len))
    1818         /* TODO: should report an error here. */
     1842        /* XXX: should report an error here. */
    18191843        break;
    18201844     
  • trunk/src/common.c

    r111 r116  
    2929const char* common_special_chars = ",\"\\";
    3030
    31 #define REGLOOKUP_VERSION "1.0.0"
     31#define REGLOOKUP_VERSION "0.9.0"
    3232
    3333
     
    357357  /* XXX: Dont know what to do with these yet, just print as binary... */
    358358  default:
     359    /* XXX: It would be really nice if this message somehow included the
     360     *      name of the current value we're having trouble with, since
     361     *      stderr/stdout don't always sync nicely.
     362     */
    359363    fprintf(stderr, "WARNING: Unrecognized registry data type (0x%.8X); quoting as binary.\n", type);
    360364   
  • trunk/src/reglookup-recover.c

    r115 r116  
    148148   *   http://msdn2.microsoft.com/en-us/library/ms724872.aspx
    149149   */
    150   /* TODO: should probably do something different here for this tool.*/
     150  /* XXX: Should probably do something different here for this tool.
     151   *      Also, It would be really nice if this message somehow included the
     152   *      name of the current value we're having trouble with, since
     153   *      stderr/stdout don't always sync nicely.
     154   */
    151155  if(size > VK_MAX_DATA_LENGTH)
    152156  {
     
    277281 * Paths returned must be free()d.
    278282 */
    279 /* TODO: This is not terribly efficient, as it may reparse many keys
    280  *       repeatedly.  Should try to add caching.  Also, piecing the path
    281  *       together is slow and redundant.
     283/* XXX: This is not terribly efficient, as it may reparse many keys
     284 *      repeatedly.  Should try to add caching.  Also, piecing the path
     285 *      together is slow and redundant.
    282286 */
    283287char* getParentPath(REGF_FILE* f, REGF_NK_REC* nk)
     
    425429  rm_idx = range_list_find(rl, offset);
    426430  if(rm_idx < 0)
     431  {
     432    fprintf(stderr, "DEBUG: removeRange: rm_idx < 0; (%d)\n", rm_idx);
    427433    return false;
     434  }
    428435
    429436  cur_elem = range_list_get(rl, rm_idx);
    430437  if(cur_elem == NULL)
    431438  {
    432     printf("removeRange: cur_elem == NULL.  rm_idx=%d\n", rm_idx);
     439    fprintf(stderr, "DEBUG: removeRange: cur_elem == NULL.  rm_idx=%d\n", rm_idx);
    433440    return false;
    434441  }
     
    438445    if(!range_list_split_element(rl, rm_idx, offset))
    439446    {
    440       printf("removeRange: first split failed\n");
     447      fprintf(stderr, "DEBUG: removeRange: first split failed\n");
    441448      return false;
    442449    }
    443450    rm_idx++;
     451    cur_elem = range_list_get(rl, rm_idx);
     452    if(cur_elem == NULL)
     453    {
     454      fprintf(stderr,
     455              "DEBUG: removeRange: cur_elem == NULL after first split.  rm_idx=%d\n",
     456              rm_idx);
     457      return false;
     458    }
    444459  }
    445460 
     
    448463    if(!range_list_split_element(rl, rm_idx, offset+length))
    449464    {
    450       printf("removeRange: second split failed\n");
     465      fprintf(stderr, "DEBUG: removeRange: second split failed\n");
    451466      return false;
    452467    }
     
    455470  if(!range_list_remove(rl, rm_idx))
    456471  {
    457     printf("removeRange: remove failed\n");
     472    fprintf(stderr, "DEBUG: removeRange: remove failed\n");
    458473    return false;
    459474  }
     
    487502          return 20;
    488503        }
    489        
    490         if(removeRange(unalloc_cells, key->offset, key->cell_size))
    491         {
    492           /* TODO: This ugly hack is needed because unalloc_cells is changing
    493            *       underneath us when we find things.  Need a better approach
    494            *       so we can parse things single-pass.
    495            */
    496           i=0;
    497           break;
    498         }
    499         else
    500           return 30;
     504        j+=key->cell_size-8;
    501505      }
    502506    }
     507  }
     508
     509  for(i=0; i<range_list_size(unalloc_keys); i++)
     510  {
     511    cur_elem = range_list_get(unalloc_keys, i);
     512    if(!removeRange(unalloc_cells, cur_elem->offset, cur_elem->length))
     513      return 30;
    503514  }
    504515
     
    743754  REGF_NK_REC* tmp_key;
    744755  REGF_VK_REC* tmp_value;
    745   uint32 argi, arge, i, j, k, ret, num_unalloc_keys;
     756  uint32 argi, arge, i, j, ret, num_unalloc_keys;
    746757  /* uint32 test_offset;*/
    747758 
  • trunk/src/reglookup.c

    r111 r116  
    4646
    4747
    48 /* TODO: a hack to share some functions with reglookup-recover.c.
    49  *       Should move these into a properly library at some point.
     48/* XXX: A hack to share some functions with reglookup-recover.c.
     49 *      Should move these into a properly library at some point.
    5050 */
    5151#include "common.c"
Note: See TracChangeset for help on using the changeset viewer.