You can dump the TEB structure with the !teb
command in the kernel debugger. The output looks like this:kd> !teb
TEB at 7ffde000
ExceptionList: 019e8e44
StackBase: 019f0000
StackLimit: 019db000
SubSystemTib: 00000000
FiberData: 00001e00
...
PEB Address: 7ffd9000
LastErrorValue: 0
LastStatusValue: c0000139
Count Owned Locks: 0
HardErrorMode: 0The CSR_THREAD, illustrated in Figure 5-10 is analogous to the data structure of CSR_PROCESS, but it’s applied to threads. As you might recall, this is maintained by each Csrss
process within a session and identifies the Windows subsystem threads running within it. The CSR_THREAD stores a handle that Csrss keeps for the thread, various flags, and a pointer to the CSR_PROCESS for the thread. It also stores another copy of the thread’s creation time.
Figure 5-10. Fields of the CSR thread
EXPERIMENT: Examining the CSR_THREAD
You can dump the CSR_THREAD structure with the !dt
command in the user-mode debugger while attached to a Csrss process. Follow the instructions in the CSR_PROCESS experiment from earlier to safely perform this operation. The output looks like this:0:000> !dt v 001c7630
PCSR_THREAD @ 001c7630:
+0x000 CreateTime : _LARGE_INTEGER 0x1cb9fb6'00f90498
+0x008 Link : _LIST_ENTRY [ 0x1c0ab0 - 0x1c0f00 ]
+0x010 HashLinks : _LIST_ENTRY [ 0x75f19b38 - 0x75f19b38 ]
+0x018 ClientId : _CLIENT_ID
+0x020 Process : 0x001c0aa0 _CSR_PROCESS
+0x024 ThreadHandle : 0x000005c4
+0x028 Flags : 0
+0x02c ReferenceCount : 1
+0x030 ImpersonateCount : 0Finally, the W32THREAD structure, illustrated in Figure 5-11, is analogous to the data structure of WIN32PROCESS, but it’s applied to threads This structure mainly contains information useful for the GDI subsystem (brushes and DC attributes) as well as for the User Mode Print Driver framework (UMPD) that vendors use to write user-mode printer drivers. Finally, it contains a rendering state useful for desktop compositing and anti-aliasing.
Figure 5-11. Fields of the Win32k thread
EXPERIMENT: Examining the W32THREAD
You can dump the W32THREAD structure by looking at the output of the !thread
command, which gives a pointer to it in the Win32Thread output field. Alternatively, if you use the dt command, the KTHREAD block has a field called Win32Thread that contains the pointer to this structure. Recall that only a GUI thread will have a W32THREAD structure, so it’s possible that certain threads, such as background or worker threads, will not have an associated W32THREAD. Because there is no extension to view a W32THREAD, you need to use the dt command, as shown here:dt win32k!_w32thread ffb79dd8
+0x000 pEThread : 0x83ad4b60 _ETHREAD
+0x004 RefCount : 1
+0x008 ptlW32 : (null)
+0x00c pgdiDcattr : 0x00130740
+0x010 pgdiBrushAttr : (null)
+0x014 pUMPDObjs : (null)
+0x018 pUMPDHeap : (null)
+0x01c pUMPDObj : (null)
...
+0x0a8 bEnableEngUpdateDeviceSurface : 0 ''
+0x0a9 bIncludeSprites : 0 ''
+0x0ac ulWindowSystemRendering : 0
Birth of a Thread
A thread’s life cycle starts when a program creates a new thread. The request filters down to the Windows executive, where the process manager allocates space for a thread object and calls the kernel to initialize the thread control block (KTHREAD). The steps in the following list are taken inside the Windows CreateThread
function in Kernel32.dll to create a Windows thread:CreateThread
converts the Windows API parameters to native flags and builds a native structure describing object parameters (OBJECT_ATTRIBUTES). See Chapter 3 for more information.CreateThread
builds an attribute list with two entries: client ID and TEB address. This allows CreateThread to receive those values once the thread has been created. (For more information on attribute lists, see the section Flow of CreateProcess earlier in this chapter.)NtCreateThreadEx
is called to create the user-mode context and probe and capture the attribute list. It then calls PspCreateThread to create a suspended executive thread object. For a description of the steps performed by this function, see the descriptions of Stage 3 and Stage 5 in the section Flow of CreateProcess.CreateThread
allocates an activation context for the thread used by side-by-side assembly support. It then queries the activation stack to see if it requires activation, and it does so if needed. The activation stack pointer is saved in the new thread’s TEB.