Richard W.M. Jones
2012-Mar-08 18:10 UTC
[Libguestfs] Fwd: hivex: patch for read support of "li"-records from "ri" intermediate
[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"
Richard W.M. Jones
2012-Oct-11 11:40 UTC
[Libguestfs] Fwd: hivex: patch for read support of "li"-records from "ri" intermediate
On Thu, Mar 08, 2012 at 06:10:00PM +0000, Richard W.M. Jones wrote:> [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'.Better late than never, I have pushed this upstream. It will be present in hivex 1.3.7 in a few hours. Thanks for your contribution. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones New in Fedora 11: Fedora Windows cross-compiler. Compile Windows programs, test, and build Windows installers. Over 70 libraries supprt'd http://fedoraproject.org/wiki/MinGW http://www.annexia.org/fedora_mingw