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

Last change on this file since 228 was 228, checked in by tim, 13 years ago

added a test case for pyregfi multithreaded use
updated the regfi multithreaded test case
fixed several ctypes interface problems in pyregfi
added locking to pyregfi iterators for thread safety
fixed regfi talloc race conditions with an additional lock

  • Property svn:keywords set to Id
File size: 25.5 KB
Line 
1/*
2 * This program attempts to recover deleted data structures in a registry hive.
3 *
4 * Copyright (C) 2008-2010 Timothy D. Morgan
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 * $Id: reglookup-recover.c 228 2011-04-18 20:25:46Z tim $
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24
25#include "talloc.h"
26#include "regfi.h"
27#include "range_list.h"
28#include "lru_cache.h"
29
30
31/* Globals, influenced by command line parameters */
32bool print_verbose = false;
33bool print_security = false;
34bool print_header = true;
35bool print_leftover = false;
36bool print_parsedraw = false;
37const char* registry_file = NULL;
38
39#include "common.c"
40
41
42char* getQuotedData(REGFI_RAW_FILE* file_cb, uint32_t offset, uint32_t length)
43{
44  uint8_t* buf;
45  char* quoted_buf;
46  uint32_t len;
47
48  if((regfi_seek(file_cb, offset, SEEK_SET)) == -1)
49    return NULL;
50
51  buf = (uint8_t*)malloc(length);
52  if(buf == NULL)
53    return NULL;
54
55  len = length;
56  if((regfi_read(file_cb, buf, &length) != 0) || length != len)
57  {
58    free(buf);
59    return NULL;
60  }
61
62  quoted_buf = quote_buffer(buf, length, common_special_chars);
63  free(buf);
64
65  return quoted_buf;
66}
67
68/* XXX: Somewhere in here, need to start looking for and handling classnames */
69void printKey(REGFI_FILE* f, REGFI_NK* nk, const char* prefix)
70{
71  char mtime[24];
72  char* quoted_name = NULL;
73  char* quoted_raw = "";
74
75  formatTime(&nk->mtime, mtime);
76 
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);
81  if (quoted_name == NULL)
82  {
83    quoted_name = malloc(1*sizeof(char));
84    if(quoted_name == NULL)
85      bailOut(REGLOOKUP_EXIT_OSERR, 
86              "ERROR: Could not allocate sufficient memory.\n");
87    quoted_name[0] = '\0';
88
89    fprintf(stderr, "WARN: NULL key name in NK record at offset %.8X.\n",
90            nk->offset);
91  }
92
93  if(print_parsedraw)
94    quoted_raw = getQuotedData(f->cb, nk->offset, nk->cell_size);
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);
101  free(quoted_name);
102}
103
104
105void printValue(REGFI_FILE* f, REGFI_VK* vk, const char* prefix)
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
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);
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     */
124    quoted_name = strdup("");
125    if(quoted_name == NULL)
126      bailOut(REGLOOKUP_EXIT_OSERR, "ERROR: Could not allocate sufficient memory.\n");
127  }
128
129  /* XXX: Add command line option to choose output encoding */
130  if(vk->data != NULL 
131     && !regfi_interpret_data(f, REGFI_ENCODING_ASCII, vk->type, vk->data))
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);
137
138  quoted_value = data_to_ascii(vk->data, &conv_error);
139  if(quoted_value == NULL)
140  {
141    quoted_value = malloc(1*sizeof(char));
142    if(quoted_value == NULL)
143      bailOut(REGLOOKUP_EXIT_OSERR, "ERROR: Could not allocate sufficient memory.\n");
144    quoted_value[0] = '\0';
145
146    if(conv_error == NULL)
147      fprintf(stderr, "WARN: Could not quote value for '%s/%s'.  "
148              "Memory allocation failure likely.\n", prefix, quoted_name);
149    else if(print_verbose)
150      fprintf(stderr, "WARN: Could not quote value for '%s/%s'.  "
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)
155    fprintf(stderr, "INFO: While quoting value for '%s/%s', "
156            "warning returned: %s\n", prefix, quoted_name, conv_error);
157
158
159  if(print_parsedraw)
160    quoted_raw = getQuotedData(f->cb, vk->offset, vk->cell_size);
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
183void printSK(REGFI_FILE* f, REGFI_SK* sk)
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)
193    quoted_raw = getQuotedData(f->cb, sk->offset, sk->cell_size);
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
221int printCell(REGFI_FILE* f, uint32_t offset)
222{
223  char* quoted_buf;
224  uint32_t cell_length;
225  bool unalloc;
226
227  if(!regfi_parse_cell(f->cb, offset, NULL, 0, &cell_length, &unalloc))
228    return 1;
229
230  quoted_buf = getQuotedData(f->cb, offset, cell_length);
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
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 */
245/* XXX: This is not terribly efficient, as it may reparse many keys
246 *      repeatedly.  Should try to add caching.
247 */
248char* getParentPath(REGFI_FILE* f, REGFI_NK* nk)
249{
250  void_stack* path_stack = void_stack_new(REGFI_MAX_DEPTH);
251  REGFI_NK* cur_ancestor;
252  char* ret_val;
253  uint32_t virt_offset, i, stack_size, ret_val_size, ret_val_used, offset;
254  int32_t max_size;
255  REGFI_BUFFER* path_element;
256 
257  /* The path_stack size limit should guarantee that we don't recurse forever. */
258  virt_offset = nk->parent_off;
259  ret_val_size = 1; /* NUL */
260  while(virt_offset != REGFI_OFFSET_NONE)
261  {
262    offset = virt_offset+REGFI_REGF_SIZE;
263    max_size = regfi_calc_maxsize(f, offset);
264    if(max_size < 0)
265      virt_offset = REGFI_OFFSET_NONE;
266    else
267    {
268      cur_ancestor = regfi_parse_nk(f, offset, max_size, true);
269      printMsgs(f);
270
271      if(cur_ancestor == NULL)
272        virt_offset = REGFI_OFFSET_NONE;
273      else
274      {
275        if(cur_ancestor->flags & REGFI_NK_FLAG_ROOT)
276          virt_offset = REGFI_OFFSET_NONE;
277        else
278          virt_offset = cur_ancestor->parent_off;
279       
280        path_element = talloc(path_stack, REGFI_BUFFER);
281        if(path_element != NULL)
282        {
283          /* XXX: Add command line option to choose output encoding */
284          regfi_interpret_keyname(f, cur_ancestor, REGFI_ENCODING_ASCII, true);
285         
286          path_element->buf = (uint8_t*)get_quoted_keyname(cur_ancestor);
287        }
288 
289        if(path_element == NULL || path_element->buf == NULL 
290           || !void_stack_push(path_stack, path_element))
291        {
292          /* XXX: Need to add a warning here */
293          regfi_free_record(f, cur_ancestor);
294          void_stack_free(path_stack);
295          return NULL;
296        }
297
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         */
302        path_element->len = strlen((char*)path_element->buf);
303        ret_val_size += path_element->len + 1;
304
305        regfi_free_record(f, cur_ancestor);
306      }
307    }
308  }
309 
310  stack_size = void_stack_size(path_stack);
311  ret_val_used = 0;
312  ret_val = malloc(ret_val_size);
313  if(ret_val == NULL)
314  {
315    void_stack_free(path_stack);
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);
323    snprintf(ret_val+ret_val_used, ret_val_size-ret_val_used, 
324             "/%s", path_element->buf);
325    ret_val_used += path_element->len + 1;
326    free(path_element->buf);
327    talloc_free(path_element);
328  }
329  void_stack_free(path_stack);
330
331  return ret_val;
332}
333
334
335static void usage(void)
336{
337  fprintf(stderr, "Usage: reglookup-recover [options] <REGISTRY_FILE>\n");
338  fprintf(stderr, "Version: %s\n", REGLOOKUP_VERSION);
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
351bool removeRange(range_list* rl, uint32_t offset, uint32_t length)
352{
353  int32_t rm_idx;
354  const range_list_element* cur_elem;
355
356  rm_idx = range_list_find(rl, offset);
357  if(rm_idx < 0)
358  {
359    fprintf(stderr, "DEBUG: removeRange: rm_idx < 0; (%d)\n", rm_idx);
360    return false;
361  }
362
363  cur_elem = range_list_get(rl, rm_idx);
364  if(cur_elem == NULL)
365  {
366    fprintf(stderr, "DEBUG: removeRange: cur_elem == NULL.  rm_idx=%d\n", rm_idx);
367    return false;
368  }
369
370  if(offset > cur_elem->offset)
371  {
372    if(!range_list_split_element(rl, rm_idx, offset))
373    {
374      fprintf(stderr, "DEBUG: removeRange: first split failed\n");
375      return false;
376    }
377    rm_idx++;
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    }
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    {
392      fprintf(stderr, "DEBUG: removeRange: second split failed\n");
393      return false;
394    }
395  }
396 
397  if(!range_list_remove(rl, rm_idx))
398  {
399    fprintf(stderr, "DEBUG: removeRange: remove failed\n");
400    return false;
401  }
402
403  return true;
404}
405
406
407int extractVKs(REGFI_FILE* f,
408               range_list* unalloc_cells,
409               range_list* unalloc_values)
410{
411  const range_list_element* cur_elem;
412  REGFI_VK* vk;
413  uint32_t i, j;
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
450int extractDataCells(REGFI_FILE* file,
451                     range_list* unalloc_cells,
452                     range_list* unalloc_values)
453{
454  const range_list_element* cur_elem;
455  REGFI_VK* vk;
456  range_list* bd_cells;
457  REGFI_BUFFER data;
458  uint32_t i, j, offset, cell_length, length;
459  int32_t max_size;
460  bool unalloc;
461
462  bd_cells = range_list_new();
463  if(bd_cells == NULL)
464    return 10;
465
466  data.buf = NULL;
467  data.len = 0;
468  for(i=0; i<range_list_size(unalloc_values); i++)
469  {
470    cur_elem = range_list_get(unalloc_values, i);
471    vk = (REGFI_VK*)cur_elem->data;
472    if(vk == NULL)
473      return 11;
474
475    length = vk->data_size;
476    vk->data = NULL;
477    if(vk->data_size != 0)
478    {
479      offset = vk->data_off+REGFI_REGF_SIZE;
480
481      if(vk->data_in_offset)
482        data = regfi_parse_little_data(file, vk->data_off, 
483                                       length, false);
484      else
485      {
486        max_size = regfi_calc_maxsize(file, offset);
487        if(max_size >= 0 
488           && regfi_parse_cell(file->cb, offset, NULL, 0,
489                               &cell_length, &unalloc)
490           && (cell_length & 0x00000007) == 0
491           && cell_length <= max_size)
492        {
493          if(cell_length - 4 < length)
494          {
495            /* Multi-cell "big data" */
496
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?
500             */
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            }
559          }
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          }
569        }
570      }
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);
575      talloc_reparent(NULL, vk, vk->data);
576    }
577  }
578
579  range_list_free(bd_cells);
580  return 0;
581}
582
583
584/* NOTE: unalloc_keys should be an empty range_list. */
585int extractKeys(REGFI_FILE* f, 
586                range_list* unalloc_cells, 
587                range_list* unalloc_keys)
588{
589  const range_list_element* cur_elem;
590  REGFI_NK* key;
591  uint32_t i, j;
592  int error_code = 0;
593
594  for(i=0; i < range_list_size(unalloc_cells); i++)
595  {
596    printMsgs(f);
597    cur_elem = range_list_get(unalloc_cells, i);
598    for(j=0; cur_elem->length > REGFI_NK_MIN_LENGTH
599          && j <= cur_elem->length-REGFI_NK_MIN_LENGTH; j+=8)
600    {
601      key = regfi_parse_nk(f, cur_elem->offset+j,
602                           cur_elem->length-j, false);
603      printMsgs(f);
604
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");
611          error_code = 20;
612          goto fail;
613        }
614        talloc_reparent(NULL, unalloc_keys, key);
615        j+=key->cell_size-8;
616      }
617    }
618  }
619
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))
624    {
625      error_code = 30;
626      goto fail;
627    }
628  }
629
630  return 0;
631
632 fail:
633  regfi_free_record(f, key);
634  return error_code;
635}
636
637int extractValueLists(REGFI_FILE* f,
638                      range_list* unalloc_cells,
639                      range_list* unalloc_keys,
640                      range_list* unalloc_linked_values)
641{
642  REGFI_NK* nk;
643  REGFI_VK* vk;
644  const range_list_element* cur_elem;
645  uint32_t i, j, num_keys, off, values_length;
646  int32_t max_size;
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
656    if(nk->num_values && (nk->values_off!=REGFI_OFFSET_NONE))
657    {
658      off = nk->values_off + REGFI_REGF_SIZE;
659      max_size = regfi_calc_maxsize(f, off);
660      if(max_size >= 0)
661      {
662        nk->values = regfi_load_valuelist(f, off, nk->num_values, 
663                                          max_size, false);
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           */
671          values_length = (nk->values->num_values+1)*sizeof(uint32_t);
672          if(values_length != (values_length & 0xFFFFFFF8))
673            values_length = (values_length & 0xFFFFFFF8) + 8;
674
675          if(!range_list_has_range(unalloc_cells, off, values_length))
676          { /* We've parsed a values-list which isn't in the unallocated list,
677             * so prune it.
678             */
679            talloc_free(nk->values);
680            nk->values = NULL;
681          }
682          else
683          { /* Values-list was recovered.  Remove from unalloc_cells and
684             * inspect values.
685             */
686            if(!removeRange(unalloc_cells, off, values_length))
687              return 20;
688
689            for(j=0; j < nk->values->num_values; j++)
690            {
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)
699              {
700                if(range_list_has_range(unalloc_cells, 
701                                        vk->offset, vk->cell_size))
702                {
703                  if(!range_list_add(unalloc_linked_values, vk->offset,
704                                     vk->cell_size, vk))
705                  {
706                    talloc_free(vk);
707                    return 30;
708                  }
709
710                  if(!removeRange(unalloc_cells, vk->offset, vk->cell_size))
711                    return 40;
712                }
713                else
714                  talloc_free(vk);
715              }
716            }
717          }
718        }
719      }
720    }
721  }
722
723  return 0;
724}
725
726
727
728/* NOTE: unalloc_sks should be an empty range_list. */
729int extractSKs(REGFI_FILE* f, 
730               range_list* unalloc_cells,
731               range_list* unalloc_sks)
732{
733  const range_list_element* cur_elem;
734  REGFI_SK* sk;
735  uint32_t i, j;
736
737  for(i=0; i < range_list_size(unalloc_cells); i++)
738  {
739    printMsgs(f);
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);
745      printMsgs(f);
746
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        }
755        talloc_reparent(NULL, unalloc_sks, sk);
756        j+=sk->cell_size-8;
757      }
758    }
759  }
760
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
768  return 0;
769}
770
771
772int main(int argc, char** argv)
773{ 
774  REGFI_FILE* f;
775  const range_list_element* cur_elem;
776  range_list* unalloc_cells;
777  range_list* unalloc_keys;
778  range_list* unalloc_linked_values;
779  range_list* unalloc_values;
780  range_list* unalloc_sks;
781  char** parent_paths;
782  char* tmp_name;
783  char* tmp_path;
784  REGFI_NK* tmp_key;
785  REGFI_VK* tmp_value;
786  uint32_t argi, arge, i, j, ret, num_unalloc_keys;
787  int fd;
788
789  /* Process command line arguments */
790  if(argc < 2)
791  {
792    usage();
793    bailOut(REGLOOKUP_EXIT_USAGE, "ERROR: Requires at least one argument.\n");
794  }
795 
796  arge = argc-1;
797  for(argi = 1; argi < arge; argi++)
798  {
799    if (strcmp("-v", argv[argi]) == 0)
800      print_verbose = true;
801    else if (strcmp("-h", argv[argi]) == 0)
802      print_header = true;
803    else if (strcmp("-H", argv[argi]) == 0)
804      print_header = false;
805    else if (strcmp("-l", argv[argi]) == 0)
806      print_leftover = true;
807    else if (strcmp("-L", argv[argi]) == 0)
808      print_leftover = false;
809    else if (strcmp("-r", argv[argi]) == 0)
810      print_parsedraw = true;
811    else if (strcmp("-R", argv[argi]) == 0)
812      print_parsedraw = false;
813    else
814    {
815      usage();
816      fprintf(stderr, "ERROR: Unrecognized option: %s\n", argv[argi]);
817      bailOut(REGLOOKUP_EXIT_USAGE, "");
818    }
819  }
820  registry_file = argv[argi];
821
822  fd = openHive(registry_file);
823  if(fd < 0)
824  {
825    fprintf(stderr, "ERROR: Couldn't open registry file: %s\n", registry_file);
826    bailOut(REGLOOKUP_EXIT_NOINPUT, "");
827  }
828
829  if(print_verbose)
830    regfi_log_set_mask(REGFI_LOG_ERROR|REGFI_LOG_WARN|REGFI_LOG_INFO);
831  else
832    regfi_log_set_mask(REGFI_LOG_ERROR);
833
834  /* XXX: add command line option to choose output encoding */
835  f = regfi_alloc(fd, REGFI_ENCODING_ASCII);
836  if(f == NULL)
837  {
838    close(fd);
839    bailOut(REGLOOKUP_EXIT_NOINPUT, "ERROR: Failed to create REGFI_FILE structure.\n");
840  }
841
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
858  unalloc_linked_values = range_list_new();
859  if(unalloc_linked_values == NULL)
860    return 10;
861
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
877  ret = extractValueLists(f, unalloc_cells, unalloc_keys,unalloc_linked_values);
878  if(ret != 0)
879  {
880    fprintf(stderr, "ERROR: extractValueLists() failed with %d.\n", ret);
881    return ret;
882  }
883
884  /* Carve any orphan values */
885  ret = extractVKs(f, unalloc_cells, unalloc_values);
886  if(ret != 0)
887  {
888    fprintf(stderr, "ERROR: extractVKs() failed with %d.\n", ret);
889    return ret;
890  }
891
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 
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
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;
921
922  for(i=0; i < num_unalloc_keys; i++)
923  {
924    cur_elem = range_list_get(unalloc_keys, i);
925    tmp_key = (REGFI_NK*)cur_elem->data;
926
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);
939    tmp_key = (REGFI_NK*)cur_elem->data;
940
941    printKey(f, tmp_key, parent_paths[i]);
942    if(tmp_key->num_values > 0 && tmp_key->values != NULL)
943    {
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);
948      tmp_path = (char*)malloc(strlen(parent_paths[i])+strlen(tmp_name)+2);
949      if(tmp_path == NULL)
950      {
951        free(tmp_name);
952        return 10;
953      }
954
955      sprintf(tmp_path, "%s/%s", parent_paths[i], tmp_name);
956      for(j=0; j < tmp_key->values->num_values; j++)
957      {
958        tmp_value = 
959          (REGFI_VK*)range_list_find_data(unalloc_linked_values, 
960                                          tmp_key->values->elements[j]
961                                          + REGFI_REGF_SIZE);
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]);
968    }
969  }
970  free(parent_paths);
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);
976    tmp_value = (REGFI_VK*)cur_elem->data; 
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
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
996  regfi_free(f);
997  close(fd);
998
999  return 0;
1000}
Note: See TracBrowser for help on using the repository browser.