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

Last change on this file since 293 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
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 233 2011-04-29 03:28:16Z 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", regfi_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.