What’s in a name? That which we call a profile
By any other name would still let us log in.


I recently ran across a case where I needed to prove which user was using which profile folder. Every once in a while, the profile folder name won’t actually be the same as the account’s username. It’s pretty easy to assume that the folder is the username, since it that is the case better than 90% of the time. But, as Admiral Akbar says, “It’s a trap!”

There are two scenarios that I’ve witnessed where this isn’t the case. If there is already a profile folder with the same username, such as if a local account was created for the user prior to them logging in with their domain credentials and both these usernames are the same, then a second profile folder will be created. Profile folders are unique by SID and even if local account and domain account are same name they will be different SIDs and thus will get their own folders. To overcome the name conflict, the system will append the domain to the username when creating the profile folder name. This is exactly what you see in the screenshot below – the \Users\benjamin.russell folder is a local account and then when Ben logged in with this domain account for the first time the system created the \Users\benjamin.russell.hitek folder. The login that associated with the former folder is benjamin.russell and the login associated with the latter is hitek\benjamin.russell. Had it happened in the opposite order, so domain credentials logged in first and then a local account was created and used, the new profile folder’s name would have hostname appended to it instead of the domain name as that is the domain context for local accounts.

Another scenario is when the user changes their name. If there is an existing profile from the user having already logged in and the user’s username changes, the system will continue to use the existing profile folder even though the name no longer matches. Changing the username doesn’t change the SID, so in the system’s mind this is not a new profile and thus it should continue with what it has. This can happen post marriage when a last name changes or can happen when a user requests their name changed for other reasons, such as in our example below where Mr. Russell said he really prefers to go by Ben. When he requested they change his login from benjamin.russell to ben.russell, the SID never changed and thus his profile is still stored in the \Users\benjamin.russell.hitek folder, as you can see in the command prompt in the screenshot below. This can very easily cause a forensic examiner to associate data from NTUSER.DAT with a non-existent username if care is not taken.




Humans are amazing, we can intuitively tell that Ben and Benjamin are the same person and that Hitek is the domain thus benjamin.russell.hitek is the profile folder of his domain account, but computers aren’t so quick. So, how do we positively tell which folder belongs to which user?

I was really hoping the NTUSER.DAT held that answer, but it doesn’t. There is no pointed reference to the username or SID anywhere in that hive. There are some consequential references, such as some MS Office, ActiveInstaller, and Media Player related keys that list usernames, but they aren’t concrete and aren’t guaranteed to be there on every system. There is a solid clue in this article. The answer is in the SYSTEM hive in the HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\ key. Within that key is a series of keys named after the SID of each user profile on the system. This includes the various system profiles and omits the \Users\Default folder that trips up a lot of automated user data processing scripts I’ve seen. If you want a script to touch every profile that actually is a profile, this is where it should go to start its search.

Inside each SID named key you will find a value named ProfileImagePath that contains the location on disk of the profile for the user that has this SID. This allows you to definitively tie this folder to this SID, but you will have to look elsewhere to tie the SID to the username (hint: PsGetSid from Sysinternals). The other values in there, according to this, are as follows, just in case you find them forensically interesting depending on your specific case needs.

Default: It’s the value whose name is null.

Flags: Enables you to control the installation and uninstallation of your registry entries. No further information available.

GUID: This is a unique ID for this user account. It is only present on domain accounts; local accounts are absent this value. Locally, it corresponds to keys in the PoliciesGUID and ProfilesGUID keys just above the ProfileList key. Inside each of those keys is a key for each GUID with a value that tells me which SID this GUID maps to. Kinda circular and not very helpful.

ProfileImagePath: The User’s profile path. This is the important one.

ProfileLoadTimeLow: These two DWORDs make up the high-order bits and low-order bits, respectively, of a double dword that is a timestamp. Combine the 4 bytes you get from each in the right order and you should get 8 bytes that become the date and time when the user logged in. I frequently find these values as zeros, though, so I’m not sure when this gets populated vs when it gets ignored.

RefCount:  value of 0 means the account has no active session, anything higher means the account has an active session. The implication is that this number indicates the number of concurrent logins by that user, but I’ve seen this number be higher than current session count so I think it counts logins but doesn’t decrement when the session ends.

RunLogonScriptSync:  Determines whether the system waits for the logon script to finish running before it starts Windows Explorer and creates the desktop.
0           The logon script and Windows Explorer can run simultaneously.
1           Windows Explorer does not start until the logon script has finished running.

Sid: The Security Identifier in binary

State:  Indicates the state of the local profile cache. For example, a state of 256 = x100 = Admin account, and 772 = x304 = x200 + x100 + x004 = a bunch of stuff.
x0001       Profile is mandatory.
x0002       Update the locally cached profile.
x0004       New local profile.
x0008       New central profile.
x0010       Update the central profile.
x0020       Delete the cached profile.
x0040       Upgrade the profile.
x0080       Using Guest user profile.
x0100       Using Administrator profile.
x0200       Default net profile is available and ready.
x0400       Slow network link identified.
x0800       Temporary profile loaded.

On Espionage

I recently read an article that included the following quote:

“During Chinese President Xi Jinping’s recent state visit, the two countries agreed to a “common understanding” that neither side would engage in or support commercial espionage. The agreement did not address legitimate intelligence espionage.”

There is a fundamental misunderstanding of foreign cultures that seems to constantly come up, both in how our delegated officials interact with foreign states and how our media reports on those interactions.

To counter the point the person being quoted is trying to make in their last sentence, we would never enter into any agreement that addresses intelligence espionage because that is how we keep check on foreign states, both ally and adversary. How do you know they are doing what they told you they would do during the diplomatic talks if you don’t monitor their actions? Every country does this. As an example, it was interception of communications between two countries that were not considered our adversaries at the time that brought us into WWI. Our intelligence apparatus is older than our country, having been formed during the Revolutionary War, and we are not, nor will any other country, going to agree to anything that will cripple intelligence gathering capabilities.

The problem comes when we try to evaluate that foreign state’s words or actions based on our own ethics, cultures, and mindsets. To China, there is NO difference between commercial espionage and intelligence espionage. To China, theft of an idea is not theft because you have not stolen a thing; thus the huge and invasive knock-off market that originates from there that permeates every industry from clothes to purses to electronics. From our point of view, government and commercial are two different things. To China, the government controls the commercial environment and takes a very active stake in bettering those companies’ placement in the world market because improving China’s commercial interests are one in the same with improving China’s governmental interests.

How can we expect them to differentiate between commercial and governmental espionage and make an active stance against theft of corporate intellectual property when in their eyes there is no difference between the two types of espionage and there is no ethical problem with conducting commercial espionage to better their interests?




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


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.



Next Page