16

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

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

我知道C3hRETN,并且我知道根据偏移量stobs将值写入操作码,并且由于.alediecxrep

我也知道如果它们在英特尔架构上作为其原始格式预取,stobs并且将运行。stosw

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

4

2 回答 2

14

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

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

本文介绍了这种反调试技术。

于 2012-04-10T14:50:25.440 回答
2

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

所以我假设调试器发生事情是 l1 调用 l3,它在 rep stosb 之后存储一个返回,并且由于调试器在单步中引起的长时间延迟,返回被执行,迫使包含 l3 的缓存行在更改后重新获取。

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

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

于 2012-04-10T14:59:12.867 回答