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

Last change on this file since 159 was 159, checked in by tim, 14 years ago

began rearranging data parsing. Moved charater set conversion and basic parsing logic into regfi

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