5.4 搞定反调试机制
现在的病毒是越来越狡猾了,无论是在感染,传播还是在反分析方面。一方面,将代码打包或者加密代码使代码模糊化,另一个方面使用反调试机制,郁闷调试者。接下来我们将 了解常用反调试机制,并用 Immunity 调试器和 Python 创造自己的脚本绕过反调试机制。
5.4.1 IsDebuggerPresent
现在最常用的反调试机制就是用 IsDebuggerPresent(由 kernel32.导出)。函数不需要参 数,如果发现有调试器附加到当前进程,就返回 1,否则返回 0.如果我们反汇编这个函数:
7C813093 >/$ 64:A1 18000000 MOV EAX,DWORD PTR FS:[18]
7C813099 |. 8B40 30 MOV EAX,DWORD PTR DS:[EAX+30]
7C81309C |. 0FB640 02 MOVZX EAX,BYTE PTR DS:[EAX+2]
7C8130A0 \. C3 RETN
代码通过不断的寻址找到能证明进程被调试的数据位,第一行,通过 FS 寄存器的第 0x18 位找到 TIB(线程信息块)的地址。第二行通过 TIB 的第 0x30 位找到 PEB(进程环境信息块) 的地址。第三行将 PEB 的 0x2 位置上的 BeingDebugged 变量存在 EAX 寄存器中,如果有调 试器附加到进程,该值为 0x1。Damian Gomez 提供了一个简单的方式绕过 IsDebuggerPresent, 可以很方便的在 Immunity 执行,或者在 PyCommand 中调用。
imm.writeMemory( imm.getPEBaddress() + 0x2, "\x00" )
上面的代码将 PEB 的 BeingDebugged 标志就当的设置成0.现在病毒无法使用 IsDebuggerPresent 来判断了调试器了,它傻了。
5.4.2 解决进程枚举
病毒会测试枚举所有运行的进程以确认是否有调试器在运行。举个例子,如果你正在用 Immunity 调试 一个病毒,就会注册一个名为 ImmunityDebugger.exe 的进程。病毒通过用 Process32First 查找第一个注册的进程,接着用 Process32Next 循环获取剩下的进程。这两个 函数调用会返回一个布尔值,告诉调用者函数是否执行成功。我们重要将函数的返回值(存 储在 EAX 寄存器中),就当的设置为 0 就能够欺骗那些调用者了。代码如下:
process32first = imm.getAddress("kernel32.Process32FirstW")
process32next = imm.getAddress("kernel32.Process32NextW")
function_list = [ process32first, process32next ]
patch_bytes = imm.Assemble( "SUB EAX, EAX\nRET" )
for address in function_list:
opcode = imm.disasmForward( address, nlines = 10 )
imm.writeMemory( opcode.address, patch_bytes )
首先获取两个函数的地址,将它们放到列表中。然后将一段补丁代码汇编成操作码,代 码将 EAX 设置成 0,然后返回。接下来反汇编 Process32First 和 Process32Next 函数第十行 的代码。这样做的目的就是一些高级的病毒会确认函数的头部是否被修改过。我们在第 10行再写入补丁,就能瞒天过海了。然后简单的将我们的补丁代码写入第 10 行,现在无论怎 么调用两个函数都会返回失败。
我们通过两个例子讲解了如何使用 Python 和 Immunity 调试器,使病毒无法发现我们。 越来越多的的反调试技术将在病毒中使用,对付他们的方法也不会完结。但是 Immunity 无 疑将会成为你对付病毒或者开发 exploit 的利器。
接下来看看在逆向工程中的 hooking 技术。