VAD概念

简介

VAD其实没有过于复杂,由于本人总是忘记,遂写个记录方便以后查询.

内存分为物理内存和虚拟内存;操作系统和进程共享物理内存,进程独享虚拟内存;物理内存可以通过CR3寄存器在进程之间互相隔离,确保进程之间互不侵犯;2位下,每个进程独享4GB内存,怎么知道哪些内存已经使用过,windwos采用virtual address descripot自平衡二叉树来管理虚拟内存,低端的内存地址放在根节点左子树,高端内存地址放根节点右子树,大致的结构如下:每当进程调用virtualAlloc分配虚拟内存时,操作系统会先遍历这个树,看看还有哪些地方的虚拟内存还未使用

64位环境下查找VAD

EPROCESS结构中保存着VadRoot根节点

1
2
3
4
5
6
7
8
9
10
11
12
13
kd> dt _EPROCESS
nt!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x160 ProcessLock : _EX_PUSH_LOCK
+0x168 CreateTime : _LARGE_INTEGER
[...]
+0x448 VadRoot : _MM_AVL_TABLE
+0x488 AlpcContext : _ALPC_PROCESS_CONTEXT
+0x4a8 TimerResolutionLink : _LIST_ENTRY
+0x4b8 RequestedTimerResolution : Uint4B
+0x4bc ActiveThreadsHighWatermark : Uint4B
+0x4c0 SmallestTimerResolution : Uint4B
+0x4c8 TimerResolutionStackRecord : Ptr64 _PO_DIAG_STACK_RECORD

64位VAD结构如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1: kd> dt _MMVAD
nt!_MMVAD
+0x000 u1 : <unnamed-tag>
+0x008 LeftChild : Ptr64 _MMVAD//左子树
+0x010 RightChild : Ptr64 _MMVAD//右子树
+0x018 StartingVpn : Uint8B//起始页
+0x020 EndingVpn : Uint8B//结束页
+0x028 u : <unnamed-tag>
+0x030 PushLock : _EX_PUSH_LOCK
+0x038 u5 : <unnamed-tag>
+0x040 u2 : <unnamed-tag>
+0x048 Subsection : Ptr64 _SUBSECTION
+0x048 MappedSubsection : Ptr64 _MSUBSECTION
+0x050 FirstPrototypePte : Ptr64 _MMPTE
+0x058 LastContiguousPte : Ptr64 _MMPTE
+0x060 ViewLinks : _LIST_ENTRY
+0x070 VadsProcess : Ptr64 _EPROCESS

!process 0 0查看EPROCESS地址

1
2
3
4
5
6
7
1: kd> !process 0 0 
**** NT ACTIVE PROCESS DUMP ****
[...]
PROCESS fffffa8004ae1b30
SessionId: 1 Cid: 0c60 Peb: 7fffffd3000 ParentCid: 062c
DirBase: 4716c000 ObjectTable: fffff8a0027e1bf0 HandleCount: 70.
Image: calc.exe

查看VAD管理各块内存属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1: kd> !vad  fffffa8004ae1b30+0x440
VAD level start end commit
c3504c4102210000: Unable to get nt!_FILE_OBJECT.FileName.Buffer
[...]
fffffa8004971d90 ( 9) 190 199 10 Private READWRITE
fffffa800492d140 ( 7) 1a0 1af 16 Private READWRITE
fffffa800461f0c0 ( 8) 1b0 1cc 29 Private READWRITE
fffffa8004b54250 ( 9) 1d0 1ec 29 Private READWRITE
fffffa8004865950 ( 4) 1f0 26f 9 Private READWRITE
fffffa80041a4870 ( 8) 270 2a8 57 Private READWRITE
fffffa8004568f70 ( 7) 2b0 2e8 57 Private READWRITE
fffffa80041a5140 ( 6) 2f0 2f9 10 Private READWRITE
fffffa80038a0b60 ( 8) 300 312 19 Private READWRITE
fffffa8004b65580 ( 9) 320 329 10 Private READWRITE
fffffa800455ded0 ( 7) 330 42f 105 Private READWRITE
fffffa8004b50750 ( 8) 430 52f 46 Private READWRITE
fffffa80044bc350 ( 5) 530 6b7 0 Mapped READONLY Pagefile-backed section
fffffa8004436bd0 ( 8) 6c0 840 0 Mapped READONLY Pagefile-backed section

接下来就可以递归遍历二叉树得到VAD树了

当内存使用完毕,调用VirtualFree,将内存从VAD卸下,后续再次遍历时才能继续使用!正常情况下,如果要卸载dll,可以调用windwos提供的freeLibrary接口(释放后再使用,躲避检测),里面有关键的函数:ZwUnmapViewOfSection,可以直接把dll对应的内存从VAD中删除,ZwUnmapViewOfSection 是傀儡执行恶意的代码的关键函数(一般傀儡进程或者直接注入的shellcode都是Private(调用VirtualAlloc)权限,并且具有EXECUTE属性,可以使用此方法检测傀儡进程)