第46章 TEB

本文最后更新于:2022年5月27日 下午

第46章 TEB

本章将学习有关TEB ( Thread Environment Block,线程环境块)的知识,它们是我们后面要学习的高级调试技术的基础,请大家认真学习,理解并掌握相关概念。

46.1 TEB

TEB指线程环境块,该结构体包含进程中运行线程的各种信息,进程中的每个线程都对应一个TEB结构体。不同OS中TEB结构体的形态略微不同,有关TEB结构体的详细说明都已被文档化,各位可以直接查看并参考。

46.1.1 TEB结构体的定义

首先看看MSDN中关于TEB结构体的说明。

1
2
3
4
5
6
7
8
9
10
11
12
typedef struct _TEB {
PVOID Reserved1[12];
PPEB ProcessEnvironmentBlock;
PVOID Reserved2[399];
BYTE Reserved3[1952];
PVOID TlsSlots[64];
BYTE Reserved4[8];
PVOID Reserved5[26];
PVOID ReservedForOle; // Windows 2000 only
PVOID Reserved6[4];
PVOID TlsExpansionSlots;
} TEB, *PTEB

正如大家所见,MSDN对TEB结构体的说明太过简单。要想查看关于TEB结构体的更多细节,必须借助类似于WinDbg的内核调试器(Kernel Debugger )才行。

安装并运行WinDbg的方法请参考“WinDbg” 一章。

46.1.2 TEB结构体成员

使用WinDbg调试器获取TEB结构体的组成成员,如下所示。

获取下面信息的方法:dt ntdll!_TEB(注意配置加载正确的符号文件)

若要详细信息

输入命令:dt -r1 ntdll!_TEB

Windows XP SP3中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
nt!_TEB
+0x000 NtTib : _NT_TIB
+0x01c EnvironmentPointer : Ptr32 Void
+0x020 ClientId : _CLIENT_ID
+0x028 ActiveRpcHandle : Ptr32 Void
+0x02c ThreadLocalStoragePointer : Ptr32 Void
+0x030 ProcessEnvironmentBlock : Ptr32 _PEB
+0x034 LastErrorValue : Uint4B
+0x038 CountOfOwnedCriticalSections : Uint4B
+0x03c CsrClientThread : Ptr32 Void
+0x040 Win32ThreadInfo : Ptr32 Void
+0x044 User32Reserved : [26] Uint4B
+0x0ac UserReserved : [5] Uint4B
+0x0c0 WOW32Reserved : Ptr32 Void
+0x0c4 CurrentLocale : Uint4B
+0x0c8 FpSoftwareStatusRegister : Uint4B
+0x0cc SystemReserved1 : [54] Ptr32 Void
+0x1a4 ExceptionCode : Int4B
+0x1a8 ActivationContextStack : _ACTIVATION_CONTEXT_STACK
+0x1bc SpareBytes1 : [24] UChar
+0x1d4 GdiTebBatch : _GDI_TEB_BATCH
+0x6b4 RealClientId : _CLIENT_ID
+0x6bc GdiCachedProcessHandle : Ptr32 Void
+0x6c0 GdiClientPID : Uint4B
+0x6c4 GdiClientTID : Uint4B
+0x6c8 GdiThreadLocalInfo : Ptr32 Void
+0x6cc Win32ClientInfo : [62] Uint4B
+0x7c4 glDispatchTable : [233] Ptr32 Void
+0xb68 glReserved1 : [29] Uint4B
+0xbdc glReserved2 : Ptr32 Void
+0xbe0 glSectionInfo : Ptr32 Void
+0xbe4 glSection : Ptr32 Void
+0xbe8 glTable : Ptr32 Void
+0xbec glCurrentRC : Ptr32 Void
+0xbf0 glContext : Ptr32 Void
+0xbf4 LastStatusValue : Uint4B
+0xbf8 StaticUnicodeString : _UNICODE_STRING
+0xc00 StaticUnicodeBuffer : [261] Uint2B
+0xe0c DeallocationStack : Ptr32 Void
+0xe10 TlsSlots : [64] Ptr32 Void
+0xf10 TlsLinks : _LIST_ENTRY
+0xf18 Vdm : Ptr32 Void
+0xf1c ReservedForNtRpc : Ptr32 Void
+0xf20 DbgSsReserved : [2] Ptr32 Void
+0xf28 HardErrorsAreDisabled : Uint4B
+0xf2c Instrumentation : [16] Ptr32 Void
+0xf6c WinSockData : Ptr32 Void
+0xf70 GdiBatchCount : Uint4B
+0xf74 InDbgPrint : UChar
+0xf75 FreeStackOnTermination : UChar
+0xf76 HasFiberData : UChar
+0xf77 IdealProcessor : UChar
+0xf78 Spare3 : Uint4B
+0xf7c ReservedForPerf : Ptr32 Void
+0xf80 ReservedForOle : Ptr32 Void
+0xf84 WaitingOnLoaderLock : Uint4B
+0xf88 Wx86Thread : _Wx86ThreadState
+0xf94 TlsExpansionSlots : Ptr32 Ptr32 Void
+0xf98 ImpersonationLocale : Uint4B
+0xf9c IsImpersonating : Uint4B
+0xfa0 NlsCache : Ptr32 Void
+0xfa4 pShimData : Ptr32 Void
+0xfa8 HeapVirtualAffinity : Uint4B
+0xfac CurrentTransactionHandle : Ptr32 Void
+0xfb0 ActiveFrame : Ptr32 _TEB_ACTIVE_FRAME
+0xfb4 SafeThunkCall : UChar
+0xfb5 BooleanSpare : [3] UChar

Windows 7中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
dt ntdll!_TEB
+0x000 NtTib : _NT_TIB
+0x01c EnvironmentPointer : Ptr32 Void
+0x020 ClientId : _CLIENT_ID
+0x028 ActiveRpcHandle : Ptr32 Void
+0x02c ThreadLocalStoragePointer : Ptr32 Void
+0x030 ProcessEnvironmentBlock : Ptr32 _PEB
+0x034 LastErrorValue : Uint4B
+0x038 CountOfOwnedCriticalSections : Uint4B
+0x03c CsrClientThread : Ptr32 Void
+0x040 Win32ThreadInfo : Ptr32 Void
+0x044 User32Reserved : [26] Uint4B
+0x0ac UserReserved : [5] Uint4B
+0x0c0 WOW32Reserved : Ptr32 Void
+0x0c4 CurrentLocale : Uint4B
+0x0c8 FpSoftwareStatusRegister : Uint4B
+0x0cc SystemReserved1 : [54] Ptr32 Void
+0x1a4 ExceptionCode : Int4B
+0x1a8 ActivationContextStackPointer : Ptr32 _ACTIVATION_CONTEXT_STACK
+0x1ac SpareBytes : [36] UChar
+0x1d0 TxFsContext : Uint4B
+0x1d4 GdiTebBatch : _GDI_TEB_BATCH
+0x6b4 RealClientId : _CLIENT_ID
+0x6bc GdiCachedProcessHandle : Ptr32 Void
+0x6c0 GdiClientPID : Uint4B
+0x6c4 GdiClientTID : Uint4B
+0x6c8 GdiThreadLocalInfo : Ptr32 Void
+0x6cc Win32ClientInfo : [62] Uint4B
+0x7c4 glDispatchTable : [233] Ptr32 Void
+0xb68 glReserved1 : [29] Uint4B
+0xbdc glReserved2 : Ptr32 Void
+0xbe0 glSectionInfo : Ptr32 Void
+0xbe4 glSection : Ptr32 Void
+0xbe8 glTable : Ptr32 Void
+0xbec glCurrentRC : Ptr32 Void
+0xbf0 glContext : Ptr32 Void
+0xbf4 LastStatusValue : Uint4B
+0xbf8 StaticUnicodeString : _UNICODE_STRING
+0xc00 StaticUnicodeBuffer : [261] Wchar
+0xe0c DeallocationStack : Ptr32 Void
+0xe10 TlsSlots : [64] Ptr32 Void
+0xf10 TlsLinks : _LIST_ENTRY
+0xf18 Vdm : Ptr32 Void
+0xf1c ReservedForNtRpc : Ptr32 Void
+0xf20 DbgSsReserved : [2] Ptr32 Void
+0xf28 HardErrorMode : Uint4B
+0xf2c Instrumentation : [9] Ptr32 Void
+0xf50 ActivityId : _GUID
+0xf60 SubProcessTag : Ptr32 Void
+0xf64 EtwLocalData : Ptr32 Void
+0xf68 EtwTraceData : Ptr32 Void
+0xf6c WinSockData : Ptr32 Void
+0xf70 GdiBatchCount : Uint4B
+0xf74 CurrentIdealProcessor : _PROCESSOR_NUMBER
+0xf74 IdealProcessorValue : Uint4B
+0xf74 ReservedPad0 : UChar
+0xf75 ReservedPad1 : UChar
+0xf76 ReservedPad2 : UChar
+0xf77 IdealProcessor : UChar
+0xf78 GuaranteedStackBytes : Uint4B
+0xf7c ReservedForPerf : Ptr32 Void
+0xf80 ReservedForOle : Ptr32 Void
+0xf84 WaitingOnLoaderLock : Uint4B
+0xf88 SavedPriorityState : Ptr32 Void
+0xf8c SoftPatchPtr1 : Uint4B
+0xf90 ThreadPoolData : Ptr32 Void
+0xf94 TlsExpansionSlots : Ptr32 Ptr32 Void
+0xf98 MuiGeneration : Uint4B
+0xf9c IsImpersonating : Uint4B
+0xfa0 NlsCache : Ptr32 Void
+0xfa4 pShimData : Ptr32 Void
+0xfa8 HeapVirtualAffinity : Uint4B
+0xfac CurrentTransactionHandle : Ptr32 Void
+0xfb0 ActiveFrame : Ptr32 _TEB_ACTIVE_FRAME
+0xfb4 FlsData : Ptr32 Void
+0xfb8 PreferredLanguages : Ptr32 Void
+0xfbc UserPrefLanguages : Ptr32 Void
+0xfc0 MergedPrefLanguages : Ptr32 Void
+0xfc4 MuiImpersonation : Uint4B
+0xfc8 CrossTebFlags : Uint2B
+0xfc8 SpareCrossTebBits : Pos 0, 16 Bits
+0xfca SameTebFlags : Uint2B
+0xfca SafeThunkCall : Pos 0, 1 Bit
+0xfca InDebugPrint : Pos 1, 1 Bit
+0xfca HasFiberData : Pos 2, 1 Bit
+0xfca SkipThreadAttach : Pos 3, 1 Bit
+0xfca WerInShipAssertCode : Pos 4, 1 Bit
+0xfca RanProcessInit : Pos 5, 1 Bit
+0xfca ClonedThread : Pos 6, 1 Bit
+0xfca SuppressDebugMsg : Pos 7, 1 Bit
+0xfca DisableUserStackWalk : Pos 8, 1 Bit
+0xfca RtlExceptionAttached : Pos 9, 1 Bit
+0xfca InitialThread : Pos 10, 1 Bit
+0xfca SpareSameTebBits : Pos 11, 5 Bits
+0xfcc TxnScopeEnterCallback : Ptr32 Void
+0xfd0 TxnScopeExitCallback : Ptr32 Void
+0xfd4 TxnScopeContext : Ptr32 Void
+0xfd8 LockCount : Uint4B
+0xfdc SpareUlong0 : Uint4B
+0xfe0 ResourceRetValue : Ptr32 Void

如上所示,借助WinDbg的符号文件,我们查看了TEB结构体的所有成员。仔细比较代码46-2与46-3可以发现,Windows 7下的TEB结构体比Windows XP下的TEB结构体大。

46.1.3重要成员

如上所示,TEB结构体的成员多而复杂,在用户模式调试中起着重要作用的成员有2个,如代码46-4所示。

1
2
+0x000 NtTib            : _NT_TIB
+0x030 ProcessEnvironmentBlock : Ptr32 _PEB

ProcessEnvironmentBlock成员

先看Offset 30处的ProcessEnvironmentBlock成员,它是指向PEB(Process Environment Block,进程环境块)结构体的指针。PEB是进程环境块,每个进程对应1个PEB结构体,下一章将详细讲解。

NtTib成员

TEB结构体的第一个成员S_NT_TIB结构体(TIB是Thread Information Block的简称,意为“线程信息块”),_NT_TIB结构体的定义如下所示:

1
2
3
4
5
6
7
8
9
typedef struct _NT_TIB {
struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList;
PVOID StackBase;
PVOID StackLimit;
PVOID SubSystemTib;
PVOID ArbitraryUserPointer;
struct _NT_TIB *Self;
} NT_TIB;
typedef NT_TIB *PNT_TIB;

ExceptionList成员指向_EXCEPTION_REGISTRATION_RECORD结构体组成的链表,它用于Windows OS的SEH。Self成员是_NT_TIB结构体的自引用指针,也是TEB结构体的指针(因为TEB结构体的第一个成员就是_NT_TIB结构体)。那么接下来的问题是,该如何在用户模式下访问TEB结构体呢?只有访问它才能使用相应信息。下一节将学习如何在用户模式下访问TEB结构体。

46.2 TEB访问方法

前面讲解过,借助WinDbg内核调试器可以很容易地访问TEB结构体。那么,该如何在用户模式下访问它呢?答案就是,通过OS提供的相关API访问。

请注意:下面示例中出现的地址会随用户计算机环境的不同而不同。

46.2.1 Ntdll.NtCurrentTeb()

Ntdll.NtCurrentTeb() API用来返回当前线程的TEB结构体的地址。该函数内部是如何实现的呢?下面使用OllyDbg工具查看。首先在OllyDbg中打开Notepad.exe程序(也可以打开其他任一程序),然后在鼠标右键菜单中选择Search for Name in all modules菜单,在Name in all modules对话框中查找ntdll.NtCurrentTeb()API,如图46-1所示(单击Name栏,按Name排序后更易查找)。

如图46-1所示,查找到NtCurrentTeb函数后,使用鼠标双击即可跳转到该API的代码处,如图46-2所示。

从上图可以看到,NtCurrentTeb()函数的内部代码非常简单,只返回FS:[18]地址值。在图46-2 的OllyDbg的代码注释窗口中可以看到FS:[18]的实际地址为7FFDF018。在内存窗口中进入7FFDF018地址,发现其值为7FFDF000,即NtCurrentTeb() API返回7FFDF000,该地址就是当前线程的TEB的地址。仔细观察图46-2中TEB结构体的地址(7FFDF000),发现它与FS段寄存器所指的段内存的基址是一样的。也就是说,TEB与FS段寄存器有着某种关联。

46.2.2 FS段寄存器

SDT(Segment Descriptor Table,段描述符表)

其实,FS段寄存器用来指示当前线程的TEB结构体。

IA-32系统中进程的虚拟内存大小为4GB,因而需要32位的指针才能访问整个内存空间。但 是FS寄存器的大小只有16位,那么它如何表示进程内存空间中的TEB结构体的地址呢?实际上,FS寄存器并非直接指向TEB结构体的地址,它持有SDT的索引,而该索引持有实际TEB地址。

SDT位于内核内存区域,其地址存储在特殊的寄存器GDTR(Global Descriptor Table Resiger,全局描述符表寄存器)中

借助示意图描述上述过程,如图46-3所示。

由于段寄存器实际存储的是SDT的索引,所以它也被称为“段选择符”(Segment Selector)。从图46-3中可以看到,TEB结构体位于FS段选择符所指的段内存的起始地址(base address)处。

  • FS:[0x18]=TEB起始地址

如果掌握了上述内容,那么就很容易理解下面公式的含义。

FS:[0x18] = TEB.NtTib.Self = address of TIB = address of TEB = FS:0 = 7FFDF000

FS:0是段内存的起始地址,FS寄存器指向(Indexing) 一个段描述符,而该描述符又指向段内存的起始地址。

从图46-2中可知,FS:[0x18]与[7FFDF018](→7FFDF000)具有相同含义。由代码46-5中的_NT_TIB结构体的定义得知,结构体的最后一个Self成员恰好位于从TEB结构体偏移018的位置(再次提醒TEB结构体的第一个成员就是_NT_TIB结构体)。Self指针变量指向偏移018的起始地址,也就是TEB的起始地址。

  • FS:[0x30]=PEB起始地址

根据代码46-2与代码46-3,FS:[0x30]可表示为如下等式:

FS:[0x30] = TEB.ProcessEnvironmentBlock = address of PEB

从图46-2中可以知道,FS:[0x30]与[7FFDF030](→7FFD3000)具有相同含义。也就是说,通过TEB的ProcessEnvironment Block成员可以获取PEB结构体的起始地址。PEB结构体多用于反调试,下一章将详细讲解。

  • FS:[0]=SEH起始地址

此外还要了解一下FS:[0]。

FS:[0] = TEB.NtTib.ExceptionList = address of SEH

从图46-2中可以知道,FS:[0]与[7FFDF000](→1DFF64)具有相同含义。

SEH是Wiondows操作系统中的结构化异常处理机制,常用于反调试技术,详细内容请参考第48章。

46.3小结

本章我们学习了FS:[0]、FS:[0xl8]、FS:[0x30]的含义,调试中会经常见到。只要理解了“FS:[0xl8]指向TEB结构体的起始地址”,就能轻松掌握它们表示的含义。为便于说明,本章并未做复杂讲解,大家具备了一定的水平与实力后;我们会另外学习IA-32内存模型的知识。刚开始学习时虽然有些枯燥乏味,但还是要先认真整理这些相关概念,随着各位对IA-32 CPU与Windows OS理解的逐渐深人,再逐步学习更高级的代码逆向分析技术。


第46章 TEB
https://m0ck1ng-b1rd.github.io/1999/04/06/逆向工程核心原理/第46章 TEB/
作者
何语灵
发布于
1999年4月6日
许可协议