Changeset 157
- Timestamp:
- 11/22/09 19:47:22 (15 years ago)
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
Makefile
r51 r157 4 4 ################################################################################ 5 5 6 SVN_URL=svn+ssh:// sentinelchicken.org/home/projects/subversion/reglookup6 SVN_URL=svn+ssh://pascal.sentinelchicken.org/home/projects/subversion/reglookup 7 7 SUB_DIRS=$(wildcard releases/*) trunk 8 8 … … 12 12 13 13 14 RELEASE_NAME=reglookup-t est14 RELEASE_NAME=reglookup-trunk 15 15 RELEASE_DEST=. 16 16 -
trunk/doc/devel/TODO
r153 r157 15 15 descriptor information. Maybe by MTIME as well. 16 16 17 - Testing, testing, and more testing. reglookup needs to be tested on18 NT/XP/2k3/Vista. A regression test suite would be nice too. Some19 thoughts on this include a script which randomly fuzzes an existing20 registry file, and tries to detect crashes of reglookup when parsing21 it. Another test script might randomly truncate an existing registry22 file, which will help improve reglookup's parsing on fragmentary23 files.17 - Testing, testing, and more testing. reglookup needs to be more 18 heavily tested on all recent Windows platforms. A regression test 19 suite would be nice too. Some thoughts on this include a script 20 which randomly fuzzes an existing registry file, and tries to detect 21 crashes of reglookup when parsing it. Another test script might 22 randomly truncate an existing registry file, which will help improve 23 reglookup's parsing on fragmentary files. 24 24 25 25 - Build system. I do not wish to use automake/autoconf in this … … 50 50 to integrate parts that are being kept into regfi or other modules. 51 51 52 - Need to figure out a reasonably correct way to convert UTF-16LE charaters 53 to ASCII under Windows/MingW or other platforms that don't have proper 54 libiconv support yet. Then a build-time option or autodetection can 55 dictate which version of conversion function is used. 52 - Consider switching from libiconv to Joachim Metz's libuna for 53 increased portability and easier builds. 56 54 57 55 - Grep through the source for 'XXX', and you'll find more. -
trunk/include/regfi.h
r152 r157 105 105 #define REGFI_SK_MIN_LENGTH 0x14 106 106 #define REGFI_SUBKEY_LIST_MIN_LEN 0x4 107 #define REGFI_BIG_DATA_MIN_LENGTH 0xC 107 108 108 109 … … 444 445 445 446 447 448 446 449 /******************************************************************************/ 447 450 /* Main iterator API */ … … 468 471 bool regfi_iterator_to_root(REGFI_ITERATOR* i); 469 472 470 bool regfi_iterator_find_subkey(REGFI_ITERATOR* i,471 const char* subkey_name);472 473 bool regfi_iterator_walk_path(REGFI_ITERATOR* i, 473 474 const char** path); … … 478 479 REGFI_NK_REC* regfi_iterator_cur_subkey(REGFI_ITERATOR* i); 479 480 REGFI_NK_REC* regfi_iterator_next_subkey(REGFI_ITERATOR* i); 480 481 bool regfi_iterator_find_value(REGFI_ITERATOR* i, 482 const char* value_name); 481 bool regfi_iterator_find_subkey(REGFI_ITERATOR* i, 482 const char* subkey_name); 483 483 484 REGFI_VK_REC* regfi_iterator_first_value(REGFI_ITERATOR* i); 484 485 REGFI_VK_REC* regfi_iterator_cur_value(REGFI_ITERATOR* i); 485 486 REGFI_VK_REC* regfi_iterator_next_value(REGFI_ITERATOR* i); 487 bool regfi_iterator_find_value(REGFI_ITERATOR* i, 488 const char* value_name); 489 490 REGFI_DATA* regfi_iterator_cur_data(REGFI_ITERATOR* i); 486 491 487 492 … … 500 505 bool strict); 501 506 507 REGFI_BUFFER regfi_load_data(REGFI_FILE* file, uint32 voffset, 508 uint32 length, bool data_in_offset, 509 bool strict); 510 511 REGFI_BUFFER regfi_load_big_data(REGFI_FILE* file, uint32 offset, 512 uint32 data_length,uint32 cell_length, 513 range_list* used_ranges, 514 bool strict); 515 502 516 /* These are cached so return values don't need to be freed. */ 503 517 const REGFI_SK_REC* regfi_load_sk(REGFI_FILE* file, uint32 offset, 504 518 bool strict); 505 const REGFI_HBIN* regfi_lookup_hbin(REGFI_FILE* file, uint32 voffset); 506 519 const REGFI_HBIN* regfi_lookup_hbin(REGFI_FILE* file, uint32 offset); 507 520 508 521 … … 535 548 uint32 max_size, bool strict); 536 549 537 REGFI_BUFFER regfi_load_data(REGFI_FILE* file,538 uint32 data_type, uint32 offset,539 uint32 length, uint32 max_size,540 bool data_in_offset, bool strict);541 542 REGFI_BUFFER regfi_load_big_data(REGFI_FILE* file,543 uint32 offset, uint32 data_length,544 uint32 cell_length, bool strict);545 546 550 REGFI_SK_REC* regfi_parse_sk(REGFI_FILE* file, uint32 offset, 547 551 uint32 max_size, bool strict); … … 556 560 uint16* name_length, 557 561 uint32 max_size, bool strict); 562 563 REGFI_BUFFER regfi_parse_data(REGFI_FILE* file, uint32 offset, 564 uint32 length, bool strict); 565 566 REGFI_BUFFER regfi_parse_little_data(REGFI_FILE* file, uint32 voffset, 567 uint32 length, bool strict); 568 558 569 559 570 /* Dispose of previously parsed records */ … … 588 599 REGFI_NK_REC* regfi_copy_nk(const REGFI_NK_REC* nk); 589 600 REGFI_VK_REC* regfi_copy_vk(const REGFI_VK_REC* vk); 601 int32 regfi_calc_maxsize(REGFI_FILE* file, uint32 offset); 590 602 591 603 #endif /* _REGFI_H */ -
trunk/include/smb_deps.h
r134 r157 40 40 #include "byteorder.h" 41 41 42 #define DEBUG(lvl,body) 043 44 void* zalloc(size_t size);45 void* zcalloc(size_t size, unsigned int count);46 47 42 /* From includes.h */ 48 43 44 /* XXX: convert all code to use the more standard "*_t" types */ 49 45 #define uint8 uint8_t 50 46 #define int16 int8_t … … 52 48 #define int32 int32_t 53 49 #define uint32 uint32_t 50 #define int64 int64_t 51 #define uint64 uint64_t 54 52 55 53 #define MIN(a,b) ((a)<(b)?(a):(b)) 56 54 #define MAX(a,b) ((a)>(b)?(a):(b)) 57 58 extern int DEBUGLEVEL;59 55 60 56 /* End of stuff from includes.h */ -
trunk/lib/regfi.c
r155 r157 471 471 472 472 473 /******************************************************************* 473 /****************************************************************************** 474 474 * Given an offset and an hbin, is the offset within that hbin? 475 475 * The offset is a virtual file offset. 476 ******************************************************************* /476 ******************************************************************************/ 477 477 static bool regfi_offset_in_hbin(const REGFI_HBIN* hbin, uint32 voffset) 478 478 { … … 489 489 490 490 491 /******************************************************************* 492 * Provide a virtual offset and receive the correpsonding HBIN491 /****************************************************************************** 492 * Provide a physical offset and receive the correpsonding HBIN 493 493 * block for it. NULL if one doesn't exist. 494 *******************************************************************/ 495 const REGFI_HBIN* regfi_lookup_hbin(REGFI_FILE* file, uint32 voffset) 496 { 497 return (const REGFI_HBIN*)range_list_find_data(file->hbins, 498 voffset+REGFI_REGF_SIZE); 499 } 500 494 ******************************************************************************/ 495 const REGFI_HBIN* regfi_lookup_hbin(REGFI_FILE* file, uint32 offset) 496 { 497 return (const REGFI_HBIN*)range_list_find_data(file->hbins, offset); 498 } 499 500 501 /****************************************************************************** 502 * Calculate the largest possible cell size given a physical offset. 503 * Largest size is based on the HBIN the offset is currently a member of. 504 * Returns negative values on error. 505 * (Since cells can only be ~2^31 in size, this works out.) 506 ******************************************************************************/ 507 int32 regfi_calc_maxsize(REGFI_FILE* file, uint32 offset) 508 { 509 const REGFI_HBIN* hbin = regfi_lookup_hbin(file, offset); 510 if(hbin == NULL) 511 return -1; 512 513 return (hbin->block_size + hbin->file_off) - offset; 514 } 501 515 502 516 … … 542 556 REGFI_SUBKEY_LIST* ret_val; 543 557 REGFI_SUBKEY_LIST** sublists; 544 const REGFI_HBIN* sublist_hbin;545 uint32 i, num_sublists, off, max_length;558 uint32 i, num_sublists, off; 559 int32 sublist_maxsize; 546 560 547 561 if(depth_left == 0) … … 565 579 { 566 580 off = ret_val->elements[i].offset + REGFI_REGF_SIZE; 567 sublist_hbin = regfi_lookup_hbin(file, ret_val->elements[i].offset); 568 if(sublist_hbin == NULL) 581 582 sublist_maxsize = regfi_calc_maxsize(file, off); 583 if(sublist_maxsize < 0) 569 584 sublists[i] = NULL; 570 585 else 571 { 572 max_length = sublist_hbin->block_size + sublist_hbin->file_off - off; 573 sublists[i] = regfi_load_subkeylist_aux(file, off, max_length, strict, 574 depth_left-1); 575 } 586 sublists[i] = regfi_load_subkeylist_aux(file, off, sublist_maxsize, 587 strict, depth_left-1); 576 588 } 577 589 talloc_free(ret_val); … … 792 804 ret_val->cell_size = max_size & 0xFFFFFFF8; 793 805 if((ret_val->cell_size < REGFI_SK_MIN_LENGTH) 794 || (strict && ret_val->cell_size != (ret_val->cell_size & 0xFFFFFFF8)))806 || (strict && (ret_val->cell_size & 0x00000007) != 0)) 795 807 { 796 808 regfi_add_message(file, REGFI_MSG_WARN, "Invalid cell size found while" … … 808 820 ret_val->desc_size = IVAL(sk_header, 0x10); 809 821 810 if( ret_val->prev_sk_off != (ret_val->prev_sk_off & 0xFFFFFFF8)811 || ret_val->next_sk_off != (ret_val->next_sk_off & 0xFFFFFFF8))822 if((ret_val->prev_sk_off & 0x00000007) != 0 823 || (ret_val->next_sk_off & 0x00000007) != 0) 812 824 { 813 825 regfi_add_message(file, REGFI_MSG_WARN, "SK record's next/previous offsets" … … 873 885 } 874 886 875 if( cell_length != (cell_length & 0xFFFFFFF8))887 if((cell_length & 0x00000007) != 0) 876 888 { 877 889 regfi_add_message(file, REGFI_MSG_WARN, "Cell length not a multiple of 8" … … 925 937 * with partial files. */ 926 938 if((ret_val->elements[i] + REGFI_REGF_SIZE > file->file_length) 927 || ((ret_val->elements[i] & 0x FFFFFFF8) != ret_val->elements[i]))939 || ((ret_val->elements[i] & 0x00000007) != 0)) 928 940 { 929 941 regfi_add_message(file, REGFI_MSG_WARN, "Invalid value pointer" … … 946 958 { 947 959 REGFI_VK_REC* ret_val = NULL; 948 const REGFI_HBIN* hbin;949 uint32 data_offset, data_maxsize;950 960 REGFI_BUFFER data; 951 952 hbin = regfi_lookup_hbin(file, offset - REGFI_REGF_SIZE); 953 if(!hbin) 954 return NULL; 955 956 ret_val = regfi_parse_vk(file, offset, 957 hbin->block_size + hbin->file_off - offset, strict); 958 961 int32 max_size; 962 963 max_size = regfi_calc_maxsize(file, offset); 964 if(max_size < 0) 965 return NULL; 966 967 ret_val = regfi_parse_vk(file, offset, max_size, strict); 959 968 if(ret_val == NULL) 960 969 return NULL; … … 964 973 else 965 974 { 966 if(ret_val->data_in_offset) 967 { 968 data = regfi_load_data(file, ret_val->type, ret_val->data_off, 969 ret_val->data_size, 4, 970 ret_val->data_in_offset, strict); 971 ret_val->data = data.buf; 972 ret_val->data_size = data.len; 973 } 974 else 975 { 976 hbin = regfi_lookup_hbin(file, ret_val->data_off); 977 if(hbin) 978 { 979 data_offset = ret_val->data_off+REGFI_REGF_SIZE; 980 data_maxsize = hbin->block_size + hbin->file_off - data_offset; 981 data = regfi_load_data(file, ret_val->type, data_offset, 982 ret_val->data_size, data_maxsize, 983 ret_val->data_in_offset, strict); 984 ret_val->data = data.buf; 985 ret_val->data_size = data.len; 986 987 } 988 else 989 { 990 regfi_add_message(file, REGFI_MSG_WARN, "Could not find HBIN for data" 991 " while parsing VK record at offset 0x%.8X.", 992 ret_val->offset); 993 ret_val->data = NULL; 994 } 995 } 975 data = regfi_load_data(file, ret_val->data_off, ret_val->data_size, 976 ret_val->data_in_offset, strict); 977 ret_val->data = data.buf; 978 ret_val->data_size = data.len; 996 979 997 980 if(ret_val->data == NULL) … … 1041 1024 REGFI_NK_REC* regfi_load_key(REGFI_FILE* file, uint32 offset, bool strict) 1042 1025 { 1043 const REGFI_HBIN* hbin;1044 const REGFI_HBIN* sub_hbin;1045 1026 REGFI_NK_REC* nk; 1046 uint32 max_length, off; 1047 1048 hbin = regfi_lookup_hbin(file, offset-REGFI_REGF_SIZE); 1049 if (hbin == NULL) 1027 uint32 off; 1028 int32 max_size; 1029 1030 max_size = regfi_calc_maxsize(file, offset); 1031 if (max_size < 0) 1050 1032 return NULL; 1051 1033 1052 1034 /* get the initial nk record */ 1053 max_length = hbin->block_size + hbin->file_off - offset; 1054 if((nk = regfi_parse_nk(file, offset, max_length, true)) == NULL) 1035 if((nk = regfi_parse_nk(file, offset, max_size, true)) == NULL) 1055 1036 { 1056 1037 regfi_add_message(file, REGFI_MSG_ERROR, "Could not load NK record at" … … 1062 1043 if(nk->num_values && (nk->values_off!=REGFI_OFFSET_NONE)) 1063 1044 { 1064 sub_hbin = hbin; 1065 if(!regfi_offset_in_hbin(hbin, nk->values_off)) 1066 sub_hbin = regfi_lookup_hbin(file, nk->values_off); 1067 1068 if(sub_hbin == NULL) 1045 off = nk->values_off + REGFI_REGF_SIZE; 1046 max_size = regfi_calc_maxsize(file, off); 1047 if(max_size < 0) 1069 1048 { 1070 1049 if(strict) … … 1079 1058 else 1080 1059 { 1081 off = nk->values_off + REGFI_REGF_SIZE; 1082 max_length = sub_hbin->block_size + sub_hbin->file_off - off; 1083 nk->values = regfi_load_valuelist(file, off, nk->num_values, max_length, 1084 true); 1060 nk->values = regfi_load_valuelist(file, off, nk->num_values, 1061 max_size, true); 1085 1062 if(nk->values == NULL) 1086 1063 { … … 1100 1077 if(nk->num_subkeys && (nk->subkeys_off != REGFI_OFFSET_NONE)) 1101 1078 { 1102 sub_hbin = hbin; 1103 if(!regfi_offset_in_hbin(hbin, nk->subkeys_off)) 1104 sub_hbin = regfi_lookup_hbin(file, nk->subkeys_off); 1105 1106 if(sub_hbin == NULL) 1079 off = nk->subkeys_off + REGFI_REGF_SIZE; 1080 max_size = regfi_calc_maxsize(file, off); 1081 if(max_size < 0) 1107 1082 { 1108 1083 if(strict) … … 1116 1091 else 1117 1092 { 1118 off = nk->subkeys_off + REGFI_REGF_SIZE;1119 max_length = sub_hbin->block_size + sub_hbin->file_off - off;1120 1093 nk->subkeys = regfi_load_subkeylist(file, off, nk->num_subkeys, 1121 max_ length, true);1094 max_size, true); 1122 1095 1123 1096 if(nk->subkeys == NULL) … … 1140 1113 { 1141 1114 REGFI_SK_REC* ret_val = NULL; 1142 const REGFI_HBIN* hbin; 1143 uint32 max_length; 1115 int32 max_size; 1144 1116 void* failure_ptr = NULL; 1145 1117 … … 1153 1125 if(ret_val == NULL) 1154 1126 { 1155 hbin = regfi_lookup_hbin(file, offset - REGFI_REGF_SIZE);1156 if( hbin == NULL)1127 max_size = regfi_calc_maxsize(file, offset); 1128 if(max_size < 0) 1157 1129 return NULL; 1158 1130 1159 max_length = hbin->block_size + hbin->file_off - offset; 1160 ret_val = regfi_parse_sk(file, offset, max_length, strict); 1131 ret_val = regfi_parse_sk(file, offset, max_size, strict); 1161 1132 if(ret_val == NULL) 1162 1133 { /* Cache the parse failure and bail out. */ … … 1868 1839 { 1869 1840 uint8 nk_header[REGFI_NK_MIN_LENGTH]; 1870 const REGFI_HBIN *hbin;1871 1841 REGFI_NK_REC* ret_val; 1872 1842 uint32 length,cell_length; 1873 uint32 class_offset, class_maxsize; 1843 uint32 class_offset; 1844 int32 class_maxsize; 1874 1845 bool unalloc = false; 1875 1846 … … 1906 1877 ret_val->cell_size = max_size & 0xFFFFFFF8; 1907 1878 if((ret_val->cell_size < REGFI_NK_MIN_LENGTH) 1908 || (strict && ret_val->cell_size != (ret_val->cell_size & 0xFFFFFFF8)))1879 || (strict && (ret_val->cell_size & 0x00000007) != 0)) 1909 1880 { 1910 1881 regfi_add_message(file, REGFI_MSG_WARN, "A length check failed while" … … 2004 1975 if(ret_val->classname_off != REGFI_OFFSET_NONE) 2005 1976 { 2006 hbin = regfi_lookup_hbin(file, ret_val->classname_off); 2007 if(hbin) 2008 { 2009 class_offset = ret_val->classname_off+REGFI_REGF_SIZE; 2010 class_maxsize = hbin->block_size + hbin->file_off - class_offset; 1977 class_offset = ret_val->classname_off + REGFI_REGF_SIZE; 1978 class_maxsize = regfi_calc_maxsize(file, class_offset); 1979 if(class_maxsize > 0) 1980 { 2011 1981 ret_val->classname 2012 1982 = regfi_parse_classname(file, class_offset, &ret_val->classname_length, … … 2044 2014 2045 2015 if(*name_length > 0 && offset != REGFI_OFFSET_NONE 2046 && offset == (offset & 0xFFFFFFF8))2016 && (offset & 0x00000007) == 0) 2047 2017 { 2048 2018 if(!regfi_parse_cell(file->fd, offset, NULL, 0, &cell_length, &unalloc)) … … 2053 2023 } 2054 2024 2055 if((cell_length & 0x FFFFFFF8) != cell_length)2025 if((cell_length & 0x0000007) != 0) 2056 2026 { 2057 2027 regfi_add_message(file, REGFI_MSG_ERROR, "Cell length not a multiple of 8" … … 2129 2099 ret_val->cell_size = max_size & 0xFFFFFFF8; 2130 2100 if((ret_val->cell_size < REGFI_VK_MIN_LENGTH) 2131 || ret_val->cell_size != (ret_val->cell_size & 0xFFFFFFF8))2101 || (ret_val->cell_size & 0x00000007) != 0) 2132 2102 { 2133 2103 regfi_add_message(file, REGFI_MSG_WARN, "Invalid cell size encountered" … … 2154 2124 raw_data_size = IVAL(vk_header, 0x4); 2155 2125 ret_val->data_size = raw_data_size & ~REGFI_VK_DATA_IN_OFFSET; 2126 /* The data is typically stored in the offset if the size <= 4, 2127 * in which case this flag is set. 2128 */ 2156 2129 ret_val->data_in_offset = (bool)(raw_data_size & REGFI_VK_DATA_IN_OFFSET); 2157 2130 ret_val->data_off = IVAL(vk_header, 0x8); … … 2215 2188 2216 2189 /****************************************************************************** 2217 *******************************************************************************/ 2218 REGFI_BUFFER regfi_load_data(REGFI_FILE* file, 2219 uint32 data_type, uint32 offset, 2220 uint32 length, uint32 max_size,2221 bool data_in_offset, boolstrict)2190 * 2191 ******************************************************************************/ 2192 REGFI_BUFFER regfi_load_data(REGFI_FILE* file, uint32 voffset, 2193 uint32 length, bool data_in_offset, 2194 bool strict) 2222 2195 { 2223 2196 REGFI_BUFFER ret_val; 2224 uint32 read_length, cell_length;2225 uint8 i;2197 uint32 cell_length, offset; 2198 int32 max_size; 2226 2199 bool unalloc; 2227 2200 2228 /* The data is typically stored in the offset if the size <= 4 */2229 2201 if(data_in_offset) 2230 { 2231 if(length > 4) 2232 { 2233 regfi_add_message(file, REGFI_MSG_ERROR, "Data in offset but length > 4" 2234 " while parsing data record at offset 0x%.8X.", 2235 offset); 2202 return regfi_parse_little_data(file, voffset, length, strict); 2203 else 2204 { 2205 offset = voffset + REGFI_REGF_SIZE; 2206 max_size = regfi_calc_maxsize(file, offset); 2207 if(max_size < 0) 2208 { 2209 regfi_add_message(file, REGFI_MSG_WARN, "Could not find HBIN for data" 2210 " at offset 0x%.8X.", offset); 2236 2211 goto fail; 2237 2212 } 2238 2239 if((ret_val.buf = talloc_array(NULL, uint8_t, length)) == NULL) 2240 goto fail; 2241 ret_val.len = length; 2242 2243 for(i = 0; i < length; i++) 2244 ret_val.buf[i] = (uint8)((offset >> i*8) & 0xFF); 2245 } 2246 else 2247 { 2213 2248 2214 if(!regfi_parse_cell(file->fd, offset, NULL, 0, 2249 2215 &cell_length, &unalloc)) … … 2254 2220 } 2255 2221 2256 if((cell_length & 0x FFFFFFF8) != cell_length)2222 if((cell_length & 0x00000007) != 0) 2257 2223 { 2258 2224 regfi_add_message(file, REGFI_MSG_WARN, "Cell length not multiple of 8" … … 2267 2233 " while parsing data record at offset 0x%.8X.", 2268 2234 offset); 2269 if(strict) 2270 goto fail; 2271 else 2272 cell_length = max_size; 2235 goto fail; 2273 2236 } 2274 2237 … … 2282 2245 { 2283 2246 /* Attempt to parse a big data record */ 2284 return regfi_load_big_data(file, offset, length, cell_length, strict); 2247 return regfi_load_big_data(file, offset, length, cell_length, 2248 NULL, strict); 2285 2249 } 2286 2250 else … … 2297 2261 } 2298 2262 2299 if((ret_val.buf = talloc_array(NULL, uint8_t, length)) == NULL) 2300 goto fail; 2301 ret_val.len = length; 2302 2303 read_length = length; 2304 if((regfi_read(file->fd, ret_val.buf, &read_length) != 0) 2305 || read_length != length) 2306 { 2307 regfi_add_message(file, REGFI_MSG_ERROR, "Could not read data block while" 2308 " parsing data record at offset 0x%.8X.", offset); 2309 talloc_free(ret_val.buf); 2310 goto fail; 2311 } 2263 ret_val = regfi_parse_data(file, offset, length, strict); 2312 2264 } 2313 2265 … … 2322 2274 2323 2275 /****************************************************************************** 2276 * Parses the common case data records stored in a single cell. 2277 ******************************************************************************/ 2278 REGFI_BUFFER regfi_parse_data(REGFI_FILE* file, uint32 offset, 2279 uint32 length, bool strict) 2280 { 2281 REGFI_BUFFER ret_val; 2282 uint32 read_length; 2283 2284 ret_val.buf = NULL; 2285 ret_val.len = 0; 2286 2287 if(lseek(file->fd, offset+4, SEEK_SET) == -1) 2288 { 2289 regfi_add_message(file, REGFI_MSG_WARN, "Could not seek while " 2290 "reading data at offset 0x%.8X.", offset); 2291 return ret_val; 2292 } 2293 2294 if((ret_val.buf = talloc_array(NULL, uint8_t, length)) == NULL) 2295 return ret_val; 2296 ret_val.len = length; 2297 2298 read_length = length; 2299 if((regfi_read(file->fd, ret_val.buf, &read_length) != 0) 2300 || read_length != length) 2301 { 2302 regfi_add_message(file, REGFI_MSG_ERROR, "Could not read data block while" 2303 " parsing data record at offset 0x%.8X.", offset); 2304 talloc_free(ret_val.buf); 2305 ret_val.buf = NULL; 2306 ret_val.buf = 0; 2307 } 2308 2309 return ret_val; 2310 } 2311 2312 2313 2314 /****************************************************************************** 2315 * 2316 ******************************************************************************/ 2317 REGFI_BUFFER regfi_parse_little_data(REGFI_FILE* file, uint32 voffset, 2318 uint32 length, bool strict) 2319 { 2320 REGFI_BUFFER ret_val; 2321 uint8 i; 2322 2323 ret_val.buf = NULL; 2324 ret_val.len = 0; 2325 2326 if(length > 4) 2327 { 2328 regfi_add_message(file, REGFI_MSG_ERROR, "Data in offset but length > 4" 2329 " while parsing data record. (voffset=0x%.8X, length=%d)", 2330 voffset, length); 2331 return ret_val; 2332 } 2333 2334 if((ret_val.buf = talloc_array(NULL, uint8_t, length)) == NULL) 2335 return ret_val; 2336 ret_val.len = length; 2337 2338 for(i = 0; i < length; i++) 2339 ret_val.buf[i] = (uint8)((voffset >> i*8) & 0xFF); 2340 2341 return ret_val; 2342 } 2343 2344 /****************************************************************************** 2345 *******************************************************************************/ 2346 REGFI_BUFFER regfi_parse_big_data_header(REGFI_FILE* file, uint32 offset, 2347 uint32 max_size, bool strict) 2348 { 2349 REGFI_BUFFER ret_val; 2350 uint32 cell_length; 2351 bool unalloc; 2352 2353 /* XXX: do something with unalloc? */ 2354 ret_val.buf = (uint8*)talloc_array(NULL, uint8, REGFI_BIG_DATA_MIN_LENGTH); 2355 if(ret_val.buf == NULL) 2356 goto fail; 2357 2358 if(REGFI_BIG_DATA_MIN_LENGTH > max_size) 2359 { 2360 regfi_add_message(file, REGFI_MSG_WARN, "Big data header exceeded max_size " 2361 "while parsing big data header at offset 0x%.8X.",offset); 2362 goto fail; 2363 } 2364 2365 if(!regfi_parse_cell(file->fd, offset, ret_val.buf, REGFI_BIG_DATA_MIN_LENGTH, 2366 &cell_length, &unalloc)) 2367 { 2368 regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while" 2369 " parsing big data header at offset 0x%.8X.", offset); 2370 goto fail; 2371 } 2372 2373 if((ret_val.buf[0] != 'd') || (ret_val.buf[1] != 'b')) 2374 { 2375 regfi_add_message(file, REGFI_MSG_WARN, "Unknown magic number" 2376 " (0x%.2X, 0x%.2X) encountered while parsing" 2377 " big data header at offset 0x%.8X.", 2378 ret_val.buf[0], ret_val.buf[1], offset); 2379 goto fail; 2380 } 2381 2382 ret_val.len = REGFI_BIG_DATA_MIN_LENGTH; 2383 return ret_val; 2384 2385 fail: 2386 if(ret_val.buf != NULL) 2387 { 2388 talloc_free(ret_val.buf); 2389 ret_val.buf = NULL; 2390 } 2391 ret_val.len = 0; 2392 return ret_val; 2393 } 2394 2395 2396 2397 /****************************************************************************** 2398 * 2399 ******************************************************************************/ 2400 uint32* regfi_parse_big_data_indirect(REGFI_FILE* file, uint32 offset, 2401 uint16 num_chunks, bool strict) 2402 { 2403 uint32* ret_val; 2404 uint32 indirect_length; 2405 int32 max_size; 2406 uint16 i; 2407 bool unalloc; 2408 2409 /* XXX: do something with unalloc? */ 2410 2411 max_size = regfi_calc_maxsize(file, offset); 2412 if((max_size < 0) || (num_chunks*sizeof(uint32) + 4 > max_size)) 2413 return NULL; 2414 2415 ret_val = (uint32*)talloc_array(NULL, uint32, num_chunks); 2416 if(ret_val == NULL) 2417 goto fail; 2418 2419 if(!regfi_parse_cell(file->fd, offset, (uint8*)ret_val, 2420 num_chunks*sizeof(uint32), 2421 &indirect_length, &unalloc)) 2422 { 2423 regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while" 2424 " parsing big data indirect record at offset 0x%.8X.", 2425 offset); 2426 goto fail; 2427 } 2428 2429 /* Convert pointers to proper endianess, verify they are aligned. */ 2430 for(i=0; i<num_chunks; i++) 2431 { 2432 ret_val[i] = IVAL(ret_val, i*sizeof(uint32)); 2433 if((ret_val[i] & 0x00000007) != 0) 2434 goto fail; 2435 } 2436 2437 return ret_val; 2438 2439 fail: 2440 if(ret_val != NULL) 2441 talloc_free(ret_val); 2442 return NULL; 2443 } 2444 2445 2446 /****************************************************************************** 2447 * Arguments: 2448 * file -- 2449 * offsets -- list of virtual offsets. 2450 * num_chunks -- 2451 * strict -- 2452 * 2453 * Returns: 2454 * A range_list with physical offsets and complete lengths 2455 * (including cell headers) of associated cells. 2456 * No data in range_list elements. 2457 ******************************************************************************/ 2458 range_list* regfi_parse_big_data_cells(REGFI_FILE* file, uint32* offsets, 2459 uint16 num_chunks, bool strict) 2460 { 2461 uint32 cell_length, chunk_offset, data_left; 2462 range_list* ret_val; 2463 uint16 i; 2464 bool unalloc; 2465 2466 /* XXX: do something with unalloc? */ 2467 ret_val = range_list_new(); 2468 if(ret_val == NULL) 2469 goto fail; 2470 2471 for(i=0; (i<num_chunks) && (data_left>0); i++) 2472 { 2473 chunk_offset = offsets[i]+REGFI_REGF_SIZE; 2474 if(!regfi_parse_cell(file->fd, chunk_offset, NULL, 0, 2475 &cell_length, &unalloc)) 2476 { 2477 regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while" 2478 " parsing big data chunk at offset 0x%.8X.", 2479 chunk_offset); 2480 goto fail; 2481 } 2482 2483 if(!range_list_add(ret_val, chunk_offset, cell_length, NULL)) 2484 goto fail; 2485 } 2486 2487 return ret_val; 2488 2489 fail: 2490 if(ret_val != NULL) 2491 range_list_free(ret_val); 2492 return NULL; 2493 } 2494 2495 2496 /****************************************************************************** 2324 2497 *******************************************************************************/ 2325 2498 REGFI_BUFFER regfi_load_big_data(REGFI_FILE* file, 2326 2499 uint32 offset, uint32 data_length, 2327 uint32 cell_length, bool strict) 2500 uint32 cell_length, range_list* used_ranges, 2501 bool strict) 2328 2502 { 2329 2503 REGFI_BUFFER ret_val; 2330 2504 uint16 num_chunks, i; 2331 uint32 indirect_offset, indirect_length, chunk_length, chunk_offset; 2332 uint32 read_length, data_left; 2333 bool unalloc; 2334 uint32* indirect_ptrs; 2335 uint8* big_data_cell = (uint8*)malloc(cell_length*sizeof(uint8)); 2336 if(big_data_cell == NULL) 2505 uint32 read_length, data_left, tmp_len, indirect_offset; 2506 uint32* indirect_ptrs = NULL; 2507 REGFI_BUFFER bd_header; 2508 range_list* bd_cells = NULL; 2509 const range_list_element* cell_info; 2510 2511 ret_val.buf = NULL; 2512 2513 /* XXX: Add better error/warning messages */ 2514 2515 bd_header = regfi_parse_big_data_header(file, offset, cell_length, strict); 2516 if(bd_header.buf == NULL) 2337 2517 goto fail; 2338 2518 2339 if(!regfi_parse_cell(file->fd, offset, big_data_cell, cell_length-4, 2340 &cell_length, &unalloc)) 2341 { 2342 regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while" 2343 " parsing big data record at offset 0x%.8X.", offset); 2344 free(big_data_cell); 2345 goto fail; 2346 } 2347 2348 if((big_data_cell[0] != 'd') || (big_data_cell[1] != 'b')) 2349 { 2350 regfi_add_message(file, REGFI_MSG_WARN, "Unknown magic number" 2351 " (0x%.2X, 0x%.2X) encountered while parsing" 2352 " big data record at offset 0x%.8X.", 2353 big_data_cell[0], big_data_cell[1], offset); 2354 free(big_data_cell); 2355 goto fail; 2356 } 2357 num_chunks = SVAL(big_data_cell, 0x2); 2358 /* XXX: Should check sanity of pointers here and in the indirect 2359 * block. At least ensure they are a multiple of 8. 2360 */ 2361 indirect_offset = IVAL(big_data_cell, 0x4) + REGFI_REGF_SIZE; 2362 free(big_data_cell); 2363 2364 indirect_ptrs = (uint32*)malloc(num_chunks*sizeof(uint32)); 2519 /* Keep track of used space for use by reglookup-recover */ 2520 if(used_ranges != NULL) 2521 if(!range_list_add(used_ranges, offset, cell_length, NULL)) 2522 goto fail; 2523 2524 num_chunks = SVAL(bd_header.buf, 0x2); 2525 indirect_offset = IVAL(bd_header.buf, 0x4) + REGFI_REGF_SIZE; 2526 talloc_free(bd_header.buf); 2527 2528 indirect_ptrs = regfi_parse_big_data_indirect(file, indirect_offset, 2529 num_chunks, strict); 2365 2530 if(indirect_ptrs == NULL) 2366 2531 goto fail; 2367 2532 2368 if(!regfi_parse_cell(file->fd, indirect_offset, (uint8*)indirect_ptrs, 2369 num_chunks*sizeof(uint32), 2370 &indirect_length, &unalloc)) 2371 { 2372 regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while" 2373 " parsing big data indirect record at offset 0x%.8X.", 2374 offset); 2375 free(indirect_ptrs); 2533 if(used_ranges != NULL) 2534 if(!range_list_add(used_ranges, indirect_offset, num_chunks*4+4, NULL)) 2535 goto fail; 2536 2537 if((ret_val.buf = talloc_array(NULL, uint8_t, data_length)) == NULL) 2376 2538 goto fail; 2377 } 2378 2379 if((ret_val.buf = talloc_array(NULL, uint8_t, data_length)) == NULL) 2380 { 2381 free(indirect_ptrs); 2539 data_left = data_length; 2540 2541 bd_cells = regfi_parse_big_data_cells(file, indirect_ptrs, num_chunks, strict); 2542 if(bd_cells == NULL) 2382 2543 goto fail; 2383 } 2384 data_left = data_length; 2385 2544 2545 talloc_free(indirect_ptrs); 2546 indirect_ptrs = NULL; 2547 2386 2548 for(i=0; (i<num_chunks) && (data_left>0); i++) 2387 2549 { 2388 /* Fix endianness of pointer and convert to physical offset */ 2389 chunk_offset = IVAL(indirect_ptrs, i*4) + REGFI_REGF_SIZE; 2390 if(!regfi_parse_cell(file->fd, chunk_offset, NULL, 0, 2391 &chunk_length, &unalloc)) 2392 { 2393 regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while" 2394 " parsing big data chunk at offset 0x%.8X.", 2395 chunk_offset); 2396 if(strict) 2397 goto chunk_fail; 2398 else 2399 break; 2400 } 2401 2402 /* XXX: This should be "chunk_length-4" to account for the 4 byte cell 2550 cell_info = range_list_get(bd_cells, i); 2551 if(cell_info == NULL) 2552 goto fail; 2553 2554 /* XXX: This should be "cell_info->length-4" to account for the 4 byte cell 2403 2555 * length. However, it has been observed that some (all?) chunks 2404 2556 * have an additional 4 bytes of 0 at the end of their cells that 2405 2557 * isn't part of the data, so we're trimming that off too. 2558 * Perhaps it's just an 8 byte alignment requirement... 2406 2559 */ 2407 if(chunk_length-8 >= data_left) 2560 if(cell_info->length - 8 >= data_left) 2561 { 2562 if(i+1 != num_chunks) 2563 { 2564 regfi_add_message(file, REGFI_MSG_WARN, "Left over chunks detected " 2565 "while constructing big data at offset 0x%.8X " 2566 "(chunk offset 0x%.8X).", offset, cell_info->offset); 2567 } 2408 2568 read_length = data_left; 2569 } 2409 2570 else 2410 read_length = chunk_length-8; 2411 2571 read_length = cell_info->length - 8; 2572 2573 2574 if(read_length > regfi_calc_maxsize(file, cell_info->offset)) 2575 { 2576 regfi_add_message(file, REGFI_MSG_WARN, "A chunk exceeded the maxsize " 2577 "while constructing big data at offset 0x%.8X " 2578 "(chunk offset 0x%.8X).", offset, cell_info->offset); 2579 goto fail; 2580 } 2581 2582 if(lseek(file->fd, cell_info->offset+sizeof(uint32), SEEK_SET) == -1) 2583 { 2584 regfi_add_message(file, REGFI_MSG_WARN, "Could not seek to chunk while " 2585 "constructing big data at offset 0x%.8X " 2586 "(chunk offset 0x%.8X).", offset, cell_info->offset); 2587 goto fail; 2588 } 2589 2590 tmp_len = read_length; 2412 2591 if(regfi_read(file->fd, ret_val.buf+(data_length-data_left), 2413 &read_length) != 0 )2592 &read_length) != 0 || (read_length != tmp_len)) 2414 2593 { 2415 2594 regfi_add_message(file, REGFI_MSG_WARN, "Could not read data chunk while" 2416 " constructing big data at offset 0x%.8X.", 2417 chunk_offset); 2418 if(strict) 2419 goto chunk_fail; 2420 else 2421 break; 2422 } 2595 " constructing big data at offset 0x%.8X" 2596 " (chunk offset 0x%.8X).", offset, cell_info->offset); 2597 goto fail; 2598 } 2599 2600 if(used_ranges != NULL) 2601 if(!range_list_add(used_ranges, cell_info->offset,cell_info->length,NULL)) 2602 goto fail; 2423 2603 2424 2604 data_left -= read_length; 2425 2605 } 2426 free(indirect_ptrs); 2606 range_list_free(bd_cells); 2607 2427 2608 ret_val.len = data_length-data_left; 2428 2429 return ret_val; 2430 2431 chunk_fail: 2432 free(indirect_ptrs); 2433 talloc_free(ret_val.buf); 2609 return ret_val; 2610 2434 2611 fail: 2612 if(ret_val.buf != NULL) 2613 talloc_free(ret_val.buf); 2614 if(indirect_ptrs != NULL) 2615 talloc_free(indirect_ptrs); 2616 if(bd_cells != NULL) 2617 range_list_free(bd_cells); 2435 2618 ret_val.buf = NULL; 2436 2619 ret_val.len = 0; … … 2466 2649 break; 2467 2650 2468 if((cell_len == 0) || ((cell_len & 0x FFFFFFF8) != cell_len))2651 if((cell_len == 0) || ((cell_len & 0x00000007) != 0)) 2469 2652 { 2470 2653 regfi_add_message(file, REGFI_MSG_ERROR, "Bad cell length encountered" -
trunk/lib/smb_deps.c
r147 r157 26 26 #include "smb_deps.h" 27 27 28 29 /* These act as replacements for numerous Samba memory allocation30 * functions.31 */32 void* zalloc(size_t size)33 {34 void* ret_val = NULL;35 if((size > 0) && (ret_val = (void*)malloc(size)) != NULL)36 memset(ret_val, 0, size);37 38 return ret_val;39 }40 41 void* zcalloc(size_t size, unsigned int count)42 {43 return zalloc(size*count);44 }45 28 46 29 /* From lib/time.c */ -
trunk/src/reglookup-recover.c
r152 r157 258 258 { 259 259 void_stack* path_stack = void_stack_new(REGFI_MAX_DEPTH); 260 const REGFI_HBIN* hbin;261 260 REGFI_NK_REC* cur_ancestor; 262 261 char* ret_val; 263 uint32 virt_offset, i, stack_size, ret_val_size, ret_val_used ;264 uint32 max_length;262 uint32 virt_offset, i, stack_size, ret_val_size, ret_val_used, offset; 263 int32 max_size; 265 264 REGFI_BUFFER* path_element; 266 265 … … 269 268 ret_val_size = 1; /* NUL */ 270 269 while(virt_offset != REGFI_OFFSET_NONE) 271 { 272 hbin = regfi_lookup_hbin(f, virt_offset); 273 if(hbin == NULL) 270 { 271 offset = virt_offset+REGFI_REGF_SIZE; 272 max_size = regfi_calc_maxsize(f, offset); 273 if(max_size < 0) 274 274 virt_offset = REGFI_OFFSET_NONE; 275 275 else 276 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); 277 cur_ancestor = regfi_parse_nk(f, offset, max_size, true); 281 278 printMsgs(f); 282 279 … … 456 453 457 454 458 int extractDataCells(REGFI_FILE* f ,455 int extractDataCells(REGFI_FILE* file, 459 456 range_list* unalloc_cells, 460 457 range_list* unalloc_values) … … 462 459 const range_list_element* cur_elem; 463 460 REGFI_VK_REC* vk; 464 const REGFI_HBIN* hbin;461 range_list* bd_cells; 465 462 REGFI_BUFFER data; 466 uint32 i, off, data_offset, data_maxsize; 463 uint32 i, j, offset, cell_length, length; 464 int32 max_size; 465 bool unalloc; 466 467 bd_cells = range_list_new(); 468 if(bd_cells == NULL) 469 return 10; 467 470 468 471 for(i=0; i<range_list_size(unalloc_values); i++) … … 471 474 vk = (REGFI_VK_REC*)cur_elem->data; 472 475 if(vk == NULL) 473 return 40;474 475 if(vk->data_size == 0)476 477 else478 { 479 off = vk->data_off+REGFI_REGF_SIZE;476 return 11; 477 478 length = vk->data_size; 479 vk->data = NULL; 480 if(vk->data_size != 0) 481 { 482 offset = vk->data_off+REGFI_REGF_SIZE; 480 483 481 484 if(vk->data_in_offset) 485 data = regfi_parse_little_data(file, vk->data_off, 486 length, false); 487 else 482 488 { 483 data = regfi_load_data(f, vk->type, vk->data_off, 484 vk->data_size, 4, 485 vk->data_in_offset, false); 489 max_size = regfi_calc_maxsize(file, offset); 490 if(max_size >= 0 491 && regfi_parse_cell(file->fd, offset, NULL, 0, 492 &cell_length, &unalloc) 493 && (cell_length & 0x00000007) == 0 494 && cell_length <= max_size) 495 { 496 if(cell_length - 4 < length) 497 { 498 /* Multi-cell "big data" */ 499 500 /* XXX: All big data records thus far have been 16 bytes long. 501 * Should we check for this precise size instead of just 502 * relying upon the above check? 503 */ 504 if (file->major_version >= 1 && file->minor_version >= 5) 505 { 506 /* Attempt to parse a big data record */ 507 data = regfi_load_big_data(file, offset, length, 508 cell_length, bd_cells, false); 509 510 /* XXX: if this turns out NULL, should fall back to truncating cell */ 511 if(data.buf != NULL) 512 { 513 for(j=0; j<range_list_size(bd_cells); j++) 514 { 515 cur_elem = range_list_get(bd_cells, j); 516 if(cur_elem == NULL) 517 return 20; 518 if(!range_list_has_range(unalloc_cells, 519 cur_elem->offset, 520 cur_elem->length)) 521 { 522 fprintf(stderr, 523 "WARN: Successfully parsed big data at offset" 524 " 0x%.8X was rejected because some substructure" 525 " (offset=0x%.8X) is allocated or used in other" 526 " recovered structures.\n", 527 offset, cur_elem->offset); 528 talloc_free(data.buf); 529 data.buf = NULL; 530 data.len = 0; 531 break; 532 } 533 } 534 535 if(data.buf != NULL) 536 { 537 for(j=0; j<range_list_size(bd_cells); j++) 538 { 539 cur_elem = range_list_get(bd_cells, j); 540 if(cur_elem == NULL) 541 return 21; 542 543 if(!removeRange(unalloc_cells, 544 cur_elem->offset, 545 cur_elem->length)) 546 { return 22; } 547 } 548 } 549 } 550 551 } 552 else 553 { 554 fprintf(stderr, 555 "WARN: Data length (0x%.8X)" 556 " larger than remaining cell length (0x%.8X)" 557 " while parsing data record at offset 0x%.8X." 558 " Truncating...\n", 559 length, cell_length - 4, offset); 560 length = cell_length - 4; 561 } 562 } 563 564 /* Typical 1-cell data */ 565 if(range_list_has_range(unalloc_cells, offset, length)) 566 { 567 data = regfi_parse_data(file, offset, length, false); 568 if(data.buf != NULL) 569 if(!removeRange(unalloc_cells, offset, length)) 570 return 30; 571 } 572 } 573 486 574 vk->data = data.buf; 487 575 vk->data_size = data.len; 488 576 } 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 577 } 578 } 579 580 range_list_free(bd_cells); 528 581 return 0; 529 582 } … … 590 643 REGFI_NK_REC* nk; 591 644 REGFI_VK_REC* vk; 592 const REGFI_HBIN* hbin;593 645 const range_list_element* cur_elem; 594 uint32 i, j, num_keys, off, values_length, max_length; 646 uint32 i, j, num_keys, off, values_length; 647 int32 max_size; 595 648 596 649 num_keys=range_list_size(unalloc_keys); … … 604 657 if(nk->num_values && (nk->values_off!=REGFI_OFFSET_NONE)) 605 658 { 606 hbin = regfi_lookup_hbin(f, nk->values_off);607 608 if( hbin != NULL)659 off = nk->values_off + REGFI_REGF_SIZE; 660 max_size = regfi_calc_maxsize(f, off); 661 if(max_size >= 0) 609 662 { 610 off = nk->values_off + REGFI_REGF_SIZE;611 max_length = hbin->block_size + hbin->file_off - off;612 663 nk->values = regfi_load_valuelist(f, off, nk->num_values, 613 max_ length, false);664 max_size, false); 614 665 if(nk->values != NULL && nk->values->elements != NULL) 615 666 {
Note: See TracChangeset
for help on using the changeset viewer.