反调试浅析
字数 744 2025-08-23 18:31:24

Windows反调试技术详解

1. 基本调试检测方法

1.1 IsDebuggerPresent API

IsDebuggerPresent 是Windows API中最基础的调试检测函数,用于确定当前进程是否被用户模式调试器调试。

#include <windows.h>

BOOL IsDebug() {
    return IsDebuggerPresent();
}

int main() {
    if (IsDebug()) {
        MessageBox(NULL, "Debug", "Debug", NULL);
        return 1;
    } else {
        MessageBox(NULL, "Not", "Not", NULL);
        MessageBox(NULL, "Hello", "Hello", NULL);
    }
}

1.2 PEB结构检测

IsDebuggerPresent内部实际上是检查PEB(Process Environment Block)中的BeingDebugged标志:

#include <windows.h>
#include <iostream>
#include "ntdll.h"

BOOL WINAPI lIsDebuggerPresent(VOID) {
    return (BOOL)NtCurrentPeb()->BeingDebugged;
}

int main() {
    if (lIsDebuggerPresent()) {
        cout << "Is Debug Now" << endl;
        return 1;
    } else {
        cout << "Not Debug" << endl;
    }
}

1.3 直接读取PEB

可以直接从寄存器读取PEB地址来检测调试器:

#include <windows.h>
#include <iostream>
#include "ntdll.h"

BOOL lBeingDebugged() {
    // 获取PEB地址
#if defined(_WIN64)
    PEB* pPEB = (PEB*)__readgsqword(0x60);
#else
    PEB* pPEB = (PEB*)__readfsdword(0x30);
#endif
    BOOL Flag = pPEB->BeingDebugged;
    return Flag;
}

int main() {
    if (lBeingDebugged()) {
        cout << "Is Debug Now" << endl;
        return 1;
    } else {
        cout << "Not Debug" << endl;
    }
}

2. 高级调试检测技术

2.1 CheckRemoteDebuggerPresent

检测指定进程是否处于调试状态:

#include <windows.h>
#include <iostream>

int main() {
    BOOL pbDebuggerPresent;
    BOOL Check = CheckRemoteDebuggerPresent(GetCurrentProcess(), &pbDebuggerPresent);
    
    if (!Check) {
        cout << "CheckRemoteDebuggerPresent Error" << GetLastError() << endl;
        return 1;
    }
    
    cout << "CheckRemoteDebuggerPresent Success" << endl;
    
    if (pbDebuggerPresent) {
        cout << "Is Debug Now" << endl;
        return 1;
    } else {
        cout << "Not Debug" << endl;
        cout << "Hello" << endl;
    }
}

2.2 NtQueryInformationProcess

CheckRemoteDebuggerPresent内部实际上是调用NtQueryInformationProcess

#include <windows.h>
#include <iostream>
#include "ntdll.h"
#pragma comment(lib, "ntdll.lib")

DWORD lBaseSetLastNTError(IN NTSTATUS Status) {
    DWORD dwErrCode;
    dwErrCode = RtlNtStatusToDosError(Status);
    SetLastError(dwErrCode);
    return dwErrCode;
}

BOOL WINAPI lCheckRemoteDebuggerPresent(IN HANDLE hProcess, OUT PBOOL pbDebuggerPresent) {
    HANDLE DebugPort;
    NTSTATUS Status;
    
    if (!(pbDebuggerPresent) || !(hProcess)) {
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }
    
    Status = NtQueryInformationProcess(hProcess, ProcessDebugPort, &DebugPort, sizeof(DebugPort), NULL);
    
    if (NT_SUCCESS(Status)) {
        *pbDebuggerPresent = DebugPort != NULL;
        return TRUE;
    }
    
    lBaseSetLastNTError(Status);
    return FALSE;
}

int main() {
    BOOL pbDebuggerPresent;
    BOOL Check = lCheckRemoteDebuggerPresent(GetCurrentProcess(), &pbDebuggerPresent);
    
    if (!Check) {
        cout << "CheckRemoteDebuggerPresent Error" << GetLastError() << endl;
        return 1;
    }
    
    cout << "CheckRemoteDebuggerPresent Success" << endl;
    
    if (pbDebuggerPresent) {
        cout << "Is Debug Now" << endl;
        return 1;
    } else {
        cout << "Not Debug" << endl;
        cout << "Hello" << endl;
    }
}

2.3 NtGlobalFlag检测

PEB中的NtGlobalFlag在调试状态下通常为0x70

#include <windows.h>
#include <iostream>
#include "ntdll.h"

BOOL lNtGlobalFlag() {
    // 获取PEB地址
#if defined(_WIN64)
    PEB* pPEB = (PEB*)__readgsqword(0x60);
#else
    PEB* pPEB = (PEB*)__readfsdword(0x30);
#endif
    DWORD Flag = pPEB->NtGlobalFlag;
    if (Flag == 0x70) {
        return TRUE;
    }
    return FALSE;
}

int main() {
    if (lNtGlobalFlag()) {
        cout << "Is Debug Now" << endl;
        return 1;
    } else {
        cout << "Not Debug" << endl;
        cout << "Hello" << endl;
    }
}

3. 进程关系检测

3.1 父进程检测

正常情况下进程的父进程是explorer.exe,调试时父进程是调试器:

#include <windows.h>
#include <iostream>
#include "ntdll.h"
#pragma comment(lib, "ntdll.lib")

int main() {
    PROCESS_BASIC_INFORMATION Pro;
    NtQueryInformationProcess(GetCurrentProcess(), ProcessBasicInformation, &Pro, sizeof(Pro), NULL);
    
    HANDLE Handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)Pro.InheritedFromUniqueProcessId);
    wchar_t path[MAX_PATH];
    DWORD maxpath = MAX_PATH;
    QueryFullProcessImageNameW(Handle, 0, path, &maxpath);
    
    if (wcsstr(path, L"explorer.exe") != NULL) {
        cout << "Not Debug" << endl;
    } else {
        cout << "Is Debug Now" << endl;
        return 1;
    }
    system("pause");
}

4. 高级反调试技术

4.1 TLS回调反调试

TLS回调函数在main函数之前执行,可用于早期反调试:

#include <Windows.h>
#include <stdio.h>

void NTAPI __stdcall TLS_CALLBACK(PVOID Dllhandle, DWORD Reason, PVOID Reserved);

// 编译器声明使用TLS
#ifdef _WIN64
#pragma comment(linker, "/INCLUDE:_tls_used")
#pragma comment(linker, "/INCLUDE:_tls_callback")
#else
#pragma comment(linker, "/INCLUDE:__tls_used")
#pragma comment(linker, "/INCLUDE:__tls_callback")
#endif

// 注册TLS回调函数
#ifdef _WIN64
#pragma const_seg(".CRT$XLF")
EXTERN_C const
#else
#pragma data_seg(".CRT$XLF")
EXTERN_C
#endif
PIMAGE_TLS_CALLBACK _tls_callback[] = { TLS_CALLBACK, 0 };

#ifdef _WIN64
#pragma const_seg()
#else
#pragma data_seg()
#endif

// TLS回调函数
void NTAPI __stdcall TLS_CALLBACK(PVOID Dllhandle, DWORD Reason, PVOID Reserved) {
    if (IsDebuggerPresent()) {
        MessageBox(NULL, "Debug", "Debug", NULL);
        ExitProcess(0);
    } else {
        MessageBox(NULL, "No Debug", "No Debug", NULL);
    }
}

int main() {
    MessageBox(NULL, "Hello", "Hello", NULL);
}

4.2 NtSetInformationThread

使线程停止发送调试事件通知:

#include <windows.h>
#include <iostream>
#include "ntdll.h"

void main() {
    NTSTATUS status = NtSetInformationThread(GetCurrentThread(), ThreadHideFromDebugger, NULL, 0);
    cout << "Hello" << endl;
}

4.3 调试信息异常检测

利用调试异常类型检测调试器:

#include <windows.h>
#include <iostream>
#define DBG_PRINTEXCEPTION_WIDE_C 0x4001000A

int main() {
    WCHAR* outputString = (WCHAR*)"Any text";
    ULONG_PTR args[4] = {0};
    args[0] = (ULONG_PTR)wcslen(outputString) + 1;
    args[1] = (ULONG_PTR)outputString;
    
    __try {
        RaiseException(DBG_PRINTEXCEPTION_WIDE_C, 0, 4, args);
        MessageBox(NULL, "Debugging", "Debugging", MB_OK);
    } __except(EXCEPTION_EXECUTE_HANDLER) {
        MessageBox(NULL, "Hello", "Hello", MB_OK);
    }
}

5. 总结

本文详细介绍了Windows平台下多种反调试技术,从基本的API检测到高级的PEB结构检查、TLS回调等。这些技术可以单独使用,也可以组合使用以提高反调试效果。在实际应用中,通常会结合多种技术来增加逆向分析的难度。

Windows反调试技术详解 1. 基本调试检测方法 1.1 IsDebuggerPresent API IsDebuggerPresent 是Windows API中最基础的调试检测函数,用于确定当前进程是否被用户模式调试器调试。 1.2 PEB结构检测 IsDebuggerPresent 内部实际上是检查PEB(Process Environment Block)中的 BeingDebugged 标志: 1.3 直接读取PEB 可以直接从寄存器读取PEB地址来检测调试器: 2. 高级调试检测技术 2.1 CheckRemoteDebuggerPresent 检测指定进程是否处于调试状态: 2.2 NtQueryInformationProcess CheckRemoteDebuggerPresent 内部实际上是调用 NtQueryInformationProcess : 2.3 NtGlobalFlag检测 PEB中的 NtGlobalFlag 在调试状态下通常为 0x70 : 3. 进程关系检测 3.1 父进程检测 正常情况下进程的父进程是explorer.exe,调试时父进程是调试器: 4. 高级反调试技术 4.1 TLS回调反调试 TLS回调函数在main函数之前执行,可用于早期反调试: 4.2 NtSetInformationThread 使线程停止发送调试事件通知: 4.3 调试信息异常检测 利用调试异常类型检测调试器: 5. 总结 本文详细介绍了Windows平台下多种反调试技术,从基本的API检测到高级的PEB结构检查、TLS回调等。这些技术可以单独使用,也可以组合使用以提高反调试效果。在实际应用中,通常会结合多种技术来增加逆向分析的难度。