BeingDebugged标记
最简单也最常用的反调试方法就是使用IsDebuggerPresent函数了,它返回一个标志位BeingDebugged,这个标志位存在于PEB(进程环境块)中,偏移位置为0x2
IsDebuggerPresent(void)
{
return NtCurrentPeb()->BeingDebugged;
}
要找到BeingDebugged在当前进程的地址,就得先找到PEB的地址,PEB的地址是无法直接获取到的,我们可以通过TEB(线程环境块)来找到PEB。Windows在调入进程、创建线程时,操作系统会为每个线程分配TEB,且fs段寄存器总是被设置为使得地址fs:[0]指向当前线程的TEB数据。
在TEB结构偏移0x30处就是PEB的地址了。而偏移0x18处则指向了TEB本身。
加密与解密中提供了从外部代码去除某进程BeingDebugged标志的方式,可以作为调试器的插件去除这种反调试方法。但BeingDebugged标记在生成时还留下了一些后患。
LdrpInitialize函数是一个新进程的初始线程开始在用户态执行的最早代码,在这个函数内部有一段这样的代码:
if (Peb->BeingDebugged) {
Peb->NtGlobalFlag |= FLG_HEAP_ENABLE_FREE_CHECK |
FLG_HEAP_ENABLE_TAIL_CHECK |
FLG_HEAP_VALIDATE_PARAMETERS;
}
这说明BeingDebugged被设置为1后,NtGlobalFlag也被设置了一个标记,通过调试可发现这个标记为0x70。
那么NtGlobalFlag有没有向BeingDebugged一样留下痕迹呢?是有的,在初始化堆的函数RtlCreateHeap中可以找到相应代码。
if (NtGlobalFlag & FLG_HEAP_VALIDATE_PARAMETERS) {
Flags |= HEAP_VALIDATE_PARAMETERS_ENABLED;
}
...
if (DEBUG_HEAP(Flags)) {
return RtlDebugCreateHeap(Flags, ···);
}
DEBUG_HEAP是一个宏,总之在这里会返回1,然后进入RtlDebugCreateHeap函数。RtlDebugCreateHeap内部实际上又调用了RtlCreateHeap,不过这次Flags参数又多了几个属性,分别是HEAP_SKIP_VALIDATION_CHEC