* See file LICENSE for the full license.
*/
+#include <config.h>
+
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
-#include <endian.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <iconv.h>
#include <sys/mman.h>
#include <sys/stat.h>
-#include <assert.h>
+#ifdef HAVE_ENDIAN_H
+#include <endian.h>
+#endif
+#ifdef HAVE_BYTESWAP_H
+#include <byteswap.h>
+#endif
+
+#define STREQ(a,b) (strcmp((a),(b)) == 0)
+#define STRCASEEQ(a,b) (strcasecmp((a),(b)) == 0)
+//#define STRNEQ(a,b) (strcmp((a),(b)) != 0)
+//#define STRCASENEQ(a,b) (strcasecmp((a),(b)) != 0)
+#define STREQLEN(a,b,n) (strncmp((a),(b),(n)) == 0)
+//#define STRCASEEQLEN(a,b,n) (strncasecmp((a),(b),(n)) == 0)
+//#define STRNEQLEN(a,b,n) (strncmp((a),(b),(n)) != 0)
+//#define STRCASENEQLEN(a,b,n) (strncasecmp((a),(b),(n)) != 0)
+//#define STRPREFIX(a,b) (strncmp((a),(b),strlen((b))) == 0)
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#ifndef be32toh
+#define be32toh(x) __bswap_32 (x)
+#endif
+#ifndef be64toh
+#define be64toh(x) __bswap_64 (x)
+#endif
+#ifndef le16toh
+#define le16toh(x) (x)
+#endif
+#ifndef le32toh
+#define le32toh(x) (x)
+#endif
+#ifndef le64toh
+#define le64toh(x) (x)
+#endif
+#else
+#ifndef be32toh
+#define be32toh(x) (x)
+#endif
+#ifndef be64toh
+#define be64toh(x) (x)
+#endif
+#ifndef le16toh
+#define le16toh(x) __bswap_16 (x)
+#endif
+#ifndef le32toh
+#define le32toh(x) __bswap_32 (x)
+#endif
+#ifndef le64toh
+#define le64toh(x) __bswap_64 (x)
+#endif
+#endif
#include "hivex.h"
#define BITMAP_SET(bitmap,off) (bitmap[(off)>>5] |= 1 << (((off)>>2)&7))
#define BITMAP_CLR(bitmap,off) (bitmap[(off)>>5] &= ~ (1 << (((off)>>2)&7)))
#define BITMAP_TST(bitmap,off) (bitmap[(off)>>5] & (1 << (((off)>>2)&7)))
-#define IS_VALID_BLOCK(h,off) \
+#define IS_VALID_BLOCK(h,off) \
(((off) & 3) == 0 && \
(off) >= 0x1000 && \
(off) < (h)->size && \
BITMAP_TST((h)->bitmap,(off)))
- /* Fields from the header, extracted from little-endianness. */
+ /* Fields from the header, extracted from little-endianness hell. */
size_t rootoffs; /* Root key offset (always an nk-block). */
/* Stats. */
} __attribute__((__packed__));
#define BLOCK_ID_EQ(h,offs,eqid) \
- (strncmp (((struct ntreg_hbin_block *)((h)->addr + (offs)))->id, (eqid), 2) == 0)
+ (STREQLEN (((struct ntreg_hbin_block *)((h)->addr + (offs)))->id, (eqid), 2))
static size_t
block_len (hive_h *h, size_t blkoff, int *used)
h->msglvl = flags & HIVEX_OPEN_MSGLVL_MASK;
const char *debug = getenv ("HIVEX_DEBUG");
- if (debug && strcmp (debug, "1") == 0)
+ if (debug && STREQ (debug, "1"))
h->msglvl = 2;
if (h->msglvl >= 2)
- printf ("hivex_open: created handle %p\n", h);
+ fprintf (stderr, "hivex_open: created handle %p\n", h);
h->fd = open (filename, O_RDONLY);
if (h->fd == -1)
goto error;
if (h->msglvl >= 2)
- printf ("hivex_open: mapped file at %p\n", h->addr);
+ fprintf (stderr, "hivex_open: mapped file at %p\n", h->addr);
/* Check header. */
if (h->hdr->magic[0] != 'r' ||
}
h->bitmap = calloc (1 + h->size / 32, 1);
+ if (h->bitmap == NULL)
+ goto error;
-#if 0 /* Doesn't work. */
/* Header checksum. */
- uint32_t *daddr = h->addr;
+ uint32_t *daddr = (uint32_t *) h->addr;
size_t i;
uint32_t sum = 0;
for (i = 0; i < 0x1fc / 4; ++i) {
- sum += le32toh (*daddr);
+ sum ^= le32toh (*daddr);
daddr++;
}
+
+#if 0 /* Doesn't work. */
if (sum != le32toh (h->hdr->csum)) {
fprintf (stderr, "hivex: %s: bad checksum in hive header\n", filename);
errno = EINVAL;
}
#endif
+ if (h->msglvl >= 2)
+ fprintf (stderr,
+ "hivex_open: header fields:\n"
+ " root offset - 4KB 0x%x\n"
+ " blocks (file size - 4KB) 0x%x (real file size 0x%zx)\n"
+ " checksum 0x%x (calculated 0x%x)\n",
+ le32toh (h->hdr->offset),
+ le32toh (h->hdr->blocks), h->size,
+ le32toh (h->hdr->csum), sum);
+
h->rootoffs = le32toh (h->hdr->offset) + 0x1000;
if (h->msglvl >= 2)
- printf ("hivex_open: root offset = %zu\n", h->rootoffs);
+ fprintf (stderr, "hivex_open: root offset = 0x%zx\n", h->rootoffs);
/* We'll set this flag when we see a block with the root offset (ie.
* the root block).
page->magic[1] != 'b' ||
page->magic[2] != 'i' ||
page->magic[3] != 'n') {
- /* This error is seemingly common in uncorrupt registry files. */
- /*
- fprintf (stderr, "hivex: %s: ignoring trailing garbage at end of file (at %zu, after %zu pages)\n",
- filename, off, h->pages);
- */
+ /* NB: This error is seemingly common in uncorrupt registry files. */
+ if (h->msglvl >= 2)
+ fprintf (stderr, "hivex: %s: ignoring trailing garbage at end of file (at 0x%zx, after %zu pages)\n",
+ filename, off, h->pages);
break;
}
if (h->msglvl >= 2)
- printf ("hivex_open: page at %zu\n", off);
+ fprintf (stderr, "hivex_open: page at 0x%zx\n", off);
if (le32toh (page->offset_next) <= sizeof (struct ntreg_hbin_page) ||
(le32toh (page->offset_next) & 3) != 0) {
}
if (h->msglvl >= 2)
- printf ("hivex_open: %s block id %d,%d at %zu%s\n",
- used ? "used" : "free", block->id[0], block->id[1], blkoff,
- is_root ? " (root)" : "");
+ fprintf (stderr, "hivex_open: %s block id %d,%d at 0x%zx%s\n",
+ used ? "used" : "free", block->id[0], block->id[1], blkoff,
+ is_root ? " (root)" : "");
if (is_root && !used)
bad_root_block = 1;
}
if (h->msglvl >= 1)
- printf ("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);
+ 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);
return h;
size_t seg_len = block_len (h, node, NULL);
if (sizeof (struct ntreg_nk_record) + len - 1 > seg_len) {
if (h->msglvl >= 2)
- printf ("hivex_node_name: returning EFAULT because node name is too long (%zu, %zu)\n",
+ fprintf (stderr, "hivex_node_name: returning EFAULT because node name is too long (%zu, %zu)\n",
len, seg_len);
errno = EFAULT;
return NULL;
subkey_lf += 0x1000;
if (!IS_VALID_BLOCK (h, subkey_lf)) {
if (h->msglvl >= 2)
- printf ("hivex_node_children: returning EFAULT because subkey_lf is not a valid block (%zu)\n",
- subkey_lf);
+ fprintf (stderr, "hivex_node_children: returning EFAULT because subkey_lf is not a valid block (%zu)\n",
+ subkey_lf);
errno = EFAULT;
return NULL;
}
size_t nr_subkeys_in_lf = le16toh (lf->nr_keys);
if (h->msglvl >= 2)
- printf ("hivex_node_children: nr_subkeys_in_nk = %zu, nr_subkeys_in_lf = %zu\n",
- nr_subkeys_in_nk, nr_subkeys_in_lf);
+ fprintf (stderr, "hivex_node_children: nr_subkeys_in_nk = %zu, nr_subkeys_in_lf = %zu\n",
+ nr_subkeys_in_nk, nr_subkeys_in_lf);
if (nr_subkeys_in_nk != nr_subkeys_in_lf) {
errno = ENOTSUP;
size_t len = block_len (h, subkey_lf, NULL);
if (8 + nr_subkeys_in_lf * 8 > len) {
if (h->msglvl >= 2)
- printf ("hivex_node_children: returning EFAULT because too many subkeys (%zu, %zu)\n",
- nr_subkeys_in_lf, len);
+ fprintf (stderr, "hivex_node_children: returning EFAULT because too many subkeys (%zu, %zu)\n",
+ nr_subkeys_in_lf, len);
errno = EFAULT;
return NULL;
}
subkey += 0x1000;
if (!IS_VALID_BLOCK (h, subkey)) {
if (h->msglvl >= 2)
- printf ("hivex_node_children: returning EFAULT because subkey is not a valid block (%zu)\n",
- subkey);
+ fprintf (stderr, "hivex_node_children: returning EFAULT because subkey is not a valid block (0x%zx)\n",
+ subkey);
errno = EFAULT;
free (ret);
return NULL;
offset += 0x1000;
if (!IS_VALID_BLOCK (h, offset)) {
if (h->msglvl >= 2)
- printf ("hivex_node_children: returning EFAULT because ri-offset is not a valid block (%zu)\n",
- offset);
+ fprintf (stderr, "hivex_node_children: returning EFAULT because ri-offset is not a valid block (0x%zx)\n",
+ offset);
errno = EFAULT;
return NULL;
}
}
if (h->msglvl >= 2)
- printf ("hivex_node_children: nr_subkeys_in_nk = %zu, counted = %zu\n",
- nr_subkeys_in_nk, count);
+ fprintf (stderr, "hivex_node_children: nr_subkeys_in_nk = %zu, counted = %zu\n",
+ nr_subkeys_in_nk, count);
if (nr_subkeys_in_nk != count) {
errno = ENOTSUP;
offset += 0x1000;
if (!IS_VALID_BLOCK (h, offset)) {
if (h->msglvl >= 2)
- printf ("hivex_node_children: returning EFAULT because ri-offset is not a valid block (%zu)\n",
- offset);
+ fprintf (stderr, "hivex_node_children: returning EFAULT because ri-offset is not a valid block (0x%zx)\n",
+ offset);
errno = EFAULT;
return NULL;
}
subkey += 0x1000;
if (!IS_VALID_BLOCK (h, subkey)) {
if (h->msglvl >= 2)
- printf ("hivex_node_children: returning EFAULT because indirect subkey is not a valid block (%zu)\n",
- subkey);
+ fprintf (stderr, "hivex_node_children: returning EFAULT because indirect subkey is not a valid block (0x%zx)\n",
+ subkey);
errno = EFAULT;
free (ret);
return NULL;
for (i = 0; children[i] != 0; ++i) {
name = hivex_node_name (h, children[i]);
if (!name) goto error;
- if (strcasecmp (name, nname) == 0) {
+ if (STRCASEEQ (name, nname)) {
ret = children[i];
break;
}
hive_node_h ret = le32toh (nk->parent);
ret += 0x1000;
- printf ("parent = %zu\n", ret);
if (!IS_VALID_BLOCK (h, ret)) {
if (h->msglvl >= 2)
- printf ("hivex_node_parent: returning EFAULT because parent is not a valid block (%zu)\n",
+ fprintf (stderr, "hivex_node_parent: returning EFAULT because parent is not a valid block (0x%zx)\n",
ret);
errno = EFAULT;
return 0;
size_t nr_values = le32toh (nk->nr_values);
if (h->msglvl >= 2)
- printf ("hivex_node_values: nr_values = %zu\n", nr_values);
+ fprintf (stderr, "hivex_node_values: nr_values = %zu\n", nr_values);
/* Deal with the common "no values" case quickly. */
hive_node_h *ret;
vlist_offset += 0x1000;
if (!IS_VALID_BLOCK (h, vlist_offset)) {
if (h->msglvl >= 2)
- printf ("hivex_node_values: returning EFAULT because value list is not a valid block (%zu)\n",
- vlist_offset);
+ fprintf (stderr, "hivex_node_values: returning EFAULT because value list is not a valid block (0x%zx)\n",
+ vlist_offset);
errno = EFAULT;
return NULL;
}
size_t len = block_len (h, vlist_offset, NULL);
if (4 + nr_values * 4 > len) {
if (h->msglvl >= 2)
- printf ("hivex_node_values: returning EFAULT because value list is too long (%zu, %zu)\n",
- nr_values, len);
+ fprintf (stderr, "hivex_node_values: returning EFAULT because value list is too long (%zu, %zu)\n",
+ nr_values, len);
errno = EFAULT;
return NULL;
}
value += 0x1000;
if (!IS_VALID_BLOCK (h, value)) {
if (h->msglvl >= 2)
- printf ("hivex_node_values: returning EFAULT because value is not a valid block (%zu)\n",
- value);
+ fprintf (stderr, "hivex_node_values: returning EFAULT because value is not a valid block (0x%zx)\n",
+ value);
errno = EFAULT;
free (ret);
return NULL;
for (i = 0; values[i] != 0; ++i) {
name = hivex_value_key (h, values[i]);
if (!name) goto error;
- if (strcasecmp (name, key) == 0) {
+ if (STRCASEEQ (name, key)) {
ret = values[i];
break;
}
size_t seg_len = block_len (h, value, NULL);
if (sizeof (struct ntreg_vk_record) + len - 1 > seg_len) {
if (h->msglvl >= 2)
- printf ("hivex_value_key: returning EFAULT because key length is too long (%zu, %zu)\n",
- len, seg_len);
+ fprintf (stderr, "hivex_value_key: returning EFAULT because key length is too long (%zu, %zu)\n",
+ len, seg_len);
errno = EFAULT;
return NULL;
}
len &= 0x7fffffff;
if (h->msglvl >= 2)
- printf ("hivex_value_value: value=%zu, t=%d, len=%zu\n",
- value, t, len);
+ fprintf (stderr, "hivex_value_value: value=0x%zx, t=%d, len=%zu\n",
+ value, t, len);
if (t_rtn)
*t_rtn = t;
data_offset += 0x1000;
if (!IS_VALID_BLOCK (h, data_offset)) {
if (h->msglvl >= 2)
- printf ("hivex_value_value: returning EFAULT because data offset is not a valid block (%zu)\n",
- data_offset);
+ fprintf (stderr, "hivex_value_value: returning EFAULT because data offset is not a valid block (0x%zx)\n",
+ data_offset);
errno = EFAULT;
free (ret);
return NULL;
size_t blen = block_len (h, data_offset, NULL);
if (blen < len) {
if (h->msglvl >= 2)
- printf ("hivex_value_value: returning EFAULT because data is longer than its block (%zu, %zu)\n",
- blen, len);
+ fprintf (stderr, "hivex_value_value: returning EFAULT because data is longer than its block (%zu, %zu)\n",
+ blen, len);
errno = EFAULT;
free (ret);
return NULL;
size_t r = iconv (ic, &inp, &inlen, &outp, &outlen);
if (r == (size_t) -1) {
if (errno == E2BIG) {
+ size_t prev = outalloc;
/* Try again with a larger output buffer. */
free (out);
outalloc *= 2;
+ if (outalloc < prev)
+ return NULL;
goto again;
}
else {
if (!BITMAP_TST (unvisited, node)) {
if (h->msglvl >= 2)
- printf ("hivex__visit_node: contains cycle: visited node %zu already\n",
- node);
+ fprintf (stderr, "hivex__visit_node: contains cycle: visited node 0x%zx already\n",
+ node);
errno = ELOOP;
return skip_bad ? 0 : -1;
for (i = 0; children[i] != 0; ++i) {
if (h->msglvl >= 2)
- printf ("hivex__visit_node: %s: visiting subkey %d (%zu)\n",
- name, i, children[i]);
+ fprintf (stderr, "hivex__visit_node: %s: visiting subkey %d (0x%zx)\n",
+ name, i, children[i]);
if (hivex__visit_node (h, children[i], vtor, unvisited, opaque, flags) == -1)
goto error;