source: trunk/src/reglookup-recover.c @ 149

Last change on this file since 149 was 149, checked in by tim, 15 years ago

minor efficiency improvement for path construction in reglookup-recover

  • Property svn:keywords set to Id
File size: 24.1 KB
RevLine 
[111]1/*
[121]2 * This program attempts to recover deleted data structures in a registry hive.
3 *
[138]4 * Copyright (C) 2008-2009 Timothy D. Morgan
[111]5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
18 *
[118]19 * $Id: reglookup-recover.c 149 2009-02-23 05:23:45Z tim $
[111]20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24
[148]25#include "talloc.h"
[147]26#include "regfi.h"
27#include "range_list.h"
28#include "lru_cache.h"
[111]29
30
31/* Globals, influenced by command line parameters */
32bool print_verbose = false;
33bool print_security = false;
34bool print_header = true;
35bool print_leftover = false;
36bool print_parsedraw = false;
37char* registry_file = NULL;
38
39#include "common.c"
40
41
42char* getQuotedData(int fd, uint32 offset, uint32 length)
43{
44  uint8* buf;
45  char* quoted_buf;
46  uint32 len;
47
48  if((lseek(fd, offset, SEEK_SET)) == -1)
49    return NULL;
50
51  buf = (uint8*)malloc(length);
52  if(buf == NULL)
53    return NULL;
54
55  len = length;
56  if((regfi_read(fd, buf, &length) != 0) || length != len)
57  {
58    free(buf);
59    return NULL;
60  }
61
62  quoted_buf = quote_buffer(buf, length, common_special_chars);
63  free(buf);
64
65  return quoted_buf;
66}
67
68
[135]69void printKey(REGFI_FILE* f, REGFI_NK_REC* nk, const char* prefix)
[111]70{
71  char mtime[20];
72  time_t tmp_time[1];
73  struct tm* tmp_time_s = NULL;
74  char* quoted_name = NULL;
75  char* quoted_raw = "";
76
77  *tmp_time = nt_time_to_unix(&nk->mtime);
78  tmp_time_s = gmtime(tmp_time);
79  strftime(mtime, sizeof(mtime), "%Y-%m-%d %H:%M:%S", tmp_time_s);
80
81  quoted_name = quote_string(nk->keyname, key_special_chars);
82  if (quoted_name == NULL)
83  {
84    quoted_name = malloc(1*sizeof(char));
85    if(quoted_name == NULL)
[143]86      bailOut(REGLOOKUP_EXIT_OSERR, "ERROR: Could not allocate sufficient memory.\n");
[111]87    quoted_name[0] = '\0';
88
[138]89    fprintf(stderr, "WARN: NULL key name in NK record at offset %.8X.\n",
[111]90            nk->offset);
91  }
92
93  if(print_parsedraw)
94    quoted_raw = getQuotedData(f->fd, nk->offset, nk->cell_size);
95
96  printf("%.8X,%.8X,KEY,%s,%s,%s,%d,,,,,,,,%s\n", nk->offset, nk->cell_size,
97         prefix, quoted_name, mtime, nk->num_values, quoted_raw);
98 
99  if(print_parsedraw)
100    free(quoted_raw);
[136]101  free(quoted_name);
[111]102}
103
104
[135]105void printValue(REGFI_FILE* f, const REGFI_VK_REC* vk, const char* prefix)
[111]106{
107  char* quoted_value = NULL;
108  char* quoted_name = NULL;
109  char* quoted_raw = "";
110  char* conv_error = NULL;
111  const char* str_type = NULL;
112  uint32 size = vk->data_size;
113
114  /* Microsoft's documentation indicates that "available memory" is
115   * the limit on value sizes.  Annoying.  We limit it to 1M which
116   * should rarely be exceeded, unless the file is corrupt or
117   * malicious. For more info, see:
118   *   http://msdn2.microsoft.com/en-us/library/ms724872.aspx
119   */
[116]120  /* XXX: Should probably do something different here for this tool.
121   *      Also, It would be really nice if this message somehow included the
122   *      name of the current value we're having trouble with, since
123   *      stderr/stdout don't always sync nicely.
124   */
[135]125  if(size > REGFI_VK_MAX_DATA_LENGTH)
[111]126  {
[138]127    fprintf(stderr, "WARN: value data size %d larger than "
[135]128            "%d, truncating...\n", size, REGFI_VK_MAX_DATA_LENGTH);
129    size = REGFI_VK_MAX_DATA_LENGTH;
[111]130  }
131 
132  quoted_name = quote_string(vk->valuename, key_special_chars);
133  if (quoted_name == NULL)
134  { /* Value names are NULL when we're looking at the "(default)" value.
135     * Currently we just return a 0-length string to try an eliminate
136     * ambiguity with a literal "(default)" value.  The data type of a line
137     * in the output allows one to differentiate between the parent key and
138     * this value.
139     */
140    quoted_name = malloc(1*sizeof(char));
141    if(quoted_name == NULL)
[143]142      bailOut(REGLOOKUP_EXIT_OSERR, "ERROR: Could not allocate sufficient memory.\n");
[111]143    quoted_name[0] = '\0';
144  }
145
146  quoted_value = data_to_ascii(vk->data, size, vk->type, &conv_error);
147  if(quoted_value == NULL)
148  {
149    quoted_value = malloc(1*sizeof(char));
150    if(quoted_value == NULL)
[143]151      bailOut(REGLOOKUP_EXIT_OSERR, "ERROR: Could not allocate sufficient memory.\n");
[111]152    quoted_value[0] = '\0';
153
154    if(conv_error == NULL)
[138]155      fprintf(stderr, "WARN: Could not quote value for '%s/%s'.  "
[111]156              "Memory allocation failure likely.\n", prefix, quoted_name);
157    else if(print_verbose)
[138]158      fprintf(stderr, "WARN: Could not quote value for '%s/%s'.  "
[111]159              "Returned error: %s\n", prefix, quoted_name, conv_error);
160  }
161  /* XXX: should these always be printed? */
162  else if(conv_error != NULL && print_verbose)
[138]163    fprintf(stderr, "INFO: While quoting value for '%s/%s', "
[111]164            "warning returned: %s\n", prefix, quoted_name, conv_error);
165
166
167  if(print_parsedraw)
168    quoted_raw = getQuotedData(f->fd, vk->offset, vk->cell_size);
169
170  str_type = regfi_type_val2str(vk->type);
171  if(str_type == NULL)
172    printf("%.8X,%.8X,VALUE,%s,%s,,,0x%.8X,%s,%d,,,,,%s\n", 
173           vk->offset, vk->cell_size, prefix, quoted_name, 
174           vk->type, quoted_value, vk->data_size, quoted_raw);
175  else
176    printf("%.8X,%.8X,VALUE,%s,%s,,,%s,%s,%d,,,,,%s\n", 
177           vk->offset, vk->cell_size, prefix, quoted_name, 
178           str_type, quoted_value, vk->data_size, quoted_raw);
179
180  if(print_parsedraw)
181    free(quoted_raw);
182  if(quoted_value != NULL)
183    free(quoted_value);
184  if(quoted_name != NULL)
185    free(quoted_name);
186  if(conv_error != NULL)
187    free(conv_error);
188}
189
190
[135]191void printSK(REGFI_FILE* f, REGFI_SK_REC* sk)
[111]192{
193  char* quoted_raw = NULL;
194  char* empty_str = "";
195  char* owner = regfi_get_owner(sk->sec_desc);
196  char* group = regfi_get_group(sk->sec_desc);
197  char* sacl = regfi_get_sacl(sk->sec_desc);
198  char* dacl = regfi_get_dacl(sk->sec_desc);
199
200  if(print_parsedraw)
201    quoted_raw = getQuotedData(f->fd, sk->offset, sk->cell_size);
202
203  if(owner == NULL)
204    owner = empty_str;
205  if(group == NULL)
206    group = empty_str;
207  if(sacl == NULL)
208    sacl = empty_str;
209  if(dacl == NULL)
210    dacl = empty_str;
211
212  printf("%.8X,%.8X,SK,,,,,,,,%s,%s,%s,%s,%s\n", sk->offset, sk->cell_size,
213         owner, group, sacl, dacl, quoted_raw);
214 
215  if(owner != empty_str)
216    free(owner);
217  if(group != empty_str)
218    free(group);
219  if(sacl != empty_str)
220    free(sacl);
221  if(dacl != empty_str)
222    free(dacl);
223
224  if(print_parsedraw)
225    free(quoted_raw);
226}
227
228
[135]229int printCell(REGFI_FILE* f, uint32 offset)
[111]230{
231  char* quoted_buf;
232  uint32 cell_length;
233  bool unalloc;
234
235  if(!regfi_parse_cell(f->fd, offset, NULL, 0, &cell_length, &unalloc))
236    return 1;
237
238  quoted_buf = getQuotedData(f->fd, offset, cell_length);
239  if(quoted_buf == NULL)
240    return 2;
241
242  printf("%.8X,%.8X,RAW,,,,,,,,,,,,%s\n", offset, cell_length, quoted_buf);
243
244  free(quoted_buf);
245  return 0;
246}
247
248
[112]249/* This function returns a properly quoted parent path or partial parent
250 * path for a given key.  Returns NULL on error, "" if no path was available.
251 * Paths returned must be free()d.
252 */
[116]253/* XXX: This is not terribly efficient, as it may reparse many keys
[149]254 *      repeatedly.  Should try to add caching.
[112]255 */
[135]256char* getParentPath(REGFI_FILE* f, REGFI_NK_REC* nk)
[112]257{
[135]258  void_stack* path_stack = void_stack_new(REGFI_MAX_DEPTH);
[146]259  const REGFI_HBIN* hbin;
[135]260  REGFI_NK_REC* cur_ancestor;
[112]261  char* ret_val;
[149]262  uint32 virt_offset, i, stack_size, ret_val_size, ret_val_used;
[112]263  uint32 max_length;
[149]264  /* A little hack so we don't have to walk a quoted string twice. */
265  struct name_holder
266  {
267    char* quoted_name;
268    uint32_t length;
269  };
270  struct name_holder* path_element;
[112]271
[149]272 
[118]273  /* The path_stack size limit should guarantee that we don't recurse forever. */
[112]274  virt_offset = nk->parent_off;
[149]275  ret_val_size = 1; /* NUL */
[135]276  while(virt_offset != REGFI_OFFSET_NONE)
[112]277  { 
278    hbin = regfi_lookup_hbin(f, virt_offset);
279    if(hbin == NULL)
[135]280      virt_offset = REGFI_OFFSET_NONE;
[112]281    else
282    {
283      max_length = hbin->block_size + hbin->file_off
[135]284        - (virt_offset+REGFI_REGF_SIZE);
285      cur_ancestor = regfi_parse_nk(f, virt_offset+REGFI_REGF_SIZE, 
[112]286                                    max_length, true);
[138]287      printMsgs(f);
288
[112]289      if(cur_ancestor == NULL)
[135]290        virt_offset = REGFI_OFFSET_NONE;
[112]291      else
292      {
[135]293        if((cur_ancestor->key_type == REGFI_NK_TYPE_ROOTKEY1) 
294           || (cur_ancestor->key_type == REGFI_NK_TYPE_ROOTKEY2))
295          virt_offset = REGFI_OFFSET_NONE;
[112]296        else
297          virt_offset = cur_ancestor->parent_off;
298       
[149]299        path_element = (struct name_holder*)malloc(sizeof(struct name_holder));
300        if(path_element != NULL)
301          path_element->quoted_name = quote_string(cur_ancestor->keyname, 
302                                                   key_special_chars);
303         
304        if(path_element == NULL || path_element->quoted_name == NULL 
305           || !void_stack_push(path_stack, path_element))
[112]306        {
307          free(cur_ancestor->keyname);
308          free(cur_ancestor);
309          void_stack_free_deep(path_stack);
310          return NULL;
311        }
312
[149]313        /* Path element and preceeding delimiter
314         * Note that this integer can't overflow since key name lengths are
315         * 16 bits and the max depth is 512.
316         */
317        path_element->length = strlen(path_element->quoted_name);
318        ret_val_size += path_element->length + 1;
319
[112]320        regfi_key_free(cur_ancestor);
321      }
322    }
323  }
324 
325  stack_size = void_stack_size(path_stack);
[149]326  ret_val_used = 0;
[112]327  ret_val = malloc(ret_val_size);
328  if(ret_val == NULL)
329  {
330    void_stack_free_deep(path_stack);
331    return NULL;
332  }
333  ret_val[0] = '\0';
334
335  for(i=0; i<stack_size; i++)
336  {
337    path_element = void_stack_pop(path_stack);
[149]338    snprintf(ret_val+ret_val_used, ret_val_size-ret_val_used, 
339             "/%s", path_element->quoted_name);
340    ret_val_used += path_element->length + 1;
341    free(path_element->quoted_name);
[112]342    free(path_element);
343  }
344  void_stack_free(path_stack);
345
346  return ret_val;
347}
348
349
[111]350static void usage(void)
351{
352  fprintf(stderr, "Usage: reglookup-recover [options] <REGISTRY_FILE>\n");
353  fprintf(stderr, "Version: %s\n", REGLOOKUP_VERSION);
354  fprintf(stderr, "Options:\n");
355  fprintf(stderr, "\t-v\t sets verbose mode.\n");
356  fprintf(stderr, "\t-h\t enables header row. (default)\n");
357  fprintf(stderr, "\t-H\t disables header row.\n");
358  fprintf(stderr, "\t-l\t enables leftover(raw) cell output.\n");
359  fprintf(stderr, "\t-L\t disables leftover(raw) cell output. (default)\n");
360  fprintf(stderr, "\t-r\t enables raw cell output for parsed cells.\n");
361  fprintf(stderr, "\t-R\t disables raw cell output for parsed cells. (default)\n");
362  fprintf(stderr, "\n");
363}
364
365
[113]366bool removeRange(range_list* rl, uint32 offset, uint32 length)
[111]367{
[113]368  int32 rm_idx;
369  const range_list_element* cur_elem;
[115]370
[113]371  rm_idx = range_list_find(rl, offset);
372  if(rm_idx < 0)
[116]373  {
374    fprintf(stderr, "DEBUG: removeRange: rm_idx < 0; (%d)\n", rm_idx);
[113]375    return false;
[116]376  }
[113]377
378  cur_elem = range_list_get(rl, rm_idx);
[111]379  if(cur_elem == NULL)
380  {
[116]381    fprintf(stderr, "DEBUG: removeRange: cur_elem == NULL.  rm_idx=%d\n", rm_idx);
[111]382    return false;
383  }
384
385  if(offset > cur_elem->offset)
386  {
387    if(!range_list_split_element(rl, rm_idx, offset))
388    {
[116]389      fprintf(stderr, "DEBUG: removeRange: first split failed\n");
[111]390      return false;
391    }
392    rm_idx++;
[116]393    cur_elem = range_list_get(rl, rm_idx);
394    if(cur_elem == NULL)
395    {
396      fprintf(stderr, 
397              "DEBUG: removeRange: cur_elem == NULL after first split.  rm_idx=%d\n",
398              rm_idx);
399      return false;
400    }
[111]401  }
402 
403  if(offset+length < cur_elem->offset+cur_elem->length)
404  {
405    if(!range_list_split_element(rl, rm_idx, offset+length))
406    {
[116]407      fprintf(stderr, "DEBUG: removeRange: second split failed\n");
[111]408      return false;
409    }
410  }
411 
412  if(!range_list_remove(rl, rm_idx))
413  {
[116]414    fprintf(stderr, "DEBUG: removeRange: remove failed\n");
[111]415    return false;
416  }
417
418  return true;
419}
420
421
[145]422int extractVKs(REGFI_FILE* f,
423               range_list* unalloc_cells,
424               range_list* unalloc_values)
425{
426  const range_list_element* cur_elem;
427  REGFI_VK_REC* vk;
428  uint32 i, j;
429
430  for(i=0; i < range_list_size(unalloc_cells); i++)
431  {
432    printMsgs(f);
433    cur_elem = range_list_get(unalloc_cells, i);
434    for(j=0; j <= cur_elem->length; j+=8)
435    {
436      vk = regfi_parse_vk(f, cur_elem->offset+j, 
437                           cur_elem->length-j, false);
438      printMsgs(f);
439
440      if(vk != NULL)
441      {
442        if(!range_list_add(unalloc_values, vk->offset,
443                           vk->cell_size, vk))
444        {
445          fprintf(stderr, "ERROR: Couldn't add value to unalloc_values.\n");
446          return 20;
447        }
448        j+=vk->cell_size-8;
449      }
450    }
451  }
452
453  /* Remove value ranges from the unalloc_cells before we continue. */
454  for(i=0; i<range_list_size(unalloc_values); i++)
455  {
456    cur_elem = range_list_get(unalloc_values, i);
457    if(!removeRange(unalloc_cells, cur_elem->offset, cur_elem->length))
458      return 30;
459  }
460
461  return 0;
462}
463
464
465int extractDataCells(REGFI_FILE* f,
466                     range_list* unalloc_cells,
467                     range_list* unalloc_values)
468{
469  const range_list_element* cur_elem;
470  REGFI_VK_REC* vk;
[146]471  const REGFI_HBIN* hbin;
[145]472  uint32 i, off, data_offset, data_maxsize;
473
474  for(i=0; i<range_list_size(unalloc_values); i++)
475  {
476    cur_elem = range_list_get(unalloc_values, i);
477    vk = (REGFI_VK_REC*)cur_elem->data;
478    if(vk == NULL)
479      return 40;
480
481    if(vk->data_size == 0)
482      vk->data = NULL;
483    else
484    {
485      off = vk->data_off+REGFI_REGF_SIZE;
486
487      if(vk->data_in_offset)
488      {
489        vk->data = regfi_parse_data(f, vk->type, vk->data_off,
490                                    vk->data_size, 4,
491                                    vk->data_in_offset, false);
492      }
493      else if(range_list_has_range(unalloc_cells, off, vk->data_size))
494      {
495        hbin = regfi_lookup_hbin(f, vk->data_off);
496        if(hbin)
497        {
498          data_offset = vk->data_off+REGFI_REGF_SIZE;
499          data_maxsize = hbin->block_size + hbin->file_off - data_offset;
500          vk->data = regfi_parse_data(f, vk->type, data_offset, 
501                                      vk->data_size, data_maxsize, 
502                                      vk->data_in_offset, false);
503          if(vk->data != NULL)
504          {
505            /* XXX: This strict checking prevents partial recovery of data
506             *      cells.  Also, see code for regfi_parse_data and note that
507             *      lengths indicated in VK records are sometimes just plain
508             *      wrong.  Need a feedback mechanism to be more fuzzy with
509             *      data cell lengths and the ranges removed.
510             */
511            /* A data record was recovered. Remove from unalloc_cells. */
512            if(!removeRange(unalloc_cells, off, vk->data_size))
513              return 50;
514          }
515        }
516        else
517          vk->data = NULL;
518      }
519    }
520  }
521
522  return 0;
523}
524
525
[117]526/* NOTE: unalloc_keys should be an empty range_list. */
[135]527int extractKeys(REGFI_FILE* f, 
[111]528                range_list* unalloc_cells, 
529                range_list* unalloc_keys)
530{
531  const range_list_element* cur_elem;
[135]532  REGFI_NK_REC* key;
[111]533  uint32 i, j;
534
535  for(i=0; i < range_list_size(unalloc_cells); i++)
536  {
[138]537    printMsgs(f);
[111]538    cur_elem = range_list_get(unalloc_cells, i);
[115]539    for(j=0; cur_elem->length > REGFI_NK_MIN_LENGTH
540          && j <= cur_elem->length-REGFI_NK_MIN_LENGTH; j+=8)
[111]541    {
[115]542      key = regfi_parse_nk(f, cur_elem->offset+j,
543                           cur_elem->length-j, false);
[138]544      printMsgs(f);
545
[111]546      if(key != NULL)
547      {
548        if(!range_list_add(unalloc_keys, key->offset, 
549                           key->cell_size, key))
550        {
551          fprintf(stderr, "ERROR: Couldn't add key to unalloc_keys.\n");
552          return 20;
553        }
[116]554        j+=key->cell_size-8;
[111]555      }
556    }
557  }
558
[116]559  for(i=0; i<range_list_size(unalloc_keys); i++)
560  {
561    cur_elem = range_list_get(unalloc_keys, i);
562    if(!removeRange(unalloc_cells, cur_elem->offset, cur_elem->length))
563      return 30;
564  }
565
[111]566  return 0;
567}
568
[135]569int extractValueLists(REGFI_FILE* f,
[111]570                      range_list* unalloc_cells,
[145]571                      range_list* unalloc_keys,
572                      range_list* unalloc_linked_values)
[111]573{
[135]574  REGFI_NK_REC* nk;
[145]575  REGFI_VK_REC* vk;
[146]576  const REGFI_HBIN* hbin;
[111]577  const range_list_element* cur_elem;
578  uint32 i, j, num_keys, off, values_length, max_length;
579
580  num_keys=range_list_size(unalloc_keys);
581  for(i=0; i<num_keys; i++)
582  {
583    cur_elem = range_list_get(unalloc_keys, i);
584    if(cur_elem == NULL)
585      return 10;
586    nk = cur_elem->data;
587
[135]588    if(nk->num_values && (nk->values_off!=REGFI_OFFSET_NONE))
[111]589    {
590      hbin = regfi_lookup_hbin(f, nk->values_off);
591     
592      if(hbin != NULL)
593      {
[135]594        off = nk->values_off + REGFI_REGF_SIZE;
[111]595        max_length = hbin->block_size + hbin->file_off - off;
[145]596        nk->values = regfi_load_valuelist(f, off, nk->num_values, 
597                                          max_length, false);
598        if(nk->values != NULL && nk->values->elements != NULL)
599        {
600          /* Number of elements in the value list may be shorter than advertised
601           * by NK record due to cell truncation.  We'll consider this valid and
602           * only throw out the whole value list if it bleeds into an already
603           * parsed structure.
604           */
605          values_length = (nk->values->num_values+1)*sizeof(uint32);
606          if(values_length != (values_length & 0xFFFFFFF8))
607            values_length = (values_length & 0xFFFFFFF8) + 8;
[111]608
[115]609          if(!range_list_has_range(unalloc_cells, off, values_length))
[111]610          { /* We've parsed a values-list which isn't in the unallocated list,
[145]611             * so prune it.
[111]612             */
[145]613            free(nk->values->elements);
[115]614            free(nk->values);
615            nk->values = NULL;
[111]616          }
617          else
618          { /* Values-list was recovered.  Remove from unalloc_cells and
619             * inspect values.
620             */
[113]621            if(!removeRange(unalloc_cells, off, values_length))
[111]622              return 20;
623
[145]624            for(j=0; j < nk->values->num_values; j++)
[111]625            {
[145]626              /* Don't bother to restrict cell length here, since we'll
627               * check our unalloc_cells range_list later.
628               */
629              vk = regfi_parse_vk(f, nk->values->elements[j]+REGFI_REGF_SIZE,
630                                  0x7FFFFFFF, false);
631              printMsgs(f);
632             
633              if(vk != NULL)
[111]634              {
[145]635                if(range_list_has_range(unalloc_cells, 
636                                        vk->offset, vk->cell_size))
[111]637                {
[145]638                  if(!range_list_add(unalloc_linked_values, vk->offset,
639                                     vk->cell_size, vk))
[111]640                  {
[145]641                    free(vk);
642                    return 30;
[111]643                  }
[145]644
645                  if(!removeRange(unalloc_cells, vk->offset, vk->cell_size))
646                    return 40;
[111]647                }
[145]648                else
649                  free(vk);
[111]650              }
651            }
652          }
653        }
654      }
655    }
656  }
657
658  return 0;
659}
660
661
662
[118]663/* NOTE: unalloc_sks should be an empty range_list. */
[135]664int extractSKs(REGFI_FILE* f, 
[111]665               range_list* unalloc_cells,
666               range_list* unalloc_sks)
667{
668  const range_list_element* cur_elem;
[135]669  REGFI_SK_REC* sk;
[111]670  uint32 i, j;
671
672  for(i=0; i < range_list_size(unalloc_cells); i++)
673  {
[138]674    printMsgs(f);
[111]675    cur_elem = range_list_get(unalloc_cells, i);
676    for(j=0; j <= cur_elem->length; j+=8)
677    {
678      sk = regfi_parse_sk(f, cur_elem->offset+j, 
679                          cur_elem->length-j, false);
[138]680      printMsgs(f);
681
[111]682      if(sk != NULL)
683      {
684        if(!range_list_add(unalloc_sks, sk->offset,
685                           sk->cell_size, sk))
686        {
687          fprintf(stderr, "ERROR: Couldn't add sk to unalloc_sks.\n");
688          return 20;
689        }
[148]690        talloc_steal(unalloc_sks, sk);
[118]691        j+=sk->cell_size-8;
[111]692      }
693    }
694  }
695
[118]696  for(i=0; i<range_list_size(unalloc_sks); i++)
697  {
698    cur_elem = range_list_get(unalloc_sks, i);
699    if(!removeRange(unalloc_cells, cur_elem->offset, cur_elem->length))
700      return 30;
701  }
702
[111]703  return 0;
704}
705
706
707int main(int argc, char** argv)
708{ 
[135]709  REGFI_FILE* f;
[111]710  const range_list_element* cur_elem;
711  range_list* unalloc_cells;
712  range_list* unalloc_keys;
[145]713  range_list* unalloc_linked_values;
[111]714  range_list* unalloc_values;
715  range_list* unalloc_sks;
[112]716  char** parent_paths;
717  char* tmp_name;
718  char* tmp_path;
[135]719  REGFI_NK_REC* tmp_key;
720  REGFI_VK_REC* tmp_value;
[116]721  uint32 argi, arge, i, j, ret, num_unalloc_keys;
[111]722 
723  /* Process command line arguments */
724  if(argc < 2)
725  {
726    usage();
[143]727    bailOut(REGLOOKUP_EXIT_USAGE, "ERROR: Requires at least one argument.\n");
[111]728  }
729 
730  arge = argc-1;
731  for(argi = 1; argi < arge; argi++)
732  {
733    if (strcmp("-v", argv[argi]) == 0)
734      print_verbose = true;
735    else if (strcmp("-h", argv[argi]) == 0)
736      print_header = true;
737    else if (strcmp("-H", argv[argi]) == 0)
738      print_header = false;
739    else if (strcmp("-l", argv[argi]) == 0)
740      print_leftover = true;
741    else if (strcmp("-L", argv[argi]) == 0)
742      print_leftover = false;
743    else if (strcmp("-r", argv[argi]) == 0)
744      print_parsedraw = true;
745    else if (strcmp("-R", argv[argi]) == 0)
746      print_parsedraw = false;
747    else
748    {
749      usage();
750      fprintf(stderr, "ERROR: Unrecognized option: %s\n", argv[argi]);
[143]751      bailOut(REGLOOKUP_EXIT_USAGE, "");
[111]752    }
753  }
754  /*test_offset = strtol(argv[argi++], NULL, 16);*/
755
756  if((registry_file = strdup(argv[argi])) == NULL)
[143]757    bailOut(REGLOOKUP_EXIT_OSERR, "ERROR: Memory allocation problem.\n");
[111]758
759  f = regfi_open(registry_file);
760  if(f == NULL)
761  {
762    fprintf(stderr, "ERROR: Couldn't open registry file: %s\n", registry_file);
[143]763    bailOut(REGLOOKUP_EXIT_NOINPUT, "");
[111]764  }
[138]765  if(print_verbose)
766    regfi_set_message_mask(f, REGFI_MSG_ERROR|REGFI_MSG_WARN|REGFI_MSG_INFO);
767  else
768    regfi_set_message_mask(f, REGFI_MSG_ERROR);
[111]769
770  if(print_header)
771    printf("OFFSET,REC_LENGTH,REC_TYPE,PATH,NAME,"
772           "NK_MTIME,NK_NVAL,VK_TYPE,VK_VALUE,VK_DATA_LEN,"
773           "SK_OWNER,SK_GROUP,SK_SACL,SK_DACL,RAW_CELL\n");
774
775  unalloc_cells = regfi_parse_unalloc_cells(f);
776  if(unalloc_cells == NULL)
777  {
778    fprintf(stderr, "ERROR: Could not obtain list of unallocated cells.\n");
779    return 1;
780  }
781
782  unalloc_keys = range_list_new();
783  if(unalloc_keys == NULL)
784    return 10;
785
[145]786  unalloc_linked_values = range_list_new();
787  if(unalloc_linked_values == NULL)
788    return 10;
789
[111]790  unalloc_values = range_list_new();
791  if(unalloc_values == NULL)
792    return 10;
793
794  unalloc_sks = range_list_new();
795  if(unalloc_sks == NULL)
796    return 10;
797
798  ret = extractKeys(f, unalloc_cells, unalloc_keys);
799  if(ret != 0)
800  {
801    fprintf(stderr, "ERROR: extractKeys() failed with %d.\n", ret);
802    return ret;
803  }
804
[145]805  ret = extractValueLists(f, unalloc_cells, unalloc_keys,unalloc_linked_values);
[111]806  if(ret != 0)
807  {
808    fprintf(stderr, "ERROR: extractValueLists() failed with %d.\n", ret);
809    return ret;
810  }
811
[145]812  /* Carve any orphan values */
813  ret = extractVKs(f, unalloc_cells, unalloc_values);
[111]814  if(ret != 0)
815  {
[145]816    fprintf(stderr, "ERROR: extractVKs() failed with %d.\n", ret);
[111]817    return ret;
818  }
819
[145]820  /* Carve any data associated with VK records */
821  ret = extractDataCells(f, unalloc_cells, unalloc_linked_values);
822  if(ret != 0)
823  {
824    fprintf(stderr, "ERROR: extractDataCells() failed with %d.\n", ret);
825    return ret;
826  }
827  ret = extractDataCells(f, unalloc_cells, unalloc_values);
828  if(ret != 0)
829  {
830    fprintf(stderr, "ERROR: extractDataCells() failed with %d.\n", ret);
831    return ret;
832  }
833 
[111]834  /* Carve any SK records */
835  ret = extractSKs(f, unalloc_cells, unalloc_sks);
836  if(ret != 0)
837  {
838    fprintf(stderr, "ERROR: extractSKs() failed with %d.\n", ret);
839    return ret;
840  }
841
[112]842  /* Now that we're done carving, associate recovered keys with parents,
843   * if at all possible.
844   */
845  num_unalloc_keys = range_list_size(unalloc_keys);
846  parent_paths = (char**)malloc(sizeof(char*)*num_unalloc_keys);
847  if(parent_paths == NULL)
848    return 10;
[111]849
[112]850  for(i=0; i < num_unalloc_keys; i++)
[111]851  {
852    cur_elem = range_list_get(unalloc_keys, i);
[135]853    tmp_key = (REGFI_NK_REC*)cur_elem->data;
[111]854
[112]855    if(tmp_key == NULL)
856      return 20;
857   
858    parent_paths[i] = getParentPath(f, tmp_key);
859    if(parent_paths[i] == NULL)
860      return 20;
861  }
862 
863  /* Now start the output */
864  for(i=0; i < num_unalloc_keys; i++)
865  {
866    cur_elem = range_list_get(unalloc_keys, i);
[135]867    tmp_key = (REGFI_NK_REC*)cur_elem->data;
[112]868
869    printKey(f, tmp_key, parent_paths[i]);
[114]870    if(tmp_key->num_values > 0 && tmp_key->values != NULL)
[111]871    {
[112]872      tmp_name = quote_string(tmp_key->keyname, key_special_chars);
873      tmp_path = (char*)malloc(strlen(parent_paths[i])+strlen(tmp_name)+2);
874      if(tmp_path == NULL)
[136]875      {
876        free(tmp_name);
[112]877        return 10;
[136]878      }
879
[112]880      sprintf(tmp_path, "%s/%s", parent_paths[i], tmp_name);
[145]881      for(j=0; j < tmp_key->values->num_values; j++)
[112]882      {
[145]883        tmp_value = 
884          (REGFI_VK_REC*)range_list_find_data(unalloc_linked_values, 
885                                              tmp_key->values->elements[j]
886                                              + REGFI_REGF_SIZE);
[112]887        if(tmp_value != NULL)
888          printValue(f, tmp_value, tmp_path);
889      }
890      free(tmp_path);
891      free(tmp_name);
892      free(parent_paths[i]);
[111]893    }
894  }
[112]895  free(parent_paths);
[111]896
897  /* Print out orphaned values */
898  for(i=0; i < range_list_size(unalloc_values); i++)
899  {
900    cur_elem = range_list_get(unalloc_values, i);
[135]901    tmp_value = (REGFI_VK_REC*)cur_elem->data; 
[111]902
903    printValue(f, tmp_value, "");
904  }
905 
906  if(print_leftover)
907  {
908    for(i=0; i < range_list_size(unalloc_cells); i++)
909    {
910      cur_elem = range_list_get(unalloc_cells, i);
911      printCell(f, cur_elem->offset);
912    }
913  }
914
[148]915  range_list_free(unalloc_cells);
916  range_list_free(unalloc_keys);
917  range_list_free(unalloc_linked_values);
918  range_list_free(unalloc_values);
919  range_list_free(unalloc_sks);
920
[111]921  return 0;
922}
Note: See TracBrowser for help on using the repository browser.