Blob Blame History Raw
From f80b9b31f99ccdc06887c23dab46a37fc4f4ce74 Mon Sep 17 00:00:00 2001
From: Dawid Zamirski <dzamirski@datto.com>
Date: Thu, 16 Feb 2017 18:17:23 -0500
Subject: [PATCH 09/16] lib: change how hbin sections are read.

Only when HIVEX_OPEN_UNSAFE flag is set:

* hivex_open: when looping over hbin sections (aka pages), handle a
  case where following hbin section may not begin at exactly at the end
  of previous one. If this happens, scan the page section until next
  one is found and validate it by checking declared offset with actual
  one - if they match, all is good and we can safely move on.

Rationale: there are registry hives there is some garbage data between
hbin section but the hive is still perfectly usable as long as the
offsets stated in hbin headers are correct.

(cherry picked from commit 8d092a746dbd9e61ec85cf17449c201bc0719721)
---
 lib/handle.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 46 insertions(+), 5 deletions(-)

diff --git a/lib/handle.c b/lib/handle.c
index dff2780..8c64b6d 100644
--- a/lib/handle.c
+++ b/lib/handle.c
@@ -227,11 +227,42 @@ hivex_open (const char *filename, int flags)
         page->magic[1] != 'b' ||
         page->magic[2] != 'i' ||
         page->magic[3] != 'n') {
-      SET_ERRNO (ENOTSUP,
-                 "%s: trailing garbage at end of file "
-                 "(at 0x%zx, after %zu pages)",
-                 filename, off, pages);
-      goto error;
+
+      if (!h->unsafe) {
+        SET_ERRNO (ENOTSUP,
+                   "%s: trailing garbage at end of file "
+                   "(at 0x%zx, after %zu pages)",
+                   filename, off, pages);
+        goto error;
+      }
+
+      DEBUG (2,
+             "page not found at expected offset 0x%zx, "
+             "seeking until one is found or EOF is reached",
+             off);
+
+      int found = 0;
+      while (off < h->size) {
+        off += 0x1000;
+
+        if (off >= h->endpages)
+          break;
+
+        page = (struct ntreg_hbin_page *) ((char *) h->addr + off);
+        if (page->magic[0] == 'h' &&
+            page->magic[1] == 'b' &&
+            page->magic[2] == 'i' &&
+            page->magic[3] == 'n') {
+          DEBUG (2, "found next page by seeking at 0x%zx", off);
+          found = 1;
+          break;
+        }
+      }
+
+      if (!found) {
+        DEBUG (2, "page not found and end of pages section reached");
+        break;
+      }
     }
 
     size_t page_size = le32toh (page->page_size);
@@ -255,6 +286,16 @@ hivex_open (const char *filename, int flags)
       goto error;
     }
 
+    size_t page_offset = le32toh(page->offset_first) + 0x1000;
+
+    if (page_offset != off) {
+      SET_ERRNO (ENOTSUP,
+                 "%s: declared page offset (0x%zx) does not match computed "
+                 "offset (0x%zx), bad registry",
+                 filename, page_offset, off);
+      goto error;
+    }
+
     /* Read the blocks in this page. */
     size_t blkoff;
     struct ntreg_hbin_block *block;
-- 
1.8.3.1