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

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

preliminary support for big data records

switched to using key flags rather than incorrect key types

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