x86 反汇编/调试器检测
您可能会惊讶地发现,正在运行的程序实际上可以检测到附加的用户模式调试器。此外,也存在检测内核模式调试器的方法,尽管使用的方法在很大程度上取决于试图检测的调试器。
本主题与本书的叙述无关,大多数读者可以将本节视为可选内容。
Win32 API 包含一个名为“IsDebuggerPresent”的函数,如果程序正在被调试,它将返回布尔值 true。以下代码片段将详细说明此函数的一般用法
if(IsDebuggerPresent())
{
TerminateProcess(GetCurrentProcess(), 1);
}
当然,在反汇编代码中很容易发现 IsDebuggerPresent() 函数的用法,并且熟练的逆向工程人员只需修补代码以删除此行。对于 OllyDbg,有很多可用的插件可以隐藏调试器,使其无法被此 API 和许多其他 API 检测到。
进程环境块存储 IsDebuggerPresent 查询以确定其返回值的值。为了避免怀疑,一些程序员直接从 PEB 访问该值,而不是调用 API 函数。以下代码片段显示了如何访问该值
mov eax, [fs:0x30]
mov al, [eax+2]
test al, al
jne @DebuggerDetected
在 Windows 32 位和 64 位 Win <XP?, 7, 8.1 和 10 上。
有一个名为 _KUSER_SHARED_DATA 的结构,它在偏移量 0x2D4 处包含一个名为 'KdDebuggerEnabled' 的字段,如果 KDM 处于活动状态,则将其设置为 0x03,否则设置为 0x00。
该结构的基地址在不同的 Windows 版本中是静态的(0x7FFE0000),即使 < XP 也是如此。
该字段由内核不断更新,最后两位设置为 '11'。
以下汇编指令将在 32 位和 64 位应用程序中都能正常工作
cmp byte ptr ds:[7FFE02D4], 3
je @DebuggerDetected
这有很多优点。 已知的资料来源。
调试器可以在代码中设置断点,因此可以停止程序执行。程序可以通过监控系统时钟来检测到这一点。如果指令之间经过的时间过长,则可以确定程序被停止并正在进行分析(尽管并非总是如此)。如果程序花费的时间过长,则程序可以终止。
请注意,在抢占式多线程系统(例如现代 Windows 或 Linux 系统)中,系统会从您的程序切换到运行其他程序。这称为线程切换。如果系统有许多线程要运行,或者某些线程占用处理器时间过长,您的程序可能会检测到长时间延迟,并错误地确定程序正在被调试。
SoftICE 是一种本地内核调试器,因此,它不像用户模式调试器那样容易检测到。IsDebuggerPresent API 函数无法检测到 SoftICE 的存在。
要检测 SoftICE,可以使用多种技术
- 搜索 SoftICE 安装目录。如果安装了 SoftICE,则用户可能是黑客或逆向工程人员。
- 检测 int 1 的存在。SoftICE 使用中断 1 进行调试,因此,如果安装了中断 1,则 SoftICE 正在运行。
OllyDbg 是一款流行的 32 位用户模式调试器。不幸的是,最近的几个版本(包括最新版本(v1.10))在处理 Win32 API 函数 OutputDebugString() 时存在漏洞。 [1] 试图阻止其程序被 OllyDbg 调试的程序员可以利用此漏洞使调试器崩溃。作者从未发布过修复程序,但有非官方版本和插件可用于保护 OllyDbg 免受利用此漏洞的攻击。