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

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

decoupled value parsing from key parsing

moved linking of value records and data records up to the load layer

rewrote key/value/data linking algorithm in reglookup-recover which improved recovery results

fixed a NULL pointer dereference in range_list.c

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