| 在这里,我们设置了一个VEH处理程序并产生中断(不需要int 1h)。在中断生成时,出现异常,控制被传送到VEH处理程序。如果设置了硬件断点,程序执行停止。如果没有硬件断点,则EIP寄存器值会增加2,以在int 1h处生成指令后继续执行。 如何避开硬件断点检查和VEH 我们来看看导致VEH处理程序的调用堆栈: 0:000> kn  # ChildEBP RetAddr   00 001cf21c 774d6822 AntiDebug!ExceptionHandler  01 001cf26c 7753d151 ntdll!RtlpCallVectoredHandlers+0xba02 001cf304 775107ff ntdll!RtlDispatchException+0x7203 001cf304 00bf4a69 ntdll!KiUserExceptionDispatcher+0xf04 001cfc1c 00c2680e AntiDebug!main+0x59  05 001cfc30 00c2665a AntiDebug!invoke_main+0x1e  06 001cfc88 00c264ed AntiDebug!__scrt_common_main_seh+0x15a  07 001cfc90 00c26828 AntiDebug!__scrt_common_main+0xd  08 001cfc98 753e7c04 AntiDebug!mainCRTStartup+0x8  09 001cfcac 7752ad1f KERNEL32!BaseThreadInitThunk+0x24 0a 001cfcf4 7752acea ntdll!__RtlUserThreadStart+0x2f 0b 001cfd04 00000000 ntdll!_RtlUserThreadStart+0x1b 
 我们可以看到,控制从主+ 0x59转移到ntdll!KiUserExceptionDispatcher。让我们看看主+ 0x59中的什么指令导致了这个调用: 0:000> u main+59 L1 AntiDebug!main+0x59 00bf4a69 cd02            int     1       
 这是产生中断的指令, KiUserExceptionDispatcher函数是系统从内核模式调用到用户模式的回调方法之一。以下是它的签名: VOID NTAPI KiUserExceptionDispatcher(     PEXCEPTION_RECORD pExcptRec,      PCONTEXT ContextFrame ); 
 下面就是避开了应用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()  // Params: PEXCEPTION_RECORD pExcptRec, PCONTEXT ContextFrame {     __asm     {         mov eax, [esp + 4]         mov ecx, [esp]         push eax         push ecx         call HandleKiUserExceptionDispatcher         jmp g_origKiUserExceptionDispatcher     } } int main() {     HMODULE hNtDll = LoadLibrary(TEXT("ntdll.dll"));     g_origKiUserExceptionDispatcher = (pfnKiUserExceptionDispatcher)GetProcAddress(hNtDll, "KiUserExceptionDispatcher");     Mhook_SetHook((PVOID*)&g_origKiUserExceptionDispatcher, HookKiUserExceptionDispatcher);     return 0; } 
 在这个例子中,DRx寄存器的值在HookKiUserExceptionDispatcher函数中被复位,即在VEH处理程序调用之前。 NtSetInformationThread —从调试器隐藏线程 (编辑:佛山站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |