summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorAlex Nelson <ajnelson@cs.ucsc.edu>2011-08-12 23:03:37 -0700
committerRichard W.M. Jones <rjones@redhat.com>2011-08-13 09:42:27 +0100
commite0b21193257f9784b28e931525f2a382a74775c6 (patch)
tree970d790ff798a915d8ec8b24b421dce551c107f2 /lib
parent98d83de9444c893fded2e92a3c454ffbda4bd4ad (diff)
downloadhivex-e0b21193257f9784b28e931525f2a382a74775c6.tar.gz
hivex-e0b21193257f9784b28e931525f2a382a74775c6.tar.xz
hivex-e0b21193257f9784b28e931525f2a382a74775c6.zip
Report last-modified time of hive root and nodes
The infrastructure for modified-time reporting has been essentially unused. These changes report the registry time by treating the time fields as Windows filetime fields stored in little-Endian (which means they can be treated as a single 64-bit little-Endian integer). This patch adds to the hivex ABI: * int64_t hivex_last_modified (hive_h *) * int64_t hivex_node_timestamp (hive_h *, hive_node_h) These two functions return the hive's last-modified time and a particular node's last-modified time, respectively. Credit to Richard Jones for the ABI suggestion, and for the tip on Microsoft's filetime time span. hivexml employs these two functions to produce mtime elements for a hive and all of its nodes, producing ISO-8601 formatted time. Signed-off-by: Alex Nelson <ajnelson@cs.ucsc.edu> A lot of code cleanup by RWMJ.
Diffstat (limited to 'lib')
-rw-r--r--lib/hivex.c49
1 files changed, 46 insertions, 3 deletions
diff --git a/lib/hivex.c b/lib/hivex.c
index fedbb6c..dceea73 100644
--- a/lib/hivex.c
+++ b/lib/hivex.c
@@ -93,6 +93,7 @@ struct hive_h {
/* Fields from the header, extracted from little-endianness hell. */
size_t rootoffs; /* Root key offset (always an nk-block). */
size_t endpages; /* Offset of end of pages. */
+ int64_t last_modified; /* mtime of base block. */
/* For writing. */
size_t endblocks; /* Offset to next block allocation (0
@@ -104,7 +105,7 @@ struct ntreg_header {
char magic[4]; /* "regf" */
uint32_t sequence1;
uint32_t sequence2;
- char last_modified[8];
+ int64_t last_modified;
uint32_t major_ver; /* 1 */
uint32_t minor_ver; /* 3 */
uint32_t unknown5; /* 0 */
@@ -173,7 +174,7 @@ struct ntreg_nk_record {
int32_t seg_len; /* length (always -ve because used) */
char id[2]; /* "nk" */
uint16_t flags;
- char timestamp[8];
+ int64_t timestamp;
uint32_t unknown1;
uint32_t parent; /* offset of owner/parent */
uint32_t nr_subkeys; /* number of subkeys */
@@ -359,6 +360,9 @@ hivex_open (const char *filename, int flags)
goto error;
}
+ /* Last modified time. */
+ h->last_modified = le64toh ((int64_t) h->hdr->last_modified);
+
if (h->msglvl >= 2) {
char *name = windows_utf16_to_utf8 (h->hdr->name, 64);
@@ -367,6 +371,8 @@ hivex_open (const char *filename, int flags)
" file version %" PRIu32 ".%" PRIu32 "\n"
" sequence nos %" PRIu32 " %" PRIu32 "\n"
" (sequences nos should match if hive was synched at shutdown)\n"
+ " last modified %" PRIu64 "\n"
+ " (Windows filetime, x 100 ns since 1601-01-01)\n"
" original file name %s\n"
" (only 32 chars are stored, name is probably truncated)\n"
" root offset 0x%x + 0x1000\n"
@@ -374,6 +380,7 @@ hivex_open (const char *filename, int flags)
" checksum 0x%x (calculated 0x%x)\n",
major_ver, le32toh (h->hdr->minor_ver),
le32toh (h->hdr->sequence1), le32toh (h->hdr->sequence2),
+ h->last_modified,
name ? name : "(conversion failed)",
le32toh (h->hdr->offset),
le32toh (h->hdr->blocks), h->size,
@@ -608,6 +615,42 @@ hivex_node_name (hive_h *h, hive_node_h node)
return ret;
}
+static int64_t
+timestamp_check (hive_h *h, hive_node_h node, int64_t timestamp)
+{
+ if (timestamp < 0) {
+ if (h->msglvl >= 2)
+ fprintf (stderr, "hivex: timestamp_check: "
+ "negative time reported at %z: %" PRIi64 "\n", node, timestamp);
+ errno = EINVAL;
+ return -1;
+ }
+
+ return timestamp;
+}
+
+int64_t
+hivex_last_modified (hive_h *h)
+{
+ return timestamp_check (h, 0, h->last_modified);
+}
+
+int64_t
+hivex_node_timestamp (hive_h *h, hive_node_h node)
+{
+ int64_t ret;
+
+ if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
+
+ ret = le64toh (nk->timestamp);
+ return timestamp_check (h, node, ret);
+}
+
#if 0
/* I think the documentation for the sk and classname fields in the nk
* record is wrong, or else the offset field is in the wrong place.
@@ -2264,7 +2307,7 @@ hivex_node_add_child (hive_h *h, hive_node_h parent, const char *name)
nk->sk = htole32 (parent_sk_offset - 0x1000);
/* Inherit parent timestamp. */
- memcpy (nk->timestamp, parent_nk->timestamp, sizeof (parent_nk->timestamp));
+ nk->timestamp = parent_nk->timestamp;
/* What I found out the hard way (not documented anywhere): the
* subkeys in lh-records must be kept sorted. If you just add a