Index: /trunk/include/regfi.h
===================================================================
--- /trunk/include/regfi.h	(revision 151)
+++ /trunk/include/regfi.h	(revision 152)
@@ -96,8 +96,6 @@
 #define REGFI_REGF_MAGIC_SIZE      4
 #define REGFI_REGF_NAME_SIZE       64
-
 #define REGFI_REGF_RESERVED1_SIZE  340
 #define REGFI_REGF_RESERVED2_SIZE  3528
-
 #define REGFI_HBIN_MAGIC_SIZE      4
 #define REGFI_CELL_MAGIC_SIZE      2
@@ -127,40 +125,62 @@
 
 /* Flags for the vk records */
+/* XXX: This next flag may be incorrect.  According to Jeffrey Muir,
+*       this may actually indicate that the value name is stored in
+*       UTF-16LE.
+*/
 #define REGFI_VK_FLAG_NAME_PRESENT 0x0001
 #define REGFI_VK_DATA_IN_OFFSET    0x80000000
-#define REGFI_VK_MAX_DATA_LENGTH   1024*1024
-
-
-/* NK record types */
-/* XXX: This is starting to look like this is a flags field.  
- *      Need to decipher the meaning of each flag.
- */
-#define REGFI_NK_TYPE_LINKKEY      0x0010
-#define REGFI_NK_TYPE_NORMALKEY    0x0020
- /* XXX: Unknown key type that shows up in Vista registries */
-#define REGFI_NK_TYPE_UNKNOWN1     0x1020
- /* XXX: Unknown key types that shows up in W2K3 registries */
-#define REGFI_NK_TYPE_UNKNOWN2     0x4020
-#define REGFI_NK_TYPE_UNKNOWN3     0x0000  /* XXX: This type seems to have UTF-16 names!!! */
-#define REGFI_NK_TYPE_ROOTKEY1     0x002c
- /* XXX: Unknown root key type that shows up in Vista registries */
-#define REGFI_NK_TYPE_ROOTKEY2     0x00ac
-
-#if 0
-/* Initial hypothesis of NK flags: */
-/***********************************/
-#define REGFI_NK_FLAG_LINK         0x0010
-/* The name will be in ASCII if this next bit is set, otherwise UTF-16LE */
-#define REGFI_NK_FLAG_ASCIINAME    0x0020
-/* These next two combine to form the "c" on both known root key types */
-#define REGFI_NK_FLAG_ROOT1        0x0008
-#define REGFI_NK_FLAG_ROOT2        0x0004
+#define REGFI_VK_MAX_DATA_LENGTH   1024*1024  /* XXX: This is arbitrary */
+
+
+/* Known key flags */
+/*******************/
 /* These next two show up on normal-seeming keys in Vista and W2K3 registries */
 #define REGFI_NK_FLAG_UNKNOWN1     0x4000
 #define REGFI_NK_FLAG_UNKNOWN2     0x1000
+
 /* This next one shows up on root keys in some Vista "software" registries */
 #define REGFI_NK_FLAG_UNKNOWN3     0x0080
-#endif
-
+
+/* Predefined handle.  Rumor has it that the valuelist count for this key is 
+ * where the handle is stored.
+ * http://msdn.microsoft.com/en-us/library/ms724836(VS.85).aspx
+ */
+#define REGFI_NK_FLAG_PREDEF_KEY   0x0040
+
+/* The name will be in ASCII if this next bit is set, otherwise UTF-16LE */
+#define REGFI_NK_FLAG_ASCIINAME    0x0020
+
+/* Symlink key.  
+ * See: http://www.codeproject.com/KB/system/regsymlink.aspx 
+ */
+#define REGFI_NK_FLAG_LINK         0x0010
+
+/* This key cannot be deleted */
+#define REGFI_NK_FLAG_NO_RM        0x0008
+
+/* Root of a hive */
+#define REGFI_NK_FLAG_ROOT         0x0004
+
+/* Mount point of another hive.  NULL/(default) value indicates which hive 
+ * and where in the hive it points to. 
+ */
+#define REGFI_NK_FLAG_HIVE_LINK    0x0002 
+
+/* These keys shouldn't be stored on disk, according to:
+ * http://geekswithblogs.net/sdorman/archive/2007/12/24/volatile-registry-keys.aspx
+ */
+#define REGFI_NK_FLAG_VOLATILE     0x0001
+
+/* Useful for identifying unknown flag types */
+#define REGFI_NK_KNOWN_FLAGS       (REGFI_NK_FLAG_PREDEF_KEY\
+				    | REGFI_NK_FLAG_ASCIINAME\
+				    | REGFI_NK_FLAG_LINK\
+				    | REGFI_NK_FLAG_NO_RM\
+				    | REGFI_NK_FLAG_ROOT\
+				    | REGFI_NK_FLAG_HIVE_LINK\
+				    | REGFI_NK_FLAG_VOLATILE\
+				    | REGFI_NK_FLAG_UNKNOWN1\
+				    | REGFI_NK_FLAG_UNKNOWN2)
 
 /* HBIN block */
@@ -350,12 +370,11 @@
 
   NTTIME mtime;
-  uint32 major_version;  /* XXX: Unverified. Set to 1 in all known hives */
-  uint32 minor_version;  /* XXX: Unverified. Set to 3 or 5 in all known hives */
+  uint32 major_version;  /* Set to 1 in all known hives */
+  uint32 minor_version;  /* Set to 3 or 5 in all known hives */
   uint32 type;           /* XXX: Unverified.  Set to 0 in all known hives */
   uint32 format;         /* XXX: Unverified.  Set to 1 in all known hives */
 
   uint32 root_cell;  /* Offset to root cell in the first (or any?) hbin block */
-  uint32 last_block; /* Offset to last hbin block in file
-		      * (or length of file minus header?) */
+  uint32 last_block; /* Offset to last hbin block in file */
 
   uint32 cluster;    /* XXX: Unverified. Set to 1 in all known hives */
@@ -516,8 +535,12 @@
 				     uint32 max_size, bool strict);
 
-REGFI_BUFFER          regfi_parse_data(REGFI_FILE* file, 
-				       uint32 data_type, uint32 offset, 
-				       uint32 length, uint32 max_size, 
-				       bool data_in_offset, bool strict);
+REGFI_BUFFER          regfi_load_data(REGFI_FILE* file, 
+				      uint32 data_type, uint32 offset, 
+				      uint32 length, uint32 max_size, 
+				      bool data_in_offset, bool strict);
+
+REGFI_BUFFER          regfi_load_big_data(REGFI_FILE* file, 
+					  uint32 offset, uint32 data_length,
+					  uint32 cell_length, bool strict);
 
 REGFI_SK_REC*         regfi_parse_sk(REGFI_FILE* file, uint32 offset, 
Index: /trunk/lib/regfi.c
===================================================================
--- /trunk/lib/regfi.c	(revision 151)
+++ /trunk/lib/regfi.c	(revision 152)
@@ -966,5 +966,5 @@
     if(ret_val->data_in_offset)
     {
-      data = regfi_parse_data(file, ret_val->type, ret_val->data_off,
+      data = regfi_load_data(file, ret_val->type, ret_val->data_off,
 			      ret_val->data_size, 4,
 			      ret_val->data_in_offset, strict);
@@ -979,5 +979,5 @@
 	data_offset = ret_val->data_off+REGFI_REGF_SIZE;
 	data_maxsize = hbin->block_size + hbin->file_off - data_offset;
-	data = regfi_parse_data(file, ret_val->type, data_offset, 
+	data = regfi_load_data(file, ret_val->type, data_offset, 
 				ret_val->data_size, data_maxsize, 
 				ret_val->data_in_offset, strict);
@@ -999,5 +999,5 @@
       regfi_add_message(file, REGFI_MSG_WARN, "Could not parse data record"
 			" while parsing VK record at offset 0x%.8X.",
-			ret_val->offset);
+			ret_val->offset, ret_val->valuename);
     }
     else
@@ -1204,6 +1204,5 @@
       if(nk != NULL)
       {
-	if((nk->key_type == REGFI_NK_TYPE_ROOTKEY1)
-	   || (nk->key_type == REGFI_NK_TYPE_ROOTKEY2))
+	if(nk->key_type & REGFI_NK_FLAG_ROOT)
 	{
 	  found = true;
@@ -1777,6 +1776,6 @@
   ret_val->thaw_rm_id = winsec_parse_uuid(ret_val, file_header+0xFD8, 16);
   ret_val->thaw_log_id = winsec_parse_uuid(ret_val, file_header+0xFE8, 16);
-  ret_val->boot_type = IVAL(file_header, 0x90);
-  ret_val->boot_recover = IVAL(file_header, 0x90);
+  ret_val->boot_type = IVAL(file_header, 0xFF8);
+  ret_val->boot_recover = IVAL(file_header, 0xFFC);
 
   return ret_val;
@@ -1918,15 +1917,10 @@
   ret_val->magic[1] = nk_header[0x1];
   ret_val->key_type = SVAL(nk_header, 0x2);
-  if((ret_val->key_type != REGFI_NK_TYPE_NORMALKEY)
-     && (ret_val->key_type != REGFI_NK_TYPE_ROOTKEY1) 
-     && (ret_val->key_type != REGFI_NK_TYPE_ROOTKEY2)
-     && (ret_val->key_type != REGFI_NK_TYPE_LINKKEY)
-     && (ret_val->key_type != REGFI_NK_TYPE_UNKNOWN1)
-     && (ret_val->key_type != REGFI_NK_TYPE_UNKNOWN2)
-     && (ret_val->key_type != REGFI_NK_TYPE_UNKNOWN3))
-  {
-    regfi_add_message(file, REGFI_MSG_WARN, "Unknown key type (0x%.4X) while"
+  
+  if((ret_val->key_type & ~REGFI_NK_KNOWN_FLAGS) != 0)
+  {
+    regfi_add_message(file, REGFI_MSG_WARN, "Unknown key flags (0x%.4X) while"
 		      " parsing NK record at offset 0x%.8X.", 
-		      ret_val->key_type, offset);
+		      (ret_val->key_type & ~REGFI_NK_KNOWN_FLAGS), offset);
   }
 
@@ -1964,5 +1958,4 @@
   ret_val->classname_length = SVAL(nk_header, 0x4A);
 
-
   if(ret_val->name_length + REGFI_NK_MIN_LENGTH > ret_val->cell_size)
   {
@@ -2106,6 +2099,6 @@
 
 
-/*******************************************************************
- *******************************************************************/
+/******************************************************************************
+*******************************************************************************/
 REGFI_VK_REC* regfi_parse_vk(REGFI_FILE* file, uint32 offset, 
 			     uint32 max_size, bool strict)
@@ -2221,8 +2214,10 @@
 
 
-REGFI_BUFFER regfi_parse_data(REGFI_FILE* file, 
-			      uint32 data_type, uint32 offset,
-			      uint32 length, uint32 max_size, 
-			      bool data_in_offset, bool strict)
+/******************************************************************************
+*******************************************************************************/
+REGFI_BUFFER regfi_load_data(REGFI_FILE* file, 
+			     uint32 data_type, uint32 offset,
+			     uint32 length, uint32 max_size, 
+			     bool data_in_offset, bool strict)
 {
   REGFI_BUFFER ret_val;
@@ -2280,19 +2275,20 @@
     if(cell_length - 4 < length)
     {
-      /* XXX: This strict condition has been triggered in multiple registries.
-       *      Not sure the cause, but the data length values are very large,
-       *      such as 53392.  For now, we're truncating the size and returning 
-       *      what we can, since this issue is so common.
-       */
-      regfi_add_message(file, REGFI_MSG_WARN, "Data length (0x%.8X) larger than"
-			" remaining cell length (0x%.8X)"
-			" while parsing data record at offset 0x%.8X.", 
-			length, cell_length - 4, offset);
-      /*
-      if(strict)
-        goto fail;
+      if (file->major_version >= 1 && file->minor_version >= 5)
+      {
+	/* Attempt to parse a big data record */
+	return regfi_load_big_data(file, offset, length, cell_length, strict);
+      }
       else
-      */
-      length = cell_length - 4;
+      {
+	regfi_add_message(file, REGFI_MSG_WARN, "Data length (0x%.8X) larger than"
+			  " remaining cell length (0x%.8X)"
+			  " while parsing data record at offset 0x%.8X.", 
+			  length, cell_length - 4, offset);
+	if(strict)
+	  goto fail;
+	else
+	  length = cell_length - 4;
+      }
     }
 
@@ -2314,4 +2310,117 @@
   return ret_val;
 
+ fail:
+  ret_val.buf = NULL;
+  ret_val.len = 0;
+  return ret_val;
+}
+
+
+/******************************************************************************
+*******************************************************************************/
+REGFI_BUFFER regfi_load_big_data(REGFI_FILE* file, 
+				 uint32 offset, uint32 data_length, 
+				 uint32 cell_length, bool strict)
+{
+  REGFI_BUFFER ret_val;
+  uint16 num_chunks, i;
+  uint32 indirect_offset, indirect_length, chunk_length, chunk_offset;
+  uint32 read_length, data_left;
+  bool unalloc;
+  uint32* indirect_ptrs;
+  uint8* big_data_cell = (uint8*)malloc(cell_length*sizeof(uint8));
+  if(big_data_cell == NULL)
+    goto fail;
+
+  if(!regfi_parse_cell(file->fd, offset, big_data_cell, cell_length-4,
+		       &cell_length, &unalloc))
+  {
+    regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while"
+		      " parsing big data record at offset 0x%.8X.", offset);
+    free(big_data_cell);
+    goto fail;
+  }
+  
+  if((big_data_cell[0] != 'd') || (big_data_cell[1] != 'b'))
+  {
+    regfi_add_message(file, REGFI_MSG_WARN, "Unknown magic number"
+		      " (0x%.2X, 0x%.2X) encountered while parsing"
+		      " big data record at offset 0x%.8X.", 
+		      big_data_cell[0], big_data_cell[1], offset);
+    free(big_data_cell);
+    goto fail;
+  }
+  num_chunks = SVAL(big_data_cell, 0x2);
+  /* XXX: Should check sanity of pointers here and in the indirect
+   *      block.  At least ensure they are a multiple of 8. 
+   */
+  indirect_offset = IVAL(big_data_cell, 0x4) + REGFI_REGF_SIZE;
+  free(big_data_cell);
+
+  indirect_ptrs = (uint32*)malloc(num_chunks*sizeof(uint32));
+  if(indirect_ptrs == NULL)
+    goto fail;
+
+  if(!regfi_parse_cell(file->fd, indirect_offset, (uint8*)indirect_ptrs,
+		       num_chunks*sizeof(uint32),
+		       &indirect_length, &unalloc))
+  {
+    regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while"
+		      " parsing big data indirect record at offset 0x%.8X.", 
+		      offset);
+    free(indirect_ptrs);
+    goto fail;
+  }
+  
+  if((ret_val.buf = talloc_array(NULL, uint8_t, data_length)) == NULL)
+  {
+    free(indirect_ptrs);
+    goto fail;
+  }
+  data_left = data_length;
+
+  for(i=0; (i<num_chunks) && (data_left>0); i++)
+  {
+    /* Fix endianness of pointer and convert to physical offset */
+    chunk_offset = IVAL(indirect_ptrs, i*4) + REGFI_REGF_SIZE;
+    if(!regfi_parse_cell(file->fd, chunk_offset, NULL, 0, 
+			 &chunk_length, &unalloc))
+    {
+      regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while"
+			" parsing big data chunk at offset 0x%.8X.", 
+			chunk_offset);
+      if(strict)
+	goto chunk_fail;
+      else
+	break;
+    }
+
+    if(chunk_length-4 > data_left)
+      read_length = data_left;
+    else
+      read_length = chunk_length-4;
+
+    if(regfi_read(file->fd, ret_val.buf+(data_length-data_left), 
+		  &read_length) != 0)
+    {
+      regfi_add_message(file, REGFI_MSG_WARN, "Could not read data chunk while"
+			" constructing big data at offset 0x%.8X.", 
+			chunk_offset);
+      if(strict)
+	goto chunk_fail;
+      else
+	break;
+    }
+
+    data_left -= read_length;
+  }
+
+  free(indirect_ptrs);
+  ret_val.len = data_length-data_left;
+  return ret_val;
+
+ chunk_fail:
+  free(indirect_ptrs);
+  talloc_free(ret_val.buf);
  fail:
   ret_val.buf = NULL;
Index: /trunk/src/reglookup-recover.c
===================================================================
--- /trunk/src/reglookup-recover.c	(revision 151)
+++ /trunk/src/reglookup-recover.c	(revision 152)
@@ -285,6 +285,5 @@
       else
       {
-	if((cur_ancestor->key_type == REGFI_NK_TYPE_ROOTKEY1) 
-	   || (cur_ancestor->key_type == REGFI_NK_TYPE_ROOTKEY2))
+	if(cur_ancestor->key_type & REGFI_NK_FLAG_ROOT)
 	  virt_offset = REGFI_OFFSET_NONE;
 	else
@@ -482,7 +481,7 @@
       if(vk->data_in_offset)
       {
-	data = regfi_parse_data(f, vk->type, vk->data_off,
-				vk->data_size, 4,
-				vk->data_in_offset, false);
+	data = regfi_load_data(f, vk->type, vk->data_off,
+			       vk->data_size, 4,
+			       vk->data_in_offset, false);
 	vk->data = data.buf;
 	vk->data_size = data.len;
@@ -495,7 +494,7 @@
 	  data_offset = vk->data_off+REGFI_REGF_SIZE;
 	  data_maxsize = hbin->block_size + hbin->file_off - data_offset;
-	  data = regfi_parse_data(f, vk->type, data_offset, 
-				  vk->data_size, data_maxsize, 
-				  vk->data_in_offset, false);
+	  data = regfi_load_data(f, vk->type, data_offset, 
+				 vk->data_size, data_maxsize, 
+				 vk->data_in_offset, false);
 	  vk->data = data.buf;
 	  vk->data_size = data.len;
@@ -503,11 +502,14 @@
 	  if(vk->data != NULL)
 	  {
+	    /* XXX: The following may not make sense now in light of big data
+	     *      records.
+	     */
 	    /* XXX: This strict checking prevents partial recovery of data 
-	     *      cells.  Also, see code for regfi_parse_data and note that
+	     *      cells.  Also, see code for regfi_load_data and note that
 	     *      lengths indicated in VK records are sometimes just plain 
 	     *      wrong.  Need a feedback mechanism to be more fuzzy with 
 	     *      data cell lengths and the ranges removed. 
 	     *
-	     *      The introduction of REGFI_BUFFER in regfi_parse_data has 
+	     *      The introduction of REGFI_BUFFER in regfi_load_data has 
 	     *      fixed some of this.  Should review again with respect to 
 	     *      the other issues mentioned above though.
