静态反调试技术(1)

声明

静态反调试目的

被调试的进程用静态反调试技术来侦测自身是否处于被调试状态,若侦测到处于被调试的状态,则执行非常规代码(主要是终止代码)来阻止。具体的实现方法包括调试器检测方法调试环境检测方法强制隔离调试器的方法等等。反调试破解方法主要用来从探测代码获取信息然后修改信息本身使反调试技术失效

注意

许多静态反调试技术对OS具有很强的依懒性。这意味着静态反调试技术在Windows XP 系统下可以正常使用,而在Windows Vista/7操作系统中可能失效

接下来的东西需要用到以下知识,请自行查看:

PEB

https://blog.csdn.net/CSNN2019/article/details/113113347

 +0x002 BeingDebugged    : UChar
 +0x00c Ldr              : Ptr32 _PEB_LDR_DATA
 +0x018 ProcessHeap      : Ptr32 Void
 +0x068 NtGlobalFlag     : Uint4B

BeingDebugged(+0x2)

kernel32.dll中有个名Kernel32!IsDebuggerPresent()的API,但普通的应用程序开发中并不常用:

BOOL WINAPI IsDebuggerPresent()

该API就是用来判断当前进程是否处于调试状态,并返回判断结果。而该API就是通过检测PEB.BeingDebugged成员来确定是否正在调试程序(是,则返回1;否,则返回0)。

老办法,查看一下OD:

在这里插入图片描述
代码如下:

75074E80 >  64:A1 30000000  mov eax,dword ptr fs:[0x30]
75074E86    0FB640 02       movzx eax,byte ptr ds:[eax+0x2]
75074E8A    C3              retn

提示:
Windows 7中,IsDebuggerPresent()API是在Kernelbase.dll中实现的。而在Windows XP 及以前版本的操作系统中,它是在kernel32.dll中。

先获取FS:[30]地址,即PEB地址,然后通过[PEB+2]访问BeingDebugged
在这里插入图片描述
这里取出来的是0的原因呢,是因为吾爱破解OD太强悍了,加了很多插件。。。
在这里插入图片描述
慢慢关闭就行,用原版OD或者IDA就能返回1。

破解之法:

用吾爱破解的OD(滑稽。。哈哈),用OD 的编辑功能把BeingDebugged改为0即可。

Ldr(0xc)

调试进程时,其堆内存区域中就会出现一些特殊标识,表示它正处于被调试状态。其中未使用的堆内存区域全部填充着0xEEFEEEFE,这证明正在调试进程。利用这点可判断进程正在被调试。

PEB.Ldr成员是一个指向_ PEB_ LDR DATA结构体的指针,而 PEB_ LDR _DATA结构体恰好是在堆里面创建的,所以扫描该区域即了轻松查找是否存在0xEEFEEEFE区域
在这里插入图片描述
PEB起始地址为0x3D2000,然后指针指向的区域是0x7710DCA0

在这里插入图片描述
在这里插入图片描述
我看了一下,我的没有。。。有的堆内存中,如果往下拖动滑动条,会看到填充着0xEEFEEEFE的区域。。

破解之法:

只要将填充着0xEEFEEEFE值的区域全部覆写为NULL即可

提示:
该方法仅仅适用于Windows XP系统,而在Windows Vista 以后的系统中则无法使用。另外,利用附加功能的将运行中的进程附加调试器时,堆内存中并不出现上述标识

ProcessHeap(+0x18)

PEB.ProcessHeap(+0x18)成员是指向HEAP结构体的指针

+0x000 Entry						:_HEAP_ENTRY
+0x008 Signature					:Unit4B
+0x00c Flags						:Unit4B
+0x010 ForceFlags					:Unit4B
+0x014 VirtualMemoryThreshold		:Unit4B
+0x018 SegmentReserve				:Unit4B
+0x01c 	SegmentCommit				:Unit4B
+0x020 DeCommitFreeBlockThreshold	:Unit4B
……………………………………………………………………

以上列出了HEAP结构体的部分成员,进程处于调试状态时,Flags(+0xC)与ForceFlags成员(+0x10)被设置为特定值

GetprocessHeap():

PEB.ProcessHeap成员(+0x18)既可以从PEB结构体直接获取,也可以通过GetprocessHeap()API获取。下面看看GetprocessHeap()API的代码
在这里插入图片描述
在这里插入图片描述
直接PEB—>PEB.ProcessHeap顺序访问
在这里插入图片描述
在这里插入图片描述
PEB.ProcessHeap=0x6B0000

Flags(0xC)&Force Flags(+0x10)

进程正常运行(非调试运行)时,Heap.Flags成员(+0xC)的值02,Heap.ForceFlags成员(+0x10)值为0。进程处于被调试状态时,这些值也会随之改变。
在这里插入图片描述

注意:
1.这里我用的是吾爱破解版的OD,插件比较多,内存单元里的值不能作参考。。。
2.该方法仅在Windows XP系统中有效,Windows 7系统则保留ForceFlags属性和Flags属性。此外,将运行中的进程附加到调试器时,也不会出现上述特征。

所以,比较这些值,就可以判断进程是否处于被调试状态。

破解之法:

只要将Heap.Flags成员(+0xC)的值设置成02,Heap.ForceFlags成员(+0x10)值设置成0。

NtGlobalFlag(+0x68)

调试进程时,PEB.NtGlobalFlag成员(+0x68)的值会被设置0x70。所以,检测该成员的值即可判断进程是否处于被调试状态。

NtGlobalFlag 0x70是下列Flags进行bit OR(位或)运算的结果

FLG_HEAP_ENABLE_TAIL_CHECK (0x10)
FLG_HEAP_ENABLE_FREE_CHECK (0x20)
FLG_HEAP_VALIDATE_PARAMETERS (0x40

在这里插入图片描述
在这里插入图片描述
被调试进程的堆内存中存在(不同于非调试运行进程的)特别标识,因此在PEB.NtGlobalFlag成员中添加了上述标志。(注意:这个OD的插件太多了。。。)

注意:
将运行的进程附加到调试器时,PEB.NtGlobalFlag的值不变

破解之法

重设PEB.NtGlobalFlag值为0即可(PEB.NtGlobalFlag=0).

strongOD->Options中的HidePEB可以绕过。

调试程序代码

#include "stdio.h"
#include "windows.h"
#include "tchar.h"
 
void PEB()
{
    
    
    HMODULE hMod = NULL;
    FARPROC pProc = NULL;
    LPBYTE pTEB = NULL;
    LPBYTE pPEB = NULL;
    BOOL bIsDebugging = FALSE;
    
    //<span style="color:#ff0000;">[pPEB+0x2]==0x1</span>
    // IsDebuggerPresent()
    bIsDebugging = IsDebuggerPresent();
    printf("IsDebuggerPresent() = %d\n", bIsDebugging);
    if( bIsDebugging )  printf("  => Debugging!!!\n\n");
    else                printf("  => Not debugging...\n\n");
 
    // Ldr xp特有
    pProc = GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtCurrentTeb");
    pTEB = (LPBYTE)(*pProc)();               // address of TEB
    pPEB = (LPBYTE)*(LPDWORD)(pTEB+0x30);     // address of PEB
 
    printf("PEB.Ldr\n");
    DWORD pLdrSig[4] = {
    
     0xEEFEEEFE, 0xEEFEEEFE, 0xEEFEEEFE, 0xEEFEEEFE };
    LPBYTE pLdr = (LPBYTE)*(LPDWORD)(<span style="color:#ff0000;">pPEB+0xC</span>);
    __try 
    {
    
    
        while( TRUE )
        {
    
    
            if( !memcmp(pLdr, pLdrSig, sizeof(pLdrSig)) )
            {
    
    
                printf("  => Debugging!!!\n\n");
                break;
            }
 
            pLdr++;
        }
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
    
    
        printf("  => Not debugging...\n\n");
    }
 
    // Process Heap - Flags     xp特有
    bIsDebugging = FALSE;
    LPBYTE pHeap = (LPBYTE)*(LPDWORD)(<span style="color:#ff0000;">pPEB+0x18</span>);
    DWORD dwFlags = *(LPDWORD)(<span style="color:#ff0000;">pHeap+0xC</span>);
    printf("PEB.ProcessHeap.Flags = 0x%X\n", dwFlags);
    if( dwFlags != 0x2 )  printf("  => Debugging!!!\n\n");
    else                  printf("  => Not debugging...\n\n");
 
    // Process Heap - ForceFlags xp特有
    bIsDebugging = FALSE;
    DWORD dwForceFlags = *(LPDWORD)(<span style="color:#ff0000;">pHeap+0x10</span>);
    printf("PEB.ProcessHeap.ForceFlags = 0x%X\n", dwForceFlags);
    if( dwForceFlags != 0x0 )  printf("  => Debugging!!!\n\n");
    else                       printf("  => Not debugging...\n\n");
 
    // NtGlobalFlag
    bIsDebugging = FALSE;
    DWORD dwNtGlobalFlag = *(LPDWORD)(<span style="color:#ff0000;">pPEB+0x68</span>);
    printf("PEB.NtGlobalFlag = 0x%X\n", dwNtGlobalFlag);
    if( (dwNtGlobalFlag & 0x70) == 0x70 )  printf("  => Debugging!!!\n\n");
    else                                   printf("  => Not debugging...\n\n");
}
 
int _tmain(int argc, TCHAR* argv[])
{
    
    
    PEB();
 
    printf("\npress any key to quit...\n");
    _gettch();
 
    return 0;
}

反调试技术系列:

静态反调试技术(1)https://blog.csdn.net/CSNN2019/article/details/113105292
静态反调试技术(2)https://blog.csdn.net/CSNN2019/article/details/113147820
静态反调试技术(3)https://blog.csdn.net/CSNN2019/article/details/113178232
动态反调试技术 https://blog.csdn.net/CSNN2019/article/details/113181558
高级反调试技术 https://blog.csdn.net/CSNN2019/article/details/113263215

猜你喜欢

转载自blog.csdn.net/CSNN2019/article/details/113105292