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

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

fixed problem with little data in reglookup-recover

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