source: releases/0.10.0/src/reglookup-recover.c@ 209

Last change on this file since 209 was 138, checked in by tim, 16 years ago

extended error message logging to allow for message type filtering

fine tuned message verbosity to more reasonable default levels for reglookup and reglookup-recover

updated related documentation

  • Property svn:keywords set to Id
File size: 23.0 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 138 2009-02-08 19:53:48Z tim $
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <sysexits.h>
25
26#include "../include/regfi.h"
27#include "../include/range_list.h"
28#include "../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(EX_OSERR, "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->fd, 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, const REGFI_VK_REC* 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 uint32 size = vk->data_size;
113
114 /* Microsoft's documentation indicates that "available memory" is
115 * the limit on value sizes. Annoying. We limit it to 1M which
116 * should rarely be exceeded, unless the file is corrupt or
117 * malicious. For more info, see:
118 * http://msdn2.microsoft.com/en-us/library/ms724872.aspx
119 */
120 /* XXX: Should probably do something different here for this tool.
121 * Also, It would be really nice if this message somehow included the
122 * name of the current value we're having trouble with, since
123 * stderr/stdout don't always sync nicely.
124 */
125 if(size > REGFI_VK_MAX_DATA_LENGTH)
126 {
127 fprintf(stderr, "WARN: value data size %d larger than "
128 "%d, truncating...\n", size, REGFI_VK_MAX_DATA_LENGTH);
129 size = REGFI_VK_MAX_DATA_LENGTH;
130 }
131
132 quoted_name = quote_string(vk->valuename, key_special_chars);
133 if (quoted_name == NULL)
134 { /* Value names are NULL when we're looking at the "(default)" value.
135 * Currently we just return a 0-length string to try an eliminate
136 * ambiguity with a literal "(default)" value. The data type of a line
137 * in the output allows one to differentiate between the parent key and
138 * this value.
139 */
140 quoted_name = malloc(1*sizeof(char));
141 if(quoted_name == NULL)
142 bailOut(EX_OSERR, "ERROR: Could not allocate sufficient memory.\n");
143 quoted_name[0] = '\0';
144 }
145
146 quoted_value = data_to_ascii(vk->data, size, vk->type, &conv_error);
147 if(quoted_value == NULL)
148 {
149 quoted_value = malloc(1*sizeof(char));
150 if(quoted_value == NULL)
151 bailOut(EX_OSERR, "ERROR: Could not allocate sufficient memory.\n");
152 quoted_value[0] = '\0';
153
154 if(conv_error == NULL)
155 fprintf(stderr, "WARN: Could not quote value for '%s/%s'. "
156 "Memory allocation failure likely.\n", prefix, quoted_name);
157 else if(print_verbose)
158 fprintf(stderr, "WARN: Could not quote value for '%s/%s'. "
159 "Returned error: %s\n", prefix, quoted_name, conv_error);
160 }
161 /* XXX: should these always be printed? */
162 else if(conv_error != NULL && print_verbose)
163 fprintf(stderr, "INFO: While quoting value for '%s/%s', "
164 "warning returned: %s\n", prefix, quoted_name, conv_error);
165
166
167 if(print_parsedraw)
168 quoted_raw = getQuotedData(f->fd, vk->offset, vk->cell_size);
169
170 str_type = regfi_type_val2str(vk->type);
171 if(str_type == NULL)
172 printf("%.8X,%.8X,VALUE,%s,%s,,,0x%.8X,%s,%d,,,,,%s\n",
173 vk->offset, vk->cell_size, prefix, quoted_name,
174 vk->type, quoted_value, vk->data_size, quoted_raw);
175 else
176 printf("%.8X,%.8X,VALUE,%s,%s,,,%s,%s,%d,,,,,%s\n",
177 vk->offset, vk->cell_size, prefix, quoted_name,
178 str_type, quoted_value, vk->data_size, quoted_raw);
179
180 if(print_parsedraw)
181 free(quoted_raw);
182 if(quoted_value != NULL)
183 free(quoted_value);
184 if(quoted_name != NULL)
185 free(quoted_name);
186 if(conv_error != NULL)
187 free(conv_error);
188}
189
190
191void printSK(REGFI_FILE* f, REGFI_SK_REC* sk)
192{
193 char* quoted_raw = NULL;
194 char* empty_str = "";
195 char* owner = regfi_get_owner(sk->sec_desc);
196 char* group = regfi_get_group(sk->sec_desc);
197 char* sacl = regfi_get_sacl(sk->sec_desc);
198 char* dacl = regfi_get_dacl(sk->sec_desc);
199
200 if(print_parsedraw)
201 quoted_raw = getQuotedData(f->fd, sk->offset, sk->cell_size);
202
203 if(owner == NULL)
204 owner = empty_str;
205 if(group == NULL)
206 group = empty_str;
207 if(sacl == NULL)
208 sacl = empty_str;
209 if(dacl == NULL)
210 dacl = empty_str;
211
212 printf("%.8X,%.8X,SK,,,,,,,,%s,%s,%s,%s,%s\n", sk->offset, sk->cell_size,
213 owner, group, sacl, dacl, quoted_raw);
214
215 if(owner != empty_str)
216 free(owner);
217 if(group != empty_str)
218 free(group);
219 if(sacl != empty_str)
220 free(sacl);
221 if(dacl != empty_str)
222 free(dacl);
223
224 if(print_parsedraw)
225 free(quoted_raw);
226}
227
228
229int printCell(REGFI_FILE* f, uint32 offset)
230{
231 char* quoted_buf;
232 uint32 cell_length;
233 bool unalloc;
234
235 if(!regfi_parse_cell(f->fd, offset, NULL, 0, &cell_length, &unalloc))
236 return 1;
237
238 quoted_buf = getQuotedData(f->fd, offset, cell_length);
239 if(quoted_buf == NULL)
240 return 2;
241
242 printf("%.8X,%.8X,RAW,,,,,,,,,,,,%s\n", offset, cell_length, quoted_buf);
243
244 free(quoted_buf);
245 return 0;
246}
247
248
249/* This function returns a properly quoted parent path or partial parent
250 * path for a given key. Returns NULL on error, "" if no path was available.
251 * Paths returned must be free()d.
252 */
253/* XXX: This is not terribly efficient, as it may reparse many keys
254 * repeatedly. Should try to add caching. Also, piecing the path
255 * together is slow and redundant.
256 */
257char* getParentPath(REGFI_FILE* f, REGFI_NK_REC* nk)
258{
259 void_stack* path_stack = void_stack_new(REGFI_MAX_DEPTH);
260 REGFI_HBIN* hbin;
261 REGFI_NK_REC* cur_ancestor;
262 char* ret_val;
263 char* path_element;
264 char* tmp_str;
265 uint32 virt_offset, i, stack_size, ret_val_size, ret_val_left, element_size;
266 uint32 max_length;
267
268 /* The path_stack size limit should guarantee that we don't recurse forever. */
269 virt_offset = nk->parent_off;
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_TYPE_ROOTKEY1)
288 || (cur_ancestor->key_type == REGFI_NK_TYPE_ROOTKEY2))
289 virt_offset = REGFI_OFFSET_NONE;
290 else
291 virt_offset = cur_ancestor->parent_off;
292
293 path_element = quote_string(cur_ancestor->keyname, key_special_chars);
294 if(path_element == NULL || !void_stack_push(path_stack, path_element))
295 {
296 free(cur_ancestor->keyname);
297 free(cur_ancestor);
298 void_stack_free_deep(path_stack);
299 return NULL;
300 }
301
302 regfi_key_free(cur_ancestor);
303 }
304 }
305 }
306
307 stack_size = void_stack_size(path_stack);
308 ret_val_size = 16*stack_size;
309 if(ret_val_size == 0)
310 ret_val_size = 1;
311 ret_val_left = ret_val_size;
312 ret_val = malloc(ret_val_size);
313 if(ret_val == NULL)
314 {
315 void_stack_free_deep(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 element_size = strlen(path_element);
324 if(ret_val_left < element_size+2)
325 {
326 ret_val_size += element_size+16;
327 ret_val_left += element_size+16;
328 tmp_str = (char*)realloc(ret_val, ret_val_size);
329 if(tmp_str == NULL)
330 {
331 free(ret_val);
332 void_stack_free_deep(path_stack);
333 return NULL;
334 }
335 ret_val = tmp_str;
336 }
337
338 ret_val_left -= snprintf(ret_val+ret_val_size-ret_val_left,ret_val_left, "/%s", path_element);
339 free(path_element);
340 }
341 void_stack_free(path_stack);
342
343 return ret_val;
344}
345
346
347static void usage(void)
348{
349 fprintf(stderr, "Usage: reglookup-recover [options] <REGISTRY_FILE>\n");
350 fprintf(stderr, "Version: %s\n", REGLOOKUP_VERSION);
351 fprintf(stderr, "Options:\n");
352 fprintf(stderr, "\t-v\t sets verbose mode.\n");
353 fprintf(stderr, "\t-h\t enables header row. (default)\n");
354 fprintf(stderr, "\t-H\t disables header row.\n");
355 fprintf(stderr, "\t-l\t enables leftover(raw) cell output.\n");
356 fprintf(stderr, "\t-L\t disables leftover(raw) cell output. (default)\n");
357 fprintf(stderr, "\t-r\t enables raw cell output for parsed cells.\n");
358 fprintf(stderr, "\t-R\t disables raw cell output for parsed cells. (default)\n");
359 fprintf(stderr, "\n");
360}
361
362
363bool removeRange(range_list* rl, uint32 offset, uint32 length)
364{
365 int32 rm_idx;
366 const range_list_element* cur_elem;
367
368 rm_idx = range_list_find(rl, offset);
369 if(rm_idx < 0)
370 {
371 fprintf(stderr, "DEBUG: removeRange: rm_idx < 0; (%d)\n", rm_idx);
372 return false;
373 }
374
375 cur_elem = range_list_get(rl, rm_idx);
376 if(cur_elem == NULL)
377 {
378 fprintf(stderr, "DEBUG: removeRange: cur_elem == NULL. rm_idx=%d\n", rm_idx);
379 return false;
380 }
381
382 if(offset > cur_elem->offset)
383 {
384 if(!range_list_split_element(rl, rm_idx, offset))
385 {
386 fprintf(stderr, "DEBUG: removeRange: first split failed\n");
387 return false;
388 }
389 rm_idx++;
390 cur_elem = range_list_get(rl, rm_idx);
391 if(cur_elem == NULL)
392 {
393 fprintf(stderr,
394 "DEBUG: removeRange: cur_elem == NULL after first split. rm_idx=%d\n",
395 rm_idx);
396 return false;
397 }
398 }
399
400 if(offset+length < cur_elem->offset+cur_elem->length)
401 {
402 if(!range_list_split_element(rl, rm_idx, offset+length))
403 {
404 fprintf(stderr, "DEBUG: removeRange: second split failed\n");
405 return false;
406 }
407 }
408
409 if(!range_list_remove(rl, rm_idx))
410 {
411 fprintf(stderr, "DEBUG: removeRange: remove failed\n");
412 return false;
413 }
414
415 return true;
416}
417
418
419/* NOTE: unalloc_keys should be an empty range_list. */
420int extractKeys(REGFI_FILE* f,
421 range_list* unalloc_cells,
422 range_list* unalloc_keys)
423{
424 const range_list_element* cur_elem;
425 REGFI_NK_REC* key;
426 uint32 i, j;
427
428 for(i=0; i < range_list_size(unalloc_cells); i++)
429 {
430 printMsgs(f);
431 cur_elem = range_list_get(unalloc_cells, i);
432 for(j=0; cur_elem->length > REGFI_NK_MIN_LENGTH
433 && j <= cur_elem->length-REGFI_NK_MIN_LENGTH; j+=8)
434 {
435 key = regfi_parse_nk(f, cur_elem->offset+j,
436 cur_elem->length-j, false);
437 printMsgs(f);
438
439 if(key != NULL)
440 {
441 if(!range_list_add(unalloc_keys, key->offset,
442 key->cell_size, key))
443 {
444 fprintf(stderr, "ERROR: Couldn't add key to unalloc_keys.\n");
445 return 20;
446 }
447 j+=key->cell_size-8;
448 }
449 }
450 }
451
452 for(i=0; i<range_list_size(unalloc_keys); i++)
453 {
454 cur_elem = range_list_get(unalloc_keys, i);
455 if(!removeRange(unalloc_cells, cur_elem->offset, cur_elem->length))
456 return 30;
457 }
458
459 return 0;
460}
461
462
463int extractValueLists(REGFI_FILE* f,
464 range_list* unalloc_cells,
465 range_list* unalloc_keys)
466{
467 REGFI_NK_REC* nk;
468 REGFI_HBIN* hbin;
469 const range_list_element* cur_elem;
470 uint32 i, j, num_keys, off, values_length, max_length;
471
472 num_keys=range_list_size(unalloc_keys);
473 for(i=0; i<num_keys; i++)
474 {
475 cur_elem = range_list_get(unalloc_keys, i);
476 if(cur_elem == NULL)
477 return 10;
478 nk = cur_elem->data;
479
480 if(nk->num_values && (nk->values_off!=REGFI_OFFSET_NONE))
481 {
482 hbin = regfi_lookup_hbin(f, nk->values_off);
483
484 if(hbin != NULL)
485 {
486 off = nk->values_off + REGFI_REGF_SIZE;
487 max_length = hbin->block_size + hbin->file_off - off;
488 /* XXX: This is a hack. We parse all value-lists, VK records,
489 * and data records without regard for current allocation status.
490 * On the off chance that such a record correctly parsed but is
491 * actually a reallocated structure used by something else, we
492 * simply prune it after the fact. Would be faster to check this
493 * up front somehow.
494 */
495 nk->values = regfi_load_valuelist(f, off, nk->num_values, max_length,
496 false);
497 values_length = (nk->num_values+1)*sizeof(uint32);
498 if(values_length != (values_length & 0xFFFFFFF8))
499 values_length = (values_length & 0xFFFFFFF8) + 8;
500
501 if(nk->values != NULL)
502 {
503 if(!range_list_has_range(unalloc_cells, off, values_length))
504 { /* We've parsed a values-list which isn't in the unallocated list,
505 * so prune it.
506 */
507 for(j=0; j<nk->num_values; j++)
508 {
509 if(nk->values[j] != NULL)
510 {
511 if(nk->values[j]->data != NULL)
512 free(nk->values[j]->data);
513 free(nk->values[j]);
514 }
515 }
516 free(nk->values);
517 nk->values = NULL;
518 }
519 else
520 { /* Values-list was recovered. Remove from unalloc_cells and
521 * inspect values.
522 */
523 if(!removeRange(unalloc_cells, off, values_length))
524 return 20;
525
526 for(j=0; j < nk->num_values; j++)
527 {
528 if(nk->values[j] != NULL)
529 {
530 if(!range_list_has_range(unalloc_cells, nk->values[j]->offset,
531 nk->values[j]->cell_size))
532 { /* We've parsed a value which isn't in the unallocated list,
533 * so prune it.
534 */
535 if(nk->values[j]->data != NULL)
536 free(nk->values[j]->data);
537 free(nk->values[j]);
538 nk->values[j] = NULL;
539 }
540 else
541 {
542 /* A VK record was recovered. Remove from unalloc_cells
543 * and inspect data.
544 */
545 if(!removeRange(unalloc_cells, nk->values[j]->offset,
546 nk->values[j]->cell_size))
547 return 21;
548
549 /* Don't bother pruning or removing from unalloc_cells if
550 * there is no data, or it is stored in the offset.
551 */
552 if(nk->values[j]->data != NULL && !nk->values[j]->data_in_offset)
553 {
554 off = nk->values[j]->data_off+REGFI_REGF_SIZE;
555 if(!range_list_has_range(unalloc_cells, off,
556 nk->values[j]->data_size))
557 { /* We've parsed a data cell which isn't in the unallocated
558 * list, so prune it.
559 */
560 free(nk->values[j]->data);
561 nk->values[j]->data = NULL;
562 }
563 else
564 { /*A data record was recovered. Remove from unalloc_cells.*/
565 if(!removeRange(unalloc_cells, off,
566 nk->values[j]->data_size))
567 return 22;
568 }
569 }
570 }
571 }
572 }
573 }
574 }
575 }
576 }
577 }
578
579 return 0;
580}
581
582
583/* NOTE: unalloc_values should be an empty range_list. */
584int extractValues(REGFI_FILE* f,
585 range_list* unalloc_cells,
586 range_list* unalloc_values)
587{
588 const range_list_element* cur_elem;
589 REGFI_VK_REC* vk;
590 uint32 i, j, off;
591
592 for(i=0; i < range_list_size(unalloc_cells); i++)
593 {
594 printMsgs(f);
595 cur_elem = range_list_get(unalloc_cells, i);
596 for(j=0; j <= cur_elem->length; j+=8)
597 {
598 vk = regfi_parse_vk(f, cur_elem->offset+j,
599 cur_elem->length-j, false);
600 printMsgs(f);
601
602 if(vk != NULL)
603 {
604 if(!range_list_add(unalloc_values, vk->offset,
605 vk->cell_size, vk))
606 {
607 fprintf(stderr, "ERROR: Couldn't add value to unalloc_values.\n");
608 return 20;
609 }
610 j+=vk->cell_size-8;
611 }
612 }
613 }
614
615 /* Remove value ranges from the unalloc_cells before we continue. */
616 for(i=0; i<range_list_size(unalloc_values); i++)
617 {
618 cur_elem = range_list_get(unalloc_values, i);
619 if(!removeRange(unalloc_cells, cur_elem->offset, cur_elem->length))
620 return 30;
621 }
622
623 /* Now see if the data associated with each value is intact */
624 for(i=0; i<range_list_size(unalloc_values); i++)
625 {
626 cur_elem = range_list_get(unalloc_values, i);
627 vk = (REGFI_VK_REC*)cur_elem->data;
628 if(vk == NULL)
629 return 40;
630
631 if(vk->data != NULL && !vk->data_in_offset)
632 {
633 off = vk->data_off+REGFI_REGF_SIZE;
634 if(!range_list_has_range(unalloc_cells, off, vk->data_size))
635 { /* We've parsed a data cell which isn't in the unallocated
636 * list, so prune it.
637 */
638 free(vk->data);
639 vk->data = NULL;
640 }
641 else
642 { /*A data record was recovered. Remove from unalloc_cells.*/
643 if(!removeRange(unalloc_cells, off, vk->data_size))
644 return 50;
645 }
646 }
647 }
648
649 return 0;
650}
651
652
653/* NOTE: unalloc_sks should be an empty range_list. */
654int extractSKs(REGFI_FILE* f,
655 range_list* unalloc_cells,
656 range_list* unalloc_sks)
657{
658 const range_list_element* cur_elem;
659 REGFI_SK_REC* sk;
660 uint32 i, j;
661
662 for(i=0; i < range_list_size(unalloc_cells); i++)
663 {
664 printMsgs(f);
665 cur_elem = range_list_get(unalloc_cells, i);
666 for(j=0; j <= cur_elem->length; j+=8)
667 {
668 sk = regfi_parse_sk(f, cur_elem->offset+j,
669 cur_elem->length-j, false);
670 printMsgs(f);
671
672 if(sk != NULL)
673 {
674 if(!range_list_add(unalloc_sks, sk->offset,
675 sk->cell_size, sk))
676 {
677 fprintf(stderr, "ERROR: Couldn't add sk to unalloc_sks.\n");
678 return 20;
679 }
680 j+=sk->cell_size-8;
681 }
682 }
683 }
684
685 for(i=0; i<range_list_size(unalloc_sks); i++)
686 {
687 cur_elem = range_list_get(unalloc_sks, i);
688 if(!removeRange(unalloc_cells, cur_elem->offset, cur_elem->length))
689 return 30;
690 }
691
692 return 0;
693}
694
695
696int main(int argc, char** argv)
697{
698 REGFI_FILE* f;
699 const range_list_element* cur_elem;
700 range_list* unalloc_cells;
701 range_list* unalloc_keys;
702 range_list* unalloc_values;
703 range_list* unalloc_sks;
704 char** parent_paths;
705 char* tmp_name;
706 char* tmp_path;
707 REGFI_NK_REC* tmp_key;
708 REGFI_VK_REC* tmp_value;
709 uint32 argi, arge, i, j, ret, num_unalloc_keys;
710 /* uint32 test_offset;*/
711
712 /* Process command line arguments */
713 if(argc < 2)
714 {
715 usage();
716 bailOut(EX_USAGE, "ERROR: Requires at least one argument.\n");
717 }
718
719 arge = argc-1;
720 for(argi = 1; argi < arge; argi++)
721 {
722 if (strcmp("-v", argv[argi]) == 0)
723 print_verbose = true;
724 else if (strcmp("-h", argv[argi]) == 0)
725 print_header = true;
726 else if (strcmp("-H", argv[argi]) == 0)
727 print_header = false;
728 else if (strcmp("-l", argv[argi]) == 0)
729 print_leftover = true;
730 else if (strcmp("-L", argv[argi]) == 0)
731 print_leftover = false;
732 else if (strcmp("-r", argv[argi]) == 0)
733 print_parsedraw = true;
734 else if (strcmp("-R", argv[argi]) == 0)
735 print_parsedraw = false;
736 else
737 {
738 usage();
739 fprintf(stderr, "ERROR: Unrecognized option: %s\n", argv[argi]);
740 bailOut(EX_USAGE, "");
741 }
742 }
743 /*test_offset = strtol(argv[argi++], NULL, 16);*/
744
745 if((registry_file = strdup(argv[argi])) == NULL)
746 bailOut(EX_OSERR, "ERROR: Memory allocation problem.\n");
747
748 f = regfi_open(registry_file);
749 if(f == NULL)
750 {
751 fprintf(stderr, "ERROR: Couldn't open registry file: %s\n", registry_file);
752 bailOut(EX_NOINPUT, "");
753 }
754 if(print_verbose)
755 regfi_set_message_mask(f, REGFI_MSG_ERROR|REGFI_MSG_WARN|REGFI_MSG_INFO);
756 else
757 regfi_set_message_mask(f, REGFI_MSG_ERROR);
758
759 if(print_header)
760 printf("OFFSET,REC_LENGTH,REC_TYPE,PATH,NAME,"
761 "NK_MTIME,NK_NVAL,VK_TYPE,VK_VALUE,VK_DATA_LEN,"
762 "SK_OWNER,SK_GROUP,SK_SACL,SK_DACL,RAW_CELL\n");
763
764 unalloc_cells = regfi_parse_unalloc_cells(f);
765 if(unalloc_cells == NULL)
766 {
767 fprintf(stderr, "ERROR: Could not obtain list of unallocated cells.\n");
768 return 1;
769 }
770
771 unalloc_keys = range_list_new();
772 if(unalloc_keys == NULL)
773 return 10;
774
775 unalloc_values = range_list_new();
776 if(unalloc_values == NULL)
777 return 10;
778
779 unalloc_sks = range_list_new();
780 if(unalloc_sks == NULL)
781 return 10;
782
783 ret = extractKeys(f, unalloc_cells, unalloc_keys);
784 if(ret != 0)
785 {
786 fprintf(stderr, "ERROR: extractKeys() failed with %d.\n", ret);
787 return ret;
788 }
789
790 ret = extractValueLists(f, unalloc_cells, unalloc_keys);
791 if(ret != 0)
792 {
793 fprintf(stderr, "ERROR: extractValueLists() failed with %d.\n", ret);
794 return ret;
795 }
796
797 /* Carve any orphan values and associated data */
798 ret = extractValues(f, unalloc_cells, unalloc_values);
799 if(ret != 0)
800 {
801 fprintf(stderr, "ERROR: extractValues() failed with %d.\n", ret);
802 return ret;
803 }
804
805 /* Carve any SK records */
806 ret = extractSKs(f, unalloc_cells, unalloc_sks);
807 if(ret != 0)
808 {
809 fprintf(stderr, "ERROR: extractSKs() failed with %d.\n", ret);
810 return ret;
811 }
812
813 /* Now that we're done carving, associate recovered keys with parents,
814 * if at all possible.
815 */
816 num_unalloc_keys = range_list_size(unalloc_keys);
817 parent_paths = (char**)malloc(sizeof(char*)*num_unalloc_keys);
818 if(parent_paths == NULL)
819 return 10;
820
821 for(i=0; i < num_unalloc_keys; i++)
822 {
823 cur_elem = range_list_get(unalloc_keys, i);
824 tmp_key = (REGFI_NK_REC*)cur_elem->data;
825
826 if(tmp_key == NULL)
827 return 20;
828
829 parent_paths[i] = getParentPath(f, tmp_key);
830 if(parent_paths[i] == NULL)
831 return 20;
832 }
833
834 /* Now start the output */
835
836 for(i=0; i < num_unalloc_keys; i++)
837 {
838 cur_elem = range_list_get(unalloc_keys, i);
839 tmp_key = (REGFI_NK_REC*)cur_elem->data;
840
841 printKey(f, tmp_key, parent_paths[i]);
842 if(tmp_key->num_values > 0 && tmp_key->values != NULL)
843 {
844 tmp_name = quote_string(tmp_key->keyname, key_special_chars);
845 tmp_path = (char*)malloc(strlen(parent_paths[i])+strlen(tmp_name)+2);
846 if(tmp_path == NULL)
847 {
848 free(tmp_name);
849 return 10;
850 }
851
852 sprintf(tmp_path, "%s/%s", parent_paths[i], tmp_name);
853 for(j=0; j < tmp_key->num_values; j++)
854 {
855 tmp_value = tmp_key->values[j];
856 if(tmp_value != NULL)
857 printValue(f, tmp_value, tmp_path);
858 }
859 free(tmp_path);
860 free(tmp_name);
861 free(parent_paths[i]);
862 }
863 }
864 free(parent_paths);
865
866 /* Print out orphaned values */
867 for(i=0; i < range_list_size(unalloc_values); i++)
868 {
869 cur_elem = range_list_get(unalloc_values, i);
870 tmp_value = (REGFI_VK_REC*)cur_elem->data;
871
872 printValue(f, tmp_value, "");
873 }
874
875 if(print_leftover)
876 {
877 for(i=0; i < range_list_size(unalloc_cells); i++)
878 {
879 cur_elem = range_list_get(unalloc_cells, i);
880 printCell(f, cur_elem->offset);
881 }
882 }
883
884 return 0;
885}
Note: See TracBrowser for help on using the repository browser.