为什么这段代码能让我检测调试器?

时间:2012-04-10 12:59:05

标签: windows debugging assembly x86 reverse-engineering

为什么以下汇编代码是反调试工具?

l1:
call l3
l2:
;some code
l3:
mov al, 0c3h
mov edi, offset l3
or ecx, -1
rep stosb

我知道C3hRETN,我知道stobs根据al中的偏移量将edi中的值写为操作码,它是由于ecx已完成rep次。

我也意识到stobsstosw如果以英特尔架构预先作为原始格式预先运行的话。

如果我们以调试模式运行程序,预取是无关紧要的,l2标签将运行(因为它是单步)否则如果没有调试器它将在l1和l3之间进行乒乓我正确?

2 个答案:

答案 0 :(得分:14)

当调试程序时(即单步),在每一步(当发生中断时)刷新预取队列。但是,正常执行时rep stosb不会发生。即使存在对缓存区域的内存写入,较旧的处理器也没有刷新它,以便支持除rep movsrep stosb之外已更改的自修改代码。 (IIRC最终在i7处理器中修复了。)

这就是为什么如果有一个调试器(单步)代码将正确执行并且rep stosb替换为ret l2的原因将被执行。当没有调试器rep stosb将继续时,因为ecx是最大可能的,它最终将写入不应该写入的地方,并且会发生异常。

this paper中描述了这种反调试技术。

答案 1 :(得分:2)

调试器在这里唯一做的就是添加时间延迟。这可能是其工作原理的关键。英特尔(我假设AMD)手册明确指出自修改代码不能“工作”,除非程序通知CPU包含修改指令的缓存行已经改变。这是为了使预取逻辑便宜;芯片设计人员不希望硬件不断测试指令高速缓存行的每个字节仍然有效。

所以我假设发生了什么 调试器是l1调用l3,它在rep stosb之后存储一个返回,并且由于调试器在单步执行中强制导致长延迟执行返回,强制执行cachecline包含要在更改后重新获取的l3。

没有调试器,我猜测stosb执行后的指令(未显示)。如果跳转到“无调试器”,那么跳转的成功将表明没有使用单步调试器。

如果我在应用程序中找到此代码,我会拒绝运行它。