<逆向工程核心原理> 静态反调试技术总结

1.PEB

#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;
}

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


2.ntdll.dll的NtQueryInformationProcess()

#include "stdio.h"
#include "windows.h"
#include "tchar.h"

enum PROCESSINFOCLASS
{
    ProcessBasicInformation = 0,
    ProcessQuotaLimits,
    ProcessIoCounters,
    ProcessVmCounters,
    ProcessTimes,
    ProcessBasePriority,
    ProcessRaisePriority,
    ProcessDebugPort = 7,
    ProcessExceptionPort,
    ProcessAccessToken,
    ProcessLdtInformation,
    ProcessLdtSize,
    ProcessDefaultHardErrorMode,
    ProcessIoPortHandlers,
    ProcessPooledUsageAndLimits,
    ProcessWorkingSetWatch,
    ProcessUserModeIOPL,
    ProcessEnableAlignmentFaultFixup,
    ProcessPriorityClass,
    ProcessWx86Information,
    ProcessHandleCount,
    ProcessAffinityMask,
    ProcessPriorityBoost,
    MaxProcessInfoClass,
    ProcessWow64Information = 26,
    ProcessImageFileName = 27,
    ProcessDebugObjectHandle = 30,
    ProcessDebugFlags = 31,
    SystemKernelDebuggerInformation = 35
};

void MyNtQueryInformationProcess()
{
    typedef NTSTATUS (WINAPI *NTQUERYINFORMATIONPROCESS)(
        HANDLE ProcessHandle,
        PROCESSINFOCLASS ProcessInformationClass,
        PVOID ProcessInformation,
        ULONG ProcessInformationLength,
        PULONG ReturnLength
    );

    NTQUERYINFORMATIONPROCESS pNtQueryInformationProcess = NULL;

    pNtQueryInformationProcess = (NTQUERYINFORMATIONPROCESS)
                                 GetProcAddress(GetModuleHandle(L"ntdll.dll"), 
                                                "NtQueryInformationProcess");

    // ProcessDebugPort (0x7)
    DWORD dwDebugPort = 0;
    pNtQueryInformationProcess(GetCurrentProcess(),
                               ProcessDebugPort,
                               &dwDebugPort,
                               sizeof(dwDebugPort),
                               NULL);
    printf("NtQueryInformationProcess(ProcessDebugPort) = 0x%X\n", dwDebugPort);
    if( dwDebugPort != 0x0  )  printf("  => Debugging!!!\n\n");
    else                       printf("  => Not debugging...\n\n");

    // ProcessDebugObjectHandle (0x1E)
    HANDLE hDebugObject = NULL;
    pNtQueryInformationProcess(GetCurrentProcess(),
                               ProcessDebugObjectHandle,
                               &hDebugObject,
                               sizeof(hDebugObject),
                               NULL);
    printf("NtQueryInformationProcess(ProcessDebugObjectHandle) = 0x%X\n", hDebugObject);
    if( hDebugObject != 0x0  )  printf("  => Debugging!!!\n\n");
    else                        printf("  => Not debugging...\n\n");

    // ProcessDebugFlags (0x1F)
    BOOL bDebugFlag = TRUE;
    pNtQueryInformationProcess(GetCurrentProcess(),
                               ProcessDebugFlags,
                               &bDebugFlag,
                               sizeof(bDebugFlag),
                               NULL);
    printf("NtQueryInformationProcess(ProcessDebugFlags) = 0x%X\n", bDebugFlag);
    if( bDebugFlag == 0x0  )  printf("  => Debugging!!!\n\n");
    else                      printf("  => Not debugging...\n\n");
}

int _tmain(int argc, TCHAR* argv[])
{
    MyNtQueryInformationProcess();

    printf("\npress any key to quit...\n");
    _gettch();

    return 0;
}

strongOD->Options中的*KernelMode可以绕过。


3.NTQuerySystemInformation()

#include "stdio.h"
#include "windows.h"
#include "tchar.h"

void MyNtQuerySystemInformation()
{
   //检测当前OS是否运行在调试模式下,WinDbg
    typedef NTSTATUS (WINAPI *NTQUERYSYSTEMINFORMATION)(
        ULONG SystemInformationClass,
        PVOID SystemInformation,
        ULONG SystemInformationLength,
        PULONG ReturnLength
    );

    typedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION 
    {
        BOOLEAN DebuggerEnabled;
        BOOLEAN DebuggerNotPresent;
    } SYSTEM_KERNEL_DEBUGGER_INFORMATION, *PSYSTEM_KERNEL_DEBUGGER_INFORMATION;

    NTQUERYSYSTEMINFORMATION NtQuerySystemInformation;
  
    NtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION)  
                                GetProcAddress(GetModuleHandle(L"ntdll"), 
                                               "NtQuerySystemInformation");

    ULONG SystemKernelDebuggerInformation = 0x23;
    ULONG ulReturnedLength = 0;
    SYSTEM_KERNEL_DEBUGGER_INFORMATION DebuggerInfo = {0,};

    NtQuerySystemInformation(SystemKernelDebuggerInformation, 
                             (PVOID) &DebuggerInfo, 
                             sizeof(DebuggerInfo),      // 2 bytes
                             &ulReturnedLength);

    printf("NtQuerySystemInformation(SystemKernelDebuggerInformation) = 0x%X 0x%X\n", 
           DebuggerInfo.DebuggerEnabled, DebuggerInfo.DebuggerNotPresent);
    if( DebuggerInfo.DebuggerEnabled )  printf("  => Debugging!!!\n\n");
    else                                printf("  => Not debugging...\n\n");
}

int _tmain(int argc, TCHAR* argv[])
{
     //基于调试环境检测反调试
    // boot.ini  /debug 
    MyNtQuerySystemInformation();

    printf("\npress any key to quit...\n");
    _gettch();

    return 0;
}

4.NTQueryObject()

#include "stdio.h"
#include "windows.h"
#include "tchar.h"

typedef enum _OBJECT_INFORMATION_CLASS {
    ObjectBasicInformation,
    ObjectNameInformation,
    ObjectTypeInformation,
  <span style="color:#ff0000;">  ObjectAllTypesInformation,</span>
    ObjectHandleInformation
} OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS;

void MyNtQueryObject()
{
     //基于检测调试环境
    //系统中的某个调试器调试进程时,会创建1个调试对象类型的内核对象。检测该对象
    //是否存在即可判断是否有进程正在被调试(注意不是当前进程)。
    typedef struct _LSA_UNICODE_STRING {
        USHORT Length;
        USHORT MaximumLength;
        PWSTR Buffer;
    } LSA_UNICODE_STRING, *PLSA_UNICODE_STRING, UNICODE_STRING, *PUNICODE_STRING;

    typedef NTSTATUS (WINAPI *NTQUERYOBJECT)(
        HANDLE Handle,
        OBJECT_INFORMATION_CLASS ObjectInformationClass,
        PVOID ObjectInformation,
        ULONG ObjectInformationLength,
        PULONG ReturnLength
    );
    
    #pragma pack(1)
    typedef struct _OBJECT_TYPE_INFORMATION {
        UNICODE_STRING TypeName;
        ULONG TotalNumberOfHandles;
        ULONG TotalNumberOfObjects;
    }OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;

    typedef struct _OBJECT_ALL_INFORMATION {
        ULONG                   NumberOfObjectsTypes;
        OBJECT_TYPE_INFORMATION ObjectTypeInformation[1];
    } OBJECT_ALL_INFORMATION, *POBJECT_ALL_INFORMATION;
    #pragma pack()
       
    POBJECT_ALL_INFORMATION pObjectAllInfo = NULL;
    void *pBuf = NULL;
    ULONG lSize = 0;
    BOOL bDebugging = FALSE;

    NTQUERYOBJECT pNtQueryObject = (NTQUERYOBJECT)
                                    GetProcAddress(GetModuleHandle(L"ntdll.dll"), 
                                                   "NtQueryObject");

    // Get the size of the list
    pNtQueryObject(NULL, ObjectAllTypesInformation, &lSize, sizeof(lSize), &lSize);

    // Allocate list buffer
    pBuf = VirtualAlloc(NULL, lSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

    // Get the actual list
    pNtQueryObject((HANDLE)0xFFFFFFFF, ObjectAllTypesInformation, pBuf, lSize, NULL);

    pObjectAllInfo = (POBJECT_ALL_INFORMATION)pBuf;

    UCHAR *pObjInfoLocation = (UCHAR *)pObjectAllInfo->ObjectTypeInformation;
    POBJECT_TYPE_INFORMATION pObjectTypeInfo = NULL;
    for( UINT i = 0; i < pObjectAllInfo->NumberOfObjectsTypes; i++ )
    {
        pObjectTypeInfo = (POBJECT_TYPE_INFORMATION)pObjInfoLocation;
     <span style="color:#ff0000;">   if( wcscmp(L"DebugObject", pObjectTypeInfo->TypeName.Buffer) == 0 )
        {
            bDebugging = (pObjectTypeInfo->TotalNumberOfObjects > 0) ? TRUE : FALSE;
            break;
        }</span>
        
        // calculate next struct
        pObjInfoLocation = (UCHAR*)pObjectTypeInfo->TypeName.Buffer;
        pObjInfoLocation += pObjectTypeInfo->TypeName.Length;
        pObjInfoLocation = (UCHAR*)(((ULONG)pObjInfoLocation & 0xFFFFFFFC) + sizeof(ULONG));
    }

    if( pBuf )
    VirtualFree(pBuf, 0, MEM_RELEASE);

    printf("NtQueryObject(ObjectAllTypesInformation)\n");
    if( bDebugging )  printf("  => Debugging!!!\n\n");
    else              printf("  => Not debugging...\n\n");
}

int _tmain(int argc, TCHAR* argv[])
{
    MyNtQueryObject();

    printf("\npress any key to quit...\n");
    _gettch();

    return 0;
}

strongOD->Options中的*KernelMode可以绕过。


5.ZwSetInformationThread()


#include "stdio.h"
#include "windows.h"
#include "tchar.h"

void DetachDebugger()
{
    //强制分离被调试者和调试器的技术。调试器与被调试进程同时终止
    typedef enum _THREAD_INFORMATION_CLASS {
        ThreadBasicInformation,
        ThreadTimes,
        ThreadPriority,
        ThreadBasePriority,
        ThreadAffinityMask,
        ThreadImpersonationToken,
        ThreadDescriptorTableEntry,
        ThreadEnableAlignmentFaultFixup,
        ThreadEventPair,
        ThreadQuerySetWin32StartAddress,
        ThreadZeroTlsCell,
        ThreadPerformanceCount,
        ThreadAmILastThread,
        ThreadIdealProcessor,
        ThreadPriorityBoost,
        ThreadSetTlsArrayAddress,
        ThreadIsIoPending,
       <span style="color:#ff0000;"> ThreadHideFromDebugger           // 17 (0x11)</span>
    } THREAD_INFORMATION_CLASS, *PTHREAD_INFORMATION_CLASS;

    typedef NTSTATUS (WINAPI* ZWSETINFORMATIONTHREAD)(
        HANDLE ThreadHandle,
        THREAD_INFORMATION_CLASS ThreadInformationClass,
        PVOID ThreadInformation,
        ULONG ThreadInformationLength
    );

    ZWSETINFORMATIONTHREAD pZwSetInformationThread = NULL;
    pZwSetInformationThread = (ZWSETINFORMATIONTHREAD)
                              GetProcAddress(GetModuleHandle(L"ntdll.dll"), 
                                             "ZwSetInformationThread");

    pZwSetInformationThread(GetCurrentThread(), ThreadHideFromDebugger, NULL, 0);

    printf("ZwSetInformationThread() -> Debugger detached!!!\n\n");
}

int _tmain(int argc, TCHAR* argv[])
{
    DetachDebugger();

    printf("\npress any key to quit...\n");
    _gettch();

    return 0;
}
经过测试,此方法在XP可行,但在WIN7无效。


6.TLS回调函数

7.检测窗口 FindWindow,FindWindowEx  检测进程 CreateToolHelp32Snapshoot

#include "stdio.h"
#include "windows.h"
#include "tchar.h"

void FindDebuggerWindow()
{
    BOOL bDebugging = FALSE;

    // using ClassName
    if( FindWindow(L"OllyDbg", NULL) ||                  // OllyDbg
        FindWindow(L"TIdaWindow", NULL) ||               // IDA Pro
        FindWindow(L"WinDbgFrameClass", NULL) )          // Windbg
        bDebugging = TRUE;

    printf("FindWindow()\n");
    if( bDebugging )    printf("  => Found a debugger window!!!\n\n");
    else                printf("  => Not found a debugger window...\n\n");

    // using WindowName
    bDebugging = FALSE;
    TCHAR szWindow[MAX_PATH] = {0,};

    HWND hWnd = GetDesktopWindow();
    hWnd = GetWindow(hWnd, GW_CHILD);
    hWnd = GetWindow(hWnd, GW_HWNDFIRST);
    while( hWnd )
    {
        if( GetWindowText(hWnd, szWindow, MAX_PATH) )
        {
            if( _tcsstr(szWindow, L"IDA") ||
                _tcsstr(szWindow, L"OllyDbg") ||
                _tcsstr(szWindow, L"WinDbg") )
            {
                bDebugging = TRUE;
                break;
            }
        }

        hWnd = GetWindow(hWnd, GW_HWNDNEXT);
    }

    printf("GetWindowText()\n");
    if( bDebugging )    printf("  => Found a debugger window!!!\n\n");
    else                printf("  => Not found a debugger window...\n\n");
}

int _tmain(int argc, TCHAR* argv[])
{
    FindDebuggerWindow();

    printf("\npress any key to quit...\n");
    _gettch();

    return 0;
}


 

你可能感兴趣的:(<逆向工程核心原理> 静态反调试技术总结)