uint16_t name_len; /* length of name */
/* length of the data:
* If data_len is <= 4, then it's stored inline.
- * If data_len is 0x80000000, then it's an inline dword.
- * Top bit may be set or not set at random.
+ * Top bit is set to indicate inline.
*/
uint32_t data_len;
uint32_t data_offset; /* pointer to the data (or data if inline) */
if (len) {
*len = le32toh (vk->data_len);
- if (*len == 0x80000000) { /* special case */
- *len = 4;
- if (t) *t = hive_t_dword;
- }
- *len &= 0x7fffffff;
+ *len &= 0x7fffffff; /* top bit indicates if data is stored inline */
}
return 0;
hive_type t;
size_t len;
+ int is_inline;
t = le32toh (vk->data_type);
len = le32toh (vk->data_len);
- if (len == 0x80000000) { /* special case */
- len = 4;
- t = hive_t_dword;
- }
+ is_inline = !!(len & 0x80000000);
len &= 0x7fffffff;
if (h->msglvl >= 2)
- fprintf (stderr, "hivex_value_value: value=0x%zx, t=%d, len=%zu\n",
- value, t, len);
+ fprintf (stderr, "hivex_value_value: value=0x%zx, t=%d, len=%zu, inline=%d\n",
+ value, t, len, is_inline);
if (t_rtn)
*t_rtn = t;
if (len_rtn)
*len_rtn = len;
+ if (is_inline && len > 4) {
+ errno = ENOTSUP;
+ return NULL;
+ }
+
/* Arbitrarily limit the length that we will read. */
if (len > HIVEX_MAX_VALUE_LEN) {
errno = ERANGE;
if (ret == NULL)
return NULL;
- /* If length is <= 4 it's always stored inline. */
- if (len <= 4) {
+ if (is_inline) {
memcpy (ret, (char *) &vk->data_offset, len);
return ret;
}
(struct ntreg_vk_record *) (h->addr + values[i]);
size_t len;
+ int is_inline;
len = le32toh (vk->data_len);
- if (len == 0x80000000) /* special case */
- len = 4;
+ is_inline = !!(len & 0x80000000); /* top bit indicates is inline */
len &= 0x7fffffff;
- if (len > 4) { /* non-inline, so remove data block */
+ if (!is_inline) { /* non-inline, so remove data block */
size_t data_offset = le32toh (vk->data_offset);
data_offset += 0x1000;
mark_block_unused (h, data_offset);
vk->name_len = htole16 (name_len);
strcpy (vk->name, values[i].key);
vk->data_type = htole32 (values[i].t);
- vk->data_len = htole16 (values[i].len);
+ uint32_t len = values[i].len;
+ if (len <= 4) /* store it inline => set MSB flag */
+ len |= 0x80000000;
+ vk->data_len = htole32 (len);
vk->flags = name_len == 0 ? 0 : 1;
- if (values[i].len <= 4) /* Store data inline. */
+ if (values[i].len <= 4) /* store it inline */
memcpy (&vk->data_offset, values[i].value, values[i].len);
else {
size_t offs = allocate_block (h, values[i].len + 4, nul_id);
let bitmatch vk_fields =
{ "vk" : 2*8 : string;
name_len : 2*8 : littleendian;
- (* No one documents the important fact that data_len can have the
- * top bit set (randomly or is it meaningful?). The length can
- * also be 0 (or 0x80000000) if the data type is NONE.
+ (* Top bit set means that the data is stored inline. In that case
+ * the data length must be <= 4. The length can also be 0 (or
+ * 0x80000000) if the data type is NONE.
*)
data_len : 4*8
: littleendian, bind (
- let data_len = Int32.logand data_len 0x7fff_ffff_l in
- Int32.to_int data_len
+ let is_inline = Int32.logand data_len 0x8000_0000_l = 0x8000_0000_l in
+ let data_len = Int32.to_int (Int32.logand data_len 0x7fff_ffff_l) in
+ if is_inline then assert (data_len <= 4) else assert (data_len > 4);
+ is_inline, data_len
);
- (* Inline data if len <= 4, offset otherwise.
- *
- * The data itself depends on the type field.
+ (* The data itself depends on the type field.
*
* For REG_SZ type, the data always seems to be NUL-terminated, which
* means because these strings are often UTF-16LE, that the string will
*)
data : 4*8
: bitstring, bind (
- if data_len <= 4 then
+ let is_inline, data_len = data_len in
+ if is_inline then
Inline (takebits (data_len*8) data)
else (
let offset =
| Offset offset ->
let (_, _, bits) = lookup "fprintf_vk (data)" offset in
bits in
- fprintf chan "VK %s %s %d %s%s %s %08x %s %08x %08x\n"
+ let is_inline, data_len = data_len in
+ fprintf chan "VK %s %s %s %d %s%s %s %08x %s %08x %08x\n"
(print_offset vk)
- name data_len
+ name (if is_inline then "inline" else "-") data_len
(match data with
| Inline _ -> ""
| Offset offset -> "["^print_offset offset^"]")
| { :vk_fields } ->
fprintf_vk stdout vk;
+ let is_inline, data_len = data_len in
+
if unknown1 <> 0 then
eprintf "VK %s unknown1 flags set (%02x)\n"
(print_offset vk) unknown1;