FS Register Access

In Win32 operating systems, the FS register is special because the pointer to the thread information block (TIB) is stored in it. The TIB is also called the thread environment block (TEB). The TIB holds all the thread-specific data so that the operating system can keep your thread access straight. This thread-specific data includes all the structured exception handling (SEH) chains, thread local storage, the thread stack, and other information needed internally. For more information about SEH, see Chapter 13. For an example of thread local storage, see the MemStress discussion in Chapter 17.

The TIB is stored in a special memory segment, and when the operating system needs to access the TIB, it converts the FS register plus an offset into a normal linear address. When you see an instruction accessing the FS register, one of the following operations is underway: an SEH frame is being created or destroyed, the TIB is being accessed, or thread local storage is being accessed.

Creating or Destroying an SEH Frame The first instructions after setting up the stack frame are often something like the following code, which is standard code to start a __try block. The first node in the chain of SEH handlers is at offset 0 in the TIB. In the following disassembly, the compiler is pushing a data value and a pointer to a function on the stack.

That function is_except_handler3 in Windows 2000 code. In Windows XP operating system code, the special function is _SEH_prolog. The first mov instruction is accessing the TIB; the offset of 0 indicates that a node is being added to the top of the exception chain. The last two instructions indicate where the code moves the actual node to the chain.

PUSH 004060d0

PUSH 004014a0

PUSH EAX

Although this example is nice and clean, the compiler doesn't always produce such tidy code. Sometimes it spreads the SEH frame creation throughout the code. Depending on the code generation and optimization flags, the compiler moves instructions around to take better advantage of the CPU's pipelining. The following disassembly example, in which KERNEL32.DLL symbols are loaded, shows the start of the Microsoft Windows 2000 isBadReadPtr function:

PUSH EBP

PUSH 0FFFFFFFFh

PUSH 7 7E8 6F4 0h

PUSH OFFSET _except_handler3

MOV EAX , DWORD PTR FS:[00000000h] PUSH EAX

What's interesting about Windows XP is that the operating system code seems to have custom exception handling that generates a call to _SEH_prolog, where most of the preceding code executes. That leads to much smaller code, and based on looking at the assembly language, it looks as if Windows XP functions that use SEH are using custom prolog and epilog to do their magic.

Destroying an SEH frame is much more mundane than creating one, as the following code shows. The key item to remember is that any access of fs:[0] means SEH.

Accessing the TIB The value at fs:[18] is the linear address of the TIB structure. In the following code, the Windows XP implementation of GetCurrentThreadId gets the linear address of the TIB, and at offset 0x24, it gets the actual thread ID.

GetCurrentThreadId:

MOV EAX , FS:[00000018h]

MOV EAX , DWORD PTR [EAX+024h]

Accessing Thread Local Storage Thread local storage is a Win32 mechanism that allows you to have variables that are global, but each thread has its own instance of the global variables. Offset 0x2C in the TIB structure is the pointer to the thread local storage array. The following disassembly shows how to access the thread local storage pointer.

+10 0

Post a comment