[Libguestfs] Fwd: hivex: patch for read support of "li"-records from "ri" intermediate
Richard W.M. Jones
rjones at redhat.com
Thu Mar 8 18:10:00 UTC 2012
[The bug which this fixes is:
https://bugzilla.redhat.com/show_bug.cgi?id=717583 ]
----- Forwarded message from Peter Fokker <peter at berestijn.nl> -----
Date: Thu, 8 Mar 2012 11:37:06 +0100 (CET)
From: Peter Fokker <peter at berestijn.nl>
To: rjones at redhat.com
Cc: Peter Fokker <peter at berestijn.nl>
Subject: hivex: patch for read support of "li"-records from "ri"
intermediate
User-Agent: SquirrelMail/1.4.9a
Richard,
Thank you for creating the hivex-library. Studying your source code helped
me a great deal to better understand the internals of the Windows Registry.
However, while I was browsing a real-world SOFTWARE-hive (XP, SP3) I
could not browse to the '\Classes' key. Instead I got this (debug)-message:
get_children: returning ENOTSUP because ri-record offset does not
point to lf/lh (0x49020)
I tracked this issue down and I discovered that the intermediate
"ri"-record may not only contain offsets to "lf" and "lh" but to
"li"-records too.
Attached is a patch against hivex.c v1.3.3 that recognises
"li"-records referenced from "ri"-records. For me this fixed the issue
with browsing the '\Classes' key.
Note that I have not fixed the related problem of rewriting
"li"-records when inserting a new subkey or deleting an
existing one. This sure would cause problems when I were to
add/delete a subkey to/from '\Classes'.
I would very much appreciate it if would be so kind to take a look at
my patch, allthough I cannot blame you if you immediately dump this
unsollicited message+patch from some random stranger from The Netherlands.
Kind regards,
--Peter Fokker
--
Peter Fokker <peter at berestijn.nl>
Ingenieursbureau PSD +31 35 695 29 99 / +31 644 238 568
Stargardlaan 7 1404 BC Bussum, The Netherlands
----- End forwarded message -----
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
libguestfs lets you edit virtual machines. Supports shell scripting,
bindings from many languages. http://libguestfs.org
-------------- next part --------------
diff -ur hivex-1.3.3-orig/lib/hivex.c hivex-1.3.3/lib/hivex.c
--- hivex-1.3.3-orig/lib/hivex.c 2011-09-07 13:31:35.000000000 +0200
+++ hivex-1.3.3/lib/hivex.c 2012-03-08 08:01:20.000000000 +0100
@@ -167,9 +167,9 @@
struct ntreg_ri_record {
int32_t seg_len;
- char id[2]; /* "ri" */
- uint16_t nr_offsets; /* number of pointers to lh records */
- uint32_t offset[1]; /* list of pointers to lh records */
+ char id[2]; /* "ri"|"li" */
+ uint16_t nr_offsets; /* number of pointers to lf/lh/li records */
+ uint32_t offset[1]; /* list of pointers to lf/lh/li records */
} __attribute__((__packed__));
/* This has no ID header. */
@@ -874,10 +874,12 @@
errno = EFAULT;
goto error;
}
- if (!BLOCK_ID_EQ (h, offset, "lf") && !BLOCK_ID_EQ (h, offset, "lh")) {
+ if (!BLOCK_ID_EQ (h, offset, "lf") &&
+ !BLOCK_ID_EQ (h, offset, "lh") &&
+ !BLOCK_ID_EQ (h, offset, "li")) {
if (h->msglvl >= 2)
- fprintf (stderr, "get_children: returning ENOTSUP"
- " because ri-record offset does not point to lf/lh (0x%zx)\n",
+ fprintf (stderr, "get_children: returning ENOTSUP because"
+ " ri-record offset does not point to lf/lh/li (0x%zx)\n",
offset);
errno = ENOTSUP;
goto error;
@@ -907,43 +909,51 @@
*/
for (i = 0; i < nr_offsets; ++i) {
hive_node_h offset = le32toh (ri->offset[i]);
- offset += 0x1000;
- if (!IS_VALID_BLOCK (h, offset)) {
- if (h->msglvl >= 2)
- fprintf (stderr, "hivex_node_children: returning EFAULT"
- " because ri-offset is not a valid block (0x%zx)\n",
- offset);
- errno = EFAULT;
- goto error;
- }
- if (!BLOCK_ID_EQ (h, offset, "lf") && !BLOCK_ID_EQ (h, offset, "lh")) {
- if (h->msglvl >= 2)
- fprintf (stderr, "get_children: returning ENOTSUP"
- " because ri-record offset does not point to lf/lh (0x%zx)\n",
- offset);
- errno = ENOTSUP;
- goto error;
- }
-
- struct ntreg_lf_record *lf =
- (struct ntreg_lf_record *) (h->addr + offset);
+ offset += 0x1000; /* already validated in the previous for-loop */
- size_t j;
- for (j = 0; j < le16toh (lf->nr_keys); ++j) {
- hive_node_h subkey = le32toh (lf->keys[j].offset);
- subkey += 0x1000;
- if (!(flags & GET_CHILDREN_NO_CHECK_NK)) {
- if (!IS_VALID_BLOCK (h, subkey)) {
- if (h->msglvl >= 2)
- fprintf (stderr, "hivex_node_children: returning EFAULT"
- " because indirect subkey is not a valid block (0x%zx)\n",
- subkey);
- errno = EFAULT;
+ if (BLOCK_ID_EQ (h, offset, "li")) {
+ /* "ri" and "li" are basically the same */
+ struct ntreg_ri_record *li =
+ (struct ntreg_ri_record *) (h->addr + offset);
+
+ size_t j;
+ for (j = 0; j < le16toh (li->nr_offsets); ++j) {
+ hive_node_h subkey = le32toh (li->offset[j]);
+ subkey += 0x1000;
+ if (!(flags & GET_CHILDREN_NO_CHECK_NK)) {
+ if (!IS_VALID_BLOCK (h, subkey)) {
+ if (h->msglvl >= 2)
+ fprintf (stderr, "hivex_node_children: returning EFAULT because"
+ " li indirect subkey is not a valid block (0x%zx)\n",
+ subkey);
+ errno = EFAULT;
+ goto error;
+ }
+ }
+ if (add_to_offset_list (&children, subkey) == -1)
goto error;
+ }
+ } else { /* "lf" or "lh" block */
+ struct ntreg_lf_record *lf =
+ (struct ntreg_lf_record *) (h->addr + offset);
+
+ size_t j;
+ for (j = 0; j < le16toh (lf->nr_keys); ++j) {
+ hive_node_h subkey = le32toh (lf->keys[j].offset);
+ subkey += 0x1000;
+ if (!(flags & GET_CHILDREN_NO_CHECK_NK)) {
+ if (!IS_VALID_BLOCK (h, subkey)) {
+ if (h->msglvl >= 2)
+ fprintf (stderr, "hivex_node_children: returning EFAULT because"
+ " lf/lh indirect subkey is not a valid block (0x%zx)\n",
+ subkey);
+ errno = EFAULT;
+ goto error;
+ }
}
+ if (add_to_offset_list (&children, subkey) == -1)
+ goto error;
}
- if (add_to_offset_list (&children, subkey) == -1)
- goto error;
}
}
goto ok;
@@ -951,7 +961,7 @@
/* else not supported, set errno and fall through */
if (h->msglvl >= 2)
fprintf (stderr, "get_children: returning ENOTSUP"
- " because subkey block is not lf/lh/ri (0x%zx, %d, %d)\n",
+ " because subkey block is not lf/lh/li/ri (0x%zx, %d, %d)\n",
subkey_lf, block->id[0], block->id[1]);
errno = ENOTSUP;
error:
@@ -2390,14 +2400,27 @@
if (compare_name_with_nk_name (h, name, nk_offs) < 0)
goto insert_it;
}
+ } /* XXX: blocks[i] could also be an "li" record.
+ Code might look like this (but is untested): */
+ /*---
+ else if (BLOCK_ID_EQ (h, blocks[i], "li")) {
+ old_offs = blocks[i];
+ old_li = (struct ntreg_ri_record *) (h->addr + old_offs);
+ for (j = 0; j < le16toh (old_li->nr_offsets); ++j) {
+ hive_node_h nk_offs = le32toh (old_li->offset[j]);
+ nk_offs += 0x1000;
+ if (compare_name_with_nk_name (h, name, nk_offs) < 0)
+ goto insert_it;
+ }
}
+ ---*/
}
/* Insert it at the end.
* old_offs points to the last lf record, set j.
*/
assert (old_offs != 0); /* should never happen if nr_subkeys > 0 */
- j = le16toh (old_lf->nr_keys);
+ j = le16toh (old_lf->nr_keys); /* XXX: this fails for an "li" record */
/* Insert it. */
insert_it:
@@ -2636,6 +2659,11 @@
goto found;
}
}
+ /* XXX Deal with the "li" case too
+ else if (block->id[0] == 'l' && (block->id[1] == 'i') {
+ ....
+ }
+ */
}
if (h->msglvl >= 2)
fprintf (stderr, "hivex_node_delete_child: could not find parent"
More information about the Libguestfs
mailing list