最近用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网上也有介绍。