- 进程在内核中对应结构体:EPROCESS
- 线程在内核中对应结构体:ETHREAD
- CPU在内核中也有一个对应的结构体:KPCR(Processor Control Region)
KPCR结构我们已经很熟悉了,在API函数的调用过程中,多次使用到了KPCR,也简要介绍过一点。在保存现场之前有一个步骤就是将fs寄存器写入0x30,并根据GDT表,让fs寄存器指向KPCR。
KPCR介绍
- 当线程进入0环时,FS:[0]指向KPCR(3环时FS:[0] -> TEB)
- 每个CPU都有一个KPCR结构体(一个核一个)
- KPCR中存储了CPU本身要用的一些重要数据:GDT、IDT以及线程相关的一些信息。
- 在Windbg中执行指令:dt _KPCR 查看KPCR结构
- 结构图:
KPCR成员
+0x000 NtTib
+0x000 ExceptionList
- 成员名:ExceptionList
- 数据类型:Ptr32 _EXCEPTION_REGISTRATION_RECORD
- 说明:指向当前线程的异常链表(SEH),包含了当前线程的异常处理函数。Ring0(KPRC的ExceptionList)和Ring3(TEB的ExceptionList)的异常处理函数不同
+0x004 StackBase/+0x008 StackLimit
- 成员名:StackBase/StackLimit
- 数据类型:Ptr32 Void
- 说明:当前线程内核栈的基址和大小(KPCR中的是Ring0相关,TEB中就是Ring3相关)
+0x018 Self
- 成员名:Self
- 数据类型:Ptr32 _NT_TIB
- 说明:指向自己(也就是指向_NT_TIB结构)这样设计的目的是为了查找方便。Ring0->KPCR,Ring3->TEB
+0x01c SelfPcr
- 成员名:SelfPcr
- 数据类型:Ptr32 _KPCR
- 说明:指向自己,方便寻址
+0x020 Prcb
- 成员名:Prcb
- 数据类型:Ptr32 _KPRCB
- 说明:指向扩展结构体KPRCB
+0x038 IDT
- 成员名:IDT
- 数据类型:Ptr32 _KIDTENTRY
- 说明:指向IDT表首地址
+0x03c GDT
- 成员名:GDT
- 数据类型:Ptr32 _KGDTENTRY
- 说明:指向GDT表首地址
+0x040 TSS
- 成员名:TSS
- 数据类型:Ptr32 _KTSS
- 说明:指向TSS,每个CPU都有一个TSS
+0x051 Number
- 成员名:Number
- 数据类型:UChar
- 说明:CPU编号
+0x120 PrcbData
KPRCB结构体
KPRCB(Kernel Processor Control Block)是KPCR的扩展结构体
+0x004 CurrentThread
成员名:CurrentThread
数据类型:Ptr32 _KTHREAD
说明:指向当前线程的KTHREAD
+0x008 NextThread
成员名:CurrentThread
数据类型:Ptr32 _KTHREAD
说明:指向下一个要执行线程的KTHREAD
+0x00c IdleThread
成员名:IdleThread
数据类型:Ptr32 _KTHREAD
说明:指向空闲线程的KTHREAD
+0x88c QuantumEnd
成员名:QuantumEnd
数据类型:Uint4B
说明:CPU时间片标志
关系梳理
在简单了解完进程结构体(EPROCESS)、线程结构体(ETHREAD)、CPU结构体(KPCR)以后,来梳理一下它们之间的关系。
已知进程
遍历进程:PsActiveProcessHead -> ActiveProcessLinks(EPROCESS+0x88)……
遍历线程:PsActiveProcessHead -> ActiveProcessLinks(EPROCESS+0x88) -> ThreadListHead(KPROCESS+0x50 / EPROCESS+0x190) -> ThreadListEntry(KTHREAD+0x1b0 / ETHREAD+0x22c)……
已知线程
遍历进程:ETHREAD+0x220 -> EPROCESS -> ActiveProcessLinks(EPROCESS+0x88)……
遍历线程:ETHREAD+0x22c / ETHREAD+0x1b0 -> ThreadListEntry……
已知KPCR
遍历进程:进入0环后 -> fs:[0] -> KPCR -> PrcbData(KPCR+0x120) -> CurrentThread(KPRCB+0x4) -> EPROCESS(ETHREAD+0x220) -> ActiveProcessLinks(EPROCESS+0x88)……
遍历线程:进入0环后 -> fs:[0] -> KPCR -> PrcbData(KPCR+0x120) -> CurrentThread(KPRCB+0x4) -> ETHREAD+0x22c / ETHREAD+0x1b0 -> ThreadListEntry……
参考教程:https://www.bilibili.com/video/BV1NJ411M7aE?p=45
参考文档:张嘉杰笔记