SEH(Struct Exception Handler,結構化異常) VEH(Vector Exception Handler,向量異常處理)
SEH是OS提供給線程來感知和處理異常的一種回調機制。
在Intel Win32平臺上,由于FS寄存器問題指向當前的TIB(線程信息塊),因此FS:[0]處能找到最新的一個EXCEPTION_REGISTRATION_RECORD結構。
typedef struct _EXCEPTION_REGISTRATION_RECORD {
??? struct _EXCEPTION_REGISTRATION_RECORD *Next;
??? PEXCEPTION_ROUTINE Handler;
} EXCEPTION_REGISTRATION_RECORD;
EXCEPTION_ROUTINE (
??? _Inout_ struct _EXCEPTION_RECORD *ExceptionRecord,
??? _In_ PVOID EstablisherFrame,
??? _Inout_ struct _CONTEXT *ContextRecord,
??? _In_ PVOID DispatcherContext
??? );
typedef EXCEPTION_ROUTINE *PEXCEPTION_ROUTINE;
typedef struct _EXCEPTION_RECORD {
??? DWORD??? ExceptionCode;
??? DWORD ExceptionFlags;
??? struct _EXCEPTION_RECORD *ExceptionRecord;
??? PVOID ExceptionAddress;
??? DWORD NumberParameters;
??? ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
??? } EXCEPTION_RECORD;
???
XP之后,在基于線程的SEH基礎增加了基于進程的VEH
比較:
1.SEH基于線程,VEH基于進程
2.優先級:調試器 > VEH > SEH?即KiUserExceptionDispatcher()函數先檢查進程是否處理調試,然后VEH,最后SEH.
3.SEH單鏈表,VEH雙鏈表,VEH節點可掛在頭上或尾上。
注冊VEH的回調API:
PVOID WINAPI AddVectoredExceptionHandler(
? __in? ULONG FirstHandler,
? __in? PVECTORED_EXCEPTION_HANDLER VectoredHandler
);
IA-32處理器定義了8個調試寄存器(DR0-DR7) DR0-DR3用于指點內存地址或I/O地址 DR4-DR5保留,DR6事件發生報告詳細信息,DR7定義中斷條件。
硬件斷點HOOK是結合DR0-DR3調試寄存器和Winows SEH或VEH機制所引入的HOOK機制,因不涉及修改代碼,不易檢驗檢測到。
?
//test.exe
#include <stdio.h>
#include <Windows.h>
#include <process.h>DWORD Counter = 0;unsigned __stdcall SecondThreadFunc( void* pArguments )
{while ( Counter < 2 ){MessageBox(NULL,"the fact infor","test SEH hook",MB_OK);Sleep(1000);Counter++;}_endthreadex( 0 );return 0;
} void main()
{HANDLE hThread;unsigned threadID;hThread = (HANDLE)_beginthreadex( NULL, 0, &SecondThreadFunc, NULL, 0, &threadID );::LoadLibraryA("WaiGua.dll");WaitForSingleObject(hThread,INFINITE);MessageBox(NULL,"the fact infor","test SEH hook",MB_OK);
}
?
//hook dll
#include <Windows.h>
#include <TlHelp32.h>
#include <stdio.h>
#include <limits.h>typedef HANDLE (WINAPI *OPENTHREAD) (DWORD dwFlag, BOOL bUnknow, DWORD dwThreadId); OPENTHREAD g_lpfnOpenThread = NULL; DWORD func_addr = 0x00401000;
DWORD func_addr_offset = func_addr + 0x2;void PrintParameters(PCONTEXT debug_context)
{printf("EAX: %X EBX: %X ECX: %X EDX: %X\n",debug_context->Eax, debug_context->Ebx, debug_context->Ecx, debug_context->Edx);printf("ESP: %X EBP: %X\n",debug_context->Esp, debug_context->Ebp);printf("ESI: %X EDI: %X\n",debug_context->Esi, debug_context->Edi);printf("Parameters\n""HWND: %X\n""text: %s\n""caption: %s\n",(HWND)(*(DWORD*)(debug_context->Esp + 0x4)),(char*)(*(DWORD*)(debug_context->Esp + 0x8)),(char*)(*(DWORD*)(debug_context->Esp + 0xC)));}void ChangeText(PCONTEXT debug_context) {char* text = (char*)(*(DWORD*)(debug_context->Esp + 0x8));int length = strlen(text);DWORD oldprotect = 0;VirtualProtect(text,length,PAGE_EXECUTE_READWRITE,&oldprotect);_snprintf(text, length, "hooked that");VirtualProtect(text,length,oldprotect,&oldprotect);
}void __declspec(naked) ReturnOriginalFunc(void) {__asm {mov edi,edi//push ebp way 222jmp [func_addr_offset]}
}LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo) {if(ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP) {if((DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress == func_addr) {//if((DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress == func_addr+2) { way 222PCONTEXT debug_context = ExceptionInfo->ContextRecord;printf("Breakpoint hit!\n");PrintParameters(debug_context);ChangeText(debug_context);debug_context->Eip = (DWORD)&ReturnOriginalFunc;return EXCEPTION_CONTINUE_EXECUTION;}}return EXCEPTION_CONTINUE_SEARCH;
}void SEHHook(void)
{HANDLE hTool32 = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);if(hTool32 != INVALID_HANDLE_VALUE) {THREADENTRY32 thread_entry32;thread_entry32.dwSize = sizeof(THREADENTRY32);FILETIME exit_time, kernel_time, user_time;FILETIME creation_time;FILETIME prev_creation_time;prev_creation_time.dwLowDateTime = 0xFFFFFFFF;prev_creation_time.dwHighDateTime = INT_MAX;HANDLE hMainThread = NULL;if(Thread32First(hTool32, &thread_entry32)) {do { //取最早啟動的線程作為hook對象if(thread_entry32.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(thread_entry32.th32OwnerProcessID)&& thread_entry32.th32OwnerProcessID == GetCurrentProcessId()/*&& thread_entry32.th32ThreadID != GetCurrentThreadId()*/){HANDLE hThread = g_lpfnOpenThread(THREAD_SET_CONTEXT | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION,FALSE, thread_entry32.th32ThreadID);GetThreadTimes(hThread, &creation_time, &exit_time, &kernel_time, &user_time);if(CompareFileTime(&creation_time, &prev_creation_time) == -1) {//creation_time 小于 prev_creation_time時候為-1memcpy(&prev_creation_time, &creation_time, sizeof(FILETIME));if(hMainThread != NULL)CloseHandle(hMainThread);hMainThread = hThread;}elseCloseHandle(hThread);}thread_entry32.dwSize = sizeof(THREADENTRY32);} while(Thread32Next(hTool32, &thread_entry32));(void)SetUnhandledExceptionFilter(ExceptionFilter);CONTEXT thread_context = {CONTEXT_DEBUG_REGISTERS};thread_context.Dr0 = func_addr;//thread_context.Dr0 = func_addr+2; way 222thread_context.Dr7 = (1 << 0);SetThreadContext(hMainThread, &thread_context);CloseHandle(hMainThread);}CloseHandle(hTool32);}
}int APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID reserved)
{if(reason == DLL_PROCESS_ATTACH) {DisableThreadLibraryCalls(hModule);if(AllocConsole()) {freopen("CONOUT$", "w", stdout);SetConsoleTitle("Console");SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);printf("DLL loaded.\n");}HMODULE hDll = ::LoadLibrary("kernel32.dll");g_lpfnOpenThread = (OPENTHREAD)::GetProcAddress(hDll, "OpenThread"); func_addr = (DWORD)GetProcAddress(GetModuleHandle("user32.dll"), "MessageBoxA");func_addr_offset = func_addr+2;//func_addr_offset = func_addr+3; way 222printf("MessageBoxA Addr: 0x%x\n",func_addr);SEHHook();}return TRUE;
}//31: MessageBox(NULL,"the fact infor","test SEH hook",MB_OK);
//008D0365 8B F4 mov esi,esp
//008D0367 6A 00 push 0
//008D0369 68 88 0C 92 00 push 920C88h
//008D036E 68 A4 0C 92 00 push 920CA4h
//008D0373 6A 00 push 0
//008D0375 FF 15 14 84 93 00 call dword ptr ds:[938414h]
//008D037B 3B F4 cmp esi,esp
//008D037D E8 2B A9 FF FF call __RTC_CheckEsp (08CACADh)
//
//_MessageBoxA@16:
//7526FD1E 8B FF mov edi,edi //func_addr is eque to 7526FD1E
//7526FD20 55 push ebp
//7526FD21 8B EC mov ebp,esp
//7526FD23 6A 00 push 0
//7526FD25 FF 75 14 push dword ptr [ebp+14h]
//7526FD28 FF 75 10 push dword ptr [ebp+10h]
//7526FD2B FF 75 0C push dword ptr [ebp+0Ch]
//7526FD2E FF 75 08 push dword ptr [ebp+8]
//7526FD31 E8 A0 FF FF FF call _MessageBoxExA@20 (7526FCD6h)
總結
以上是生活随笔為你收集整理的通过SEH 非inline hook的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。