Собственно очередная техника перехвата любых функций. только в начало пишется не джамп - а привелегированная инструкция, система генерирует исключение - а обработчик то уже тоже перехвачен. поэтому управление получает наш заранее подготовленный перехватчик. недоработок много - в частности не доделал снятие этого хука - но в этом ничего сложного нет. можете и сами. особые спасиба кезу, который как всегда помог советом и делом =) вообщем, кодоманы, это для вас сорсы с билдом тут - webfile.ru/3886408 пасс 123123 а это кусок движка: Code: ////////////////////////////////////////////////////////////////////////// // (c) Exception hook engine by sn0w. big thx to kez for good advices ;) // (c) cih.[ms] community, 2009 ////////////////////////////////////////////////////////////////////////// #include <windows.h> #include "alldefs.h" ////////////////////////////////////////////////////////////////////////// // анхук не поддерживается, пока. впадлу бля) ////////////////////////////////////////////////////////////////////////// LIST_ENTRY exception_list_head; ////////////////////////////////////////////////////////////////////////// #define InitializeListHead(ListHead) (\ (ListHead)->Flink = (ListHead)->Blink = (ListHead)) #define InsertHeadList(ListHead,Entry) {\ PLIST_ENTRY _EX_Flink;\ PLIST_ENTRY _EX_ListHead;\ _EX_ListHead = (ListHead);\ _EX_Flink = _EX_ListHead->Flink;\ (Entry)->Flink = _EX_Flink;\ (Entry)->Blink = _EX_ListHead;\ _EX_Flink->Blink = (Entry);\ _EX_ListHead->Flink = (Entry);\ } ////////////////////////////////////////////////////////////////////////// PHOOK_ENTRY find_hook_entry(LPVOID real_address) { PLIST_ENTRY current_list; PHOOK_ENTRY pcurr_hook; current_list = exception_list_head.Flink; while(current_list != &exception_list_head){ pcurr_hook = CONTAINING_RECORD(current_list, HOOK_ENTRY, list_entry); if ((DWORD)pcurr_hook->real_address == (DWORD)real_address) return pcurr_hook; current_list = current_list->Flink; } return NULL; } ////////////////////////////////////////////////////////////////////////// VOID (WINAPI * Real_KiUserExceptionDispatcher)(IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextFrame); VOID WINAPI My_KiUserExceptionDispatcher(IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextFrame) { if(ExceptionRecord->ExceptionCode == STATUS_PRIVILEGED_INSTRUCTION){ PHOOK_ENTRY hhk; hhk = find_hook_entry(ExceptionRecord->ExceptionAddress); if(hhk){ ContextFrame->Eip = (DWORD)hhk->handler; NtContinue(ContextFrame, FALSE); } } Real_KiUserExceptionDispatcher(ExceptionRecord,ContextFrame); } ////////////////////////////////////////////////////////////////////////// __declspec(naked) VOID WINAPI Stub_KiUserExceptionDispatcher(IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextFrame) { __asm{ sub esp, 4 jmp My_KiUserExceptionDispatcher } } ////////////////////////////////////////////////////////////////////////// inline void generate_pushret_code(LPVOID at_address, LPVOID to_address) { *(LPBYTE)at_address = 0x68; *(DWORD*)((LPBYTE)at_address + 1) = (DWORD)to_address; *((LPBYTE)at_address + 5) = 0xC3; } ////////////////////////////////////////////////////////////////////////// PHOOK_ENTRY ExceptionHookFunction(LPVOID function, LPVOID handler) { BYTE privileged_opcodes[] = {0xFA, 0xFB, 0xEE, 0xEF, 0xEC, 0x6C, 0x6F}; LPVOID trampoline; DWORD first_inst_len, protection; PHOOK_ENTRY phhk; get_instruction_length(function, &first_inst_len); trampoline = valloc(first_inst_len + 6); memcpy(trampoline, function, first_inst_len); generate_pushret_code((LPVOID)((LPBYTE)trampoline + first_inst_len), (LPVOID)((LPBYTE)function + first_inst_len)); phhk = (PHOOK_ENTRY)valloc(sizeof(HOOK_ENTRY)); phhk->handler = handler; phhk->real_address = function; phhk->trampoline = trampoline; InsertHeadList(&exception_list_head, &phhk->list_entry); VirtualProtect(function, first_inst_len, PAGE_EXECUTE_READWRITE, &protection); *(LPBYTE)function = privileged_opcodes[brandom(0, sizeof(privileged_opcodes) - 1)]; VirtualProtect(function, first_inst_len, protection, &protection); return phhk; } ////////////////////////////////////////////////////////////////////////// void InitializeExceptionHook() { InitializeListHead(&exception_list_head); SpliceHookFunction((DWORD)GetProcAddress(GetModuleHandle("ntdll.dll"), "KiUserExceptionDispatcher"), Stub_KiUserExceptionDispatcher, (DWORD*)&Real_KiUserExceptionDispatcher); } //////////////////////////////////////////////////////////////////////////
В принципе тоже самое можно и реализовать с помощью DebugAPI Так же пищем в начало функции ($CC), при обработке дебага EXCEPTION_EVENT-> EXCEPTION_BREAKPOINT, проводим перехват с помощью OpenThread/SetThreadContext и обработичке перехвата вызываем нужную функцию. Недостаток лишь в том, что оно палиться через kernel32.dll! IsDebuggerPresent, хотя можно эту функцию перехватить и вернуть false
вот такой стаб для IsDebuggerPresent =) Code: LPVOID lpdbg; DWORD prot; char code[] = {0x33, 0xc0, 0xc3}; // xor eax, eax; retn; lpdbg = GetProcAddress(GetModuleHandle("kernel32.dll"), "IsDebuggerPresent"); VirtualProtect(lpdbg, sizeof(code), PAGE_EXECUTE_READWRITE, &prot); memcpy(lpdbg, code, sizeof(code)); VirtualProtect(lpdbg, sizeof(code), prot, &prot); и она никогда не вернет значение того что прога под отладчиком. другой вопрос что ее инструкции Code: mov eax, dword ptr fs:[18] mov eax, dword ptr ds:[eax+30] movzx eax, byte ptr ds:[eax+2] могут использоваться где угодно в программе
А нахера патчить IsDebuggerPresent? Если её код Code: mov eax, fs:[18h]; // адрес TEB mov eax, [eax+30h] // адрес PEB movzx eax, [eax+2h] // флаг BeingDebugged ret Так что можно просто изменить значения в BeingDebugged и всё будет норм и менее паливно. Хотя с другой стороны - привязка к структуре TEB и PEB
вот добавил анхук Code: void ExceptionUnhookFunction(LPVOID real_address) { PLIST_ENTRY pcurr_entry; PHOOK_ENTRY pcurr_item; pcurr_item = find_hook_entry(real_address); if(!pcurr_item) return; //repair function DWORD prot, len; len = get_instruction_length(pcurr_item->trampoline); VirtualProtect(real_address, len, PAGE_EXECUTE_READWRITE, &prot); memcpy(real_address, pcurr_item->trampoline, len); VirtualProtect(real_address, len, prot, &prot); vfree(pcurr_item->trampoline); pcurr_entry = &pcurr_item->list_entry; RemoveEntryList(pcurr_entry); vfree(pcurr_item); }
2sn0w - fix InsertHeadList Code: #if 0 #define InsertHeadList(ListHead,Entry) {\ PLIST_ENTRY _EX_Flink;\ PLIST_ENTRY _EX_ListHead;\ _EX_ListHead = (ListHead);\ _EX_Flink = _EX_ListHead->Flink;\ (Entry)->Flink = _EX_Flink;\ (Entry)->Blink = _EX_ListHead;\ _EX_Flink->Blink = (Entry);\ _EX_ListHead->Flink = (Entry);\ } #endif #define InsertHeadList(ListHead,Entry) do { \ LIST_ENTRY *E_Entry = (Entry); \ LIST_ENTRY *E_ListHead = (ListHead); \ E_Entry->Flink = E_ListHead->Flink; \ E_Entry->Blink = E_ListHead; \ E_ListHead->Flink->Blink = E_Entry; \ E_ListHead->Flink = E_Entry; \ } while (0) побочный эффект в макросе 4 раза вычисляется второй аргумент плюс без do {} while (0) нельзя вставить что то в список в условии if else или придется не ставить точку с запятой после InsertHeadList