反调试技术

NtGlobalFlag

在 32 位机器上,NtGlobalFlag字段位于PEB(进程环境块)0x68的偏移处,64 位机器则是在偏移0xBC位置。该字段的默认值为 0。当调试器正在运行时,该字段会被设置为一个特定的值(0x70,FLG_HEAP_ENABLE_TAIL_CHECK (0x10) FLG_HEAP_ENABLE_FREE_CHECK (0x20) FLG_HEAP_VALIDATE_PARAMETERS (0x40))。
1
2
3
4
mov eax, fs:[30h] ;Process Environment Block
mov al, [eax+68h] ;NtGlobalFlag
and al, 70h
cmp al, 70h

Ollydbg对cmp前设置设置断点,运行程序触发断点。然后打开CommandLine插件用dump fs:[30]+0x68dump 出NtGlobalFlag的内容,右键选择Binary->Fill with 00's将值0x70替换为0x00即可。

IsDebuggerPresent

这个函数只是单纯地返回了BeingDebugged标志的值(非0存在调试)。检查BeingDebugged标志位的方法也可以用以下 代码实现,绕过方法:只需要将BeingDebugged标志设为0即可。

#32位代码检查32位环境
mov eax, fs:[30h] ;Process Environment Block
cmp b [eax+2], 0 ;check BeingDebugged
#64位代码检测64位环境
push 60h
pop rsi
gs:lodsq ;Process Environment Block
cmp b [rax+2], 0 ;check BeingDebugged
#32位代码检测64位环境
mov eax, fs:[30h] ;Process Environment Block
cmp b [eax+1002h], 0 ;check BeingDebugged

CheckRemoteDebuggerPresent

1
2
3
4
BOOL WINAPI CheckRemoteDebuggerPresent(
  _In_    HANDLE hProcess,
  _Inout_ PBOOL  pbDebuggerPresent
);

如果调试器存在 (通常是检测自己是否正在被调试),该函数会将pbDebuggerPresent指向的值设为0xffffffffCheckRemoteDebuggerPresent内部其实是通过调用NtQueryInformationProcess

NtQueryInformationProcess

未公开的ntdllNtQueryInformationProcess()函数接受一个信息类的参数用于查询。常用的查询信息类:

  • ProcessDebugPort(7),当进程正在被调试时,返回值为0xffffffff
  • ProcessDebugObjectHandle (0x1e),当进程正在被调试时,返回值为1
  • ProcessDebugFlags (0x1f),当进程正在被调试时,返回值为0

ZwSetInformationThread

关键代码为ZwSetInformationThread(GetCurrentThread(), ThreadHideFromDebugger, 0, 0);,如果处于调试状态,执行完该行代码,程序就会退出。第2个参数为 ThreadHideFromDebugger,其值为 0x11。调试执行到该函数时,若发现第 2 个参数值为 0x11,跳过或者将 0x11 修改为其他值即可。

时间差监测

通过两次GetTickCount()差值判断程序是否处于被调试状态

ProcmonDebugLogger

通过检测设备文件\\\\.\\Global\\ProcmonDebugLogger来检测ProcessMonitor

检测VMware

如果程序在 VMware 内运行,程序使用In指令通过0x5658端口读取数据时, EBX寄存器的值就会变为0x564D5868(0x564D5868 == "VMXh")

.text:0040127D                 mov     eax, 564D5868h   //  <------VMXh
.text:00401282                 mov     ebx, 0
.text:00401287                 mov     ecx, 0Ah
.text:0040128C                 mov     edx, 5658h   //  <------in 0x5658
.text:00401291                 in      eax, dx