反调试浅析
字数 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回调等。这些技术可以单独使用,也可以组合使用以提高反调试效果。在实际应用中,通常会结合多种技术来增加逆向分析的难度。