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

Last change on this file since 113 was 113, checked in by tim, 16 years ago

fixed some VK record parsing bugs

added more strict checking on unallocated ranges

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