天天看点

调试器的工作原理

调试器的工作原理《黑客调试技术揭秘》  

理解调试器的工作原理  

对调试器的工作原理毫无所知就贸然地使用它是很愚蠢的。所以,在本节中,我将介绍调试器工作的基本原理和理论基础。这可不是一个简明易懂的论述,不过,能让你抓住所要研究问题的主要思想。“Intel Architecture Software Developer’s Manual Volume 3: System Programming Guide”(英特尔免费分发的一本指南)的“Debugging and Performance Monitoring”一章包含了相关的技术细节。 

现有的所有调试器都可分为两大类。第一类调试器利用处理器提供的调试工具,而第二类调试器自行仿真处理器并完全控制所调试程序的执行过程。 

程序是既不能检测到也不能绕过高质量仿真调试器的。可是,在本书写作时还不存在功能完备的针对奔腾处理器的仿真器,而且也不太可能会很快出现。 

但是,是否有必要开发这类仿真调试器呢?奔腾处理器提供了一系列的控制功能,它们甚至可以控制特许操作代码!它们支持单步执行程序,捕获位于指定地址的指令执行,并提供对指定的内存单元(或者输入/输出端口)的访问,以及任务切换等功能。 

如果标志寄存器的追踪位被置位,那么执行每一条机器指令后都会产生调试中断INT 1,并将控制传给调试器。通过分析标志寄存器,被调试的代码能够检测到追踪。因此,为了保证其操作不被发现,调试器必须识别读取标志寄存器的指令,并通过返回值为零的追踪位来仿真其执行结果。 

必须注意如下的一种重要情形:在执行了修改SS寄存器的指令之后,并不会引发调试异常。调试器必须知道如何识别这种情形,并自行在下一条指令上设置断点。否则,追踪者就不能进入指令POP SS后面的过程(例如:PUSH SS; POP SS; CALL MySecrectProc)。并不是所有的当代调试器都具有这一功能的,因此,虽然这一点已被发现了很长时间,但这种技巧可能依然有效。 

有四个调试寄存器(即DR0~DR3),它们用于存放四个断点的线性地址,而控制寄存器DR7包含了这四个断点中的每一个的控制条件。当满足该条件时,处理器产生INT 0x1异常并将控制传给调试器。总共有四个中断的条件:当执行指令时发生中断,如果内存单元被修改则发生中断,当读取或者修改但不执行内存单元时发生中断,以及当访问输入/输出端口时发生中断。 

通过设置特定的数据位,就可以在调试寄存器被访问的任何时间引发调试异常。即使是特许执行代码试图读取(或者修改)这些寄存器时,也会引发调试异常。无论被调试的代码有怎样的执行特权,设计精良的调试器都能够隐藏自己的行迹而不让被调试的代码发现自己(虽然如果操作代码调试自己,那么调试器不能使用全部的四个断点)。 

如果任务的任务状态段(TSS)的T位被置位,那么每当切换到该任务时,在执行该任务的第一条指令之前,都会引发调试异常。为了防止正被调试的代码发现调试器的存在,调试器应该追踪访问其TSS的所有操作,并把虚构的数据返回程序。必须注意:基于性能的考虑,Windows NT并不使用TSS(或者更精确地说,在一个硬件任务的所有运行时间内,它都只使用一个TSS),因此在这种情形中,调试可能是无效的。 

软件断点是惟一的一种不编写功能完整的处理器仿真器就不能被隐藏的对象。它表示为一个字节的代码0xCC,放在指令之前,当出现任何企图执行它的操作时都将引发INT 0x3异常。对于被调试的程序,计算求和校验位就足以发现是否至少设置了一个断点。可以使用诸如MOV,MOVS,LOAS,POP,CMP或者CMPS之类的指令来实现这一点,因为没有一种调试器能够追踪和仿真全部的这类指令。 

我们强烈地建议,只有在硬件断点不满足需要时,才使用软件断点。然而,实际上,所有的当代调试器(包括SoftIce)都默认地设置软件断点而不是硬件断点。这一事实可以成功地用于保护机制。在第12章“如何防止追踪”一节中提供了几个例子,以说明这种机制的实现方法。

转:http://blog.csdn.net/bysdy/article/details/2458438

继续阅读