Named Key cells are the data structures within the Registry that hold the Keys and provide the parent/child data necessary to build the tree. Different documentation calls these Named Keys, Node Keys, or NT Keys. It is unclear which is correct, so I’m going to go with Noodle Keys.
offset | length | type | what is it? |
x00 | 4 | int32 | Cell Length |
x04 | 2 | string | Signature: “nk” |
x06 | 2 | binary | Flags |
x08 | 8 | datetime | Last Modified Date |
x10 | 4 | int32 | unknown |
x14 | 4 | int32 | Parent Key Offset |
x18 | 4 | int32 | Number of stable sub keys |
x1C | 4 | int32 | Number of volatile sub keys |
x20 | 4 | int32 | Sub key offset |
x24 | 4 | int32 | Volatile sub key offset |
x28 | 4 | int32 | Value List Count |
x2C | 4 | int32 | Value List Offset |
x30 | 4 | int32 | Security key offset |
x34 | 4 | int32 | Class name offset |
x38 | 4 | int32 | Max name length |
x3C | 4 | int32 | Max class name size |
x40 | 4 | int32 | Max value name size |
x44 | 4 | int32 | Max value data size |
x48 | 4 | int32 | Unknown |
x4C | 2 | int16 | Key name size (n) |
x4E | 2 | int16 | Class name size |
x50 | n | string | Key name |
This is what one would look like in a hex editor:
Offset | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | |
00 | A8 | FF | FF | FF | 6E | 6B | 20 | 00 | EE | C5 | D7 | 48 | 45 | 04 | CA | 01 | ¨ÿÿÿnk··îÅ×HE·Ê |
Length | Sig | Flags | Last Modified Date | ||||||||||||||
10 | 00 | 00 | 00 | 00 | 20 | 00 | 00 | 00 | 01 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | ················ |
Unknown | Parent | # Skey subs | # Vkey sub | ||||||||||||||
20 | B0 | 01 | 00 | 00 | FF | FF | FF | FF | 00 | 00 | 00 | 00 | FF | FF | FF | FF | °···ÿÿÿÿ····ÿÿÿÿ |
Skey offset | Vkey offset | VL count | VL offset | ||||||||||||||
30 | D0 | 00 | 00 | 00 | FF | FF | FF | FF | 12 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | з··ÿÿÿÿ········ |
Seckey offset | Class offset | Max Name Len | Max Cls Sz | ||||||||||||||
40 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 08 | 00 | 00 | 00 | ················ |
Max Name Sz | Max Data Sz | Unknown | KNS | CNS | |||||||||||||
50 | 53 | 6F | 66 | 74 | 77 | 61 | 72 | 65 | Software | ||||||||
Name |
Notes and observations:
The length field at the beginning is a negative number for allocated cells. So, an 88 byte cell has a length of xA8FFFFFF and a really long cell of 264 bytes would be xF8FEFFFF. When this number is positive it describes an unallocated cell. When searching for unallocated cells, I’ve seen three scenarios: 1. the cell is empty (length makes no sense), 2. the cell is partially overwritten (size is logical, but another record is found much sooner), and 3. the cell is a whole deleted record (yea!).
Scenario 1 looks like this. Note the length set to x00 and the complete lack of usefulness. This appears to be the case when an unallocated cell’s ‘nk’ signature appears in slack space of another cell. In this example below, the x0000 at offset x00 is the null terminator to the string on the previous line and that cell consumes all the way to offset x07 with the next cell starting at offset x08.
Offset | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | |
00 | 00 | 00 | 00 | 00 | 6E | 6B | 20 | 00 | E0 | FF | FF | FF | 76 | 6B | 07 | 00 | nk àÿÿÿvk |
Scenario 2 looks like this. This appears to be legit data that was partially overwritten. We have a length field of x58 or 88 bytes, yet we have another cell starting after 64 bytes.
Offset | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | |
00 | 58 | 00 | 00 | 00 | 6E | 6B | 20 | 00 | 68 | 51 | 82 | 45 | 30 | 89 | CB | 01 | X nk hQ‚E0‰Ë |
10 | 00 | 00 | 00 | 00 | 60 | 6E | 33 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | `n3 |
20 | FF | FF | FF | FF | FF | FF | FF | FF | 00 | 00 | 00 | 00 | FF | FF | FF | FF | ÿÿÿÿÿÿÿÿ ÿÿÿÿ |
30 | FF | FF | FF | FF | FF | FF | FF | FF | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | ÿÿÿÿÿÿÿÿ |
40 | A8 | FF | FF | FF | 6E | 6B | 20 | 00 | 37 | 7A | B2 | 76 | 18 | 3E | D0 | 01 | ¨ÿÿÿnk 7z²v >Ð |
50 | 00 | 00 | 00 | 00 | 60 | 33 | 2F | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | `3/ |
The flags at offset x6 tell us some interesting things about this key. They parse out as:
00000001 | x01 | Is volatile |
00000010 | x02 | Is mount point |
00000100 | x04 | Is root |
00001000 | x08 | Cannot be deleted |
00010000 | x10 | Is symbolic link |
00100000 | x20 | Name is ASCII, 0 = Unicode |
01000000 | x40 | Is predefined handle |
Most of these fields seem self explanatory based on the names, but I’ve seen conflicting names in different documentation.
Several of the fields will be xffffffff if they are undefined, such as Volatile Sub Key Offset and other offsets.
Parent Key Offset at offset x14 provides the location of the cell that is this cell’s parent. Offset starts from start of first bin, so add 4096 to cover regf header. Root cell has a value in this field even though it doesn’t have a parent and that value is garbage that points to a location that doesn’t make any sense. Not sure why that isn’t just zeroed out.
Sub Key Offset will point to an lf cell that lists all of the children cells and provides their locations. The best and most succinct explanation of this relationship is in appendix 22 of Norris’s documentation. More on that later.
The Value Key Offset and Count work just like the Sub Key data but for Values.