用windbg为无效页面建立页面映射

来源:互联网 发布:apache 支持php 编辑:程序博客网 时间:2024/05/16 07:19

    前几天和同事扯淡,说调试驱动时访问无效内存会蓝屏,好麻烦,应该让windbg自动建立一个有效的页面,这样就不用蓝屏重启了。虽然说这是扯淡,但仔细想想貌似也不是不可能实现。

    首先回顾一下OS解决内存缺页时简单步骤:1.搜索物理页面;2.修改虚拟地址对应的pte表的值;3.重新执行访存失败的指令。基于这样的思路,我也试了一下在windbg中手工建立内存映射(环境:win7 x32)

1.在内核空间中找一个无效地址。先枚举内核中所有已加载的模块,各模块之间的内存间隙应该有不少无效地址.

kd> lmstart    end        module name82a06000 82a3d000   hal        (deferred)             82a3d000 82e4d000   nt         (pdb symbols)      kd> dd 82a06000-0x100082a05000  ???????? ???????? ???????? ????????kd> ed 82a05000   0x00                     ^ Memory access error in 'ed 82a05000   0x00'
模块nt加载在0x82a0d000,从这开始是模块nt的PE头/text区...要在这些位置中找到一段无效内存还是有点难度的,但是往前搜索一个内存页,说不定能找到无效内存。而windbg以????的形式显示无效地址。果然,我在0x82a05000处找到一块无效内存。往这块内存写入值就报出了错误"^ Memory access error in 'ed 82a05000   0x00'"


2.找一块物理地址,用于建立映射到虚拟内存上。我猜想模块nt的PE头应该是有效内存.验证一下:

kd> !pte 82a06000                    VA 82a06000PDE at C06020A8            PTE at C0415030contains 00000000001D1063  contains 0000000002A06963pfn 1d1       ---DA--KWEV  pfn 2a06      -G-DA--KWEVkd> dd 82a06000 L4 ;虚拟页面的内容82a06000  00905a4d 00000003 00000004 0000ffffkd> !dd 2A06000 ;物理页面的内容# 2a06000 00905a4d 00000003 00000004 0000ffff
nt的PE头位于0x82a06000,通过!pte命令查看其页表项,我们知道0x82a06000所在的页面是有效页面,页面物理地址是0x2a06000。另外,虚拟页面的内容和其所映射的物理页面的内容是一致的。接下来,我会用这个物理页面映射到虚拟地址0x82a05000上。(移花接木之术)

3.定位虚拟地址0x82a05000的pte,然后修改pte中存储的值为物理页面0x2a06000。

kd> !pte 82a05000                      VA 82a05000PDE at C06020A8            PTE at C0415028contains 00000000001D1063  contains 0000000000000000pfn 1d1       ---DA--KWEV  not validkd> ed C0415028 2A06963kd> !pte 82a05000                      VA 82a05000PDE at C06020A8            PTE at C0415028contains 00000000001D1063  contains 0000000002A06963pfn 1d1       ---DA--KWEV  pfn 2a06      -G-DA--KWEV
修改前,0x82a05000对应的pte (位于C0415028)是无效pte;修改后,变成了有效pte

4.看看修改的结果。

kd> dd 82a05000  82a05000  00905a4d 00000003 00000004 0000ffff82a05010  000000b8 00000000 00000040 0000000082a05020  00000000 00000000 00000000 00000000
以前0x82a05000处是无效内存,结果页面映射,现在已经有除????以外的数值。恩,页面映射成功

------------------------------------------------------------------------------

后记:

这次修改有2个有意思的地方:

1.修改后,有时候执行

dd 0x82a05000,还是会看到????,不要以为这是映射失败。要经过一段时间或者编辑一下内存才能看到内存值被修改了。我问过群里的大神,他们的回复这种现象是由于Cpu TLB(快表)的存在,要使TLB中的页表失效,才能重新获得新的页表

2.现在虚拟地址0x82a05000和0x82a06000两个页面的确指向同一块物理页面。理论上,修改其中一个页面的值,势必会影响另一个页面的值,然而,调试过程中并非如此:

我尝试修改页面0x82a05000的值,却并没有影响到页面0x82a06000的值。开始时,我以为发生了写时复制,可是查看0x82a05000的页表项,其值并没有改变。

kd> ed 82a05000   90909090 ;修改虚拟内存的内容kd> dd 82a05000  L482a05000  90909090 00000003 00000004 0000ffffkd> dd 82a06000 L4 ;查看nt模块的pe头,值没有改变82a06000  00905a4d 00000003 00000004 0000ffffkd> !pte 82a05000  ;查看两个虚拟地址对应的pte,也没有发生改变,仍然指向相同的物理地址                     VA 82a05000PDE at C06020A8            PTE at C0415028contains 00000000001D1063  contains 0000000002A06963pfn 1d1       ---DA--KWEV  pfn 2a06      -G-DA--KWEVkd> !pte 82a06000                     VA 82a06000PDE at C06020A8            PTE at C0415030contains 00000000001D1063  contains 0000000002A06963pfn 1d1       ---DA--KWEV  pfn 2a06      -G-DA--KWEVkd> !dd 2A06000 ;前面修改82a05000的值已经成功,物理页面的内容已经被改变# 2a06000 90909090 00000003 00000004 0000ffff

对于这个现象,我实在无法解释,只能等路过的大神帮忙解答了


0 0
原创粉丝点击