
相关函数我们只需要用到 AddVectoredExceptionHandler 设置VEH异常捕获PVOID WINAPIAddVectoredExceptionHandler(_In_ ULONG FirstHandler,_In_ PVECTORED_EXCEPTION_HANDLER VectoredHandler);ULONG WINAPIRemoveVectoredExceptionHandler(_In_ PVOID Handler);PVOID WINAPIAddVectoredContinueHandler(_In_ ULONG FirstHandler,_In_ PVECTORED_EXCEPTION_HANDLER VectoredHandler);ULONG WINAPIRemoveVectoredContinueHandler(_In_ PVOID Handler);设置异常捕获后我们的callback就能处理异常_EXCEPTION_POINTERS 可以获得ExceptionRecordExceptionRecord中还有异常代码(ExceptionCode)和异常地址(ExceptionAddress)VEH HOOK原理1.将需要HOOK的函数入口内容改为0xcc中断如果你不了解中断向量表和int软中断你可以理解为设置了个断点这样运行时就会产生异常2.由我们的异常处理函数捕获后修改寄存器的值(原参数)然后将异常地址指令修改回原值设置TF单步返回EXCEPTION_CONTINUE_EXECUTION程序重新执行正确指令并且由于设置了TF程序可以在下一条指令继续进入异常处理3.在单步异常捕获中继续将上一条HOOK地址指令改回0xcc这样下次进入又会断下来让我们改参数注意这里的例子没有考虑多线程竞争。下面是个DLL你需要自己手动在DLL_PROCESS_ATTACH时运行VEH_HOOK_MessageBoxA();编译后随便写个EXE载入DLL调用MessageBoxA试试吧// Dll.cpp : 定义 DLL 应用程序的导出函数。//// Dll.cpp : 定义 DLL 应用程序的导出函数。//#includestdafx.h#includeDll.h#includestdio.h#defineBREAKPOINTLEN1PVOID MessageBoxA_Addr;BYTE MessageBoxA_New_INT;BYTE MessageBoxA_Ole_INT;DWORD dwNewProtectPAGE_EXECUTE_READWRITE;DWORD dwOldProtect;charlpText[]修改内容;LONG NTAPICALL_MessageBoxA(struct_EXCEPTION_POINTERS*ExceptionInfo){printf_s(异常地址 %p EIP %lx\r\n,ExceptionInfo-ExceptionRecord-ExceptionAddress,ExceptionInfo-ContextRecord-Eip);if(ExceptionInfo-ExceptionRecord-ExceptionCodeEXCEPTION_BREAKPOINT)//判断异常类型是否是断点{PVOID addrExceptionInfo-ExceptionRecord-ExceptionAddress;//获得异常地址if(addrMessageBoxA_Addr){//修改参数*(int*)((ExceptionInfo-ContextRecord-Esp)0x8)(int)lpText;*(int*)((ExceptionInfo-ContextRecord-Esp)0xc)(int)lpText;//DWORD EFlags ExceptionInfo-ContextRecord-EFlags;ExceptionInfo-ContextRecord-EFlags|0x100;//TF//恢复代码VirtualProtect((void*)addr,BREAKPOINTLEN,dwNewProtect,dwOldProtect);*(BYTE*)(addr)MessageBoxA_Ole_INT;//把首个字节地址改回去VirtualProtect((void*)addr,BREAKPOINTLEN,dwOldProtect,dwNewProtect);returnEXCEPTION_CONTINUE_EXECUTION;}returnEXCEPTION_CONTINUE_SEARCH;}if(ExceptionInfo-ExceptionRecord-ExceptionCodeSTATUS_SINGLE_STEP){//TF触发继续改成0xccULONG32 addr(ULONG32)ExceptionInfo-ExceptionRecord-ExceptionAddress;//获得异常地址if(addr(ULONG32)MessageBoxA_Addr8addr(ULONG32)MessageBoxA_Addr){VirtualProtect((void*)MessageBoxA_Addr,BREAKPOINTLEN,dwNewProtect,dwOldProtect);*(BYTE*)(MessageBoxA_Addr)0xcc;//把首个字节地址改回去VirtualProtect((void*)MessageBoxA_Addr,BREAKPOINTLEN,dwOldProtect,dwNewProtect);returnEXCEPTION_CONTINUE_EXECUTION;}returnEXCEPTION_CONTINUE_SEARCH;}returnEXCEPTION_CONTINUE_SEARCH;}voidVEH_HOOK_MessageBoxA(){AddVectoredExceptionHandler(0,CALL_MessageBoxA);//设置VEH异常捕获//AddVectoredExceptionHandler(1, HOOK_MessageBoxA); 如果设置了这个他永远无法恢复被HOOK的东西了因为刚恢复完又被这个改成CC然后无限循环//如果想在HOOK后继续下CC断点我觉得可以使用beginthread和Interlocked 判断是否被恢复被恢复执行完后再改成cc即可MessageBoxA_Addr(PVOID)MessageBoxA;//MessageBoxA地址MessageBoxA_Ole_INT*(BYTE*)MessageBoxA_Addr;//MessageBoxA 首个字节VirtualProtect((void*)MessageBoxA_Addr,BREAKPOINTLEN,dwNewProtect,dwOldProtect);*(BYTE*)(MessageBoxA_Addr)0xcc;//首个字节内容改成CC断点VirtualProtect((void*)MessageBoxA_Addr,BREAKPOINTLEN,dwOldProtect,dwNewProtect);}关于Eflags|0x100看下面的图程序状态字(标志寄存器)TF在8但是开头是从0开始的所以应该在从右向左第9个bit。