X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=lib%2Fhivex.c;h=4b9fcf0512a80a1184417ce9ed541fae9b3440d3;hb=96f1edbae1ed41ec1c4e558060b7b33b6b749ea4;hp=a72fa776907a294666944e5ec5f92f3a111640f5;hpb=6780483c3c00913e718a6134e12d82665e9ce0a6;p=hivex.git diff --git a/lib/hivex.c b/lib/hivex.c index a72fa77..4b9fcf0 100644 --- a/lib/hivex.c +++ b/lib/hivex.c @@ -38,10 +38,6 @@ #include "full-read.h" #include "full-write.h" -#ifndef O_CLOEXEC -#define O_CLOEXEC 0 -#endif - #define STREQ(a,b) (strcmp((a),(b)) == 0) #define STRCASEEQ(a,b) (strcasecmp((a),(b)) == 0) //#define STRNEQ(a,b) (strcmp((a),(b)) != 0) @@ -97,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 @@ -108,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 */ @@ -177,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 */ @@ -297,9 +294,16 @@ hivex_open (const char *filename, int flags) if (h->filename == NULL) goto error; +#ifdef O_CLOEXEC h->fd = open (filename, O_RDONLY | O_CLOEXEC); +#else + h->fd = open (filename, O_RDONLY); +#endif if (h->fd == -1) goto error; +#ifndef O_CLOEXEC + fcntl (h->fd, F_SETFD, FD_CLOEXEC); +#endif struct stat statbuf; if (fstat (h->fd, &statbuf) == -1) @@ -321,6 +325,13 @@ hivex_open (const char *filename, int flags) if (full_read (h->fd, h->addr, h->size) < h->size) goto error; + + /* We don't need the file descriptor along this path, since we + * have read all the data. + */ + if (close (h->fd) == -1) + goto error; + h->fd = -1; } /* Check header. */ @@ -356,6 +367,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); @@ -364,6 +378,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" @@ -371,6 +387,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, @@ -543,7 +560,10 @@ hivex_close (hive_h *h) munmap (h->addr, h->size); else free (h->addr); - r = close (h->fd); + if (h->fd >= 0) + r = close (h->fd); + else + r = 0; free (h->filename); free (h); @@ -602,6 +622,43 @@ 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 %zu: %" 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. @@ -2258,7 +2315,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