/* Fields from the header, extracted from little-endianness hell. */
size_t rootoffs; /* Root key offset (always an nk-block). */
size_t endpages; /* Offset of end of pages. */
-
- /* Stats. */
- size_t pages; /* Number of hbin pages read. */
- size_t blocks; /* Total number of blocks found. */
- size_t used_blocks; /* Total number of used blocks found. */
- size_t used_size; /* Total size (bytes) of used blocks. */
};
/* NB. All fields are little endian. */
struct ntreg_hbin_page {
char magic[4]; /* "hbin" */
uint32_t offset_first; /* offset from 1st block */
- uint32_t offset_next; /* offset of next (relative to this) */
+ uint32_t page_size; /* size of this page (multiple of 4KB) */
char unknown[20];
/* Linked list of blocks follows here. */
} __attribute__((__packed__));
char name[1]; /* key name follows here */
} __attribute__((__packed__));
+static uint32_t
+header_checksum (hive_h *h)
+{
+ uint32_t *daddr = (uint32_t *) h->addr;
+ size_t i;
+ uint32_t sum = 0;
+
+ for (i = 0; i < 0x1fc / 4; ++i) {
+ sum ^= le32toh (*daddr);
+ daddr++;
+ }
+
+ return sum;
+}
+
hive_h *
hivex_open (const char *filename, int flags)
{
goto error;
/* Header checksum. */
- uint32_t *daddr = (uint32_t *) h->addr;
- size_t i;
- uint32_t sum = 0;
- for (i = 0; i < 0x1fc / 4; ++i) {
- sum ^= le32toh (*daddr);
- daddr++;
- }
-
+ uint32_t sum = header_checksum (h);
if (sum != le32toh (h->hdr->csum)) {
fprintf (stderr, "hivex: %s: bad checksum in hive header\n", filename);
errno = EINVAL;
*/
int seen_root_block = 0, bad_root_block = 0;
+ /* Collect some stats. */
+ size_t pages = 0; /* Number of hbin pages read. */
+ size_t smallest_page = SIZE_MAX, largest_page = 0;
+ size_t blocks = 0; /* Total number of blocks found. */
+ size_t smallest_block = SIZE_MAX, largest_block = 0, blocks_bytes = 0;
+ size_t used_blocks = 0; /* Total number of used blocks found. */
+ size_t used_size = 0; /* Total size (bytes) of used blocks. */
+
/* Read the pages and blocks. The aim here is to be robust against
* corrupt or malicious registries. So we make sure the loops
* always make forward progress. We add the address of each block
*/
size_t off;
struct ntreg_hbin_page *page;
- for (off = 0x1000; off < h->size; off += le32toh (page->offset_next)) {
+ for (off = 0x1000; off < h->size; off += le32toh (page->page_size)) {
if (off >= h->endpages)
break;
page->magic[2] != 'i' ||
page->magic[3] != 'n') {
fprintf (stderr, "hivex: %s: trailing garbage at end of file (at 0x%zx, after %zu pages)\n",
- filename, off, h->pages);
+ filename, off, pages);
errno = ENOTSUP;
goto error;
}
+ size_t page_size = le32toh (page->page_size);
if (h->msglvl >= 2)
- fprintf (stderr, "hivex_open: page at 0x%zx\n", off);
- h->pages++;
-
- if (le32toh (page->offset_next) <= sizeof (struct ntreg_hbin_page) ||
- (le32toh (page->offset_next) & 3) != 0) {
- fprintf (stderr, "hivex: %s: pagesize %d at %zu, bad registry\n",
- filename, le32toh (page->offset_next), off);
+ fprintf (stderr, "hivex_open: page at 0x%zx, size %zu\n", off, page_size);
+ pages++;
+ if (page_size < smallest_page) smallest_page = page_size;
+ if (page_size > largest_page) largest_page = page_size;
+
+ if (page_size <= sizeof (struct ntreg_hbin_page) ||
+ (page_size & 0x0fff) != 0) {
+ fprintf (stderr, "hivex: %s: page size %zu at 0x%zx, bad registry\n",
+ filename, page_size, off);
errno = ENOTSUP;
goto error;
}
/* Read the blocks in this page. */
size_t blkoff;
struct ntreg_hbin_block *block;
- int32_t seg_len;
+ size_t seg_len;
for (blkoff = off + 0x20;
- blkoff < off + le32toh (page->offset_next);
+ blkoff < off + page_size;
blkoff += seg_len) {
- h->blocks++;
+ blocks++;
int is_root = blkoff == h->rootoffs;
if (is_root)
}
if (h->msglvl >= 2)
- fprintf (stderr, "hivex_open: %s block id %d,%d at 0x%zx%s\n",
+ fprintf (stderr, "hivex_open: %s block id %d,%d at 0x%zx size %zu%s\n",
used ? "used" : "free", block->id[0], block->id[1], blkoff,
- is_root ? " (root)" : "");
+ seg_len, is_root ? " (root)" : "");
+
+ blocks_bytes += seg_len;
+ if (seg_len < smallest_block) smallest_block = seg_len;
+ if (seg_len > largest_block) largest_block = seg_len;
if (is_root && !used)
bad_root_block = 1;
if (used) {
- h->used_blocks++;
- h->used_size += seg_len;
+ used_blocks++;
+ used_size += seg_len;
/* Root block must be an nk-block. */
if (is_root && (block->id[0] != 'n' || block->id[1] != 'k'))
if (h->msglvl >= 1)
fprintf (stderr,
"hivex_open: successfully read Windows Registry hive file:\n"
- " pages: %zu\n"
- " blocks: %zu\n"
- " blocks used: %zu\n"
- " bytes used: %zu\n",
- h->pages, h->blocks, h->used_blocks, h->used_size);
+ " pages: %zu [sml: %zu, lge: %zu]\n"
+ " blocks: %zu [sml: %zu, avg: %zu, lge: %zu]\n"
+ " blocks used: %zu\n"
+ " bytes used: %zu\n",
+ pages, smallest_page, largest_page,
+ blocks, smallest_block, blocks_bytes / blocks, largest_block,
+ used_blocks, used_size);
return h;
goto error;
}
- switch (t) {
- case hive_t_none:
+ if (vtor->value_any) {
str = hivex_value_value (h, values[i], &t, &len);
if (str == NULL) {
ret = skip_bad ? 0 : -1;
goto error;
}
- if (t != hive_t_none) {
- ret = skip_bad ? 0 : -1;
- goto error;
- }
- if (vtor->value_none &&
- vtor->value_none (h, opaque, node, values[i], t, len, key, str) == -1)
+ if (vtor->value_any (h, opaque, node, values[i], t, len, key, str) == -1)
goto error;
free (str); str = NULL;
- break;
-
- case hive_t_string:
- case hive_t_expand_string:
- case hive_t_link:
- str = hivex_value_string (h, values[i]);
- if (str == NULL) {
- if (errno != EILSEQ && errno != EINVAL) {
+ }
+ else {
+ switch (t) {
+ case hive_t_none:
+ str = hivex_value_value (h, values[i], &t, &len);
+ if (str == NULL) {
ret = skip_bad ? 0 : -1;
goto error;
}
- if (vtor->value_string_invalid_utf16) {
- str = hivex_value_value (h, values[i], &t, &len);
- if (vtor->value_string_invalid_utf16 (h, opaque, node, values[i], t, len, key, str) == -1)
- goto error;
- free (str); str = NULL;
+ if (t != hive_t_none) {
+ ret = skip_bad ? 0 : -1;
+ goto error;
}
+ if (vtor->value_none &&
+ vtor->value_none (h, opaque, node, values[i], t, len, key, str) == -1)
+ goto error;
+ free (str); str = NULL;
break;
- }
- if (vtor->value_string &&
- vtor->value_string (h, opaque, node, values[i], t, len, key, str) == -1)
- goto error;
- free (str); str = NULL;
- break;
-
- case hive_t_dword:
- case hive_t_dword_be: {
- int32_t i32 = hivex_value_dword (h, values[i]);
- if (vtor->value_dword &&
- vtor->value_dword (h, opaque, node, values[i], t, len, key, i32) == -1)
- goto error;
- break;
- }
- case hive_t_qword: {
- int64_t i64 = hivex_value_qword (h, values[i]);
- if (vtor->value_qword &&
- vtor->value_qword (h, opaque, node, values[i], t, len, key, i64) == -1)
- goto error;
- break;
- }
+ case hive_t_string:
+ case hive_t_expand_string:
+ case hive_t_link:
+ str = hivex_value_string (h, values[i]);
+ if (str == NULL) {
+ if (errno != EILSEQ && errno != EINVAL) {
+ ret = skip_bad ? 0 : -1;
+ goto error;
+ }
+ if (vtor->value_string_invalid_utf16) {
+ str = hivex_value_value (h, values[i], &t, &len);
+ if (vtor->value_string_invalid_utf16 (h, opaque, node, values[i], t, len, key, str) == -1)
+ goto error;
+ free (str); str = NULL;
+ }
+ break;
+ }
+ if (vtor->value_string &&
+ vtor->value_string (h, opaque, node, values[i], t, len, key, str) == -1)
+ goto error;
+ free (str); str = NULL;
+ break;
- case hive_t_binary:
- str = hivex_value_value (h, values[i], &t, &len);
- if (str == NULL) {
- ret = skip_bad ? 0 : -1;
- goto error;
+ case hive_t_dword:
+ case hive_t_dword_be: {
+ int32_t i32 = hivex_value_dword (h, values[i]);
+ if (vtor->value_dword &&
+ vtor->value_dword (h, opaque, node, values[i], t, len, key, i32) == -1)
+ goto error;
+ break;
}
- if (t != hive_t_binary) {
- ret = skip_bad ? 0 : -1;
- goto error;
+
+ case hive_t_qword: {
+ int64_t i64 = hivex_value_qword (h, values[i]);
+ if (vtor->value_qword &&
+ vtor->value_qword (h, opaque, node, values[i], t, len, key, i64) == -1)
+ goto error;
+ break;
}
- if (vtor->value_binary &&
- vtor->value_binary (h, opaque, node, values[i], t, len, key, str) == -1)
- goto error;
- free (str); str = NULL;
- break;
- case hive_t_multiple_strings:
- strs = hivex_value_multiple_strings (h, values[i]);
- if (strs == NULL) {
- if (errno != EILSEQ && errno != EINVAL) {
+ case hive_t_binary:
+ str = hivex_value_value (h, values[i], &t, &len);
+ if (str == NULL) {
ret = skip_bad ? 0 : -1;
goto error;
}
- if (vtor->value_string_invalid_utf16) {
- str = hivex_value_value (h, values[i], &t, &len);
- if (vtor->value_string_invalid_utf16 (h, opaque, node, values[i], t, len, key, str) == -1)
+ if (t != hive_t_binary) {
+ ret = skip_bad ? 0 : -1;
+ goto error;
+ }
+ if (vtor->value_binary &&
+ vtor->value_binary (h, opaque, node, values[i], t, len, key, str) == -1)
+ goto error;
+ free (str); str = NULL;
+ break;
+
+ case hive_t_multiple_strings:
+ strs = hivex_value_multiple_strings (h, values[i]);
+ if (strs == NULL) {
+ if (errno != EILSEQ && errno != EINVAL) {
+ ret = skip_bad ? 0 : -1;
goto error;
- free (str); str = NULL;
+ }
+ if (vtor->value_string_invalid_utf16) {
+ str = hivex_value_value (h, values[i], &t, &len);
+ if (vtor->value_string_invalid_utf16 (h, opaque, node, values[i], t, len, key, str) == -1)
+ goto error;
+ free (str); str = NULL;
+ }
+ break;
}
+ if (vtor->value_multiple_strings &&
+ vtor->value_multiple_strings (h, opaque, node, values[i], t, len, key, strs) == -1)
+ goto error;
+ free_strings (strs); strs = NULL;
break;
- }
- if (vtor->value_multiple_strings &&
- vtor->value_multiple_strings (h, opaque, node, values[i], t, len, key, strs) == -1)
- goto error;
- free_strings (strs); strs = NULL;
- break;
- case hive_t_resource_list:
- case hive_t_full_resource_description:
- case hive_t_resource_requirements_list:
- default:
- str = hivex_value_value (h, values[i], &t, &len);
- if (str == NULL) {
- ret = skip_bad ? 0 : -1;
- goto error;
+ case hive_t_resource_list:
+ case hive_t_full_resource_description:
+ case hive_t_resource_requirements_list:
+ default:
+ str = hivex_value_value (h, values[i], &t, &len);
+ if (str == NULL) {
+ ret = skip_bad ? 0 : -1;
+ goto error;
+ }
+ if (vtor->value_other &&
+ vtor->value_other (h, opaque, node, values[i], t, len, key, str) == -1)
+ goto error;
+ free (str); str = NULL;
+ break;
}
- if (vtor->value_other &&
- vtor->value_other (h, opaque, node, values[i], t, len, key, str) == -1)
- goto error;
- free (str); str = NULL;
- break;
}
free (key); key = NULL;