线程信息块
此條目需要补充更多来源。 (2019年1月12日) |
Win32线程信息块(TIB)是32位Windows操作系统的线程使用的数据结构,存储了每个线程的运行时信息。 也称作“线程环境块”(Thread Environment Block,TEB)。[1]
Windows NT系列的DDK在winnt.h中包括了一个struct NT_TIB,为独立于subsystem的部分。Wine包含了TIB与subsystem相关的扩展部分。由于非常多程序使用了TIB,事实上TIB成为Windows API的一部分。[1]
TIB可用于获取很多进程相关信息,而不必调用Win32 API。例如,模拟GetLastError()或GetVersion()。通过PEB可以获取访问导入表(import table, IAT)、进程启动参数、程序名字等。
32位程序通过FS段寄存器,64位程序通过GS段寄存器可以获得TIB
TIB的内容
编辑字节/
类型 |
偏移
(32 比特, FS) |
偏移
(64 比特, GS) |
Windows 版本 | 描述 |
---|---|---|---|---|
pointer | FS:[0x00] | GS:[0x00] | Win9x and NT | 当前结构化异常 (SEH) 帧 |
pointer | FS:[0x04] | GS:[0x08] | Win9x and NT | 栈基 / 栈底部 (高地址) |
pointer | FS:[0x08] | GS:[0x10] | Win9x and NT | 栈上限 / 栈的天顶 (低地址) |
pointer | FS:[0x0C] | GS:[0x18] | NT | SubSystemTib |
pointer | FS:[0x10] | GS:[0x20] | NT | 纤程数据 |
pointer | FS:[0x14] | GS:[0x28] | Win9x and NT | 任意数据slot |
pointer | FS:[0x18] | GS:[0x30] | Win9x and NT | TEB的线性地址 |
---- 以上为独立于NT subsystem的部分 ---- | ||||
pointer | FS:[0x1C] | GS:[0x38] | NT | 环境指针 |
pointer | FS:[0x20] | GS:[0x40] | NT | 进程ID (某些Windows版本这里也用作 'DebugContext') |
4 | FS:[0x24] | GS:[0x48] | NT | 当前线程ID |
4 | FS:[0x28] | GS:[0x54] | NT | 活动的RPC句柄 |
4 | FS:[0x2C] | GS:[0x58] | Win9x and NT | 线程局部存储数组的线性地址 |
4 | FS:[0x30] | GS:[0x60] | NT | PEB的线性地址 |
4 | FS:[0x34] | GS:[0x68] | NT | 最后一个错误号 |
4 | FS:[0x38] | NT | 拥有的临界区数量 | |
4 | FS:[0x3C] | NT | CSR客户线程地址 | |
4 | FS:[0x40] | NT | Win32线程信息 | |
124 | FS:[0x44] | NT, Wine | Win32客户信息(NT), user32私有数据(Wine), 0x60 = LastError (Win95), 0x74 = LastError (WinME) | |
4 | FS:[0xC0] | NT | 保留给Wow64.到FastSysCall的指针 | |
4 | FS:[0xC4] | NT | 当前Locale | |
4 | FS:[0xC8] | NT | FP软件状态寄存器 | |
216 | FS:[0xCC] | NT, Wine | 保留给OS (NT), kernel32私有数据(Wine) 因此: FS:[0x124] 4 NT 到 KTHREAD (ETHREAD)结构的指针 | |
4 | FS:[0x1A4] | NT | 异常码 | |
18 | FS:[0x1A8] | NT | 活动上下文栈 | |
24 | FS:[0x1BC] | NT, Wine | 空闲字节(NT), ntdll私有数据(Wine) | |
40 | FS:[0x1D4] | NT, Wine | 保留给OS (NT), ntdll私有数据(Wine) | |
1248 | FS:[0x1FC] | NT, Wine | GDI TEB Batch (OS), vm86私有数据(Wine) | |
4 | FS:[0x6DC] | NT | GDI Region | |
4 | FS:[0x6E0] | NT | GDI Pen | |
4 | FS:[0x6E4] | NT | GDI Brush | |
4 | FS:[0x6E8] | NT | 真实进程ID | |
4 | FS:[0x6EC] | NT | 真实线程ID | |
4 | FS:[0x6F0] | NT | GDI缓存的进程句柄 | |
4 | FS:[0x6F4] | NT | GDI客户进程ID (PID) | |
4 | FS:[0x6F8] | NT | GDI客户线程ID (TID) | |
4 | FS:[0x6FC] | NT | GDI线程locale信息 | |
20 | FS:[0x700] | NT | 保留给用户应用程序 | |
1248 | FS:[0x714] | NT | 保留给GL | |
4 | FS:[0xBF4] | GS:[0x1250] | NT | 最后状态值 |
532 | FS:[0xBF8] | GS:[0x1258] | NT | 静态UNICODE_STRING缓冲区 |
pointer | FS:[0xE0C] | GS:[0x1478] | NT | 分配格栈的内存地址 |
pointer[] | FS:[0xE10] | GS:[0x1480] | NT | TLS槽, 4/8字节每槽,64个槽 |
8 | FS:[0xF10] | GS:[0x1680] | NT | TLS链接(LIST_ENTRY结构) |
4 | FS:[0xF18] | NT | VDM | |
4 | FS:[0xF1C] | NT | 保留给RPC | |
4 | FS:[0xF28] | NT | 线程错误模式(RtlSetThreadErrorMode) |
访问TIB
编辑// gcc (AT&T-style inline assembly).
void *getTIB() {
void *pTIB;
__asm__("movl %%fs:0x18, %0" : "=r" (pTIB) : : );
return pTIB;
}
// Microsoft C
__declspec(naked)
void *getTIB() {
__asm mov EAX, FS:[18h]
}
// Using Microsoft's intrinsics instead of inline assembly (works for both X86 and X64 architectures)
void *getTIB() {
#ifdef _M_IX86
return (void *)__readfsdword(0x18);
#elif _M_AMD64
return (void *)__readgsqword(0x30);
#endif
}
参见
编辑参考文献
编辑- ^ 1.0 1.1 Pietrek, Matt. Under The Hood. Microsoft Systems Journal. May 1996 [2010-07-07]. (原始内容存档于2016-03-03).
进一步阅读
编辑- Pietrek, Matt. Windows 95 Programming Secrets (PDF). IDG. March 1996: 136–138 [2010-07-17]. ISBN 978-1-56884-318-6. (原始内容 (pdf)存档于2011-05-14).