|
众所周知,进程模块的信息分别存在于PEB和VAD里。枚举PEB的文章很多,我就不赘述了。枚举VAD的文章很少,而且代码写得乱七八糟,于是决定写篇文章科普一下。由于VAD并不是微软公开的结构,所以不同系统的变化比较大,在我看来基本分为三个阶段:WINXP、WIN2K3~WIN8、WIN8.1~WIN10(目前版本是16299)。不过,所谓变化,都是形变神不变,这里以XP系统举例,因为XP系统的VAD结构最简单,方便理解。
VAD入口是EPROCESS->VadRoot。在XP下,WINDBG显示VadRoot的类型为PVOID,实际上它是MMVAD结构体的指针:- /*lkd> 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
- +0x018 ControlArea : Ptr32 _CONTROL_AREA
- +0x01c FirstPrototypePte : Ptr32 _MMPTE
- +0x020 LastContiguousPte : Ptr32 _MMPTE
- +0x024 u2 : __unnamed*/
- typedef struct _MMVAD2600
- {
- ULONG StartingVpn;
- ULONG EndingVpn;
- struct _MMVAD2600 *Parent;
- struct _MMVAD2600 *LeftChild;
- struct _MMVAD2600 *RightChild;
- void *u;
- PCONTROL_AREA2600 ControlArea;
- }MMVAD2600, *PMMVAD2600;
复制代码 VAD结构本身并没有模块名称和模块地址,它们存储在ControlArea的下级结构里:- /*lkd> 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 <---这里是模块对应文件的文件对象
- +0x028 WaitingForDeletion : Ptr32 _EVENT_COUNTER
- +0x02c ModifiedWriteCount : Uint2B
- +0x02e NumberOfSystemCacheViews : Uint2B*/
- typedef struct _CONTROL_AREA2600
- {
- PSEGMENT2600 Segment;
- UCHAR WhoCare[0x24-sizeof(void*)];
- PFILE_OBJECT FilePointer;
- }CONTROL_AREA2600, *PCONTROL_AREA2600;
复制代码- /*lkd> dt_segment
- nt!_SEGMENT
- +0x000 ControlArea : Ptr32 _CONTROL_AREA
- +0x004 TotalNumberOfPtes : Uint4B
- +0x008 NonExtendedPtes : Uint4B
- +0x00c WritableUserReferences : Uint4B
- +0x010 SizeOfSegment : Uint8B
- +0x018 SegmentPteTemplate : _MMPTE
- +0x020 NumberOfCommittedPages : Uint4B
- +0x024 ExtendInfo : Ptr32 _MMEXTEND_INFO
- +0x028 SystemImageBase : Ptr32 Void
- +0x02c BasedAddress : Ptr32 Void <---这里是模块地址
- +0x030 u1 : __unnamed
- +0x034 u2 : __unnamed
- +0x038 PrototypePte : Ptr32 _MMPTE
- +0x040 ThePtes : [1] _MMPTE*/
- typedef struct _SEGMENT2600
- {
- UCHAR WhoCare[0x2C];
- PVOID BasedAddress;
- }SEGMENT2600, *PSEGMENT2600;
复制代码 VAD并不是简单的数组或链表结构,而是树结构。这棵树具体怎么样我就不多说了,反正你知道,它有“左孩子”和“右孩子”,得到第一个VAD结构体之后,顺着两个“孩子”走下去,直到“孩子”的地址为0或非法即可。枚举代码如下:接下来是干货内容,关于在WIN7、WIN8和WIN10上枚举VAD需要注意的地方。 |
|