inline hook __usercall 函数
生活随笔
收集整理的這篇文章主要介紹了
inline hook __usercall 函数
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
usercall 調用約定表示這個函數用寄存器傳參,hook 它就沒那么方便,需要整一個包裝函數。原理是很簡單的,下面給個例子,一看就懂:
說明一下我這里用的是 tramp hook 技術,或者叫“蹦床”hook,其實和普通inline hook也沒什么區別,封裝了一下而已。
//int* __usercall AccessEntInfoList@<eax>(int a1@<ecx>, int a2@<ebx>, int a3@<esi>) int* __cdecl HookedAccessEntInfoList(int a1, int a2, int a3) {EntInfoList = a1 + 0x188;__asm{leavepopfdpopadpop ecxpop ebxpop esijmp OldAccessEntInfoList}return 0; // 不會執行 }// hook __usercall 這種函數需要包裝一下 __declspec(naked) void WrapperHookedAccessEntInfoList() {__asm{push esipush ebxpush ecxpushadpushfdjmp HookedAccessEntInfoList} }typedef int* (__cdecl *tAccessEntInfoList)(int a1, int a2, int a3); tAccessEntInfoList OldAccessEntInfoList = NULL; // 蹦床 // hook client.dll + 204660 to get the ent info list OldAccessEntInfoList = (tAccessEntInfoList)Internal::HookFunction((uintptr_t)hClientDll + (uintptr_t)0x204660, 6, (uintptr_t)WrapperHookedAccessEntInfoList);我有一個 AccessEntInfoList 函數,他用了3個寄存器傳參,不是標準的調用約定,于是我就寫一個裸函數 WrapperHookedAccessEntInfoList,將這三個寄存器push到棧里,保存其他寄存器,然后 jmp 到 HookedAccessEntInfoList。
HookedAccessEntInfoList 可以按正常函數的方式編程,定義局部變量都是可以的,返回的時候要先恢復寄存器,然后依次將棧里的值彈回給寄存器,然后執行被替換的代碼。
hook 用到的工具函數:
BOOL Internal::InlineHook(uintptr_t AddressToHook, size_t nByte, uintptr_t NewAddress) { #ifdef _WIN64InterlockedCompareExchange128return FALSE; #elseif (nByte < 5 || nByte > 8){return FALSE;}// 把原始的8字節拷貝過來BYTE Replace[8] = { 0 };memcpy(Replace, (BYTE*)AddressToHook, 8);Replace[0] = 0xE9;DWORD RelativeAddress = NewAddress - AddressToHook - 5;memcpy(Replace + 1, &RelativeAddress, 4);// 要 patch nByte 個字節,前5字節是JMP,其余是 NOPfor (size_t i = 5; i < nByte; i++){Replace[i] = 0x90;}AtomicWrite64(AddressToHook, *(LONG64*)Replace);return TRUE; #endif }BOOL Internal::Nop(uintptr_t BeginAddress, size_t nByte) {return Internal::InlineHook(BeginAddress, 5, BeginAddress + nByte); }uintptr_t Internal::HookFunction(uintptr_t FunctionToHook, size_t nByte, uintptr_t NewFunction) { #ifdef _WIN64 return 0; #elseif (nByte < 5 || nByte > 8) return 0;// Create the gateway (len + 5 for the overwritten bytes + the jmp)uintptr_t gateway = (uintptr_t)VirtualAlloc(0, nByte + 5, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);// Put the bytes that will be overwritten in the gatewaymemcpy((void*)gateway, (void*)FunctionToHook, nByte);// Get the gateway to destination addyuintptr_t gateJmpAddy = FunctionToHook - gateway - 5;// Add the jmp opcode to the end of the gateway*(BYTE*)(gateway + nByte) = (BYTE)0xE9;// Add the address to the jmp*(uintptr_t*)(gateway + nByte + 1) = gateJmpAddy;if (Internal::InlineHook((uintptr_t)FunctionToHook, nByte, (uintptr_t)NewFunction)){return gateway;}else return 0; #endif }void Internal::UnhookFunction(uintptr_t FunctionToUnhook, size_t nByte, uintptr_t Gateway) { #ifdef _WIN64 return 0; #elseBYTE BytesToReplace[8] = { 0 };Internal::Read(FunctionToUnhook, TRUE, BytesToReplace, 8);BYTE OriginalBytes[8] = { 0 };Internal::Read(Gateway, TRUE, OriginalBytes, nByte);memcpy(BytesToReplace, OriginalBytes, nByte);AtomicWrite64(FunctionToUnhook, *(LONG64*)BytesToReplace);VirtualFree((LPVOID)Gateway, 0, MEM_RELEASE); #endif }總結
以上是生活随笔為你收集整理的inline hook __usercall 函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用 rsync / scp 命令下载l
- 下一篇: ida demangled names