Win32 Thread Environment Block

From Shit we found out
Jump to: navigation, search

The Thread Environment Block (TEB) or Thread Information Block (TIB) is located at the address held in the FS segment register, that is at address FS:[0x00]. However, it is common to access the TEB from FS:[0x18] instead, where a linear self-pointer is stored.

Hence, the TEB can be retrieved by the following function (on x86) (from Wikipedia):

void *getTIB()
{
  void *pTib;
  __asm__("movl %%fs:0x18, %0" : "=r" (pTib) : : );
  return pTib;
}

or by using the Microsoft compiler intrinsic

void *getTib()
{
  return (void *) __readfsdword (0x18);
}

However, the Microsoft x64 compiler does not have support for inline assembly, so for 64-bit the intrinsic is the only option:

vx_uint64_t __readgsqword (_In_ vx_uint32_t Offset);

static void *
getTib64 (void)
{
  return (void *) __readgsqword(0x30);
}


Note that on x64, the GS register holds the TEB instead of the FS register, and that the self-pointer is at offset 0x30 instead of offset 0x18.


TEB structure

The TEB looks something like this:

struct _TEB {                                                     //  x86  /  x64
  struct _NT_TIB                    NtTib;                        // 0x000 / 0x000
  void                             *EnvironmentPointer;           // 0x01c / 0x038
  struct _CLIENT_ID                 ClientId;                     // 0x020 / 0x040
  void                             *ActiveRpcHandle;              // 0x028 / 0x050
  void                             *ThreadLocalStoragePointer;    // 0x02c / 0x058
  struct _PEB                      *ProcessEnvironmentBlock;      // 0x030 / 0x060
  uint32_t                          LastErrorValue;               // 0x034 / 0x068
  uint32_t                          CountOfOwnedCriticalSections; // 0x038 / 0x06c
  void                             *CsrClientThread;              // 0x03c / 0x070
  void                             *Win32ThreadInfo;              // 0x040 / 0x078
  uint32_t                          User32Reserved[26];           // 0x044 / 0x080
  uint32_t                          UserReserved[5];              // 0x0ac / 0x0e8
  void                             *WOW32Reserved;                // 0x0c0 / 0x100?
  uint32_t                          CurrentLocale;                // 0x0c4
  uint32_t                          FpSoftwareStatusRegister;     // 0x0c8
  void                             *SystemReserved1[54];          // 0x0cc
  uint32_t                          ExceptionCode;                // 0x1a4
  struct _ACTIVATION_CONTEXT_STACK  ActivationContextStack;       // 0x1a8
  uint8_t                           SpareBytes1[24];              // 0x1bc
  //struct _GDI_TEB_BATCH           GdiTebBatch;                  // 0x1d4
} __PACKED;

Where the first part is an NT subsystem independent part defined as:

/* This structure is 56 bytes on x64, and 28 bytes on x86 */
struct _NT_TIB {              //  x86  /  x64
  void *ExceptionList;        // 0x000 / 0x000
  void *StackBase;            // 0x004 / 0x008
  void *StackLimit;           // 0x008 / 0x010
  void *SubSystemTib;         // 0x00c / 0x018
  union {
    void *FiberData;          // 0x010 / 0x020
    uint32_t Version;         // 0x010 / 0x020
  };
  void *ArbitraryUserPointer; // 0x014 / 0x028
  struct _NT_TIB *Self;       // 0x018 / 0x030
};


The TEB may be used to locate the Win32 Process Environment Block, of which the address is located at offset 0x30 of the TEB on x86.