不请自来,我竟然在知乎上看到人问od(见鬼的表情
首先是关于内存断点的一些前置知识:
1.在windows系统上,内存是一页一页的,也就是说并不是
0x00000000~0x7FFFFFFF(0xFFFFFFFF)中任何一个地址都是可以访问的,不然每个程序都有真正
的2g内存太可怕了。实际情况是,你程序申请了一块0x2000的内存,这时候windows内核经过一
系列处理,告诉你,我在某个地址上(比如说0x00500000)给你设置了0x2000的内存,你可以拿去
用了。这时候0x00500000~0x00502000这块内存你才可以访问,你要是尝试访问0x00502001依
然会出错,因为这个地址根本不存在。
2.每个内存页都是有属性的,比如你申请时可以要求当前页面里的内容不可作为代码执行,因为你
只是拿来存数据的,如果不这样设置的话可能会遭到恶意利用。(比如说缓冲区溢出攻击)
3.调试器可以先于被调试程序拿到一些系统下发的消息,比如说被调试程序中出现了异常。
------------------------------------------------
现在可以说说内存断点都做了些什么了。
内存断点的实现方式是将你欲下断地址所在的内存页增加一个名为PAGE_NOACCESS的属性,这
个属性会把当前内存页设为禁止任何形式的访问,如果进行访问会触发一个内存访问异常。在这同
时,od开始捕获目标程序中出现的这个异常,并判断触发这个异常的位置是否跟你下断的地址相
同,如果相同则内存断点触发,暂停被调试程序的运行,否则放行。
这就是内存断点的基本原理,补充一些相关的东西:
1.内存断点很消耗资源,因为PAGE_NOACCESS属性一设置就是一整个内存页无法访问,那么当程
序访问该内存页中非断点地址的内容同样会触发异常,这时od收到异常后需要进行特殊处理,临时
放行,非常消耗资源,甚至这使得内存断点在调试很多大型程序时慢到近乎不可用。
2.虽然内存断点的效率经常很不理想,但是因为仅仅是修改了一个内存属性,所以内存断点可以下
数量非常多、单断点范围非常大。这是它的优势。
3.只在写入时断下的内存断点通常是将内存属性设为PAGE_EXECUTE_READ,也就是不可写来实
现的。对这种属性的内存进行写操作将会触发异常。
4.关于内存属性相关的知识:msdn.microsoft.com/en-u...
------------------------------------------------
------------------------------------------------
接下来是硬件断点的前置知识。
1.现代cpu为程序调试提供了6个寄存器,名为DRx,仔细说的话就是
DR0/DR1/DR2/DR3/DR6/DR7。没错就是没有4和5,我没写错。cpu内部对这6个寄存器作为硬
件断点提供了支持。