[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