中东一哥,叶海亚将军最近刷屏了,再配上抖音那首《人间半途》的“把酒叹平生,把往事熬成药;一秋风雨敬苍天,从此无年少;我问月亮借华韶,再听秋风诉情长;一段芳华煮清欢,琐碎了平凡”,那容颜、那气质,文质彬彬却又杀气腾腾,温文尔雅又铮铮铁骨,敢跟美帝叫板的硬汉,连我此等俗人都赞叹仰慕不已,那歌词真是绝配了,循环了无数遍。
正 文
说起 PEB和TEB,那真是老生常谈了,光在我的公众号里就出现过若干次,有《windows下的反调试》《识别和分析 shellcode的一些方法》《Soloz的静态恶意代码免杀》《汇编:定位kernel32的基地址》《工具Pe2shc (Pe to Shellcode) 的源码级分析(下)》《对<由一道CTF对10种反调试的探究>一文的学习》《带你认识绕不开的ASLR》,没想到有这么多。
今天值班,再次有时间,将Peb和Teb详细地理了一遍,分享给大家。
一、简单介绍
在 Windows 操作系统中,进程和线程的管理涉及到一系列复杂的数据结构。两个关键的内部数据结构是 PEB(进程环境块,Process Environment Block)和 TEB(线程环境块,Thread Environment Block)。这些数据结构对于操作系统管理进程和线程的状态、资源和环境至关重要。本文将深入探讨 PEB 和 TEB 的定义、结构和用途。
1. 什么是 PEB?
PEB(Process Environment Block)是一个包含进程相关信息的数据结构。每个进程在创建时都会有一个对应的 PEB,它存储了该进程的全局状态和环境信息。
1.1 PEB 的作用
PEB 包含进程的许多重要信息,例如:
-
环境变量
-
映像基地址(Image Base Address)
-
进程启动参数
-
加载的模块列表
-
堆的管理信息
-
1.2 PEB 的结构
在 Windows 操作系统中,PEB 的结构在不同版本之间可能略有不同。以下是一个简化的 PEB 结构示例:
2. 什么是 TEB?
TEB(Thread Environment Block)是一个包含线程相关信息的数据结构。每个线程在创建时都会有一个对应的 TEB,它存储了该线程的局部状态和环境信息。
2.1 TEB 的作用
TEB 包含线程的许多重要信息,例如:
-
线程局部存储(TLS)
-
异常处理链
-
堆栈基址和栈顶地址
-
当前线程的环境变量指针
-
线程ID
-
2.2 TEB 的结构
TEB 的结构也在不同的 Windows 版本之间有所不同。以下是一个简化的 TEB 结构示例:
3. PEB 和 TEB 的关系
每个线程都通过其 TEB 关联到进程的 PEB,这样线程可以访问进程级的全局信息。TEB 包含一个指向其所属进程的 PEB 的指针,这使得线程可以方便地获取进程的环境信息。
引用《工具Pe2shc (Pe to Shellcode) 的源码级分析(下)》中图示:
4. 获取 PEB 和 TEB 的方法
在 Windows 上,可以使用多种方法来获取当前进程的 PEB 和当前线程的 TEB。例如,在 64 位系统上,可以通过以下代码获取 PEB 和 TEB:
获取 PEB:
获取 TEB:
这些函数使用了特定的 CPU 寄存器来读取 PEB 和 TEB 的基地址。
二、详细了解
以下部分,参考AperOdry一文;
TEB即为线程环境块, 进程中每一条线程都对应着的自己的“TEB”。
TEB的访问方法:
ntdll.NtCurrentTeb() 函数用来返回当前线程的TEB结构体指针
从图中我们可以看到NtCurrentTeb() 函数所返回的结构体指针即为 fs:[0x18] 的值,里面的值即为TEB的结构体指针,对比数据窗口即可发现
fs:[0]的值即为TEB的起始地址。
(一)TEB结构
1.+0x000 NtTib : _NT_TIB
TEB结构体的第一个成员NtTib即为我们常说的TIB,TIB(Thread Information Block,线程信息块);
-
ExceptionList:即为指向_EXCEPTION_REGISTRATION_RECORD结构体的链表指针(SEH)
-
StackBase:这里为线程堆栈顶部
-
StackLimit :这里为线程堆栈底部
-
Self:这为_NT_TIB结构体的自引用指针,即为NtCurrentTeb() 函数所读出的TEB结构体指针
2.+0x020 ClientId : _CLIENT_ID
(1)UniqueProcess:这个为当前进程的的Pid,可用函数 GetCurrentProcessId() 访问当前结构体成员获取进程标识符:
-
-
-
可以看到TEB+0x20即为 UniqueProcess 的成员变量。
(2)UniqueThread: 这个为当前进程的的Tid,可用函数 GetCurrentThreadId() 访问当前结构体成员获取线程标识符:
可以看到TEB+0x20即为 UniqueThread 的成员变量。
3.+0x030 ProcessEnvironmentBlock : Ptr32 _PEB
这个即为PEB结构体的指针,所以说一般 fs:[0x30] 即为PEB的起始地址。线程TEB结构体中,每个TEB+0x30(fs:[0x30])中都指向同一个地址(TEB.ProcessEnvironmentBlock)。我们可以用fs:[0x30]来访问PEB的结构体地址。
这里我们可以看到 [TEB.ProcessEnvironmentBlock] = = fs:[0x30],而EP中 EBX寄存器默认为PEB的结构体地址。
(二)PEB的数据结构:
(1)+0x002 BeingDebugged : UChar
这个结构体成员表示当前进程是否处于调试状态,也就是函数 IsDebuggerPresent() 所访问的结构体成员。
看到先是取出PEB的结构体地址,在取出PEB.BeingDebugged 结构体成员然后返回。
(2)+0x008 ImageBaseAddress : Ptr32 Void
这个结构体成员我们也经常用到,也就是自身的 ImageBase ,和PE结构中的 IMAGE_OPTIONAL_HEADER.ImageBase 。
可用函 GetModuleHandle (0) 获取自身模块句柄来访问这个结构体成员:
这里判断参数是否为0,也就是取自身的模块句柄 (ImaheBase)
这里也同上,先是取出PEB结构体地址,再取出 ImageBaseAddress 。
(3)+0x00c Ldr : Ptr32 _PEB_LDR_DATA
这个结构体成员就很复杂了,它是指向 _PEB_LDR_DATA 的结构体指针,当DLL加载到进程,可从 PEB.Ldr 中获取该模块的基址和其他信息:
InLoadOrderModuleList、InMemoryOrderModuleList、InInitializationOrderModuleList 这三个结构体成员都是指向LIST_ENTRY
的结构体指针,我们查询下这个数据结构:
可以看出这是一个双向链表,链表中存放着 _LDR_DATA_TABLE_ENTRY 的结构体信息:
每个进程中的DLL加载进来都有与之对于的 _LDR_DATA_TABLE_ENTRY 结构体,这些结构相互链接就形成了双向链表
(4)+0x018 ProcessHeap : Ptr32 Void
这个结构体成员就是进程堆的句柄,也就是指向结构体HEAP的指针,我们查询下结构体成员:
程序正常运行时,ProcessHeap.Flags的值为2 , ProcessHeap. ForceFlags 的值为0,也常用于反调试。
ProcessHeap结构体成员指向的HEAP结构体指针可用函数 GetProcessHeap()获取:
(5)+0x068 NtGlobalFlag : Uint4B
再调试状态时,PEB.NtGlobalFlag 的值为0x70 ,这个值我也不清楚 只记得几个Flages的值进行 OR(位或) 的结果。
三、一个实例
A simple PoC to locate hooked functions within ntdll.dll to further EDR evasion research.
源码地址:https://github.com/fin3ss3g0d/HookFinder
这段代码实现了一个简单的 Windows 下的钩子检测程序。它通过读取线程环境块(TEB)和进程环境块(PEB),检查 NTDLL.dll 中的导出函数表(EAT)来检测是否有函数被钩住(hooked)。
-
获取 TEB 和 PEB
RtlGetThreadEnvironmentBlock(): 通过内联汇编获取 TEB(线程环境块)的地址。对于 64 位系统,使用 __readgsqword(0x30)
,对于 32 位系统,使用 __readfsdword(0x16)
。
2. 获取图像导出目录
GetImageExportDirectory(): 通过解析 DOS 和 NT 头获取图像导出目录(EAT)的地址。
3. 主函数
-
wmain(): 获取当前线程的 TEB 和当前进程的 PEB,验证它们的有效性并检查操作系统的主版本号是否为 10。
-
从 PEB 中获取 NTDLL 模块的基地址,然后获取 NTDLL 的导出地址表(EAT),并调用
HookFinder()
来检测钩子。
4. 钩子检测
后记:今天是端午节,祝大家端午安康!!
端午节是一个充满文化和历史意义的节日,它在每年的农历五月初五庆祝,纪念古代爱国诗人屈原。通过丰富多彩的传统习俗和活动,不仅纪念了屈原的爱国精神,也表达了人们对健康和平安的美好愿望。无论是在中国还是在世界其他地方,端午节都成为了一个具有深厚文化内涵的节日。
主要习俗
-
赛龙舟
-
龙舟竞赛是端午节最重要的活动之一。龙舟是雕刻成龙形的长船,比赛时,参赛者们划着龙舟在江河湖泊中竞速。赛龙舟不仅是对屈原的纪念,也是一种传统体育活动,吸引了大量观众观看和参与。
-
吃粽子
-
粽子是端午节的传统食物,是用糯米包裹各种馅料(如红豆、红枣、咸蛋黄、猪肉等),用竹叶或苇叶包裹后蒸煮而成。人们通过吃粽子来纪念屈原。
-
挂艾草和菖蒲
-
在端午节期间,人们会在门前挂艾草和菖蒲,认为可以驱邪避害,保持健康。艾草和菖蒲有特殊的香味,据说可以驱赶蚊虫和邪气。
-
喝雄黄酒
-
雄黄酒是一种用雄黄(一种矿物)泡制的酒,古人认为雄黄酒可以驱毒避邪。在端午节,尤其是南方一些地区,人们会饮用雄黄酒或在孩子身上涂抹雄黄,以祈求健康平安。
-
佩戴香包
-
香包是一种用布做的小袋子,里面装有香草或药材,有驱虫和防病的作用。端午节期间,家长会给孩子佩戴香包,寓意驱邪保平安。
原文始发于微信公众号(MicroPest):深入理解 PEB 和 TEB:Windows 操作系统的内部数据结构
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论