Windows内核重要结构体

前言

Windows操作系统的内核代码使用C和汇编进行编写,内核中最重要的就是一些结构体和算法,了解了这些结构体后可以帮助我们对内核的代码进行分析。本文将介绍四个非常重要的结构体。
TRAP_FRAME结构体是由操作系统维护的一块数据,在内核层用来保存用户层现场的结构体(例如线程在用户层进行系统服务函数调用、中断、异常和在内核层执行APC调用时线程都要暂时将用户层的现场保存在TRAP_FRAME中),该结构体地址由每一个线程的KTHREAD.TrapFrame成员指定,Windbg中使用dt nt!_KTRAP_FRAME查看其结构。
EPROCESS结构体是Windows系统中的每一个进程在内核层描述进程信息的结构体, 这个结构体包含了进程所有的重要的信息。在Winbbg中 使用dt _EPROCESS查看EPROCESS结构体的信息。
ETHREAD结构体,每一个线程在内核层都有一个对应的结构体,该结构体保存了与线程相关的所有信息。在Windbg中 使用dt _ETHREAD查看ETHREAD结构体的信息。
KPCR结构体,描述了当前CPU的各种状态,包括当前CPU正在运行的线程的部分经常使用的信息,每一个CPU都有一个对应的结构体,Windbg中通过dd KeNumberProcessors 查看当前操作系统的CPU数量,通过dd KiProcessorBlock Lxxx查看xxx个KPCR结构体的地址。注意: dd KiProcessorBlock 显示的数据对应的是KPCR结尾的地址,应当减去KPCR结构体的大小。

他们的结构关系如下图所示:

注意:teb.NtTib指向的地址不等于KPCR.NtTib

Trap_Frame

使用Windbg查看TRAP_FRAME的结构:

使用图形来进行表述:

 

 

 值得注意的是:

  在保护模式下,并不使用最下方的紫色4个成员。

  在中断模式下如果发生提权,中断门会将用户层的5个寄存器压入对应的5个成员中(Eip,SegCs,EFlags、HardwareEsp和HardwareSegSs);如果未发生提权只会将用户层的3个成员压入对应的成员中(Eip,SegCs和EFlags)。

EPROCESS(进程内核对象)

EPROCESS结构体包含了KPROCESS结构体,使用Windbg查看EPROCESS的结构体如下

对EPROCESS结构体中的重要成员进行说明(使用偏移进行说明到底在KPROCESS中还是在EPROCESS中)

01) +0x000 Header : _DISPATCHER_HEADER //“可等待”对象,比如Mutex互斥体、Event事件等(WaitForSingleObject)
02) +0x018 DirectoryTableBase : [2] Uint4B //页目录表的基址
03) +0x020 LdtDescriptor : _KGDTENTRY
      +0x028 Int21Descriptor : _KIDTENTRY //历史遗留,16位Windows 段选择子不够 每个进程都有一个LDT表,Int21Descriptor 是 DOS下要用的
04) +0x038 KernelTime : Uint4B
      +0x03c UserTime : Uint4B //统计信息 记录了一个进程在内核模式/用户模式下所花的时间
05) +0x05c Affinity : Uint4B //规定进程里面的所有线程能在哪些个CPU上跑,第i位为1表示能在第i个核上运行。Xp是4个字节共32位,所以最多32核 Windows64位就64核。当设置运行的CPU不存在时进程无法运行。64位的操作系统将不适用。
06) +0x062 BasePriority : Char //基础优先级或最低优先级 该进程中的所有线程最起码的优先
07) +0x070 CreateTime : _LARGE_INTEGER
      +0x078 ExitTime : _LARGE_INTEGER//进程的创建/退出时间
08) +0x084 UniqueProcessId : Ptr32 Void //进程的编号(就是在任务管理器中的PID)
09) +0x088 ActiveProcessLinks : _LIST_ENTRY//双向链表,将所有的活动进程都连接在一起,构成了一个链表,进程结构体们彼此拴着各自的腰。而PsActiveProcessHead符号指向全局链表头。如下图所示表述了活动的进程

11) +0x090 QuotaUsage : [3] Uint4B //物理页相关的统计信息
12) +0x09c QuotaPeak : [3] Uint4B //物理页相关的统计峰值信息
13) +0x0a8 CommitCharge : Uint4B
      +0x0ac PeakVirtualSize : Uint4B
      +0x0b0 VirtualSize : Uint4B //虚拟内存相关的统计信息
14) +0x11c VadRoot          : Ptr32 Void //一颗平衡二叉树,标识0-2G哪些地址没占用了,记录了模块映射信息。
15) +0x0bc DebugPort : Ptr32 Void
      +0x0c0 ExceptionPort : Ptr32 Void //调试相关,如果被调试了DebugPort保存调试对象的地址
16) +0x0c4 ObjectTable : Ptr32 _HANDLE_TABLE//句柄表,记录了被当前进程打开的所有的句柄
17) +0x174 ImageFileName : [16] Uchar//进程镜像文件名 最多16个字节
18) +0x1a0 ActiveThreads : Uint4B//活动线程的数量
19) +0x1b0 Peb : Ptr32 _PEB//PEB((Process Environment Block 进程环境块):进程在3环的一个结构体,里面包含了进程的模块列表、是否处于调试状态等信息。

PEB(进程环境块)

PEB是处在用户层的一个数据结构,记录了进程的相关信息,该结构留在用户层主要是减少频繁的进入内核层查询数据,以提高系统的运行速度。PEB结构体成员如下图所示,部分重要成员已在图中进行说明。

 

ETHREAD(线程内核对象)

ETHREAD结构体包含了KTHREAD结构体,使用Windbg查看ETHREAD结构体如下:

对ETHREAD结构体中的重要成员进行说明(使用偏移进行说明到底在KTHREAD中还是在ETHREAD中)

01) +0x000 Header : _DISPATCHER_HEADER//“可等待”对象,比如Mutex互斥体、Event事件等(WaitForSingleObject)
02) +0x018 InitialStack : Ptr32 Void
      +0x01c StackLimit : Ptr32 Void
      +0x028 KernelStack : Ptr32 Void//与线程切换相关
03) +0x020 Teb : Ptr32 Void //TEB,Thread Environment Block,线程环境块。大小4KB,位于用户地址空间。线程在用户层FS:[0] = TEB,线程在内核层FS[0]=KPCR(线程在3环时FS[0]指向它的teb,在0环时FS[0]指向KPCR结构体)
04) +0x02c DebugActive : UChar//如果值为-1,将不能使用调试寄存器:Dr0 - Dr7
05) +0x034 ApcState : _KAPC_STATE
   +0x0e8 ApcQueueLock : Uint4B
      +0x138 ApcStatePointer : [2] Ptr32 _KAPC_STATE
      +0x14c SavedApcState : _KAPC_STATE//与APC相关
06) +0x02d State : UChar //线程状态:就绪、等待还是运行
07) +0x06c BasePriority : Char//其初始值是所属进程的BasePriority值(KPROCESS->BasePriority),以后可以通过KeSetBasePriorityThread()函数重新设定
08) +0x070 WaitBlock : [4] _KWAIT_BLOCK//记录了当前线程在进行同步时等待了哪些个对象(WaitForSingleObject)
09) +0x0e0 ServiceTable : Ptr32 Void //指向系统服务表基址(Windows vista后已弃用)
10) +0x134 TrapFrame//进0环时保存环境
11) +0x140 PreviousMode : Char//某些内核函数会判断程序是0环调用还是3环调用的
12) +0x1b0 ThreadListEntry : _LIST_ENTRY//双向链表 一个进程所有的线程 都挂在一个链表中挂的就是这个位置,一共有两个这样的链表
13) +0x1ec Cid : _CLIENT_ID //线程ID
14) +0x220 ThreadsProcess : Ptr32 _EPROCESS//指向自己所属进程的EPROCESS地址
15) +0x22c ThreadListEntry : _LIST_ENTRY//是一个双向链表,一个进程所有的线程都挂在这个链表中,挂的就是这个位置,一共有两个这样的链表。(如下图所示,进程的所有线程通过链表拴住各自的腰)

KPCR(CPU控制区)

简介:

1) 当线程从3环进入0环时,FS:[0]指向KPCR(3环时FS:[0] 指向TEB结构体)
2) 每个CPU都有一个KPCR结构体(一个核一个)
3) KPCR中存储了CPU本身要用的一些重要数据:GDT、IDT以及线程相关的一些信息。(只是为了快而使用KPCR),在Windbg中使用命令dt _kpcr查看KPCR结构体的成员,如下图所示

 

 KPCR内的重要成员已在下图中进行说明

 

 

 

 

 

posted @ 2019-03-24 16:55  J坚持C  阅读(2296)  评论(0编辑  收藏  举报