source: releases/0.11.0/src/reglookup-recover.c@ 293

Last change on this file since 293 was 152, checked in by tim, 16 years ago

preliminary support for big data records

switched to using key flags rather than incorrect key types

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