Usage of TEB ArbitraryUserPointer

This note describes the various uses of the ArbitraryUserPointer field in the Thread Environment Block (TEB) data structure which is associated with every single user mode thread in the system. Since the TEB and all of the fields of the TEB are associated with a single thread, i.e. the thread owning the TEB, the code that modifies the ArbitraryUserPointer saves the current value, modifies it to the desired value as discussed below and then restores it back to the original saved value without having to worry about reentrancy.

Here is the partial TEB structure showing the ArbitraryUserPointer field.

0:001> dt ntdll!_TEB NtTib.
   +0x000 NtTib  : 
      +0x000 ExceptionList : Ptr64 _EXCEPTION_REGISTRATION_RECORD
      +0x008 StackBase : Ptr64 Void
      +0x010 StackLimit : Ptr64 Void
      +0x018 SubSystemTib : Ptr64 Void
      +0x020 FiberData : Ptr64 Void
      +0x020 Version : Uint4B
      +0x028 ArbitraryUserPointer : Ptr64 Void
      +0x030 Self   : Ptr64 _NT_TIB

The NTDLL function LdrpMapViewOfSection() uses TEB.NT_TIB.ArbitraryUserPointer to pass the FullDllName (type PWCHAR) to the debugger for module load notifications before calling into the kernel via ntdll!NtMapViewOfSection().

Threads in WOW64 processes have two different TEBs associated with them, i.e. the 32 bit TEB (ntdll!_TEB32) and the standard 64 bit TEB (ntdll!_TEB). The 32 bit TEB for a WOW64 thread is as follows.

0:001> dt ntdll!_TEB32 NtTib.
   +0x000 NtTib  :
      +0x000 ExceptionList : Uint4B
      +0x004 StackBase : Uint4B
      +0x008 StackLimit : Uint4B
      +0x00c SubSystemTib : Uint4B
      +0x010 FiberData : Uint4B
      +0x010 Version : Uint4B
      +0x014 ArbitraryUserPointer : Uint4B
      +0x018 Self   : Uint4B

The following section refers to the 64-bit version of the TEB in WOW64 processes.

During WOW64 process startup, the WOW64.dll function InitializeContextMapper() maps \KnownDlls\kernel32.dll and \KnownDlls32\kernel32.dll i.e. the 64-bit and 32-bit versions of kernel32.dll into the WOW64 address space, for the purpose of thunking. Before calling ntdll!NtMapViewOfSection() it sets TEB.NT_TIB.ArbitraryUserPointer to the string "WOW64_IMAGE_SECTION".

Additionally, the WOW64.dll function Map64BitDLLs() reserves memory addresses by mapping \KnownDlls\kernel32.dll and the \KnownDlls\user32.dll i.e. 64-bit versions of kernel32 and user32.dll, into the WOW64 address space to avoid address conflicts with 32-bit versions of these DLLs. Before calling NtMapViewOfSection(), it sets the TEB.NT_TIB.ArbitraryUserPointer to the string "NOT_AN_IMAGE".

Call stacks for all of the above mentioned functions can be obtained by running a WOW64 process under the 64-bit version of WinDBG and setting the following execution breakpoint to display pertinent information, during process startup.

bp ntdll!NtMapViewOfSection "du @@c++( @$teb->NtTib.ArbitraryUserPointer);!handle @rcx f;g;"

In kernel mode, the NTOSKRNL function DbgkSendSystemDllMessages() sends information about the DLLs listed in the array nt!PspSystemDlls i.e. "\SystemRoot\System32\ntdll.dll" and "\SystemRoot\SysWOW64\ntdll.dll" to the debugger by copying (RtlStringCbCopyW()) the DLL name to TEB.StaticUnicodeBuffer. Before calling DbgkpSendApiMessage() it sets TEB.NT_TIB.ArbitraryUserPointer to point to TEB.StaticUnicodeBuffer.