1. 初衷

其他笔记中,涉及到结构体的时候,都只是记录了其中一部分(完整记录会显得篇幅过长),这就导致查阅起来比较麻烦,这里做一个完整的结构体文档,以便查阅。

2. 内核

2.1. _KTRAP_FRAME

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
kd> dt _kTrap_Frame
nt!_KTRAP_FRAME
+0x000 DbgEbp : Uint4B ; 调试等其他作用
+0x004 DbgEip : Uint4B ;
+0x008 DbgArgMark : Uint4B ;
+0x00c DbgArgPointer : Uint4B ;
+0x010 TempSegCs : Uint4B ;
+0x014 TempEsp : Uint4B ;
+0x018 Dr0 : Uint4B ;
+0x01c Dr1 : Uint4B ;
+0x020 Dr2 : Uint4B ;
+0x024 Dr3 : Uint4B ;
+0x028 Dr6 : Uint4B ;
+0x02c Dr7 : Uint4B ;
+0x030 SegGs : Uint4B ;
+0x034 SegEs : Uint4B ;
+0x038 SegDs : Uint4B ;
+0x03c Edx : Uint4B ;
+0x040 Ecx : Uint4B ;
+0x044 Eax : Uint4B ;
+0x048 PreviousPreviousMode : Uint4B ; Windows中的非易失性寄存器需要在中断例程中先保存
+0x04c ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD ;
+0x050 SegFs : Uint4B ;
+0x054 Edi : Uint4B ;
+0x058 Esi : Uint4B ;
+0x05c Ebx : Uint4B ;
+0x060 Ebp : Uint4B ;
+0x064 ErrCode : Uint4B ;
+0x068 Eip : Uint4B ; 中断门时保存代码段和地址,iret返回时用
+0x06c SegCs : Uint4B ;
+0x070 EFlags : Uint4B ;
+0x074 HardwareEsp : Uint4B ; 中断门时若发生权限切换,保存旧堆栈
+0x078 HardwareSegSs : Uint4B ;
+0x07c V86Es : Uint4B ; 虚拟8086模式下保存段寄存器,保护模式下不使用
+0x080 V86Ds : Uint4B ;
+0x084 V86Fs : Uint4B ;
+0x088 V86Gs : Uint4B ;

2.2. _CONTEXT

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
kd> dt _CONTEXT
nt!_CONTEXT
+0x000 ContextFlags : Uint4B
+0x004 Dr0 : Uint4B
+0x008 Dr1 : Uint4B
+0x00c Dr2 : Uint4B
+0x010 Dr3 : Uint4B
+0x014 Dr6 : Uint4B
+0x018 Dr7 : Uint4B
+0x01c FloatSave : _FLOATING_SAVE_AREA
+0x08c SegGs : Uint4B
+0x090 SegFs : Uint4B
+0x094 SegEs : Uint4B
+0x098 SegDs : Uint4B
+0x09c Edi : Uint4B
+0x0a0 Esi : Uint4B
+0x0a4 Ebx : Uint4B
+0x0a8 Edx : Uint4B
+0x0ac Ecx : Uint4B
+0x0b0 Eax : Uint4B
+0x0b4 Ebp : Uint4B
+0x0b8 Eip : Uint4B
+0x0bc SegCs : Uint4B
+0x0c0 EFlags : Uint4B
+0x0c4 Esp : Uint4B
+0x0c8 SegSs : Uint4B
+0x0cc ExtendedRegisters : [512] UChar

2.3. _KPCR

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
kd> dt _kpcr
nt!_KPCR
+0x000 NtTib : _NT_TIB
+0x01c SelfPcr : Ptr32 _KPCR ;指向自身(_KPCR)
+0x020 Prcb : Ptr32 _KPRCB ;指针,指向_KPCR的PrcbData成员,方便日后修改拓展_KPCR结构体
+0x024 Irql : UChar
+0x028 IRR : Uint4B
+0x02c IrrActive : Uint4B
+0x030 IDR : Uint4B
+0x034 KdVersionBlock : Ptr32 Void
+0x038 IDT : Ptr32 _KIDTENTRY ;IDT表基址,每个CPU都有自己独立的IDT表
+0x03c GDT : Ptr32 _KGDTENTRY ;GDT表基址,每个CPU都有自己独立的GDT表
+0x040 TSS : Ptr32 _KTSS ;TSS任务段基址,每个CPU都有自己独立的TSS任务段
+0x044 MajorVersion : Uint2B
+0x046 MinorVersion : Uint2B
+0x048 SetMember : Uint4B
+0x04c StallScaleFactor : Uint4B
+0x050 DebugActive : UChar
+0x051 Number : UChar ;当前CPU编号
+0x052 Spare0 : UChar
+0x053 SecondLevelCacheAssociativity : UChar
+0x054 VdmAlert : Uint4B
+0x058 KernelReserved : [14] Uint4B
+0x090 SecondLevelCacheSize : Uint4B
+0x094 HalReserved : [16] Uint4B
+0x0d4 InterruptMode : Uint4B
+0x0d8 Spare1 : UChar
+0x0dc KernelReserved2 : [17] Uint4B
+0x120 PrcbData : _KPRCB ;_KPCR的拓展结构体

2.3.1. _NT_TIB

1
2
3
4
5
6
7
8
9
10
kd> dt _NT_TIB
nt!_NT_TIB
+0x000 ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD ;当前线程内核异常链表(SEH)
+0x004 StackBase : Ptr32 Void ;当前线程内核栈基址
+0x008 StackLimit : Ptr32 Void ;当前线程内核栈大小
+0x00c SubSystemTib : Ptr32 Void
+0x010 FiberData : Ptr32 Void
+0x010 Version : Uint4B
+0x014 ArbitraryUserPointer : Ptr32 Void
+0x018 Self : Ptr32 _NT_TIB ;指向自身(_NT_TIB和_KPCR)

2.3.2. _KPRCB

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
kd> dt _KPRCB
nt!_KPRCB
+0x000 MinorVersion : Uint2B
+0x002 MajorVersion : Uint2B
+0x004 CurrentThread : Ptr32 _KTHREAD ;CPU当前正在运行的线程
+0x008 NextThread : Ptr32 _KTHREAD ;CPU下一个调度的线程
+0x00c IdleThread : Ptr32 _KTHREAD ;空闲线程,如果没有其它线程可以调度时,CPU需要调度的线程
+0x010 Number : Char ;CPU编号
+0x011 Reserved : Char
+0x012 BuildType : Uint2B
+0x014 SetMember : Uint4B
+0x018 CpuType : Char
+0x019 CpuID : Char
+0x01a CpuStep : Uint2B ;CPU子版本号
+0x01c ProcessorState : _KPROCESSOR_STATE ;CPU状态
+0x33c KernelReserved : [16] Uint4B
+0x37c HalReserved : [16] Uint4B
+0x3bc PrcbPad0 : [92] UChar
+0x418 LockQueue : [16] _KSPIN_LOCK_QUEUE
+0x498 PrcbPad1 : [8] UChar
+0x4a0 NpxThread : Ptr32 _KTHREAD ;NPX浮点寄存器,最后一次用过NPX浮点寄存器的线程
+0x4a4 InterruptCount : Uint4B ;中断次数
+0x4a8 KernelTime : Uint4B ;统计信息
+0x4ac UserTime : Uint4B ;统计信息
+0x4b0 DpcTime : Uint4B
+0x4b4 DebugDpcTime : Uint4B
+0x4b8 InterruptTime : Uint4B
+0x4bc AdjustDpcThreshold : Uint4B
+0x4c0 PageColor : Uint4B
+0x4c4 SkipTick : Uint4B
+0x4c8 MultiThreadSetBusy : UChar
+0x4c9 Spare2 : [3] UChar
+0x4cc ParentNode : Ptr32 _KNODE
+0x4d0 MultiThreadProcessorSet : Uint4B
+0x4d4 MultiThreadSetMaster : Ptr32 _KPRCB
+0x4d8 ThreadStartCount : [2] Uint4B
+0x4e0 CcFastReadNoWait : Uint4B
+0x4e4 CcFastReadWait : Uint4B
+0x4e8 CcFastReadNotPossible : Uint4B
+0x4ec CcCopyReadNoWait : Uint4B
+0x4f0 CcCopyReadWait : Uint4B
+0x4f4 CcCopyReadNoWaitMiss : Uint4B
+0x4f8 KeAlignmentFixupCount : Uint4B
+0x4fc KeContextSwitches : Uint4B
+0x500 KeDcacheFlushCount : Uint4B
+0x504 KeExceptionDispatchCount : Uint4B
+0x508 KeFirstLevelTbFills : Uint4B
+0x50c KeFloatingEmulationCount : Uint4B
+0x510 KeIcacheFlushCount : Uint4B
+0x514 KeSecondLevelTbFills : Uint4B
+0x518 KeSystemCalls : Uint4B
+0x51c SpareCounter0 : [1] Uint4B
+0x520 PPLookasideList : [16] _PP_LOOKASIDE_LIST
+0x5a0 PPNPagedLookasideList : [32] _PP_LOOKASIDE_LIST
+0x6a0 PPPagedLookasideList : [32] _PP_LOOKASIDE_LIST
+0x7a0 PacketBarrier : Uint4B
+0x7a4 ReverseStall : Uint4B
+0x7a8 IpiFrame : Ptr32 Void
+0x7ac PrcbPad2 : [52] UChar
+0x7e0 CurrentPacket : [3] Ptr32 Void
+0x7ec TargetSet : Uint4B
+0x7f0 WorkerRoutine : Ptr32 void
+0x7f4 IpiFrozen : Uint4B
+0x7f8 PrcbPad3 : [40] UChar
+0x820 RequestSummary : Uint4B
+0x824 SignalDone : Ptr32 _KPRCB
+0x828 PrcbPad4 : [56] UChar
+0x860 DpcListHead : _LIST_ENTRY
+0x868 DpcStack : Ptr32 Void
+0x86c DpcCount : Uint4B
+0x870 DpcQueueDepth : Uint4B
+0x874 DpcRoutineActive : Uint4B
+0x878 DpcInterruptRequested : Uint4B
+0x87c DpcLastCount : Uint4B
+0x880 DpcRequestRate : Uint4B
+0x884 MaximumDpcQueueDepth : Uint4B
+0x888 MinimumDpcRate : Uint4B
+0x88c QuantumEnd : Uint4B ;标志当前线程的CPU时间片是否用完,没用完的时候是0,用完的时候是非0值
+0x890 PrcbPad5 : [16] UChar
+0x8a0 DpcLock : Uint4B
+0x8a4 PrcbPad6 : [28] UChar
+0x8c0 CallDpc : _KDPC
+0x8e0 ChainedInterruptList : Ptr32 Void
+0x8e4 LookasideIrpFloat : Int4B
+0x8e8 SpareFields0 : [6] Uint4B
+0x900 VendorString : [13] UChar
+0x90d InitialApicId : UChar
+0x90e LogicalProcessorsPerPhysicalProcessor : UChar
+0x910 MHz : Uint4B ;频率
+0x914 FeatureBits : Uint4B
+0x918 UpdateSignature : _LARGE_INTEGER
+0x920 NpxSaveArea : _FX_SAVE_AREA
+0xb30 PowerState : _PROCESSOR_POWER_STATE

2.4. _ETHREAD

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
kd> dt _ETHREAD
nt!_ETHREAD
+0x000 Tcb : _KTHREAD ;指向内核层的KTHREAD对象
+0x1c0 CreateTime : _LARGE_INTEGER ;线程的创建时间
+0x1c0 NestedFaultCount : Pos 0, 2 Bits
+0x1c0 ApcNeeded : Pos 2, 1 Bit
+0x1c8 ExitTime : _LARGE_INTEGER ;线程的退出时间,在ExitThread中赋值
+0x1c8 LpcReplyChain : _LIST_ENTRY ;用于跨进程通信(LPC)
+0x1c8 KeyedWaitChain : _LIST_ENTRY ;用于带键事件的等待链表
+0x1d0 ExitStatus : Int4B ;线程的退出状态,当线程主动退出或被动退出时这个域会由框架代码填充
+0x1d0 OfsChain : Ptr32 Void
+0x1d4 PostBlockList : _LIST_ENTRY ;双向链表,链表中的各个节点类型为PCM_POST_BLOCK,它被用于一个线程向"配置管理器"登记注册表键的变化通知
+0x1dc TerminationPort : Ptr32 _TERMINATION_PORT ;链表头,当一个线程退出时,系统会通知所有已经登记过要接收其终止事件的那些"端口"
+0x1dc ReaperLink : Ptr32 _ETHREAD ;单链表节点,仅在线程退出时使用。当线程被终止时,该节点将被挂到PsReaperListHead链表上(用以告知内核当前线程将要退出了,请收到相关的线程资源),所以,在线程回收器(reaper)的工作项目(WorkItem)中该线程的内核栈得以收回
+0x1dc KeyedWaitValue : Ptr32 Void
+0x1e0 ActiveTimerListLock : Uint4B ;双向链表头,包含了当前线程的所有定时器
+0x1e4 ActiveTimerListHead : _LIST_ENTRY ;操作这个链表(包含当前线程的所有定时器的双链表)的自旋锁。使用自旋锁可以把原本可能发生的并行事件导致的问题通过强制串行化得到解决。比如对线程中的定时器这个互斥资源就典型的需要串行化,否则将导致定时器的错乱等很多问题
+0x1ec Cid : _CLIENT_ID ;进程ID和线程ID
+0x1f4 LpcReplySemaphore : _KSEMAPHORE ;用于LPC应答通知
+0x1f4 KeyedWaitSemaphore : _KSEMAPHORE ;用于处理带键的事件
+0x208 LpcReplyMessage : Ptr32 Void ;LPC应答的消息
+0x208 LpcWaitingOnPort : Ptr32 Void ;说明了线程在哪个"端口对象"上等待消息
+0x20c ImpersonationInfo : Ptr32 _PS_IMPERSONATION_INFORMATION ;线程的模仿信息,windows允许一个线程在执行过程中模仿其他的用户来执行一段功能,这样可以实现更为灵活的访问控制安全特性
+0x210 IrpList : _LIST_ENTRY ;双向链表头,其中包含了当前线程所有正在处理但尚未完成的I/O请求(Irp对象)
+0x218 TopLevelIrp : Uint4B ;指向线程的顶级IRP
+0x21c DeviceToVerify : Ptr32 _DEVICE_OBJECT;指向的是一个"待检验"的设备,当磁盘或CD-ROM设备的驱动程序"发现"自从上一次该线程访问该设备以来,该设备有了"变化",就会设置线程的DeviceToVerify域,从而使最高层的驱动程序(比如文件系统),可以检测到设备变化
+0x220 ThreadsProcess : Ptr32 _EPROCESS ;当前进程结构体的指针,可以定位进程
+0x224 StartAddress : Ptr32 Void ;线程的启动地址,通常是系统DLL中的线程启动地址,(例如kernel32.dll中的BaseProcessStart或BaseThreadStart函数)
+0x228 Win32StartAddress : Ptr32 Void ;线程的启动地址,windows子系统接收到的线程启动地址,即CreateThread API函数接收到的线程启动地址
+0x228 LpcReceivedMessageId : Uint4B ;包含了接收到的LPC消息的ID
+0x22c ThreadListEntry : _LIST_ENTRY ;连接一个进程所有线程的双向链表,总共存在两个这样的链表
+0x234 RundownProtect : _EX_RUNDOWN_REF
+0x238 ThreadLock : _EX_PUSH_LOCK ;推锁,用户保护线程的数据属性
+0x23c LpcReplyMessageId : Uint4B ;指明了当前线程正在等待对一个LPC消息的应答
+0x240 ReadClusterSize : Uint4B ;指明了在一次I/O操作中读取多少个页面,用于页面交换文件和内存映射文件的读操作
+0x244 GrantedAccess : Uint4B ;线程的访问权限
+0x248 CrossThreadFlags : Uint4B ;针对跨线程访问的标志位
+0x248 Terminated : Pos 0, 1 Bit ;线程已终止操作
+0x248 DeadThread : Pos 1, 1 Bit ;线程创建失败
+0x248 HideFromDebugger : Pos 2, 1 Bit ;该线程对于调试器不可见
+0x248 ActiveImpersonationInfo : Pos 3, 1 Bit ;线程正在模仿
+0x248 SystemThread : Pos 4, 1 Bit ;是一个系统线程
+0x248 HardErrorsAreDisabled : Pos 5, 1 Bit ;对于该线程,硬件错误无效
+0x248 BreakOnTermination : Pos 6, 1 Bit ;调试器在线程终止时停下该线程
+0x248 SkipCreationMsg : Pos 7, 1 Bit ;不向调试器发送创建消息
+0x248 SkipTerminationMsg : Pos 8, 1 Bit ;不向调试器发送终止消息
+0x24c SameThreadPassiveFlags : Uint4B ;一些只有在最低中断级别(被动级别)上只能被该线程自身访问的标志位,访问时无需互锁操作
+0x24c ActiveExWorker : Pos 0, 1 Bit
+0x24c ExWorkerCanWaitUser : Pos 1, 1 Bit
+0x24c MemoryMaker : Pos 2, 1 Bit
+0x250 SameThreadApcFlags : Uint4B ;一些在APC中断级别(也是很低的级别)上被该线程自身访问的标志位,访问时无需互锁操作
+0x250 LpcReceivedMsgIdValid : Pos 0, 1 Bit
+0x250 LpcExitThreadCalled : Pos 1, 1 Bit
+0x250 AddressSpaceOwner : Pos 2, 1 Bit
+0x254 ForwardClusterOnly : UChar ;指示是否仅仅前向聚集,页面错误处理相关
+0x255 DisablePageFaultClustering : UChar ;用于控制页面交换的聚集与否。页面错误处理相关

2.4.1. _KTHREAD

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
kd> dt _kthread
nt!_KTHREAD
+0x000 Header : _DISPATCHER_HEADER ;标识_KTHREAD即线程为可等待对象
+0x010 MutantListHead : _LIST_ENTRY ;线程拥有的互斥体双向链表
+0x018 InitialStack : Ptr32 Void ;线程切换相关
+0x01c StackLimit : Ptr32 Void ;线程切换相关
+0x020 Teb : Ptr32 Void ;Thread Environment Block,线程环境块,大小4KB,线程在3环的一个结构体(3环进程可以对其进行读写),里面包含了线程的重要信息,在三环时fs:[0] -> teb,在0环时fs:[0] -> _kpcr
+0x024 TlsArray : Ptr32 Void
+0x028 KernelStack : Ptr32 Void ;线程切换时存储栈顶指针
+0x02c DebugActive : UChar ;调试相关,该值为-1的话不能使用调试寄存器Dr0-Dr7,3环进入0环时不会填充_kTrap_Frame中调试相关成员的值
+0x02d State : UChar ;线程状态:就绪、等待、运行,仅仅用作记录,和线程的调度无关,1-就绪,2-运行,5-等待
+0x02e Alerted : [2] UChar
+0x030 Iopl : UChar
+0x031 NpxState : UChar
+0x032 Saturation : Char
+0x033 Priority : Char
+0x034 ApcState : _KAPC_STATE ;APC队列
+0x04c ContextSwitches : Uint4B
+0x050 IdleSwapBlock : UChar
+0x051 Spare0 : [3] UChar
+0x054 WaitStatus : Int4B
+0x058 WaitIrql : UChar
+0x059 WaitMode : Char
+0x05a WaitNext : UChar
+0x05b WaitReason : UChar
+0x05c WaitBlockList : Ptr32 _KWAIT_BLOCK ;等待块列表,同步机制中线程等待与唤醒相关
+0x060 WaitListEntry : _LIST_ENTRY ;线程所属等待链表,线程调度相关
+0x060 SwapListEntry : _SINGLE_LIST_ENTRY ;线程所属调度链表,线程调度相关,和线程所属等待链表占据同一个位置,也就是说线程只能同时属于其中一个链表
+0x068 WaitTime : Uint4B
+0x06c BasePriority : Char ;基础优先级,从所属进程继承而来(KPROCESS->BasePriority),但是可以通过KeSetBasePriorityThread函数重新设置
+0x06d DecrementCount : UChar
+0x06e PriorityDecrement : Char
+0x06f Quantum : Char ;调度相关,CPU时间片
+0x070 WaitBlock : [4] _KWAIT_BLOCK ;指示线程等待的是哪个对象
+0x0d0 LegoData : Ptr32 Void
+0x0d4 KernelApcDisable : Uint4B ;判断当前线程是否禁用内核APC,非0代表禁用,0代表不禁用
+0x0d8 UserAffinity : Uint4B
+0x0dc SystemAffinityActive : UChar
+0x0dd PowerState : UChar
+0x0de NpxIrql : UChar
+0x0df InitialNode : UChar
+0x0e0 ServiceTable : Ptr32 Void ;系统服务表基址
+0x0e4 Queue : Ptr32 _KQUEUE
+0x0e8 ApcQueueLock : Uint4B ;APC相关
+0x0f0 Timer : _KTIMER
+0x118 QueueListEntry : _LIST_ENTRY
+0x120 SoftAffinity : Uint4B
+0x124 Affinity : Uint4B
+0x128 Preempted : UChar
+0x129 ProcessReadyQueue : UChar
+0x12a KernelStackResident : UChar
+0x12b NextProcessor : UChar
+0x12c CallbackStack : Ptr32 Void
+0x130 Win32Thread : Ptr32 Void ;对于非GUI程序,该值为NULL,对于GUI程序,该值指向THREADINFO结构体(含有成员消息队列MessageQueue)
+0x134 TrapFrame : Ptr32 _KTRAP_FRAME ;用于进0环时保存环境
+0x138 ApcStatePointer : [2] Ptr32 _KAPC_STATE ;正常情况下,ApcStatePointer[0]指向ApcState,ApcStatePointer[1]指向SavedApcState,线程挂靠情况下,指针指向相反
+0x140 PreviousMode : Char ;先前模式,用于某些内核函数判断程序是0环调用的还是3环调用的
+0x141 EnableStackSwap : UChar
+0x142 LargeStack : UChar
+0x143 ResourceIndex : UChar
+0x144 KernelTime : Uint4B
+0x148 UserTime : Uint4B
+0x14c SavedApcState : _KAPC_STATE ;备用APC队列
+0x164 Alertable : UChar ;标识当前线程在等待时是否可以被APC唤醒,0代表不可以,1代表可以;SleepEx和WaitForSingleObjectEx函数可以通过最后一个参数显示指定该值(该参数为True代表可以被唤醒,False代表不可以)
+0x165 ApcStateIndex : UChar ;标识当前线程处于什么状态,0表示正常状态,1表示挂靠状态
+0x166 ApcQueueable : UChar ;表示是否可以向线程的APC队列中插入APC,当线程正在执行退出的代码时,会将这个值设置为0,如果此时执行插入APC的代码(KeInsertQueueApc),在插入函数中会判断这个值是否为0,如果是则插入失败
+0x167 AutoAlignment : UChar
+0x168 StackBase : Ptr32 Void
+0x16c SuspendApc : _KAPC
+0x19c SuspendSemaphore : _KSEMAPHORE
+0x1b0 ThreadListEntry : _LIST_ENTRY ;连接一个进程所有线程的双向链表,总共存在两个这样的链表
+0x1b8 FreezeCount : Char
+0x1b9 SuspendCount : Char
+0x1ba IdealProcessor : UChar
+0x1bb DisableBoost : UChar

2.4.1.1. _DISPATCHER_HEADER

1
2
3
4
5
6
7
8
9
x86asm
kd> dt _DISPATCHER_HEADER
nt!_DISPATCHER_HEADER
+0x000 Type : UChar ;可等待对象类型,0-事件,1-事件,2-互斥体,5-信号量
+0x001 Absolute : UChar ;三个统计信息
+0x002 Size : UChar
+0x003 Inserted : UChar
+0x004 SignalState : Int4B ;是否有信号
+0x008 WaitListHead : _LIST_ENTRY ;链表头,指向等待块列表,这是一个双向循环链表,链接了所有等待该可等待对象的线程的等待块

2.4.1.2. _KAPC_STATE

1
2
3
4
5
6
7
kd> dt _KAPC_STATE
nt!_KAPC_STATE
+0x000 ApcListHead : [2] _LIST_ENTRY ;APC队列,两个双向链表,里面存储了线程需要执行的APC函数。第一个是内核APC链表(函数为内核空间函数),第二个是用户APC链表(函数为用户空间函数)
+0x010 Process : Ptr32 _KPROCESS ;指向为线程提供CR3的进程
+0x014 KernelApcInProgress : UChar ;指示内核APC函数是否正在执行,1代表正在执行
+0x015 KernelApcPending : UChar ;是否存在内核APC函数,存在则置1,不存在置0
+0x016 UserApcPending : UChar ;是否存在用户APC函数,存在则置1,不存在置0

2.4.1.3. _KAPC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
kd> dt _KAPC
nt!_KAPC
+0x000 Type : Int2B ;Windows内核对象(进程、线程、事件等)类型,APC为0x12
+0x002 Size : Int2B ;本结构体大小,0x30
+0x004 Spare0 : Uint4B ;无意义,用于内存对齐
+0x008 Thread : Ptr32 _KTHREAD ;目标线程
+0x00c ApcListEntry : _LIST_ENTRY ;APC队列所挂位置
+0x014 KernelRoutine : Ptr32 void ;指向一个函数,APC函数执行完毕之后Windows会调用这个函数,该函数需调用ExFreePoolWithTag来销毁KAPC结构体
+0x018 RundownRoutine : Ptr32 void ;未使用
+0x01c NormalRoutine : Ptr32 void ;用户APC:用户APC总入口;内核APC:函数地址
+0x020 NormalContext : Ptr32 Void ;内核APC:NULL;用户APC:函数地址
+0x024 SystemArgument1 : Ptr32 Void ;APC参数1
+0x028 SystemArgument2 : Ptr32 Void ;APC参数2
+0x02c ApcStateIndex : Char ;标识希望APC挂在哪个队列
+0x02d ApcMode : Char ;0代表内核APC,1代表用户APC
+0x02e Inserted : UChar ;标识当前APC是否已经插入队列,是为1,否为0

2.4.1.4. _KWAIT_BLOCK

1
2
3
4
5
6
7
8
kd> dt _KWAIT_BLOCK
nt!_KWAIT_BLOCK
+0x000 WaitListEntry : _LIST_ENTRY ;连接一个被等待对象的所有等待块的双向链表
+0x008 Thread : Ptr32 _KTHREAD ;等待块对应线程
+0x00c Object : Ptr32 Void ;被等待对象的地址
+0x010 NextWaitBlock : Ptr32 _KWAIT_BLOCK ;连接一个线程的所有等待块的单向循环链表中的下一跳指针
+0x014 WaitKey : Uint2B ;线程的等待块的索引
+0x016 WaitType : Uint2B ;等待类型,0代表需要所有被等待对象都符合条件才能激活,1代表只需要一个被等待对象符合条件就可以激活

2.4.2. _CM_POST_BLOCK

1
2
3
4
5
6
7
8
9
10
11
12
typedef struct _CM_POST_BLOCK
{
#if DBG
BOOLEAN TraceIntoDebugger;
#endif
LIST_ENTRY NotifyList;
LIST_ENTRY ThreadList;
LIST_ENTRY CancelPostList; //slave notifications that are attached to this notification
struct _CM_POST_KEY_BODY *PostKeyBody;
ULONG NotifyType;
PCM_POST_BLOCK_UNION u;
} CM_POST_BLOCK, *PCM_POST_BLOCK;

2.4.3. _CLIENT_ID

1
2
3
4
5
typedef struct _CLIENT_ID
{
PVOID UniqueProcess; //等于所属进程的UniqueProcessId
PVOID UniqueThread; //等于此线程对象在进程句柄表中的句柄
} CLIENT_ID, *PCLIENT_ID;

2.5. _EPROCESS

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
101
102
103
104
105
106
107
108
109
kd> dt _EPROCESS
nt!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x06c ProcessLock : _EX_PUSH_LOCK ;控制结构体只允许一个人改
+0x070 CreateTime : _LARGE_INTEGER ;进程的创建时间
+0x078 ExitTime : _LARGE_INTEGER ;进程的退出时间
+0x080 RundownProtect : _EX_RUNDOWN_REF ;线程的停止保护锁,对于跨线程引用TEB结构或者挂起线程的执行等操作,需要获得此锁才能运行,以避免在操作过程中线程被销毁
+0x084 UniqueProcessId : Ptr32 Void ;进程ID
+0x088 ActiveProcessLinks : _LIST_ENTRY ;连接所有活动进程的双向链表,全局变量PsActiveProcessHead指向链表头。利用PsActiveProcessHead加上该成员可以遍历所有进程,通过断链可以使得可以从WindowsAPI中隐藏进程,但是进程仍然可以正常运行(Windows的调度单元是线程,进程仅仅提供了一个运行环境如资源和物理页基址)
+0x090 QuotaUsage : [3] Uint4B ;物理页相关统计信息
+0x09c QuotaPeak : [3] Uint4B ;物理页相关统计信息
+0x0a8 CommitCharge : Uint4B ;物理页相关
+0x0ac PeakVirtualSize : Uint4B ;虚拟内存峰值(虚拟内存就是用磁盘充当内存)
+0x0b0 VirtualSize : Uint4B ;虚拟内存大小
+0x0b4 SessionProcessLinks : _LIST_ENTRY
+0x0bc DebugPort : Ptr32 Void ;调试端口(INT 01和INT 03,消息发到调试端口,这两种异常调试器一般要单独处理),该值为0的情况下无法通过正常手段来调试进程(可以通过其它手段)
+0x0c0 ExceptionPort : Ptr32 Void ;异常端口(其它异常,消息先发到调试器,然后发到异常端口),调试相关
+0x0c4 ObjectTable : Ptr32 _HANDLE_TABLE ;对象句柄表,存有进程使用的各种其它内核的对象(事件、互斥体、文件等)的句柄
+0x0c8 Token : _EX_FAST_REF
+0x0cc WorkingSetLock : _FAST_MUTEX
+0x0ec WorkingSetPage : Uint4B
+0x0f0 AddressCreationLock : _FAST_MUTEX
+0x110 HyperSpaceLock : Uint4B
+0x114 ForkInProgress : Ptr32 _ETHREAD
+0x118 HardwareTrigger : Uint4B
+0x11c VadRoot : Ptr32 Void ;标识用户地址空间0-2G使用情况(虚拟地址描述符)
+0x120 VadHint : Ptr32 Void
+0x124 CloneRoot : Ptr32 Void
+0x128 NumberOfPrivatePages : Uint4B
+0x12c NumberOfLockedPages : Uint4B
+0x130 Win32Process : Ptr32 Void
+0x134 Job : Ptr32 _EJOB
+0x138 SectionObject : Ptr32 Void
+0x13c SectionBaseAddress : Ptr32 Void
+0x140 QuotaBlock : Ptr32 _EPROCESS_QUOTA_BLOCK
+0x144 WorkingSetWatch : Ptr32 _PAGEFAULT_HISTORY
+0x148 Win32WindowStation : Ptr32 Void
+0x14c InheritedFromUniqueProcessId : Ptr32 Void
+0x150 LdtInformation : Ptr32 Void
+0x154 VadFreeHint : Ptr32 Void
+0x158 VdmObjects : Ptr32 Void
+0x15c DeviceMap : Ptr32 Void
+0x160 PhysicalVadList : _LIST_ENTRY
+0x168 PageDirectoryPte : _HARDWARE_PTE
+0x168 Filler : Uint8B
+0x170 Session : Ptr32 Void
+0x174 ImageFileName : [16] UChar ;进程镜像文件名,最多显示16个字节,多余字节将被截断
+0x184 JobLinks : _LIST_ENTRY
+0x18c LockedPagesList : Ptr32 Void
+0x190 ThreadListHead : _LIST_ENTRY ;连接该进程所有线程的双向链表(总共存在两个这样的链表)的头,示意图见2.1节
+0x198 SecurityPort : Ptr32 Void
+0x19c PaeTop : Ptr32 Void
+0x1a0 ActiveThreads : Uint4B ;活动线程的数量,0代表无活动线程,进程即将结束,将会从活动进程链表中被移除
+0x1a4 GrantedAccess : Uint4B
+0x1a8 DefaultHardErrorProcessing : Uint4B
+0x1ac LastThreadExitStatus : Int4B ;进程中的每个线程退出时,除了对ETHREAD的ExitStatus赋值以外,还会给当前线程所属的进程的该域进行赋值
+0x1b0 Peb : Ptr32 _PEB ;Process Environment Block,进程环境块,进程在3环的一个结构体(3环进程可以对其进行读写),里面包含了进程的模块列表、是否处于调试状态等重要信息
+0x1b4 PrefetchTrace : _EX_FAST_REF
+0x1b8 ReadOperationCount : _LARGE_INTEGER
+0x1c0 WriteOperationCount : _LARGE_INTEGER
+0x1c8 OtherOperationCount : _LARGE_INTEGER
+0x1d0 ReadTransferCount : _LARGE_INTEGER
+0x1d8 WriteTransferCount : _LARGE_INTEGER
+0x1e0 OtherTransferCount : _LARGE_INTEGER
+0x1e8 CommitChargeLimit : Uint4B
+0x1ec CommitChargePeak : Uint4B
+0x1f0 AweInfo : Ptr32 Void
+0x1f4 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
+0x1f8 Vm : _MMSUPPORT ;进程已经使用的物理页相关内容
+0x238 LastFaultCount : Uint4B
+0x23c ModifiedPageCount : Uint4B
+0x240 NumberOfVads : Uint4B
+0x244 JobStatus : Uint4B
+0x248 Flags : Uint4B
+0x248 CreateReported : Pos 0, 1 Bit
+0x248 NoDebugInherit : Pos 1, 1 Bit
+0x248 ProcessExiting : Pos 2, 1 Bit
+0x248 ProcessDelete : Pos 3, 1 Bit
+0x248 Wow64SplitPages : Pos 4, 1 Bit
+0x248 VmDeleted : Pos 5, 1 Bit
+0x248 OutswapEnabled : Pos 6, 1 Bit
+0x248 Outswapped : Pos 7, 1 Bit
+0x248 ForkFailed : Pos 8, 1 Bit
+0x248 HasPhysicalVad : Pos 9, 1 Bit
+0x248 AddressSpaceInitialized : Pos 10, 2 Bits
+0x248 SetTimerResolution : Pos 12, 1 Bit
+0x248 BreakOnTermination : Pos 13, 1 Bit
+0x248 SessionCreationUnderway : Pos 14, 1 Bit
+0x248 WriteWatch : Pos 15, 1 Bit
+0x248 ProcessInSession : Pos 16, 1 Bit
+0x248 OverrideAddressSpace : Pos 17, 1 Bit
+0x248 HasAddressSpace : Pos 18, 1 Bit
+0x248 LaunchPrefetched : Pos 19, 1 Bit
+0x248 InjectInpageErrors : Pos 20, 1 Bit
+0x248 VmTopDown : Pos 21, 1 Bit
+0x248 Unused3 : Pos 22, 1 Bit
+0x248 Unused4 : Pos 23, 1 Bit
+0x248 VdmAllowed : Pos 24, 1 Bit
+0x248 Unused : Pos 25, 5 Bits
+0x248 Unused1 : Pos 30, 1 Bit
+0x248 Unused2 : Pos 31, 1 Bit
+0x24c ExitStatus : Int4B
+0x250 NextPageColor : Uint2B
+0x252 SubSystemMinorVersion : UChar
+0x253 SubSystemMajorVersion : UChar
+0x252 SubSystemVersion : Uint2B
+0x254 PriorityClass : UChar
+0x255 WorkingSetAcquiredUnsafe : UChar
+0x258 Cookie : Uint4B

2.5.1. _KPROCESS

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
kd> dt _KPROCESS
nt!_KPROCESS
+0x000 Header : _DISPATCHER_HEADER ;标识_KPROCESS即进程为可等待对象(即可被WaitForSingleObject等函数等待的对象,如Mutex互斥体、Event事件等),所有可等待对象的第一个成员均为_DISPATCHER_HEADER结构体
+0x010 ProfileListHead : _LIST_ENTRY
+0x018 DirectoryTableBase : [2] Uint4B ;页目录表的基址
+0x020 LdtDescriptor : _KGDTENTRY ;历史遗留问题,16位Windows段选择子不够,所以每个进程都有一个LDT表;32位Windows下该成员无意义
+0x028 Int21Descriptor : _KIDTENTRY ;DOS下使用
+0x030 IopmOffset : Uint2B
+0x032 Iopl : UChar
+0x033 Unused : UChar
+0x034 ActiveProcessors : Uint4B
+0x038 KernelTime : Uint4B ;统计信息,统计进程在内核模式下所花的时间
+0x03c UserTime : Uint4B ;统计信息,统计进程在用户模式下所花的时间
+0x040 ReadyListHead : _LIST_ENTRY
+0x048 SwapListEntry : _SINGLE_LIST_ENTRY
+0x04c VdmTrapcHandler : Ptr32 Void
+0x050 ThreadListHead : _LIST_ENTRY ;连接该进程所有线程的双向链表(总共存在两个这样的链表)的头
+0x058 ProcessLock : Uint4B
+0x05c Affinity : Uint4B ;规定进程里面的所有线程能够在哪个CPU上运行,比特位为1的下标号对应的CPU可以运行,比如4(100)代表可以在2号CPU上运行,如果此时只有一个或者两个CPU,该进程将会结束。所以32位最多32核,64位最多64核
+0x060 StackCount : Uint2B
+0x062 BasePriority : Char ;基础优先级,该进程中所有线程最起码的优先级(即所有线程的优先级均会大于等于此优先级)
+0x063 ThreadQuantum : Char ;调度相关,线程CPU时间片基础值
+0x064 AutoAlignment : UChar
+0x065 State : UChar
+0x066 ThreadSeed : UChar
+0x067 DisableBoost : UChar
+0x068 PowerState : UChar
+0x069 DisableQuantum : UChar
+0x06a IdealNode : UChar
+0x06b Flags : _KEXECUTE_OPTIONS
+0x06b ExecuteOptions : UChar

2.5.2. _HANDLE_TABLE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
nt!_HANDLE_TABLE
+0x000 TableCode : Uint4B ;句柄表地址
+0x004 QuotaProcess : Ptr32 _EPROCESS
+0x008 UniqueProcessId : Ptr32 Void
+0x00c HandleTableLock : [4] _EX_PUSH_LOCK
+0x01c HandleTableList : _LIST_ENTRY
+0x024 HandleContentionEvent : _EX_PUSH_LOCK
+0x028 DebugInfo : Ptr32 _HANDLE_TRACE_DEBUG_INFO
+0x02c ExtraInfoPages : Int4B
+0x030 FirstFree : Uint4B
+0x034 LastFree : Uint4B
+0x038 NextHandleNeedingPool : Uint4B
+0x03c HandleCount : Int4B
+0x040 Flags : Uint4B
+0x040 StrictFIFO : Pos 0, 1 Bit

2.5.3. _MMVAD

1
2
3
4
5
6
7
8
9
10
11
12
kd> dt _MMVAD
nt!_MMVAD
+0x000 StartingVpn : Uint4B ;起始线性地址
+0x004 EndingVpn : Uint4B ;结束线性地址
+0x008 Parent : Ptr32 _MMVAD ;父节点
+0x00c LeftChild : Ptr32 _MMVAD ;左子节点
+0x010 RightChild : Ptr32 _MMVAD ;右子节点
+0x014 u : __unnamed ;类型为_MMVAD_FLAGS,指示了内存块的一些属性
+0x018 ControlArea : Ptr32 _CONTROL_AREA ;内存块类别
+0x01c FirstPrototypePte : Ptr32 _MMPTE
+0x020 LastContiguousPte : Ptr32 _MMPTE
+0x024 u2 : __unnamed

2.5.3.1. _CONTROL_AREA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
kd> dt _CONTROL_AREA
nt!_CONTROL_AREA
+0x000 Segment : Ptr32 _SEGMENT
+0x004 DereferenceList : _LIST_ENTRY
+0x00c NumberOfSectionReferences : Uint4B
+0x010 NumberOfPfnReferences : Uint4B
+0x014 NumberOfMappedViews : Uint4B
+0x018 NumberOfSubsections : Uint2B
+0x01a FlushInProgressCount : Uint2B
+0x01c NumberOfUserReferences : Uint4B
+0x020 u : __unnamed
+0x024 FilePointer : Ptr32 _FILE_OBJECT ;私有内存-NULL;映射内存的文件映射-文件路径;映射内存的共享内存-NULL
+0x028 WaitingForDeletion : Ptr32 _EVENT_COUNTER
+0x02c ModifiedWriteCount : Uint2B
+0x02e NumberOfSystemCacheViews : Uint2B

2.5.3.2. _MMVAD_FLAGS

1
2
3
4
5
6
7
8
9
10
11
12
13
kd> dt _MMVAD_FLAGS
nt!_MMVAD_FLAGS
+0x000 CommitCharge : Pos 0, 19 Bits
+0x000 PhysicalMapping : Pos 19, 1 Bit
+0x000 ImageMap : Pos 20, 1 Bit ;如果内存是映射内存,指示映射文件是否为可执行文件,1代表是,0代表不是
+0x000 UserPhysicalPages : Pos 21, 1 Bit
+0x000 NoChange : Pos 22, 1 Bit
+0x000 WriteWatch : Pos 23, 1 Bit
+0x000 Protection : Pos 24, 5 Bits ;内存的权限:1-READONLY,2-EXECUTE,3-EXECUTE_READ,4-READWRITE
;5-WRITECOPY,6-EXECUTE_READWRITE,7-EXECUTE_WRITECOPY
+0x000 LargePages : Pos 29, 1 Bit
+0x000 MemCommit : Pos 30, 1 Bit
+0x000 PrivateMemory : Pos 31, 1 Bit ;指示了内存块的类型,1代表私有内存,0代表映射内存

2.6. 可等待对象

2.6.1. _KSEMAPHORE

1
2
3
nt!_KSEMAPHORE
+0x000 Header : _DISPATCHER_HEADER
+0x010 Limit : Int4B

2.6.2. _KMUTANT

1
2
3
4
5
6
7
kd> dt _KMUTANT
nt!_KMUTANT
+0x000 Header : _DISPATCHER_HEADER
+0x010 MutantListEntry : _LIST_ENTRY ;是个链表头,圈着所有互斥体
+0x018 OwnerThread : Ptr32 _KTHREAD ;正在拥有互斥体的线程
+0x01c Abandoned : UChar ;是否已经被放弃不用
+0x01d ApcDisable : UChar ;是否禁用内核APC

2.7. 异常相关

2.7.1. _EXCEPTION_RECORD

1
2
3
4
5
6
7
8
typedef struct _EXCEPTION_RECORD {
DWORD ExceptionCode; //异常代码
DWORD ExceptionFlags; //异常状态,CPU异常值为0,软件模拟异常值为1,嵌套异常值为0x10
struct _EXCEPTION_RECORD *ExceptionRecord; //下一个异常,通常为空,出现嵌套异常时,会用到这个成员
PVOID ExceptionAddress; //异常发生地址
DWORD NumberParameters; //附加参数个数,用以进一步描述异常的信息,很少用到
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; //附加参数指针,用以进一步描述异常的信息,很少用到
} EXCEPTION_RECORD;

2.7.2. _EXCEPTION_REGISTRATION_RECORD

1
2
3
4
5
typedef struct _EXCEPTION_REGISTRATION_RECORD
{
PEXCEPTION_REGISTRATION_RECORD Next; //异常链表下一个异常结构体指针
PEXCEPTION_DISPOSITION Handler; //异常处理函数句柄
} EXCEPTION_REGISTRATION_RECORD, *PEXCEPTION_REGISTRATION_RECORD;

2.7.3. VC_EXCEPTION_REGISTRATION

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct VC_EXCEPTION_REGISTRATION
{
VC_EXCEPTION_REGISTRATION* prev; //前一个结构体的指针
FARPROC handler; //永远指向_exception_handler3回调函数
scopetable_entry* scopetable; //作用域表,scopetable指向了一个scopetable_entry结构体数组,函数中每个try{}都会在其中占据一个位置
int _index; //scopetable_entry结构体数组的索引,trylevel
//该值会在函数执行期间被改变(每当代码进入新的try{}结构时该值会变化),
//该值指示当前执行代码所位于的try{}结构在scopetable中的索引,
//如果当前执行代码不位于任何try{}结构中,_index会被设置为-1。
DWORD _ebp; //函数起始时压入的ebp,上一个函数体的栈基址
//对于使用FPO优化的函数,编译器通常不生成标准的堆栈帧
//如果函数使用了SEH,那么无论是否使用FPO优化,编译器一定生成标准的堆栈帧(第一条指令PUSH EBP)
//函数刚进入,压入EBP,移动esp之后,便压入了该异常结构,所以ebp的负偏移可以用于寻址
}

2.7.3.1. scopetable_entry

1
2
3
4
5
6
struct scopetable_entry
{
DWORD prev_entryindex; //该try{}结构的上层try{}结构在scopetable中的索引,如果没有上层try{}结构,则该值为-1
FARPROC lpfnFilter; //过滤函数地址,except的小括号代码块地址,finally时为NULL
FARPROC lpfnHandler; //异常处理程序地址,except或finally代码块地址
}

2.7.4. _VECTORED_EXCEPTION_NODE

VEH结点。

1
2
3
4
5
6
struct _VECTORED_EXCEPTION_NODE
{
DWORD m_pNextNode;
DWORD m_pPreviousNode;
PVOID m_pfnVectoredHandler;
}

2.8. _MMPFN

物理页相关。该结构体包含大量union,意义复杂。不同的操作系统版本该结构体的大小不同,有的是0x18,有的是0x1C。

1
2
3
4
5
6
7
8
kd> dt _MMPFN
nt!_MMPFN
+0x000 u1 : __unnamed
+0x004 PteAddress : Ptr32 _MMPTE
+0x008 u2 : __unnamed
+0x00c u3 : __unnamed
+0x010 OriginalPte : _MMPTE
+0x018 u4 : __unnamed

2.9. TEB

TEB(Thread Environment Block,线程环境块),其中存放着进程中所有线程的各种信息。ntdll.NtCurrentTeb函数,fs:[0x18],fs:[0x0]均可定位TEB。

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 ;TIB(Thread Information Block,线程信息块)
+0x01c EnvironmentPointer : Ptr32 Void
+0x020 ClientId : _CLIENT_ID ;存储了PID和TID
+0x028 ActiveRpcHandle : Ptr32 Void
+0x02c ThreadLocalStoragePointer : Ptr32 Void
+0x030 ProcessEnvironmentBlock : Ptr32 _PEB ;指向PEB,EP中EBX寄存器默认为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

2.9.1. _NT_TIB

1
2
3
4
5
6
7
8
9
10
kd> dt _NT_TIB
nt!_NT_TIB
+0x000 ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD ;当前线程异常链表(SEH)
+0x004 StackBase : Ptr32 Void ;当前线程栈基址
+0x008 StackLimit : Ptr32 Void ;当前线程栈大小
+0x00c SubSystemTib : Ptr32 Void
+0x010 FiberData : Ptr32 Void
+0x010 Version : Uint4B
+0x014 ArbitraryUserPointer : Ptr32 Void
+0x018 Self : Ptr32 _NT_TIB ;指向自身(_NT_TIB和_TEB)

2.9.2. _CLIENT_ID

1
2
3
4
kd> dt _CLIENT_ID
nt!_CLIENT_ID
+0x000 UniqueProcess : Ptr32 Void ;当前进程的的PID,函数GetCurrentProcessId访问的结构体成员
+0x004 UniqueThread : Ptr32 Void ;当前线程的的TID,函数GetCurrentThreadId访问的结构体成员

2.9.3. PEB

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
nt!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged : UChar ;表示当前进程是否处于调试状态,函数IsDebuggerPresent访问的结构体成员
+0x003 SpareBool : UChar
+0x004 Mutant : Ptr32 Void
+0x008 ImageBaseAddress : Ptr32 Void ;自身映像基址,函数GetModuleHandle(0)获取自身模块句柄所访问的结构体成员
+0x00c Ldr : Ptr32 _PEB_LDR_DATA ;结构体指针,可以获取进程加载的所有模块的基址和其他信息
+0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
+0x014 SubSystemData : Ptr32 Void
+0x018 ProcessHeap : Ptr32 Void ;指向进程堆的相关结构体_HEAP的指针,函数GetProcessHeap访问的结构体成员
+0x01c FastPebLock : Ptr32 _RTL_CRITICAL_SECTION
+0x020 FastPebLockRoutine : Ptr32 Void
+0x024 FastPebUnlockRoutine : Ptr32 Void
+0x028 EnvironmentUpdateCount : Uint4B
+0x02c KernelCallbackTable : Ptr32 Void
+0x030 SystemReserved : [1] Uint4B
+0x034 AtlThunkSListPtr32 : Uint4B
+0x038 FreeList : Ptr32 _PEB_FREE_BLOCK
+0x03c TlsExpansionCounter : Uint4B
+0x040 TlsBitmap : Ptr32 Void
+0x044 TlsBitmapBits : [2] Uint4B
+0x04c ReadOnlySharedMemoryBase : Ptr32 Void
+0x050 ReadOnlySharedMemoryHeap : Ptr32 Void
+0x054 ReadOnlyStaticServerData : Ptr32 Ptr32 Void
+0x058 AnsiCodePageData : Ptr32 Void
+0x05c OemCodePageData : Ptr32 Void
+0x060 UnicodeCaseTableData : Ptr32 Void
+0x064 NumberOfProcessors : Uint4B
+0x068 NtGlobalFlag : Uint4B ;在调试状态时,值为0x70
+0x070 CriticalSectionTimeout : _LARGE_INTEGER
+0x078 HeapSegmentReserve : Uint4B
+0x07c HeapSegmentCommit : Uint4B
+0x080 HeapDeCommitTotalFreeThreshold : Uint4B
+0x084 HeapDeCommitFreeBlockThreshold : Uint4B
+0x088 NumberOfHeaps : Uint4B
+0x08c MaximumNumberOfHeaps : Uint4B
+0x090 ProcessHeaps : Ptr32 Ptr32 Void
+0x094 GdiSharedHandleTable : Ptr32 Void
+0x098 ProcessStarterHelper : Ptr32 Void
+0x09c GdiDCAttributeList : Uint4B
+0x0a0 LoaderLock : Ptr32 Void
+0x0a4 OSMajorVersion : Uint4B
+0x0a8 OSMinorVersion : Uint4B
+0x0ac OSBuildNumber : Uint2B
+0x0ae OSCSDVersion : Uint2B
+0x0b0 OSPlatformId : Uint4B
+0x0b4 ImageSubsystem : Uint4B
+0x0b8 ImageSubsystemMajorVersion : Uint4B
+0x0bc ImageSubsystemMinorVersion : Uint4B
+0x0c0 ImageProcessAffinityMask : Uint4B
+0x0c4 GdiHandleBuffer : [34] Uint4B
+0x14c PostProcessInitRoutine : Ptr32 void
+0x150 TlsExpansionBitmap : Ptr32 Void
+0x154 TlsExpansionBitmapBits : [32] Uint4B
+0x1d4 SessionId : Uint4B
+0x1d8 AppCompatFlags : _ULARGE_INTEGER
+0x1e0 AppCompatFlagsUser : _ULARGE_INTEGER
+0x1e8 pShimData : Ptr32 Void
+0x1ec AppCompatInfo : Ptr32 Void
+0x1f0 CSDVersion : _UNICODE_STRING
+0x1f8 ActivationContextData : Ptr32 Void
+0x1fc ProcessAssemblyStorageMap : Ptr32 Void
+0x200 SystemDefaultActivationContextData : Ptr32 Void
+0x204 SystemAssemblyStorageMap : Ptr32 Void
+0x208 MinimumStackCommit : Uint4B

2.9.3.1. _PEB_LDR_DATA

1
2
3
4
5
6
7
8
9
10
ntdll!_PEB_LDR_DATA
+0x000 Length ;结构体大小
+0x004 Initialized ;进程是否初始化完成
+0x008 SsHandle
+0x00c InLoadOrderModuleList : _LIST_ENTRY ;双向链表,链接了进程中加载的所有DLL对应的_LDR_DATA_TABLE_ENTRY结构体
+0x014 InMemoryOrderModuleList : _LIST_ENTRY ;双向链表,链接了进程中加载的所有DLL对应的_LDR_DATA_TABLE_ENTRY结构体
+0x01c InInitializationOrderModuleList : _LIST_ENTRY ;双向链表,链接了进程中加载的所有DLL对应的_LDR_DATA_TABLE_ENTRY结构体
+0x024 EntryInProgress
+0x028 ShutdownInProgress
+0x02c ShutdownThreadId
2.9.3.1.1. _LDR_DATA_TABLE_ENTRY

进程中每个加载的DLL都有一个对应的_LDR_DATA_TABLE_ENTRY结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
kd> dt _LDR_DATA_TABLE_ENTRY
nt!_LDR_DATA_TABLE_ENTRY
+0x000 InLoadOrderLinks : _LIST_ENTRY
+0x008 InMemoryOrderLinks : _LIST_ENTRY
+0x010 InInitializationOrderLinks : _LIST_ENTRY
+0x018 DllBase : Ptr32 Void
+0x01c EntryPoint : Ptr32 Void
+0x020 SizeOfImage : Uint4B
+0x024 FullDllName : _UNICODE_STRING
+0x02c BaseDllName : _UNICODE_STRING
+0x034 Flags : Uint4B
+0x038 LoadCount : Uint2B
+0x03a TlsIndex : Uint2B
+0x03c HashLinks : _LIST_ENTRY
+0x03c SectionPointer : Ptr32 Void
+0x040 CheckSum : Uint4B
+0x044 TimeDateStamp : Uint4B
+0x044 LoadedImports : Ptr32 Void
+0x048 EntryPointActivationContext : Ptr32 Void
+0x04c PatchInformation : Ptr32 Void
2.9.3.1.2. _UNICODE_STRING
1
2
3
4
5
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

2.9.3.2. _HEAP

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
kd> dt _HEAP
nt!_HEAP
+0x000 Entry : _HEAP_ENTRY
+0x008 Signature : Uint4B
+0x00c Flags : Uint4B ;程序正常运行(非调试)时,值为2
+0x010 ForceFlags : Uint4B ;程序正常运行(非调试)时,值为0
+0x014 VirtualMemoryThreshold : Uint4B
+0x018 SegmentReserve : Uint4B
+0x01c SegmentCommit : Uint4B
+0x020 DeCommitFreeBlockThreshold : Uint4B
+0x024 DeCommitTotalFreeThreshold : Uint4B
+0x028 TotalFreeSize : Uint4B
+0x02c MaximumAllocationSize : Uint4B
+0x030 ProcessHeapsListIndex : Uint2B
+0x032 HeaderValidateLength : Uint2B
+0x034 HeaderValidateCopy : Ptr32 Void
+0x038 NextAvailableTagIndex : Uint2B
+0x03a MaximumTagIndex : Uint2B
+0x03c TagEntries : Ptr32 _HEAP_TAG_ENTRY
+0x040 UCRSegments : Ptr32 _HEAP_UCR_SEGMENT
+0x044 UnusedUnCommittedRanges : Ptr32 _HEAP_UNCOMMMTTED_RANGE
+0x048 AlignRound : Uint4B
+0x04c AlignMask : Uint4B
+0x050 VirtualAllocdBlocks : _LIST_ENTRY
+0x058 Segments : [64] Ptr32 _HEAP_SEGMENT
+0x158 u : __unnamed
+0x168 u2 : __unnamed
+0x16a AllocatorBackTraceIndex : Uint2B
+0x16c NonDedicatedListLength : Uint4B
+0x170 LargeBlocksIndex : Ptr32 Void
+0x174 PseudoTagEntries : Ptr32 _HEAP_PSEUDO_TAG_ENTRY
+0x178 FreeLists : [128] _LIST_ENTRY
+0x578 LockVariable : Ptr32 _HEAP_LOCK
+0x57c CommitRoutine : Ptr32 long
+0x580 FrontEndHeap : Ptr32 Void
+0x584 FrontHeapLockCount : Uint2B
+0x586 FrontEndHeapType : UChar
+0x587 LastSegmentIndex : UChar

3. PE文件格式

3.1. DOS头

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
IMAGE_DOS_HEADER STRUCT 
+00h WORD e_magic // Magic DOS signature MZ(4Dh 5Ah) DOS可执行文件标记,恒定为4D 5A(MZ),IMAGE_DOS_SIGNATURE
+02h WORD e_cblp // Bytes on last page of file
+04h WORD e_cp // Pages in file
+06h WORD e_crlc // Relocations
+08h WORD e_cparhdr // Size of header in paragraphs
+0ah WORD e_minalloc // Minimun extra paragraphs needs
+0ch WORD e_maxalloc // Maximun extra paragraphs needs
+0eh WORD e_ss // intial(relative)SS value DOS代码的初始化堆栈SS
+10h WORD e_sp // intial SP value DOS代码的初始化堆栈指针SP
+12h WORD e_csum // Checksum
+14h WORD e_ip // intial IP value DOS代码的初始化指令入口[指针IP]
+16h WORD e_cs // intial(relative)CS value DOS代码的初始堆栈入口 CS
+18h WORD e_lfarlc // File Address of relocation table
+1ah WORD e_ovno // Overlay number
+1ch WORD e_res[4] // Reserved words
+24h WORD e_oemid // OEM identifier(for e_oeminfo)
+26h WORD e_oeminfo // OEM information;e_oemid specific
+29h WORD e_res2[10] // Reserved words
+3ch LONG e_lfanew // Offset to start of PE header 指向PE文件头
IMAGE_DOS_HEADER ENDS

3.2. PE头

1
2
3
4
5
IMAGE_NT_HEADERS STRUCT 
+00h DWORD Signature // PE文件标识,恒定为50 45 00 00(PE)
+04h IMAGE_FILE_HEADER FileHeader // 标准PE头
+18h IMAGE_OPTIONAL_HEADER32 OptionalHeader // 拓展PE头
IMAGE_NT_HEADERS ENDS

3.2.1. IMAGE_FILE_HEADER

1
2
3
4
5
6
7
8
9
IMAGE_FILE_HEADER STRUCT
+04h WORD Machine; // 运行平台
+06h WORD NumberOfSections; // 文件的区块数目,区块表紧跟在IMAGE_NT_HEADERS后边
+08h DWORD TimeDateStamp; // 文件创建日期和时间,采用1970/01/01以来的格林威治时间(GMT)计算的秒数
+0Ch DWORD PointerToSymbolTable; // COFF符号表(用于调试)的文件偏移位置,现在基本没用了
+10h DWORD NumberOfSymbols; // COFF符号表中的符号数目,COFF符号是一个大小固定的结构,如果想找到COFF 符号表的结束位置,则需要这个变量
+14h WORD SizeOfOptionalHeader; // IMAGE_OPTIONAL_HEADER32结构大小,对于32位PE文件,这个值通常是00E0h;对于64位PE32+文件,这个值是00F0h
+16h WORD Characteristics; // 文件属性
IMAGE_FILE_HEADER ENDS

3.2.1.1. Machine

1
2
3
4
0x0000                            // 任意平台
0x014C IMAGE_FILE_MACHINE_I386 // x86
0x0200 IMAGE_FILE_MACHINE_IA64 // Intel Itanium
0x8664 IMAGE_FILE_MACHINE_AMD64 // x64

更多定义参见Windows.inc文件。

3.2.1.2. Characteristics

与运算获取。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
0x0001 IMAGE_FILE_RELOCS_STRIPPED     // 禁止重定位,必须从指定基地址加载,若地址被占用,则报错
0x0002 IMAGE_FILE_EXECUTABLE_IMAGE // 文件可执行
0x0004 IMAGE_FILE_LINE_NUMS_STRIPPED // 不存在行信息
0x0008 IMAGE_FILE_LOCAL_SYMS_STRIPPED // 不存在符号信息
0x0010 IMAGE_FILE_AGGRESIVE_WS_TRIM // 调整工作集
0x0020 IMAGE_FILE_LARGE_ADDRESS_AWARE // 应用程序可以处理大于2GB的地址
0x0080 IMAGE_FILE_BYTES_REVERSED_LO // 小尾方式
0x0100 IMAGE_FILE_32BIT_MACHINE // 只在32位平台运行
0x0200 IMAGE_FILE_DEBUG_STRIPPED // 不包含调试信息
0x0400 IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP // 不能从可移动盘运行
0x0800 IMAGE_FILE_NET_RUN_FROM_SWAP // 不能从网络运行
0x1000 IMAGE_FILE_SYSTEM // 系统文件
0x2000 IMAGE_FILE_DLL // DLL文件
0x4000 IMAGE_FILE_UP_SYSTEM_ONLY // 不能在多处理器计算机上运行
0x8000 IMAGE_FILE_BYTES_REVERSED_HI // 大尾方式

3.2.2. IMAGE_OPTIONAL_HEADER32

以下偏移以IMAGE_NT_HEADERS为基准。

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
IMAGE_OPTIONAL_HEADER32 STRUCT
+18h WORD Magic; // 标志字, ROM 映像(0107h),PE32(010Bh),PE32+(020Bh)
+1Ah BYTE MajorLinkerVersion; // 链接程序的主版本号
+1Bh BYTE MinorLinkerVersion; // 链接程序的次版本号
+1Ch DWORD SizeOfCode; // 所有含代码的节的总大小 文件对齐后大小 编译器填写 无用
+20h DWORD SizeOfInitializedData; // 所有含已初始化数据的节的总大小 文件对齐后大小 编译器填写 无用
+24h DWORD SizeOfUninitializedData; // 所有含未初始化数据的节的大小 文件对齐后大小 编译器填写 无用
+28h DWORD AddressOfEntryPoint; // 程序执行入口RVA
+2Ch DWORD BaseOfCode; // 代码的区块的起始RVA 编译器填写 无用
+30h DWORD BaseOfData; // 数据的区块的起始RVA 编译器填写 无用
+34h DWORD ImageBase; // 程序的首选装载地址
+38h DWORD SectionAlignment; // 内存中的区块的对齐大小
+3Ch DWORD FileAlignment; // 文件中的区块的对齐大小
+40h WORD MajorOperatingSystemVersion; // 要求操作系统最低版本号的主版本号
+42h WORD MinorOperatingSystemVersion; // 要求操作系统最低版本号的副版本号
+44h WORD MajorImageVersion; // 可运行于操作系统的主版本号
+46h WORD MinorImageVersion; // 可运行于操作系统的次版本号
+48h WORD MajorSubsystemVersion; // 要求最低子系统版本的主版本号
+4Ah WORD MinorSubsystemVersion; // 要求最低子系统版本的次版本号
+4Ch DWORD Win32VersionValue; // 一般为0
+50h DWORD SizeOfImage; // 映像装入内存后的总尺寸,可以比实际值大,必须内存对齐
+54h DWORD SizeOfHeaders; // 所有头 + 区块表的尺寸大小,必须文件对齐
+58h DWORD CheckSum; // 映像的校检和
+5Ch WORD Subsystem; // 可执行文件期望的子系统,驱动(1),图形界面(2),控制台、DLL(3)
+5Eh WORD DllCharacteristics; // DllMain()函数何时被调用,默认为 0
+60h DWORD SizeOfStackReserve; // 初始化时的栈大小
+64h DWORD SizeOfStackCommit; // 初始化时实际提交的栈大小
+68h DWORD SizeOfHeapReserve; // 初始化时保留的堆大小
+6Ch DWORD SizeOfHeapCommit; // 初始化时实际提交的堆大小
+70h DWORD LoaderFlags; // 与调试有关,默认为0
+74h DWORD NumberOfRvaAndSizes; // 下边数据目录的项数,这个字段自Windows NT 发布以来一直是16
+78h IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; // 数据目录表,指向多种不同用途的数据块
IMAGE_OPTIONAL_HEADER32 ENDS

3.2.3. Subsystem

1
2
3
4
5
6
7
8
0x0 IMAGE_SUBSYSTEM_UNKNOWN         // 未知的子系统
0x1 IMAGE_SUBSYSTEM_NATIVE // 不需要子系统(如驱动程序)
0x2 IMAGE_SUBSYSTEM_WINDOWS_GUI // Windows图形界面
0x3 IMAGE_SUBSYSTEM_WINDOWS_CUI // Windows控制台界面
0x5 IMAGE_SUBSYSTEM_OS2_CUI // OS2控制台界面
0x7 IMAGE_SUBSYSTEM_POSIX_CUI // POSIX控制台界面
0x8 IMAGE_SUBSYSTEM_NATIVE_WINDOWS // 不需要子系统
0x9 IMAGE_SUBSYSTEM_WINDOWS_CE_GUI // Windows CE图形界面

3.2.4. IMAGE_DATA_DIRECTORY

每个项的结构如下

1
2
3
4
IMAGE_DATA_DIRECTORY STRUCT
+0x0 DWORD VirtualAddress // 数据的起始RVA
+0x4 DWORD isize // 数据块的长度
IMAGE_DATA_DIRECTORY END

所有项目如下,以下偏移以IMAGE_NT_HEADERS为基准。

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
0x78 DWORD EXPORT          // 导出表
0x7C DWORD
0x80 DWORD IMPORT // 导入表
0x84 DWORD
0x88 DWORD RESOURCE // 资源
0x8C DWORD
0x90 DWORD EXCEPTION // 异常
0x94 DWORD
0x98 DWORD SECURITY // 安全
0x9C DWORD
0xA0 DWORD BASERELOC // 重定位
0xA4 DWORD
0xA8 DWORD DEBUG // 调试
0xAC DWORD
0xB0 DWORD COPYRIGHT // 描述字串
0xB4 DWORD
0xB8 DWORD GLOBALPTR // RVA to be used as Global Pointer (IA-64 only)
0xBC DWORD
0xC0 DWORD TLS // TLS
0xC4 DWORD
0xC8 DWORD LOAD_CONFIG // 载入配置
0xCC DWORD
0xD0 DWORD BOUND_IMPORT // 绑定导入表
0xD4 DWORD
0xD8 DWORD IAT // 导入地址表
0xDC DWORD
0xE0 DWORD DELAY_IMPORT // 延迟载入描述
0xE4 DWORD
0xE8 DWORD COM_DESCRIPTOR // COM信息
0xEC DWORD
0xF0 DWORD Reserved // 保留
0xF4 DWORD

3.3. 节表

节表位于IMAGE_NT_HEADERS之后。由一系列的IMAGE_SECTION_HEADER结构排列而成,每个结构用来描述一个节,结构的排列顺序和它们描述的节在文件中的排列顺序是一致的。全部有效结构的最后以一个空的IMAGE_SECTION_HEADER结构作为结束。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typedef struct _IMAGE_SECTION_HEADER {
+0x0 BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; // 节名称,前边带有“$” 的相同名字的区块在载入时候将会按照“$” 后边的字符的字母顺序进行合并
+0x8 union {
DWORD PhysicalAddress;
DWORD VirtualSize; // 在内存中实际占用的大小,当前节数据内存中文件对齐前的真实尺寸
} Misc;
+0xC DWORD VirtualAddress; // 在内存中的偏移地址,该偏移地址加上imagebase就是当前节数据在内存中的真正地址
+0x10 DWORD SizeOfRawData; // 当前节数据在文件中对齐后的大小
+0x14 DWORD PointerToRawData; // 当前节数据在文件中的偏移地址
+0x18 DWORD PointerToRelocations; // 调试相关
+0x1C DWORD PointerToLinenumbers; // 调试相关
+0x20 WORD NumberOfRelocations; // 调试相关
+0x22 WORD NumberOfLinenumbers; // 调试相关
+0x24 DWORD Characteristics; // 文件属性,比如该节数据属性是否为可执行属性,都在这里面
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

3.3.1. 节属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
0x00000020 IMAGE_SCN_CNT_CODE               // Section contains code.(包含可执行代码)
0x00000040 IMAGE_SCN_CNT_INITIALIZED_DATA // Section contains initialized data(该块包含已初始化的数据)
0x00000080 IMAGE_SCN_CNT_UNINITIALIZED_DATA // Section contains uninitialized data(该块包含未初始化的数据)
0x00000200 IMAGE_SCN_LNK_INFO // Section contains comments or some other type of information
0x00000800 IMAGE_SCN_LNK_REMOVE // Section contents will not become part of image
0x00001000 IMAGE_SCN_LNK_COMDAT // Section contents comdat
0x00004000 IMAGE_SCN_NO_DEFER_SPEC_EXC // Reset speculative exceptions handling bits in the TLB entries for this section
0x00008000 IMAGE_SCN_GPREL // Section content can be accessed relative to GP
0x00500000 IMAGE_SCN_ALIGN_16BYTES // Default alignment if no others are specified
0x01000000 IMAGE_SCN_LNK_NRELOC_OVFL // Section contains extended relocations
0x02000000 IMAGE_SCN_MEM_DISCARDABLE // Section can be discarded
0x04000000 IMAGE_SCN_MEM_NOT_CACHED // Section is not cachable
0x08000000 IMAGE_SCN_MEM_NOT_PAGED // Section is not pageable
0x10000000 IMAGE_SCN_MEM_SHARED // Section is shareable(该块为共享块)
0x20000000 IMAGE_SCN_MEM_EXECUTE // Section is executable.(该块可执行)
0x40000000 IMAGE_SCN_MEM_READ // Section is readable(该块可读)
0x80000000 IMAGE_SCN_MEM_WRITE // Section is writeable(该块可写)

3.4. 导入表

导入表以IMAGE_IMPORT_DESCRIPTOR的数组开始,每个被PE文件链接进来的DLL文件都分别对应一个项,最后以一个全0的IID作为结束标志。

1
2
3
4
5
6
7
8
9
10
struct _IMAGE_IMPORT_DESCRIPTOR {
+0x00 union {
DWORD Characteristics;
DWORD OriginalFirstThunk; // INT即导入名称表的RVA(IMAGE_THUNK_DATA数组)
} DUMMYUNIONNAME;
+0x04 DWORD TimeDateStamp; // 时间戳,一般为空
+0x08 DWORD ForwarderChain; // 一般情况下忽略,老版功能遗留
+0x0C DWORD Name; // 导入模块名的RVA
+0x10 DWORD FirstThunk; // IAT即导入地址表的RVA(IMAGE_THUNK_DATA数组)
} IMAGE_IMPORT_DESCRIPTOR;

3.4.1. IMAGE_THUNK_DATA

1
2
3
4
5
6
7
8
struct _IMAGE_THUNK_DATA{
+0x0 union {
DWORD ForwarderString // 只有当IMAGE_IMPORT_DESCRIPTOR中的ForwarderChain有值时,它才有效
DWORD Function // 函数的实际内存地址,只有在载入内存中时才有效
DWORD Ordinal // 最高位为1时,表示函数以序号方式输入,这时候低31位被看作一个函数序号
DWORD AddressOfData // 最高位为0时,表示函数以字符串类型的函数名方式输入,该值是一个RVA,指向一个IMAGE_IMPORT_BY_NAME结构
}u1;
}IMAGE_THUNK_DATA32;

3.4.1.1. _IMAGE_IMPORT_BY_NAME

1
2
3
4
struct _IMAGE_IMPORT_BY_NAME {
+0x0 WORD Hint; // 指出函数在所在的dll的输出表中的序号
+0x2 BYTE Name[1]; // 指出要输入的函数的函数名
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

3.5. 导出表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
IMAGE_EXPORT_DIRECTORY STRUCT
{
+00h DWORD Characteristics // 未使用,总是定义为0
+04h DWORD TimeDateStamp // 文件生成时间
+08h WORD MajorVersion // 未使用,总是定义为0
+0Ah WORD MinorVersion // 未使用,总是定义为0
+0Ch DWORD Name // 模块的真实名称,编译时写入
+10h DWORD Base // 基数,加上序数就是函数地址数组的索引值
+14h DWORD NumberOfFunctions // 导出函数的总数
+18h DWORD NumberOfNames // 以名称方式导出的函数的总数,该字段的值只会小于或者等于NumberOfFunctions
+1Ch DWORD AddressOfFunctions // 指向输出函数地址的RVA数组
+20h DWORD AddressOfNames // 指向输出函数名字的RVA数组
+24h DWORD AddressOfNameOrdinals // 指向输出函数序号的RVA数组
};IMAGE_EXPORT_DIRECTORY ENDS

3.6. 重定位表

1
2
3
4
5
6
7
IMAGE_BASE_RELOCATION STRUC
{
+00h DWORD VirtualAddress // 重定位数据开始的RVA 地址
+04h DWORD SizeOfBlock // 重定位块得长度,标识重定向字段个数
+08h WORD TypeOffset // 指向数组,每项大小为16位,高4位代表重定位类型,低12位是重定位地址,它与VirtualAddress相加即是指向PE映像中需要修改的那个代码的地址
};
IMAGE_BASE_RELOCATION ENDS

TypeOffset高位字节的代码定义:

1
2
3
4
5
6
7
8
0x0 IMAGE_REL_BASED_ABSOLUTE   // 使块按照32位对齐,位置为0
0x1 IMAGE_REL_BASED_HIGH // 高16位必须应用于偏移量所指高字16位
0x2 IMAGE_REL_BASED_LOW // 低16位必须应用于偏移量所指低字16位
0x3 IMAGE_REL_BASED_HIGHLOW // 全部32位应用于所有32位
0x4 IMAGE_REL_BASED_HIGHADJ // 需要32位,高16位为偏移量,低16位为下一个偏移量数组元素,组合为一个带符号数,加上32位的一个数,然后加上8000,把高16位保存在偏移量的16位域内
0x5 IMAGE_REL_BASED_MIPS_JMPADDR // Unknown
0x6 IMAGE_REL_BASED_SECTION // Unknown
0x7 IMAGE_REL_BASED_REL32 // Unknown

3.7. 资源

PE文件中的资源是按照资源类型 -> 资源ID -> 资源代码页的3层树型目录结构来组织资源的。每一层都是以IMAGE_RESOURCE_DIRECTORY结构为头部,后面跟着一个IMAGE_RESOURCE_DIRECTORY_ENTRY结构数组。其中IMAGE_RESOURCE_DIRECTORY负责指出后面数组中的成员个数,IMAGE_RESOURCE_DIRECTORY_ENTRY数组成员分别指向下一层目录结构。

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
IMAGE_RESOURCE_DIRECTORY STRUCT    // 其中结构体中的成员指出的RVA偏移量都是对于此结构体的地址作为基地址
{
+00h DWORD Characteristics // 理论上为资源的属性,不过事实上总是0
+04h DWORD TimeDateStamp // 资源的产生时刻
+08h WORD MajorVersion // 理论上为资源的版本,不过事实上总是0
+0Ah WORD MinorVersion
+0Ch WORD NumberOfNamedEntries // 以名称(字符串)命名的入口数量
+0Eh WORD NumberOfIdEntries // 以ID(整型数字)命名的入口数量
};IMAGE_RESOURCE_DIRECTORY ENDS

IMAGE_RESOURCE_DIRECTORY_ENTRY STRUCT // 该结构的偏移以节点头为基准
{
+10h DWORD Name // 第一层目录时,代表资源类型
// 第二层目录时,代表资源名称;最高位为0时,低位为ID值;最高位为1时,低位为字符串(IMAGE_RESOURCE_DIR_STRING_U)
// 第三层目录时,代表资源语言类型
+14h DWORD OffsetToData // 第一、二层目录时,代表下层数据偏移地址;第三层目录时,代表资源数据地址(IMAGE_RESOURCE_DATA_ENTRY)
};IMAGE_RESOURCE_DIRECTORY_ENTRY ENDS

typedef struct _IMAGE_RESOURCE_DATA_ENTRY {
+0x0 DWORD OffsetToData // 资源数据的RVA
+0x4 DWORD Size // 资源数据的长度
+0x8 DWORD CodePage // 代码页, 一般为0
+0xC DWORD Reserved // 保留字段
} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;

IMAGE_RESOURCE_DIR_STRING_U STRUCT
{
+00h DWORD Length // 字符串的长度
+04h DWORD NameString // UNICODE字符串,由于字符串是不定长的。由Length指定长度
};IMAGE_RESOURCE_DIR_STRING_U ENDS

以下为资源类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
0x1  光标
0x2 位图
0x3 图标
0x4 菜单
0x5 对话框
0x6 字符串
0x7 字体目录
0x8 字体
0x9 加速键
0xA 未格式化资源
0xB 消息表
0xC 光标组
0xD 未知类型
0xE 图标组
0xF 未知类型
0x10 版本信息