扫一扫
关注微信公众号

恶意软件反检测技术简介:反调试技术解析 (1)
2008-10-13   

在上篇中,我们会为读者介绍恶意软件常用来的反仿真技术。本文中,我们将向读者介绍恶意软件用以阻碍对其进行逆向工程的各种反调试技术,以帮助读者很好的理解这些技术,从而能够更有效地对恶意软件进行动态检测和分析。

一、反调试技术

反调试技术是一种常见的反检测技术,因为恶意软件总是企图监视自己的代码以检测是否自己正在被调试。为做到这一点,恶意软件可以检查自己代码是否被设置了断点,或者直接通过系统调用来检测调试器。

1.断点

为了检测其代码是否被设置断点,恶意软件可以查找指令操作码0xcc(调试器会使用该指令在断点处取得恶意软件的控制权),它会引起一个SIGTRAP。如果恶意软件代码本身建立了一个单独的处理程序的话,恶意软件也可以设置伪断点。用这种方法恶意软件可以在被设置断点的情况下继续执行其指令。

恶意软件也可以设法覆盖断点,例如有的病毒采用了反向解密循环来覆盖病毒中的断点。相反,还有的病毒则使用汉明码自我纠正自身的代码。汉明码使得程序可以检测并修改错误,但是在这里却使病毒能够检测并清除在它的代码中的断点。

2.计算校验和

恶意软件也可以计算自身的校验和,如果校验和发生变化,那么病毒会假定它正在被调试,并且其代码内部已被放置断点。VAMPiRE是一款抗反调试工具,可用来逃避断点的检测。VaMPiRE通过在内存中维护一张断点表来达到目的,该表记录已被设置的所有断点。该程序由一个页故障处理程序(PFH),一个通用保护故障处理程序(GPFH),一个单步处理程序和一个框架API组成。当一个断点被触发的时候,控制权要么传给PFH(处理设置在代码、数据或者内存映射I/O中的断点),要么传给GPFH(处理遗留的I/O断点)。单步处理程序用于存放断点,使断点可以多次使用。

3.检测调试器

在Linux系统上检测调试器有一个简单的方法,只要调用Ptrace即可,因为对于一个特定的进程而言无法连续地调用Ptrace两次以上。在Windows中,如果程序目前处于被调试状态的话,系统调用isDebuggerPresent将返回1,否则返回0。这个系统调用简单检查一个标志位,当调试器正在运行时该标志位被置1。直接通过进程环境块的第二个字节就可以完成这项检查,以下代码为大家展示的就是这种技术:

mov eax, fs:[30h]
move eax, byte [eax+2]
test eax, eax    
jne @DdebuggerDetected

在上面的代码中,eax被设置为PEB(进程环境块),然后访问PEB的第二个字节,并将该字节的内容移入eax。通过查看eax是否为零,即可完成这项检测。如果为零,则不存在调试器;否则,说明存在一个调试器。

如果某个进程为提前运行的调试器所创建的,那么系统就会给ntdll.dll中的堆操作例程设置某些标志,这些标志分别是FLG_HEAP_ENABLE_TAIL_CHECK、FLG_HEAP_ENABLE_FREE_CHECK和FLG_HEAP_VALIDATE_PARAMETERS。我们可以通过下列代码来检查这些标志:

mov eax, fs:[30h]
mov eax, [eax+68h]
and eax, 0x70
test eax, eax
jne @DebuggerDetected

在上面的代码中,我们还是访问PEB,然后通过将PEB的地址加上偏移量68h到达堆操作例程所使用的这些标志的起始位置,通过检查这些标志就能知道是否存在调试器。

检查堆头部内诸如ForceFlags之类的标志也能检测是否有调试器在运行,如下所示:

mov eax, fs:[30h]
mov eax, [eax+18h] ;process heap
mov eax, [eax+10h] ;heap flags
test eax, eax
jne @DebuggerDetected

上面的代码向我们展示了如何通过PEB的偏移量来访问进程的堆及堆标志,通过检查这些内容,我们就能知道Force标志是否已经被当前运行的调试器提前设置为1了。

另一种检测调试器的方法是,使用NtQueryInformationProcess这个系统调用。我们可以将ProcessInformationClass设为7来调用该函数,这样会引用ProcessDebugPort,如果该进程正在被调试的话,该函数将返回-1。示例代码如下所示。

push 0
push 4
push offset isdebugged
push 7 ;ProcessDebugPort
push -1
call NtQueryInformationProcess
test eax, eax
jne @ExitError
cmp isdebugged, 0
jne @DebuggerDetected

在本例中,首先把NtQueryInformationProcess的参数压入堆栈。这些参数介绍如下:第一个是句柄(在本例中是0),第二个是进程信息的长度(在本例中为4字节),接下来是进程信息类别(在本例中是7,表示ProcessDebugPort),下一个是一个变量,用于返回是否存在调试器的信息。如果该值为非零值,那么说明该进程正运行在一个调试器下;否则,说明一切正常。最后一个参数是返回长度。使用这些参数调用NtQueryInformationProcess后的返回值位于isdebugged中。随后测试该返回值是否为0即可。

另外,还有其他一些检测调试器的方法,如检查设备列表是否含有调试器的名称,检查是否存在用于调试器的注册表键,以及通过扫描内存以检查其中是否含有调试器的代码等。

另一种非常类似于EPO的方法是,通知PE加载器通过PE头部中的线程局部存储器(TLS)表项来引用程序的入口点。这会导致首先执行TLS中的代码,而不是先去读取程序的入口点。因此,TLS在程序启动就可以完成反调试所需检测。从TLS启动时,使得病毒得以能够在调试器启动之前就开始运行,因为一些调试器是在程序的主入口点处切入的。


共3页: 1 [2] [3] 下一页
 第 1 页:  第 2 页:探测单步执行
 第 3 页:解除调试器线程

热词搜索:

上一篇:恶意软件反检测技术简介:模拟器超限技术 (1)
下一篇:利用跨站脚本攻击(XSS)摧毁Web(1)

分享到: 收藏