Windows 平台反调试相关的技术方法总结—part 3
字数 1297 2025-08-05 08:19:19
Windows平台反调试技术及绕过方法详解
1. SEH(结构化异常处理)反调试技术
1.1 SEH检查原理
SEH(结构化异常处理)是Windows平台的一种异常处理机制,反调试技术可以通过检查SEH处理程序的调用堆栈来检测调试器。
1.2 典型调用堆栈
0:000> kn
# ChildEBP RetAddr
00 0059f06c 775100b1 AntiDebug!ExceptionRoutine
01 0059f090 77510083 ntdll!ExecuteHandler2+0x26
02 0059f158 775107ff ntdll!ExecuteHandler+0x24
03 0059f158 003b11a5 ntdll!KiUserExceptionDispatcher+0xf
04 0059fa90 003d7f4e AntiDebug!main+0xb5
1.3 绕过方法
- 在
ntdll!ExecuteHandler2+0x24处设置断点:
0:000> u ntdll!ExecuteHandler2+24 L3
ntdll!ExecuteHandler2+0x24:
775100af ffd1 call ecx
775100b1 648b2500000000 mov esp,dword ptr fs:[0]
775100b8 648f0500000000 pop dword ptr fs:[0]
0:000> bp 775100af
- 分析每个调用SEH处理程序的代码
2. VEH(向量化异常处理)反调试技术
2.1 VEH原理
VEH是Windows XP引入的SEH变体,处理程序列表存储在ntdll!LdrpVectorHandlerList未导出变量中。
2.2 关键API
PVOID WINAPI AddVectoredExceptionHandler(
ULONG FirstHandler,
PVECTORED_EXCEPTION_HANDLER VectoredHandler);
ULONG WINAPI RemoveVectoredExceptionHandler(
PVOID Handler);
LONG CALLBACK VectoredHandler(
PEXCEPTION_POINTERS ExceptionInfo);
2.3 典型实现示例
LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
{
PCONTEXT ctx = ExceptionInfo->ContextRecord;
if (ctx->Dr0 != 0 || ctx->Dr1 != 0 || ctx->Dr2 != 0 || ctx->Dr3 != 0) {
std::cout << "Stop debugging program!" << std::endl;
exit(-1);
}
ctx->Eip += 2;
return EXCEPTION_CONTINUE_EXECUTION;
}
int main()
{
AddVectoredExceptionHandler(0, ExceptionHandler);
__asm int 1h;
return 0;
}
2.4 绕过方法
- 钩取
KiUserExceptionDispatcher函数:
typedef VOID (NTAPI *pfnKiUserExceptionDispatcher)(
PEXCEPTION_RECORD pExcptRec,
PCONTEXT ContextFrame
);
pfnKiUserExceptionDispatcher g_origKiUserExceptionDispatcher = NULL;
VOID NTAPI HandleKiUserExceptionDispatcher(
PEXCEPTION_RECORD pExcptRec,
PCONTEXT ContextFrame)
{
if (ContextFrame && (CONTEXT_DEBUG_REGISTERS & ContextFrame->ContextFlags)) {
ContextFrame->Dr0 = 0;
ContextFrame->Dr1 = 0;
ContextFrame->Dr2 = 0;
ContextFrame->Dr3 = 0;
ContextFrame->Dr6 = 0;
ContextFrame->Dr7 = 0;
ContextFrame->ContextFlags &= ~CONTEXT_DEBUG_REGISTERS;
}
}
__declspec(naked) VOID NTAPI HookKiUserExceptionDispatcher()
{
__asm {
mov eax, [esp + 4]
mov ecx, [esp]
push eax
push ecx
call HandleKiUserExceptionDispatcher
jmp g_origKiUserExceptionDispatcher
}
}
3. NtSetInformationThread反调试技术
3.1 原理
使用ThreadHideFromDebugger(0x11)信息类隐藏线程,使线程停止发送调试事件通知。
3.2 实现代码
typedef NTSTATUS (NTAPI *pfnNtSetInformationThread)(
_In_ HANDLE ThreadHandle,
_In_ ULONG ThreadInformationClass,
_In_ PVOID ThreadInformation,
_In_ ULONG ThreadInformationLength
);
const ULONG ThreadHideFromDebugger = 0x11;
void HideFromDebugger()
{
HMODULE hNtDll = LoadLibrary(TEXT("ntdll.dll"));
pfnNtSetInformationThread NtSetInformationThread =
(pfnNtSetInformationThread)GetProcAddress(hNtDll, "NtSetInformationThread");
NTSTATUS status = NtSetInformationThread(
GetCurrentThread(),
ThreadHideFromDebugger,
NULL,
0);
}
3.3 绕过方法
钩取NtSetInformationThread函数:
pfnNtSetInformationThread g_origNtSetInformationThread = NULL;
NTSTATUS NTAPI HookNtSetInformationThread(
_In_ HANDLE ThreadHandle,
_In_ ULONG ThreadInformationClass,
_In_ PVOID ThreadInformation,
_In_ ULONG ThreadInformationLength)
{
if (ThreadInformationClass == ThreadHideFromDebugger &&
ThreadInformation == 0 &&
ThreadInformationLength == 0) {
return STATUS_SUCCESS;
}
return g_origNtSetInformationThread(
ThreadHandle,
ThreadInformationClass,
ThreadInformation,
ThreadInformationLength);
}
4. NtCreateThreadEx反调试技术
4.1 原理
使用THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER(0x00000004)标志创建隐藏线程。
4.2 线程创建标志
#define THREAD_CREATE_FLAGS_CREATE_SUSPENDED 0x00000001
#define THREAD_CREATE_FLAGS_SKIP_THREAD_ATTACH 0x00000002
#define THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER 0x00000004
#define THREAD_CREATE_FLAGS_HAS_SECURITY_DESCRIPTOR 0x00000010
#define THREAD_CREATE_FLAGS_ACCESS_CHECK_IN_TARGET 0x00000020
#define THREAD_CREATE_FLAGS_INITIAL_THREAD 0x00000080
4.3 绕过方法
钩取NtCreateThreadEx函数并重置THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER标志。
5. 句柄跟踪反调试技术
5.1 原理
Windows XP引入的句柄跟踪机制会在使用无效句柄时生成EXCEPTION_INVALID_HANDLE异常。
5.2 实现示例
EXCEPTION_DISPOSITION ExceptionRoutine(
PEXCEPTION_RECORD ExceptionRecord,
PVOID EstablisherFrame,
PCONTEXT ContextRecord,
PVOID DispatcherContext)
{
if (EXCEPTION_INVALID_HANDLE == ExceptionRecord->ExceptionCode) {
std::cout << "Stop debugging program!" << std::endl;
exit(-1);
}
return ExceptionContinueExecution;
}
int main()
{
__asm {
// set SEH handler
push ExceptionRoutine
push dword ptr fs:[0]
mov dword ptr fs:[0], esp
}
CloseHandle((HANDLE)0xBAAD);
__asm {
// return original SEH handler
mov eax, [esp]
mov dword ptr fs:[0], eax
add esp, 8
}
return 0;
}
6. 堆栈段操作反调试技术
6.1 原理
操作SS堆栈段寄存器时,调试器会跳过指令跟踪。
6.2 实现示例
push ss
pop ss
mov eax, 0xC000C1EE // 调试器会跳过这行
xor edx, edx // 调试器会直接跳到这里
7. 调试信息反调试技术
7.1 原理
Windows 10后,OutputDebugString改为使用RaiseException实现,通过检查异常处理情况检测调试器。
7.2 实现示例
#define DBG_PRINTEXCEPTION_WIDE_C 0x4001000A
WCHAR * outputString = L"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);
printf("Debugger detected");
}
__except (EXCEPTION_EXECUTE_HANDLER) {
printf("Debugger NOT detected");
}
8. 其他反调试技术
- 自调试过程:程序自身作为调试器运行
- FindWindow检测:查找调试器窗口
- 时间计算方法:检测代码执行时间异常
- NtQueryObject:查询调试对象信息
- BlockInput:阻止用户输入
- NtSetDebugFilterState:设置调试过滤状态
- 自修改代码:动态修改代码防止分析
9. 总结
本文详细介绍了Windows平台常见的反调试技术及其绕过方法,包括:
- SEH/VEH异常处理检测
- 线程隐藏技术(NtSetInformationThread/NtCreateThreadEx)
- 句柄跟踪检测
- 堆栈段操作技巧
- 调试信息异常检测
每种技术都有相应的检测方法和绕过策略,但需要注意的是,没有绝对安全的保护方法,反调试技术的主要目的是增加逆向工程的难度。实际应用中通常会组合多种技术来提高保护强度。