📄 jiurl玩玩win2k内存篇 vad.htm
字号:
0x81070188<BR>/*14*/ ULONG CommitCharge:20; = 0x00000<BR>/*14*/ ULONG
Flags :12; = 0x010<BR>/*18*/ PVOID ControlArea; = 0x810e7228<BR>/*1C*/
PVOID FirstProtoPte; = 0xe2beebe0<BR>/*20*/ PVOID LastPTE; =
0xe2beece0<BR>/*24*/ ULONG Unknown; = 0x00000000<BR>/*28*/ LIST_ENTRY
Secured; = 0x00000000 0x00000000<BR><BR><BR>0x81070188 [11] 0x00380
0x0038f 6 840<BR>StartVirtualAddress: 0x00380000 EndVirtualAddress:
0x0038ffff<BR>/*00*/ PVOID StartVPN; = 0x00380<BR>/*04*/ PVOID EndVPN; =
0x0038f<BR>/*08*/ _VAD_HEADER* ParentLink; = 0x82b056e8<BR>/*0C*/
_VAD_HEADER* LeftLink; = 0x00000000<BR>/*10*/ _VAD_HEADER* RightLink; =
0x00000000<BR>/*14*/ ULONG CommitCharge:20; = 0x00006<BR>/*14*/ ULONG
Flags :12; = 0x840<BR>/*18*/ PVOID ControlArea; = 0x02018001<BR>/*1C*/
PVOID FirstProtoPte; = 0x6d665346<BR>/*20*/ PVOID LastPTE; =
0x00000001<BR>/*24*/ ULONG Unknown; = 0x00000000<BR>/*28*/ LIST_ENTRY
Secured; = 0x00000000 0x00040001<BR><BR><BR>0x810482a8 [ 0] 0x00400
0x00405 2 071<BR>StartVirtualAddress: 0x00400000 EndVirtualAddress:
0x00405fff<BR>/*00*/ PVOID StartVPN; = 0x00400<BR>/*04*/ PVOID EndVPN; =
0x00405<BR>/*08*/ _VAD_HEADER* ParentLink; = 0x00000000<BR>/*0C*/
_VAD_HEADER* LeftLink; = 0x82b05928<BR>/*10*/ _VAD_HEADER* RightLink; =
0x83040348<BR>/*14*/ ULONG CommitCharge:20; = 0x00002<BR>/*14*/ ULONG
Flags :12; = 0x071<BR>/*18*/ PVOID ControlArea; = 0x8401f428<BR>/*1C*/
PVOID FirstProtoPte; = 0xe2beb260<BR>/*20*/ PVOID LastPTE; =
0xfffffffc<BR>/*24*/ ULONG Unknown; = 0x40000000<BR>/*28*/ LIST_ENTRY
Secured; = 0x00000000 0x00000000<BR><BR><BR>0x86348b68 [ 3] 0x00410
0x0050f 8 840<BR>StartVirtualAddress: 0x00410000 EndVirtualAddress:
0x0050ffff<BR>/*00*/ PVOID StartVPN; = 0x00410<BR>/*04*/ PVOID EndVPN; =
0x0050f<BR>/*08*/ _VAD_HEADER* ParentLink; = 0x810bba08<BR>/*0C*/
_VAD_HEADER* LeftLink; = 0x00000000<BR>/*10*/ _VAD_HEADER* RightLink; =
0x8109de08<BR>/*14*/ ULONG CommitCharge:20; = 0x00008<BR>/*14*/ ULONG
Flags :12; = 0x840<BR>/*18*/ PVOID ControlArea; = 0x01018001<BR>/*1C*/
PVOID FirstProtoPte; = 0x53646156<BR>/*20*/ PVOID LastPTE; =
0x00000010<BR>/*24*/ ULONG Unknown; = 0x00000010<BR>/*28*/ LIST_ENTRY
Secured; = 0x810745e8 0x00000000<BR><BR><BR>0x8109de08 [ 4] 0x00510
0x00511 0 010<BR>StartVirtualAddress: 0x00510000 EndVirtualAddress:
0x00511fff<BR>/*00*/ PVOID StartVPN; = 0x00510<BR>/*04*/ PVOID EndVPN; =
0x00511<BR>/*08*/ _VAD_HEADER* ParentLink; = 0x86348b68<BR>/*0C*/
_VAD_HEADER* LeftLink; = 0x00000000<BR>/*10*/ _VAD_HEADER* RightLink; =
0x00000000<BR>/*14*/ ULONG CommitCharge:20; = 0x00000<BR>/*14*/ ULONG
Flags :12; = 0x010<BR>/*18*/ PVOID ControlArea; = 0x810e7a08<BR>/*1C*/
PVOID FirstProtoPte; = 0xe139cf40<BR>/*20*/ PVOID LastPTE; =
0xe139cf44<BR>/*24*/ ULONG Unknown; = 0x80000000<BR>/*28*/ LIST_ENTRY
Secured; = 0x00000000 0x00000000<BR><BR><BR>0x810bba08 [ 2] 0x77e60
0x77f34 2 071<BR>StartVirtualAddress: 0x77e60000 EndVirtualAddress:
0x77f34fff<BR>/*00*/ PVOID StartVPN; = 0x77e60<BR>/*04*/ PVOID EndVPN; =
0x77f34<BR>/*08*/ _VAD_HEADER* ParentLink; = 0x83040348<BR>/*0C*/
_VAD_HEADER* LeftLink; = 0x86348b68<BR>/*10*/ _VAD_HEADER* RightLink; =
0x00000000<BR>/*14*/ ULONG CommitCharge:20; = 0x00002<BR>/*14*/ ULONG
Flags :12; = 0x071<BR>/*18*/ PVOID ControlArea; = 0x810f4f28<BR>/*1C*/
PVOID FirstProtoPte; = 0xe17bfc40<BR>/*20*/ PVOID LastPTE; =
0xfffffffc<BR>/*24*/ ULONG Unknown; = 0x40000000<BR>/*28*/ LIST_ENTRY
Secured; = 0x00000000 0x00000000<BR><BR><BR>0x83040348 [ 1] 0x77f80
0x77ff8 3 071<BR>StartVirtualAddress: 0x77f80000 EndVirtualAddress:
0x77ff8fff<BR>/*00*/ PVOID StartVPN; = 0x77f80<BR>/*04*/ PVOID EndVPN; =
0x77ff8<BR>/*08*/ _VAD_HEADER* ParentLink; = 0x810482a8<BR>/*0C*/
_VAD_HEADER* LeftLink; = 0x810bba08<BR>/*10*/ _VAD_HEADER* RightLink; =
0x8106a248<BR>/*14*/ ULONG CommitCharge:20; = 0x00003<BR>/*14*/ ULONG
Flags :12; = 0x071<BR>/*18*/ PVOID ControlArea; = 0x813e6a08<BR>/*1C*/
PVOID FirstProtoPte; = 0xe13c9520<BR>/*20*/ PVOID LastPTE; =
0xfffffffc<BR>/*24*/ ULONG Unknown; = 0x40000000<BR>/*28*/ LIST_ENTRY
Secured; = 0x00000000 0x00000000<BR><BR><BR>0x810b7e48 [ 3] 0x7f6f0
0x7f7ef 0 034<BR>StartVirtualAddress: 0x7f6f0000 EndVirtualAddress:
0x7f7effff<BR>/*00*/ PVOID StartVPN; = 0x7f6f0<BR>/*04*/ PVOID EndVPN; =
0x7f7ef<BR>/*08*/ _VAD_HEADER* ParentLink; = 0x8106a248<BR>/*0C*/
_VAD_HEADER* LeftLink; = 0x00000000<BR>/*10*/ _VAD_HEADER* RightLink; =
0x00000000<BR>/*14*/ ULONG CommitCharge:20; = 0x00000<BR>/*14*/ ULONG
Flags :12; = 0x034<BR>/*18*/ PVOID ControlArea; = 0x810e8ca8<BR>/*1C*/
PVOID FirstProtoPte; = 0xe2be6be0<BR>/*20*/ PVOID LastPTE; =
0xe2be6fdc<BR>/*24*/ ULONG Unknown; = 0x01000000<BR>/*28*/ LIST_ENTRY
Secured; = 0x00000000 0x00000000<BR><BR><BR>0x8106a248 [ 2] 0x7ffa0
0x7ffd2 0 014<BR>StartVirtualAddress: 0x7ffa0000 EndVirtualAddress:
0x7ffd2fff<BR>/*00*/ PVOID StartVPN; = 0x7ffa0<BR>/*04*/ PVOID EndVPN; =
0x7ffd2<BR>/*08*/ _VAD_HEADER* ParentLink; = 0x83040348<BR>/*0C*/
_VAD_HEADER* LeftLink; = 0x810b7e48<BR>/*10*/ _VAD_HEADER* RightLink; =
0x81fd5708<BR>/*14*/ ULONG CommitCharge:20; = 0x00000<BR>/*14*/ ULONG
Flags :12; = 0x014<BR>/*18*/ PVOID ControlArea; = 0x8141bae8<BR>/*1C*/
PVOID FirstProtoPte; = 0xe10089e0<BR>/*20*/ PVOID LastPTE; =
0xe1008aa8<BR>/*24*/ ULONG Unknown; = 0x41000000<BR>/*28*/ LIST_ENTRY
Secured; = 0x00000000 0x00000000<BR><BR><BR>0x82b052a8 [ 4] 0x7ffde
0x7ffde 1 c64<BR>StartVirtualAddress: 0x7ffde000 EndVirtualAddress:
0x7ffdefff<BR>/*00*/ PVOID StartVPN; = 0x7ffde<BR>/*04*/ PVOID EndVPN; =
0x7ffde<BR>/*08*/ _VAD_HEADER* ParentLink; = 0x81fd5708<BR>/*0C*/
_VAD_HEADER* LeftLink; = 0x00000000<BR>/*10*/ _VAD_HEADER* RightLink; =
0x00000000<BR>/*14*/ ULONG CommitCharge:20; = 0x00001<BR>/*14*/ ULONG
Flags :12; = 0xc64<BR>/*18*/ PVOID ControlArea; = 0x00000000<BR>/*1C*/
PVOID FirstProtoPte; = 0x00000002<BR>/*20*/ PVOID LastPTE; =
0xe13d08a0<BR>/*24*/ ULONG Unknown; = 0x12000000<BR>/*28*/ LIST_ENTRY
Secured; = 0x7ffde000 0x7ffdefff<BR><BR><BR>0x81fd5708 [ 3] 0x7ffdf
0x7ffdf 1 c64<BR>StartVirtualAddress: 0x7ffdf000 EndVirtualAddress:
0x7ffdffff<BR>/*00*/ PVOID StartVPN; = 0x7ffdf<BR>/*04*/ PVOID EndVPN; =
0x7ffdf<BR>/*08*/ _VAD_HEADER* ParentLink; = 0x8106a248<BR>/*0C*/
_VAD_HEADER* LeftLink; = 0x82b052a8<BR>/*10*/ _VAD_HEADER* RightLink; =
0x00000000<BR>/*14*/ ULONG CommitCharge:20; = 0x00001<BR>/*14*/ ULONG
Flags :12; = 0xc64<BR>/*18*/ PVOID ControlArea; = 0x00000000<BR>/*1C*/
PVOID FirstProtoPte; = 0x00000002<BR>/*20*/ PVOID LastPTE; =
0xffffffff<BR>/*24*/ ULONG Unknown; = 0x12000000<BR>/*28*/ LIST_ENTRY
Secured; = 0x7ffdf000 0x7ffdffff<BR><BR><BR><B>遍历VAD二叉排序树的一种方法</B></P>
<P>为了使函数简单清楚一些,没有用 程序JiurlVadSee
中的函数做例子。下面的函数需要放在驱动程序(VAD二叉树在系统地址空间中,ring0程序才能访问)中,DbgPrint()的输出,可以使用
www.sysinternals.com 的工具 Dbgview 查看。<BR><BR>void JiurlDumpVad(PVAD_HEADER
pVad, ULONG level)<BR>{<BR>
if(pVad->LeftLink!=NULL)<BR> {<BR>
level++;<BR>
JiurlDumpVad(pVad->LeftLink,level);<BR>
level--;<BR> }<BR><BR> DbgPrint("0x%08x [%2d] 0x%08x 0x%08x
%7d
%03x\n",<BR>
pVad,level,pVad->StartVPN,pVad->EndVPN,<BR>
pVad->CommitCharge,pVad->Flags);<BR><BR>
if(pVad->RightLink!=NULL)<BR> {<BR>
level++;<BR>
JiurlDumpVad(pVad->RightLink,level);<BR>
level--;<BR>
}<BR>}<BR><BR>通过递归,先左子树,再根节点,再右子树。这样会按VAD代表地址段的先后顺序输出。<BR><BR><BR><B>程序申请内存,使用内存,释放内存
VAD 二叉树的变化</B><BR><BR>运行一个小程序分别申请,使用,释放内存,每步之间使用 getch() 停住,观察该进程 VAD 二叉树
和 该进程的页目录和页表的变化。我们在 地址空间中的 0x60000000 处进行试验。<BR><BR>1
getch();<BR><BR>0x60000000 没有相应的VAD,观察页目录,对应PDE无效 c0300600:
00000000<BR><BR>2
VirtualAlloc((void*)0x60000000,0x3000,MEM_RESERVE,PAGE_READONLY);<BR><BR>从0x60000000
开始处,保留3页。 <BR><BR>Vad Level StartVPN EndVPN Commit
Flags<BR>0x830ac008 [ 5] 0x60000 0x60002 0
810<BR><BR>出现了相应的VAD,可以看到保留了3页,但是并没有提交页<BR><BR>观察页目录,对应PDE无效 c0300600:
00000000<BR>尝试 char buf[100]; memcpy(buf,(void*)0x60000000,100); 将会导致
Access violation<BR><BR>3
VirtualAlloc((void*)0x60000000,0x2000,MEM_COMMIT,PAGE_READONLY);<BR><BR>从0x60000000
开始处,提交2页。(注意,使用MEM_COMMIT之前,必须MEM_RESERVE)<BR><BR>Vad Level StartVPN
EndVPN Commit Flags<BR>0x830ac008 [ 5] 0x60000 0x60002 2
810<BR><BR>刚才出现的VAD中已经表明提交了2页<BR><BR>观察页目录,对应PDE有效了 c0300600: 03cbc067
对应PTE仍然无效 c0180000: 00000020 00000020 00000000<BR><BR>4 char buf[100];
memcpy(buf,(void*)0x60000000,100);<BR><BR>读取 0x60000000
开始处的100字节,读取成功。<BR><BR>Vad Level StartVPN EndVPN Commit
Flags<BR>0x849f3328 [ 5] 0x60000 0x60002 2 810<BR><BR>对应PDE c0300600:
03cbc067<BR>对应PTE c0180000: 00559025 00000020
00000000<BR>这时被访问的一页对应的PTE有效了<BR><BR>5
VirtualFree((void*)0x60000000,0,MEM_RELEASE);<BR><BR>0x60000000
相应的VAD消失,观察页目录,对应PDE又变成无效 c0300600:
00000000<BR><BR>我们可以看到。保留地址空间,只建立一个相应的VAD。提交页只是设置相应的页目录项和页表项(有可能需要给页表分配物理内存)。只有当访问该地址的时候才真正给该地址映射物理页。Win2k
使用的这种思想叫做lazy-evaluation algorithm
,可以提高内存的使用效率。<BR><BR><BR><B>结构和标志位的定义</B><BR><BR>在 www.insidewindows.inf
的非官方的 ntifs.h 文件中,对 VAD_HEADER 定义如下<BR><BR>typedef struct _VAD_HEADER
{<BR>PVOID StartVPN;<BR>PVOID EndVPN;<BR>PVAD_HEADER
ParentLink;<BR>PVAD_HEADER LeftLink;<BR>PVAD_HEADER RightLink;<BR>ULONG
Flags; // LSB = CommitCharge<BR>PVOID ControlArea;<BR>PVOID
FirstProtoPte;<BR>PVOID LastPTE;<BR>ULONG Unknown;<BR>LIST_ENTRY
Secured;<BR>} VAD_HEADER, *PVAD_HEADER;<BR><BR>在对VAD的分析过程中,发现其中 Flags
字段,定义的不是很清楚。于是写了一个驱动程序和一个应用程序,应用程序负责接收输入的一个DWORD值,然后和驱动程序通信,把这个值传给驱动程序。驱动程序负责申请一段在系统地址空间中的内存,大小和
VAD_HEADER 的大小一样,接收到应用程序传来的DWORD之后,放在 Flags
的位置上,其他位置的值是固定的一些设计好的值。并且用DbgPrint() 输出这段内存的首地址。得到了这段空间的首地址之后,对这个地址使用 kd 的
!vad 命令,看命令的结果。在应用程序中输入新的值。再用!vad命令看输出结果。通过几次比较之后发现,VAD中 0x14 处的这个DWORD
的低20位用来保存提交的页数(20bit最大可以表示提交1024*1024页,对应4GB大小),高12位作为标志。通过这种方法,得到了部分标志位的定义(由于
!vad 可能并不解释一些标志位)。<BR><BR>#define MEM_IMAGE 0x001 // 指明页映射的是一个 image
section<BR>#define MEM_PRIVATE 0x800 // 指明页是私有的(不和别的进程共享)<BR><BR>#define
PAGE_READONLY 0x010<BR>#define PAGE_READWRITE 0x040<BR>#define
PAGE_WRITECOPY 0x050 // copy-on-write<BR>#define PAGE_EXECUTE
0x020<BR>#define PAGE_EXECUTE_READ 0x030<BR>#define PAGE_EXECUTE_READWRITE
0x060<BR>#define PAGE_EXECUTE_WRITECOPY 0x070<BR><BR>这些标志和 VirtualAlloc
中的同名的相对应。使用 VirtualAlloc 指定标志 PAGE_READONLY 申请了一段内存<BR>,使用 !vad
观察该进程的这段内存对应的VAD,发现 Flags:12 的值的确是 0x010
,验证了上面定义是正确的。如果想得到所有的标志定义,可以使用这种方法。也可以分析相关函数的汇编代码。
<P><B>进程地址空间中的物理页</B>
<P><B>
</B>通过一个进程的页目录和页表,我们可以知道这个进程地址空间的哪些部分映射了物理页。我写了一个叫 <A
href="http://jiurl.cosoft.org.cn/jiurl/document/JiurlPlayWin2k/JiurlValidPageSee.zip">JiurlValidPageSee</A>
的程序,可以得到指定进程的4GB地址空间的哪些部分映射了物理页。需要注意的是,一个物理页可以被以映射到虚拟地址空间的多个页中。
<P>欢迎交流,欢迎交朋友,<BR>欢迎访问 <A
href="http://jiurl.yeah.net/">http://jiurl.yeah.net/</A> <A
href="http://jiurl.cosoft.org.cn/forum">http://jiurl.cosoft.org.cn/forum</A>
<BR>
<P><BR><A
href="http://jiurl.cosoft.org.cn/jiurl/document/JiurlPlayWin2k/JiurlVadSee.zip">下载
JiurlVadSee 可执行文件及源程序</A><BR><A
href="http://jiurl.cosoft.org.cn/jiurl/document/JiurlPlayWin2k/JiurlValidPageSee.zip">下载
JiurlValidPageSee 可执行文件及源程序</A>
<P>
<P>
<P>
<P> </P></TD></TR></TBODY></TABLE></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -