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

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

reorganized data parsing in regfi

simplified some length validation

added big data support to reglookup-recover

fixed reglookup-recover's handling of data values in the offset

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