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

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

added support for UTF-16LE key names

  • Property svn:keywords set to Id
File size: 25.1 KB
RevLine 
[111]1/*
[121]2 * This program attempts to recover deleted data structures in a registry hive.
3 *
[138]4 * Copyright (C) 2008-2009 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 161 2009-12-07 17:01:22Z 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
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
[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
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)
[150]86      bailOut(REGLOOKUP_EXIT_OSERR, 
87              "ERROR: Could not allocate sufficient memory.\n");
[111]88    quoted_name[0] = '\0';
89
[138]90    fprintf(stderr, "WARN: NULL key name in NK record at offset %.8X.\n",
[111]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);
[136]102  free(quoted_name);
[111]103}
104
105
[135]106void printValue(REGFI_FILE* f, const REGFI_VK_REC* vk, const char* prefix)
[111]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)
[143]124      bailOut(REGLOOKUP_EXIT_OSERR, "ERROR: Could not allocate sufficient memory.\n");
[111]125    quoted_name[0] = '\0';
126  }
[159]127  /* XXX: Add command line option to choose output encoding */
128  if(vk->data != NULL 
[161]129     && !regfi_interpret_data(f, REGFI_ENCODING_ASCII, vk->type, vk->data))
[159]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);
[111]135
[159]136  quoted_value = data_to_ascii(vk->data, &conv_error);
[111]137  if(quoted_value == NULL)
138  {
139    quoted_value = malloc(1*sizeof(char));
140    if(quoted_value == NULL)
[143]141      bailOut(REGLOOKUP_EXIT_OSERR, "ERROR: Could not allocate sufficient memory.\n");
[111]142    quoted_value[0] = '\0';
143
144    if(conv_error == NULL)
[138]145      fprintf(stderr, "WARN: Could not quote value for '%s/%s'.  "
[111]146              "Memory allocation failure likely.\n", prefix, quoted_name);
147    else if(print_verbose)
[138]148      fprintf(stderr, "WARN: Could not quote value for '%s/%s'.  "
[111]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)
[138]153    fprintf(stderr, "INFO: While quoting value for '%s/%s', "
[111]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
[135]181void printSK(REGFI_FILE* f, REGFI_SK_REC* sk)
[111]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
[135]219int printCell(REGFI_FILE* f, uint32 offset)
[111]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
[112]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 */
[116]243/* XXX: This is not terribly efficient, as it may reparse many keys
[149]244 *      repeatedly.  Should try to add caching.
[112]245 */
[135]246char* getParentPath(REGFI_FILE* f, REGFI_NK_REC* nk)
[112]247{
[135]248  void_stack* path_stack = void_stack_new(REGFI_MAX_DEPTH);
249  REGFI_NK_REC* cur_ancestor;
[112]250  char* ret_val;
[157]251  uint32 virt_offset, i, stack_size, ret_val_size, ret_val_used, offset;
252  int32 max_size;
[151]253  REGFI_BUFFER* path_element;
[149]254 
[118]255  /* The path_stack size limit should guarantee that we don't recurse forever. */
[112]256  virt_offset = nk->parent_off;
[149]257  ret_val_size = 1; /* NUL */
[135]258  while(virt_offset != REGFI_OFFSET_NONE)
[157]259  {
260    offset = virt_offset+REGFI_REGF_SIZE;
261    max_size = regfi_calc_maxsize(f, offset);
262    if(max_size < 0)
[135]263      virt_offset = REGFI_OFFSET_NONE;
[112]264    else
265    {
[157]266      cur_ancestor = regfi_parse_nk(f, offset, max_size, true);
[138]267      printMsgs(f);
268
[112]269      if(cur_ancestor == NULL)
[135]270        virt_offset = REGFI_OFFSET_NONE;
[112]271      else
272      {
[161]273        if(cur_ancestor->flags & REGFI_NK_FLAG_ROOT)
[135]274          virt_offset = REGFI_OFFSET_NONE;
[112]275        else
276          virt_offset = cur_ancestor->parent_off;
277       
[151]278        path_element = talloc(path_stack, REGFI_BUFFER);
[149]279        if(path_element != NULL)
[151]280          path_element->buf = (uint8*)quote_string(cur_ancestor->keyname, 
[149]281                                                   key_special_chars);
282         
[151]283        if(path_element == NULL || path_element->buf == NULL 
[149]284           || !void_stack_push(path_stack, path_element))
[112]285        {
[150]286          /* XXX: Need to add a warning here */
287          regfi_free_key(cur_ancestor);
288          void_stack_free(path_stack);
[112]289          return NULL;
290        }
291
[149]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         */
[151]296        path_element->len = strlen((char*)path_element->buf);
297        ret_val_size += path_element->len + 1;
[149]298
[150]299        regfi_free_key(cur_ancestor);
[112]300      }
301    }
302  }
303 
304  stack_size = void_stack_size(path_stack);
[149]305  ret_val_used = 0;
[112]306  ret_val = malloc(ret_val_size);
307  if(ret_val == NULL)
308  {
[150]309    void_stack_free(path_stack);
[112]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);
[149]317    snprintf(ret_val+ret_val_used, ret_val_size-ret_val_used, 
[151]318             "/%s", path_element->buf);
319    ret_val_used += path_element->len + 1;
320    free(path_element->buf);
[150]321    talloc_free(path_element);
[112]322  }
323  void_stack_free(path_stack);
324
325  return ret_val;
326}
327
328
[111]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
[113]345bool removeRange(range_list* rl, uint32 offset, uint32 length)
[111]346{
[113]347  int32 rm_idx;
348  const range_list_element* cur_elem;
[115]349
[113]350  rm_idx = range_list_find(rl, offset);
351  if(rm_idx < 0)
[116]352  {
353    fprintf(stderr, "DEBUG: removeRange: rm_idx < 0; (%d)\n", rm_idx);
[113]354    return false;
[116]355  }
[113]356
357  cur_elem = range_list_get(rl, rm_idx);
[111]358  if(cur_elem == NULL)
359  {
[116]360    fprintf(stderr, "DEBUG: removeRange: cur_elem == NULL.  rm_idx=%d\n", rm_idx);
[111]361    return false;
362  }
363
364  if(offset > cur_elem->offset)
365  {
366    if(!range_list_split_element(rl, rm_idx, offset))
367    {
[116]368      fprintf(stderr, "DEBUG: removeRange: first split failed\n");
[111]369      return false;
370    }
371    rm_idx++;
[116]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    }
[111]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    {
[116]386      fprintf(stderr, "DEBUG: removeRange: second split failed\n");
[111]387      return false;
388    }
389  }
390 
391  if(!range_list_remove(rl, rm_idx))
392  {
[116]393    fprintf(stderr, "DEBUG: removeRange: remove failed\n");
[111]394    return false;
395  }
396
397  return true;
398}
399
400
[145]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
[157]444int extractDataCells(REGFI_FILE* file,
[145]445                     range_list* unalloc_cells,
446                     range_list* unalloc_values)
447{
448  const range_list_element* cur_elem;
449  REGFI_VK_REC* vk;
[157]450  range_list* bd_cells;
[151]451  REGFI_BUFFER data;
[157]452  uint32 i, j, offset, cell_length, length;
453  int32 max_size;
454  bool unalloc;
[145]455
[157]456  bd_cells = range_list_new();
457  if(bd_cells == NULL)
458    return 10;
459
[159]460  data.buf = NULL;
461  data.len = 0;
[145]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)
[157]467      return 11;
[145]468
[157]469    length = vk->data_size;
470    vk->data = NULL;
471    if(vk->data_size != 0)
[145]472    {
[157]473      offset = vk->data_off+REGFI_REGF_SIZE;
[145]474
475      if(vk->data_in_offset)
[157]476        data = regfi_parse_little_data(file, vk->data_off, 
477                                       length, false);
478      else
[145]479      {
[157]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)
[145]486        {
[157]487          if(cell_length - 4 < length)
488          {
489            /* Multi-cell "big data" */
[151]490
[157]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?
[152]494             */
[157]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            }
[145]553          }
[157]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          }
[145]563        }
[159]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);
[145]569      }
570    }
571  }
572
[157]573  range_list_free(bd_cells);
[145]574  return 0;
575}
576
577
[117]578/* NOTE: unalloc_keys should be an empty range_list. */
[135]579int extractKeys(REGFI_FILE* f, 
[111]580                range_list* unalloc_cells, 
581                range_list* unalloc_keys)
582{
583  const range_list_element* cur_elem;
[135]584  REGFI_NK_REC* key;
[111]585  uint32 i, j;
[150]586  int error_code = 0;
[111]587
588  for(i=0; i < range_list_size(unalloc_cells); i++)
589  {
[138]590    printMsgs(f);
[111]591    cur_elem = range_list_get(unalloc_cells, i);
[115]592    for(j=0; cur_elem->length > REGFI_NK_MIN_LENGTH
593          && j <= cur_elem->length-REGFI_NK_MIN_LENGTH; j+=8)
[111]594    {
[115]595      key = regfi_parse_nk(f, cur_elem->offset+j,
596                           cur_elem->length-j, false);
[138]597      printMsgs(f);
598
[111]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");
[150]605          error_code = 20;
606          goto fail;
[111]607        }
[150]608        talloc_steal(unalloc_keys, key);
[116]609        j+=key->cell_size-8;
[111]610      }
611    }
612  }
613
[116]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))
[150]618    {
619      error_code = 30;
620      goto fail;
621    }
[116]622  }
623
[111]624  return 0;
[150]625
626 fail:
627  regfi_free_key(key);
628  return error_code;
[111]629}
630
[135]631int extractValueLists(REGFI_FILE* f,
[111]632                      range_list* unalloc_cells,
[145]633                      range_list* unalloc_keys,
634                      range_list* unalloc_linked_values)
[111]635{
[135]636  REGFI_NK_REC* nk;
[145]637  REGFI_VK_REC* vk;
[111]638  const range_list_element* cur_elem;
[157]639  uint32 i, j, num_keys, off, values_length;
640  int32 max_size;
[111]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
[135]650    if(nk->num_values && (nk->values_off!=REGFI_OFFSET_NONE))
[111]651    {
[157]652      off = nk->values_off + REGFI_REGF_SIZE;
653      max_size = regfi_calc_maxsize(f, off);
654      if(max_size >= 0)
[111]655      {
[145]656        nk->values = regfi_load_valuelist(f, off, nk->num_values, 
[157]657                                          max_size, false);
[145]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;
[111]668
[115]669          if(!range_list_has_range(unalloc_cells, off, values_length))
[111]670          { /* We've parsed a values-list which isn't in the unallocated list,
[145]671             * so prune it.
[111]672             */
[150]673            talloc_free(nk->values);
[115]674            nk->values = NULL;
[111]675          }
676          else
677          { /* Values-list was recovered.  Remove from unalloc_cells and
678             * inspect values.
679             */
[113]680            if(!removeRange(unalloc_cells, off, values_length))
[111]681              return 20;
682
[145]683            for(j=0; j < nk->values->num_values; j++)
[111]684            {
[145]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)
[111]693              {
[145]694                if(range_list_has_range(unalloc_cells, 
695                                        vk->offset, vk->cell_size))
[111]696                {
[145]697                  if(!range_list_add(unalloc_linked_values, vk->offset,
698                                     vk->cell_size, vk))
[111]699                  {
[150]700                    talloc_free(vk);
[145]701                    return 30;
[111]702                  }
[145]703
704                  if(!removeRange(unalloc_cells, vk->offset, vk->cell_size))
705                    return 40;
[111]706                }
[145]707                else
[150]708                  talloc_free(vk);
[111]709              }
710            }
711          }
712        }
713      }
714    }
715  }
716
717  return 0;
718}
719
720
721
[118]722/* NOTE: unalloc_sks should be an empty range_list. */
[135]723int extractSKs(REGFI_FILE* f, 
[111]724               range_list* unalloc_cells,
725               range_list* unalloc_sks)
726{
727  const range_list_element* cur_elem;
[135]728  REGFI_SK_REC* sk;
[111]729  uint32 i, j;
730
731  for(i=0; i < range_list_size(unalloc_cells); i++)
732  {
[138]733    printMsgs(f);
[111]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);
[138]739      printMsgs(f);
740
[111]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        }
[148]749        talloc_steal(unalloc_sks, sk);
[118]750        j+=sk->cell_size-8;
[111]751      }
752    }
753  }
754
[118]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
[111]762  return 0;
763}
764
765
766int main(int argc, char** argv)
767{ 
[135]768  REGFI_FILE* f;
[111]769  const range_list_element* cur_elem;
770  range_list* unalloc_cells;
771  range_list* unalloc_keys;
[145]772  range_list* unalloc_linked_values;
[111]773  range_list* unalloc_values;
774  range_list* unalloc_sks;
[112]775  char** parent_paths;
776  char* tmp_name;
777  char* tmp_path;
[135]778  REGFI_NK_REC* tmp_key;
779  REGFI_VK_REC* tmp_value;
[116]780  uint32 argi, arge, i, j, ret, num_unalloc_keys;
[111]781 
782  /* Process command line arguments */
783  if(argc < 2)
784  {
785    usage();
[143]786    bailOut(REGLOOKUP_EXIT_USAGE, "ERROR: Requires at least one argument.\n");
[111]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]);
[143]810      bailOut(REGLOOKUP_EXIT_USAGE, "");
[111]811    }
812  }
813  /*test_offset = strtol(argv[argi++], NULL, 16);*/
814
815  if((registry_file = strdup(argv[argi])) == NULL)
[143]816    bailOut(REGLOOKUP_EXIT_OSERR, "ERROR: Memory allocation problem.\n");
[111]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);
[143]822    bailOut(REGLOOKUP_EXIT_NOINPUT, "");
[111]823  }
[138]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);
[111]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
[145]845  unalloc_linked_values = range_list_new();
846  if(unalloc_linked_values == NULL)
847    return 10;
848
[111]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
[145]864  ret = extractValueLists(f, unalloc_cells, unalloc_keys,unalloc_linked_values);
[111]865  if(ret != 0)
866  {
867    fprintf(stderr, "ERROR: extractValueLists() failed with %d.\n", ret);
868    return ret;
869  }
870
[145]871  /* Carve any orphan values */
872  ret = extractVKs(f, unalloc_cells, unalloc_values);
[111]873  if(ret != 0)
874  {
[145]875    fprintf(stderr, "ERROR: extractVKs() failed with %d.\n", ret);
[111]876    return ret;
877  }
878
[145]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 
[111]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
[112]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;
[111]908
[112]909  for(i=0; i < num_unalloc_keys; i++)
[111]910  {
911    cur_elem = range_list_get(unalloc_keys, i);
[135]912    tmp_key = (REGFI_NK_REC*)cur_elem->data;
[111]913
[112]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);
[135]926    tmp_key = (REGFI_NK_REC*)cur_elem->data;
[112]927
928    printKey(f, tmp_key, parent_paths[i]);
[114]929    if(tmp_key->num_values > 0 && tmp_key->values != NULL)
[111]930    {
[112]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)
[136]934      {
935        free(tmp_name);
[112]936        return 10;
[136]937      }
938
[112]939      sprintf(tmp_path, "%s/%s", parent_paths[i], tmp_name);
[145]940      for(j=0; j < tmp_key->values->num_values; j++)
[112]941      {
[145]942        tmp_value = 
943          (REGFI_VK_REC*)range_list_find_data(unalloc_linked_values, 
944                                              tmp_key->values->elements[j]
945                                              + REGFI_REGF_SIZE);
[112]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]);
[111]952    }
953  }
[112]954  free(parent_paths);
[111]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);
[135]960    tmp_value = (REGFI_VK_REC*)cur_elem->data; 
[111]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
[148]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
[111]980  return 0;
981}
Note: See TracBrowser for help on using the repository browser.