反调试技术(一)--静态反调试
为了保护自己的程序不被破译等,很多软件使用了反调试技术来阻止逆向程序员对自己程序进行爆破,这同时也催生了另一种技术--反调试破解技术的出现。反调试技术分为静态反调试技术和动态反调试技术。相比来说静态反调试技术更容易实现,破解一般也只需要一次,我们这次就先谈一下静态反调试技术,以及对应的破解之道。
1.PEB结构中有几个重要的成员标示了进程是否处于被调试状态。(以下以32位为例)
+0x002 BeingDebugged : UChar
+0x00c Ldr : _PEB_LDR_DATA
+0x018 ProcessHeap : Ptr32 Void
+0x068 NtGlobalFlag : Uint4B
BeingDebugged成员在被调试状态会显示1,正常情况下为0。解决方法:更改该值为0。
Ldr:进程在被调试状态时堆内存区域会出现一些特殊的标志,未使用的堆内存区域全部填充着0xFEEEFEEE,而Ldr正好在堆内存中被创建(只在XP系统中有,Vista之后的系统没有这种标志)。解决方法:将该区域覆盖为NULL即可。
ProcessHeap:ProcessHeap.Flags(+0x00c)在正常情况下值为0x2,ProcessHeap.ForceFlags成员(+0x10)的值为0x0,当调试时,该值会改变。(只在XP中有效)。解决办法:只需将值改回去即可。
NtGlobalFalg:PEB.NtGlobalFlag会在调试情况下显示0x70,该值是以下Flags值or运算的结果:(附加到进程无效,只有启动调试有效)
FLG_HEAP_ENABLE_TAIL_CHECK (0x10)
FLG_HEAP_ENABLE_FREE_CHECK (0x20)
FLG_HEAP_VALIDATE_PARAMETERS (0x40)
解决方法:重置0即可
2.NtQueryInformationProcess()可以查询ProcessDebugPort(0x7),ProcessDebugObjectHandle(0x1E)ProcessDebugFlags(0x1F)
当进程处于调试状态时,系统会给它分配一个调试端口(Debug Port),正常状态dwDebugPort为,调试状态为0xFFFFFFFF
当进程处于调试状态时,ProcessDebugObjectHandle一个句柄值,正常状态为NULL
当进程处于调试状态时,ProcessDebugFlags为0,正常为1
3.NtQueryObject()函数可以枚举系统所有对象,通过观察系统是否有调试对象句柄,就可以知道是否有进程在被调试。(wcscmp(L"DebugObject",pObjectTypeInfo->TypeName.Buffer)==0),解决方法,改变该函数参数
4.ZwSetInformationThread()该函数顾名思义是给线程设置信息的。该函数有两个参数,第一个参数ThreadHandle为线程句柄,第二参数ThreadInformationClass表示线程信息类型,其值设置为ThreadHideFromDebugger(0x11),调用该函数后,调试进程将会与调试器分离开来,使调试器终止调试,同时终止自身进程。该函数对正常运行程序没有影响。
6.TLS(线程局部存储)TLS函数代码一般先于main()函数执行,于是我们可以在这里进行对程序是否被调试的判断,例如判断是否被下了int3断点,PEB中的BeingDebugged是否为1等。相关具体问题可以看我另一篇关于TLS的博文。
7.ETC利用API获得进程窗口,进程,计算机名称,虚拟机是否在运行状态等判断运行环境是否安全。