最近用OD对内存设断点时候想到内存断点有2种 内存访问和内存写入 ,但为什么没有内存读取断点呢?
下面是自己的一点想法,有错误的话麻烦各位大虾不吝指教。。
从http://bbs.pediy.com/showthread.php?threadid=10829 我了解到内存断点的原理即
如果是内存写断点,OD就修改相应的页面属性为RE(可读,可执行)
如果是内存访问断点,OD就修改相应的页面属性为NO ACCESS(不可访问)
修改页面属性肯定一般用到VirtualProtect 这个函数有个参数是修改后的页面属性:
关于读写和执行的有
PAGE_EXECUTE_READWRITE
PAGE_EXECUTE
PAGE_READONLY
PAGE_READWRITE
PAGE_NOACCESS
PAGE_EXECUTE_READ
对于这个函数先看到这里 ,后面会用到,下面看分页机制。
分页机制是保护模式的重要成员之一,引用书上的话解释就是:
在保护模式下,控制寄存器CR0中的最高位PG位控制分页管理机制是否生效。如果PG=1,分页机制生效,把线性地址转换为物理地址。如果PG=0,分页机制无效,线性地址就直接作为物理地址。必须注意,只有在保护方式下分页机制才可能生效。只有在保证使PE位为1的前提下,才能够使PG位为1,否则将引起通用保护故障。
关于怎样计算的就不介绍了,可以自己网上查。
分页机制个人认为分为2种一个是开启PAE的分页机制和普通的分页机制
普通的分页机制页表和页目录项是32位即4字节而PAE下的是8字节。
简单的讲PAE下的分页机制可以将虚拟地址映射到更大的物理内存上。
对于普通的分页机制,与页的保护有关的内容是页表或页目录项的低12位,图如下:
其中U/S位是代表相应的页可以访问的特权级,为0 只有RING0、1、2可以访问 为1任意特权级都可以访问。
P位是代表所对应的页有没有映射到物理内存。
R/W是代表所对应的页面是否可以读/写/执行,这个标志位只对于CPU处于ring3级别才有效。为1的时候代表 可读可写可执行 为0的时候代表可读可执行
上述条件一旦CPU在检查部通过的时候就会触发14(0eh)号异常,然后执行操作系统布置好的代码。
那么现在就清楚了:
内存写断点是OD用PAGE_EXECUTE_READ调用VirtualProtect,最后内核中的函数会把相应的页表项r/w位设置为0
内存访问断点是OD用PAGE_NOACCESS调用VirtualProtect,最后内核中的函数会把相应的页表项P位设置为0
至于为什么没有内存读取断点,这就显而易见了,因为页表项不支持,如果R/W位为0代表可写可执行就可以了,页的执行权始终是有的
另外对于开启PAE下的分页机制与普通的分页机制除了在计算上的差别,还有一点很重要的差别就是利用页表项的第63位即最高位作为代码执行权的标准。这个位置1,表示此页不可执行。没有置位,
表示此页可以执行。即页的执行权要依据条件了。
XP SP2中的DEP技术就是利用这一点来完成的,这在MSDN中有所体现,对于PAGE_READONLY和
PAGE_READWRITE 在MSDN中都有这么一句话“If Data Execution Prevention is enabled, attempting to execute code in the committed region results in an access violation.“
但是PAGE_EXECUTE却没有这一句,原文是这样说的”An attempt to read from or write to the committed region results in an access violation. “我认为还是需要借助于PAE来实现的,于是我测验了一下,环境是XP sp3 没有开启PAE
代码如下:
int _tmain(int argc, _TCHAR* argv[]) { DWORD curAddress; _asm { call l; l: pop eax; mov curAddress ,eax; } curAddress = curAddress &(0xFFFFF000); printf("%8X\n", curAddress); DWORD old; if(!VirtualProtect((LPVOID)curAddress, 0x1000, PAGE_EXECUTE, &old)) { printf("VirtualProtect Error %d\n", GetLastError()); return 0; } printf("旧的属性是%8X\n", old); //试着去读取 _asm { //读取 mov eax, curAddress; mov eax , dword ptr[eax]; //写入 mov eax, curAddress; mov dword ptr[eax] , eax; } return 0; }
结果是只有写入的时候才报异常,读取没有异常。截图如下:

可见并没有像微软说的这么神乎,我推断是在没有开PAE的机器上只是将R/W位置0,这时只是可读可执行的,但是写入的话CPU会触发异常,然后执行操作系统的代码,弹出框框。
关于DEP实现的详细内容可以参考:http://forum.byr.edu.cn/article/Security/4293
另外怎样启动和关闭PAE网上也有介绍。