反调试技术大致分为静态反调试和动态反调试 。静态的只要在开始破解一次就可解除全部反调试限制。而动态的则要一边调试,一边破解。这里简单描述下静态反调试的实现方法。许多静态反调试技术对OS有较强的依赖性,这意味着有些反调试技术在不同的平台上可能会失效。
一.PEB(进程环境块)
mov eax, dword ptr FS:[0x30] //直接获取PEB的地址,
或者
mov eax, dword ptr Fs:[0x18] //TEB的起始地址
mov eax , dword ptr ds:[eax+30] //PEB的地址
1 ,BeingDebugged(0x2)
调试状态下,PEB.BeingDebugged 成员(0x2)的值设置为1。
非调试状态下,其值设置为0.
IsDebuggerPresent() API 来获取PEB.BeingDebugged的值来判断进程是否处于被调试状态。
破解之法:借助ollydbg调试器的编辑功能,将PEB.BeingDebugged的值修改为0即可
2,ldr(0xc)
调试进程时,堆内存中会出现一些特殊标识,表示正处于被调试状态,其中最醒目的就是未使用的堆内存区域全部填充着0xFEEEFEEE。根据这一原理,我们可以判断进程是否处于调试状态。
根据相应的偏移位置找到PEB.ldr位置,查找0xFEEEFEEE,
破解之法:将填充着0xFEEEFEEE的区域全部覆盖为NULL即可
注意:该方法只适用windows xp系统,在vista 之后的系统则无法使用。另外,利用附加进程将运行中的进程附加到调试器,堆内存也不会出现上述标识。
3.Process Heap(0x18)
PEB.ProcessHeap成员是指向HEAD结构体的指针。其中比较重要的是Flags(+0xC)成员和Force Flags(+0x10).
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.。进程被调试时这些值都会改变。所以比较这些值就可以判断进程是否被调试。
破解之法:将heap.flags的值修改为0x2. heap.Forceflags的值修改为0x0。
注意:该方法只适用windows xp系统,在win7之后的系统则无法使用。另外,利用附加进程将运行中的进程附加到调试器,堆内存也不会出现上述标识。
4.NtGlobalFlag(0x68)
调试进程时,PEB.NtGlobalFlag成员的值会被设置为0x70.所以检测该成员的值即可判断是否处于被调试状态。NtGlobalFlag 0x70是flags值进行位或运算的结果。
被调试进程的堆内存中存在特殊标识,所以在成员中添加了上述标识。
破解之法:将PEB.NtGlobalFlag的值设为0即可。
二,API
1,NtqueryInformationProcess()
通过NtqueryInformationProcess API可以获取各种与进程调试相关的信息。
函数定义中有几个重要的成员,ProcessDebugPort(0x7).ProcessDebugObject-Handle(0x1E)。ProcessDebugFlags(0x1F).
ProcessDebugPort(0x7)
进程处于调试状态,系统会为它分配一个调试端口,ProcessInformationClass参数的值为ProcessDebugPort(0x7).若程序处于非调试状态,则变量dwDebugPort的值设置为0,若进程处于调试状态,则值设置为0xFFFFFFF.
使用CheckRemoteDebuggerPresent() API,可以查看是否调用了NtqueryInformationProcess(),
破解之法:使用CheckRemoteDebuggerPresent()
ProcessDebugObjectHandle(0x1E)
调试进程时会生成调试对象,函数的第二个参数值为ProcessDebugObjectHandle,调用参数后就能获取调试对象句柄,进程处于调试状态时,调试对象句柄的值就存在,若进程处于非调试状态,则调试对象句柄值为NULL.
ProcessDebugFlags(0x1F)
检测debug flag调试标志的值也可以判断是否处于被调试状态,函数 的第二个参数设置为processdebugflag(0x1)时,调用函数后通过第三个参数即可获的调试标志的值,若为0,则进程处于被调试状态,若为1,则进程处于非调试状态。
2,NtquerySystemInformation()
ntdll!NtquerySystemInformation()API是一个系统函数,用来获取当前运行的多种OS信息。
向SystemInformationclass参数传入Systemkerneldebuggerinformation的值(0X23)即可判断出当前系统是否处于调试模式下进行。
当API返回时,若系统处在调试模式下,第二个参数的值设置为1,
破解之法:windows xp系统中编辑boot.ini文件,删除 "/debugport=com1 /baudrate=115200 /Debug"值。
windows 7系统的命令窗口执行bsdedit/debug off 命令即可。并且若重启系统则要以正常模式启动。
3,NTQueryObject()
系统中的某个调试器调试进程时,会创建一个调试对象类型的内核对象。检测该对象是否存在课判断是否有进程正在被调试。
ntdll!NtqueryObject()API用来获取各种内核对象的信息,
破解之法,钩取API.
4,ZwSetInformationThread()
强制分离被调试者和调试器的技术。利用ZwSetInformationThread()API可将被调试者和调试器分离出来。
该函数是一个原生API,用来为线程设置信息的,有两个参数,一是用来接收线程的句柄,二是表示线程信息类型,若其值设置为threadhideformdebugger(0x11),调用该函数后,调试进程就会被分离出来。
破解之法:把threadhideformdebugger(0x11)的值修改为0后继续运行即可。
当然也可以钩取相应的API.
提示:其工作原理是将线程隐藏起来,调试器就接收不到信息,从而无法调试。而且,windows Xp之后新增了DebugActiveProcessstop()API.
5,TLS回调函数
6,ETC
很多反调试技术是借助win32API获取系统信息来实现。
检测ollydbg窗口 findWindow()
检测ollydbg进程 createToolhelp32snapshot()
检测计算机名称是否为“Test”,“analysis”,等 getcomputername()
检测程序运行路径中是否存在“test”,"sample".等名称 getcomandline()
检测虚拟机是否处于运行状态,虚拟机特有的进程名称 vmwareservice.exe vmwareTray.exe vmwareUser.exe