静态反调试技术总结
静态反调试技术
静态反调试技术只需要在程序运行之前进行一次破解即可解除全部限制,且不需要二次操作。而且静态反调试技术对于操作系统的依赖性非常大,相同的反调试技术在不同的操作系统表现可能不同。这里举例表述几个较为常用的反调试技术。
利用PEB结构体进行反调试
mov eax,dword ptr fs:[0x30] // 直接获取PEB结构体的地址 mov eax,dword ptr fs:[0x18] //先获取TEB结构体的地址 mov eax,dword ptr fs:[eax+30] //通过TEB结构体获取指向PEB结构体的指针
PEB结构体的0x2偏移处所含立即数是PEB.BeingDebugger成员,若进程未处于被调试状态,则该成员值为0,否则为1。
mov eax,fs:[0x30] inc eax inc eax //两步eax+1到达了PEB结构体的0x2偏移处 mov eax,[eax] and eax,0x000000ff test eax,eax jne rt_label jmp rt_label
破解方法就是追踪PEB.BeingDebugged 的值然后进行修改。
利用进程堆(HEAP)进行反调试
PEB.ProcessHeap成员是指向HEAD结构体的指针,其中比较重要的是FLAGS成员和Force FLAG成员。
mov eax, dword ptr fs:[0x18] //TEB的起始地址 mov eax , dword ptr ds:[eax+30] //PEB的地址 mov eax , dword ptr ds:[eax+18] /PEB.Processheap的地址
进程正常运行时,heap.flags的值为0x2,heap.Forceflags的值为0x0,当被调试时这些值都会被改变。
利用PEB_NtGlobalFlags进行反调试
PEB_NtGlobalFlags 位于PEB环境中偏移为0x68的位置,当进程被调试的时候,该成员的值为0x70
mov eax, fs:[30h] mov eax, [eax+68h] and eax, 0x70 test eax, eax jne rt_label jmp rf_label
利用NtqueryInformationProcess() API进行反调试
该API当中含有几个重要成员,其中一个为ProcessDebugPort(0x7),进程被调试的时候,系统会为其分配一个调试端口,以便于调试器相连接。
当程序处于调试状态的时候,Port值会变成0xFFFFFFFF ,处于非调试状态的时候会变成0。
使用CheckRemoteDebuggerPresent() 可以查看是否调用了NtquerylnformationProcess() API
利用ProcessDebugFlags进行反调试
检测debug flag调试标志的值也可以判断是否处于被调试状态,调用函数后通过该函数的第三个参数即可获得调试标志的值,若为0 则处于被调试状态,若为1则处于非调试状态。
利用Find_Debugger_Window()进行反调试
该API所起的作用是寻找目标调试器窗口,如果发现,则进行反调试操作。
//ollyice hWnd=CWnd::FindWindow(_T("1212121"),NULL); if (hWnd!=NULL) return true; //ollydbg v1.1 hWnd=CWnd::FindWindow(_T("icu_dbg"),NULL); if (hWnd!=NULL) return true; //ollyice pe--diy hWnd=CWnd::FindWindow(_T("pe--diy"),NULL); if (hWnd!=NULL) return true; //ollydbg ?-°? hWnd=CWnd::FindWindow(_T("ollydbg"),NULL); if (hWnd!=NULL) return true; //ollydbg ?-°? hWnd=CWnd::FindWindow(_T("odbydyk"),NULL); if (hWnd!=NULL) return true; //windbg hWnd=CWnd::FindWindow(_T("WinDbgFrameClass"),NULL); if (hWnd!=NULL) return true; //dede3.50 hWnd=CWnd::FindWindow(_T("TDeDeMainForm"),NULL); if (hWnd!=NULL) return true; //IDA5.20 hWnd=CWnd::FindWindow(_T("TIdaWindow"),NULL); if (hWnd!=NULL) return true; //others hWnd=CWnd::FindWindow(_T("TESTDBG"),NULL); if (hWnd!=NULL) return true; hWnd=CWnd::FindWindow(_T("kk1"),NULL); if (hWnd!=NULL) return true; hWnd=CWnd::FindWindow(_T("Eew75"),NULL); if (hWnd!=NULL) return true; hWnd=CWnd::FindWindow(_T("Shadow"),NULL); if (hWnd!=NULL) return true; //PEiD v0.94 hWnd=CWnd::FindWindow(NULL,"PEiD v0.94"); if (hWnd!=NULL) return true; //RegMON hWnd=CWnd::FindWindow(NULL,"Registry Monitor - Sysinternals: www.sysinternals.com"); if (hWnd!=NULL) return true; //File Monitor hWnd=CWnd::FindWindow(NULL,"File Monitor - Sysinternals: www.sysinternals.com"); if (hWnd!=NULL) return true; //Import Rec v1.6 hWnd=CWnd::FindWindow(NULL,"Import REConstructor v1.6 FINAL (C) 2001-2003 MackT/uCF"); if (hWnd!=NULL) return true; return false;
利用Find_Device_Driver()进行反调试
调试工具通常会使用内核驱动,因此如果尝试是否可以打开一些调试器所用到的设备,就可以判断是否存在调试器。
\\.\SICE (SoftICE)
\\.\SIWVID(SoftICE)
\\.\NTICE (SoftICE)
\\.\REGVXG(RegMON)
\\.\REGVXD(RegMON)
\\.\REGSYS(RegMON)
\\.\REGSYS(RegMON)
\\.\FILEVXG(FileMON)
\\.\FILEM(FileMON)
\\.\TRW(TRW2000)
利用Exception_Int3()进行反调试
INT3会产生异常中断,当INT3被执行到的时候,如果程序未被调试,将会异常处理器程序继续执行,如果处于被调试状态,则会被调试器误认为是自己的一个断点,从而不进入异常处理程序。
__asm { push offset exception_handler; set exception handler push dword ptr fs:[0h] mov dword ptr fs:[0h],esp xor eax,eax;reset EAX invoke int3 int 3h pop dword ptr fs:[0h];restore exception handler add esp,4 test eax,eax; check the flag je rt_label jmp rf_label exception_handler: mov eax,dword ptr [esp+0xc];EAX = ContextRecord mov dword ptr [eax+0xb0],0xffffffff;set flag (ContextRecord.EAX) inc dword ptr [eax+0xb8];set ContextRecord.EIP xor eax,eax retn rt_label: xor eax,eax inc eax mov esp,ebp pop ebp retn rf_label: xor eax,eax mov esp,ebp pop ebp retn }
利用OutpuDebugString()进行反调试技术
在调试器不存在和存在两种情况下,该API 的结果是不同的,如果有调试器存在,GetLastError()的返回值为零。
OutputDebugString(""); tmpD=GetLastError(); if(tmpD==0) return true; return false;
利用VMWare_VMX进行反调试技术
VMware提供一种主机与客户机之间进行通信的方式,这里可以被用作一种VMWARE的反调试,Vmware将会处理IN(端口为0x5658/'VX')指令,它会返回一个magic数值“VMXh”到ebx寄存器当中。
当在保护模式操作系统下的ring3运行时,in指令的执行将会产生异常,除非我们修改了I/O的优先级等级,然而,如果在Vmware下运行,则不会产生任何异常,正常运行,且EBX寄存器但当中会含有'VMXh' magic数值,ECX寄存器当中含有VMWARE的产品ID.
这种技巧在病毒中比较常见,称为"in指令反调试"。
bool IsInsideVMWare_() { bool r; _asm { push edx push ecx push ebx mov eax, 'VMXh' mov ebx, 0 // any value but MAGIC VALUE mov ecx, 10 // get VMWare version mov edx, 'VX' // port number in eax, dx // read port // on return EAX returns the VERSION cmp ebx, 'VMXh' // is it a reply from VMWare? setz [r] // set return value pop ebx pop ecx pop edx } return r; } bool FV_VMWare_VMX() { __try { return IsInsideVMWare_(); } __except(1) // 1 = EXCEPTION_EXECUTE_HANDLER { return false; } }