33d974
From 8e187357f466c31a9e75ac4924b32bbf4823e73f Mon Sep 17 00:00:00 2001
33d974
From: Dawid Zamirski <dzamirski@datto.com>
33d974
Date: Thu, 16 Feb 2017 18:17:24 -0500
214838
Subject: [PATCH 10/16] lib: allow to walk registry with corrupted blocks
33d974
33d974
Only when HIVEX_OPEN_UNSAFE flag is set.
33d974
33d974
There are some corrupted registry files that have invalid hbin cells
33d974
but are still readable. This patch makes the following changes:
33d974
33d974
* hivex_open - do not abort with complete failure if we run across a
33d974
  block with invalid size (unless it's the root block). Instead just
33d974
  log the event, and move on. This will allow open hives that have
33d974
  apparent invalid blocks but the ones of potential interest might be
33d974
  perfectly accessible.
33d974
* _hivex_get_children - similiarly, if the's invalid subkey, just skip
33d974
  it instead of failing so one can continue to browse other valid
33d974
  subkeys.
33d974
33d974
The above is similar to the behavior to Windows regedit where one can
33d974
load such corrupted hives with e.g. "reg load HKU\Corrupted" and
33d974
browse/change it despite some keys might be missing.
33d974
33d974
(cherry picked from commit 5345ec8f1df304dc93a6b1e4cbb40e7c1cf6f88d)
33d974
---
33d974
 lib/handle.c | 16 ++++++++++++----
33d974
 lib/node.c   | 46 +++++++++++++++++++++++++++++++++++-----------
33d974
 2 files changed, 47 insertions(+), 15 deletions(-)
33d974
33d974
diff --git a/lib/handle.c b/lib/handle.c
33d974
index 8c64b6d..0d2b24b 100644
33d974
--- a/lib/handle.c
33d974
+++ b/lib/handle.c
33d974
@@ -313,10 +313,18 @@ hivex_open (const char *filename, int flags)
33d974
       int used;
33d974
       seg_len = block_len (h, blkoff, &used);
33d974
       if (seg_len <= 4 || (seg_len & 3) != 0) {
33d974
-        SET_ERRNO (ENOTSUP,
33d974
-                   "%s: block size %" PRIu32 " at 0x%zx, bad registry",
33d974
-                   filename, le32toh (block->seg_len), blkoff);
33d974
-        goto error;
33d974
+        if (is_root || !h->unsafe) {
33d974
+          SET_ERRNO (ENOTSUP,
33d974
+                     "%s, the block at 0x%zx has invalid size %" PRIi32
33d974
+                     ", bad registry",
33d974
+                     filename, blkoff, le32toh (block->seg_len));
33d974
+          goto error;
33d974
+        } else {
33d974
+          DEBUG (2,
33d974
+                 "%s: block at 0x%zx has invalid size %" PRIi32 ", skipping",
33d974
+                 filename, blkoff, le32toh (block->seg_len));
33d974
+          break;
33d974
+        }
33d974
       }
33d974
 
33d974
       if (h->msglvl >= 2) {
33d974
diff --git a/lib/node.c b/lib/node.c
33d974
index 22d1861..a90c964 100644
33d974
--- a/lib/node.c
33d974
+++ b/lib/node.c
33d974
@@ -343,11 +343,18 @@ _hivex_get_children (hive_h *h, hive_node_h node,
33d974
    */
33d974
   size_t nr_children = _hivex_get_offset_list_length (&children);
33d974
   if (nr_subkeys_in_nk != nr_children) {
33d974
-    SET_ERRNO (ENOTSUP,
33d974
-               "nr_subkeys_in_nk = %zu "
33d974
-               "is not equal to number of children read %zu",
33d974
-               nr_subkeys_in_nk, nr_children);
33d974
-    goto error;
33d974
+    if (!h->unsafe) {
33d974
+      SET_ERRNO (ENOTSUP,
33d974
+                 "nr_subkeys_in_nk = %zu "
33d974
+                 "is not equal to number of childred read %zu",
33d974
+                 nr_subkeys_in_nk, nr_children);
33d974
+      goto error;
33d974
+    } else {
33d974
+      DEBUG (2,
33d974
+             "nr_subkeys_in_nk = %zu "
33d974
+             "is not equal to number of children read %zu",
33d974
+             nr_subkeys_in_nk, nr_children);
33d974
+    }
33d974
   }
33d974
 
33d974
  out:
33d974
@@ -407,8 +414,14 @@ _get_children (hive_h *h, hive_node_h blkoff,
33d974
     for (i = 0; i < nr_subkeys_in_lf; ++i) {
33d974
       hive_node_h subkey = le32toh (lf->keys[i].offset);
33d974
       subkey += 0x1000;
33d974
-      if (check_child_is_nk_block (h, subkey, flags) == -1)
33d974
-        return -1;
33d974
+      if (check_child_is_nk_block (h, subkey, flags) == -1) {
33d974
+        if (h->unsafe) {
33d974
+          DEBUG (2, "subkey at 0x%zx is not an NK block, skipping", subkey);
33d974
+          continue;
33d974
+        } else {
33d974
+          return -1;
33d974
+        }
33d974
+      }
33d974
       if (_hivex_add_to_offset_list (children, subkey) == -1)
33d974
         return -1;
33d974
     }
33d974
@@ -435,8 +448,14 @@ _get_children (hive_h *h, hive_node_h blkoff,
33d974
     for (i = 0; i < nr_offsets; ++i) {
33d974
       hive_node_h subkey = le32toh (ri->offset[i]);
33d974
       subkey += 0x1000;
33d974
-      if (check_child_is_nk_block (h, subkey, flags) == -1)
33d974
-        return -1;
33d974
+      if (check_child_is_nk_block (h, subkey, flags) == -1) {
33d974
+        if (h->unsafe) {
33d974
+          DEBUG (2, "subkey at 0x%zx is not an NK block, skipping", subkey);
33d974
+          continue;
33d974
+        } else {
33d974
+          return -1;
33d974
+        }
33d974
+      }
33d974
       if (_hivex_add_to_offset_list (children, subkey) == -1)
33d974
         return -1;
33d974
     }
33d974
@@ -458,8 +477,13 @@ _get_children (hive_h *h, hive_node_h blkoff,
33d974
       hive_node_h offset = le32toh (ri->offset[i]);
33d974
       offset += 0x1000;
33d974
       if (!IS_VALID_BLOCK (h, offset)) {
33d974
-        SET_ERRNO (EFAULT, "ri-offset is not a valid block (0x%zx)", offset);
33d974
-        return -1;
33d974
+        if (h->unsafe) {
33d974
+          DEBUG (2, "ri-offset is not a valid block (0x%zx), skipping", offset);
33d974
+          continue;
33d974
+        } else {
33d974
+          SET_ERRNO (EFAULT, "ri-offset is not a valid block (0x%zx)", offset);
33d974
+          return -1;
33d974
+        }
33d974
       }
33d974
 
33d974
       if (_get_children (h, offset, children, blocks, flags) == -1)
33d974
-- 
33d974
1.8.3.1
33d974