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

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

improved version information interface by adding a special purpose function

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