日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

inline hook __usercall 函数

發(fā)布時(shí)間:2025/3/21 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 inline hook __usercall 函数 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

usercall 調(diào)用約定表示這個(gè)函數(shù)用寄存器傳參,hook 它就沒(méi)那么方便,需要整一個(gè)包裝函數(shù)。原理是很簡(jiǎn)單的,下面給個(gè)例子,一看就懂:

說(shuō)明一下我這里用的是 tramp hook 技術(shù),或者叫“蹦床”hook,其實(shí)和普通inline hook也沒(méi)什么區(qū)別,封裝了一下而已。

//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; // 不會(huì)執(zhí)行 }// hook __usercall 這種函數(shù)需要包裝一下 __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);

我有一個(gè) AccessEntInfoList 函數(shù),他用了3個(gè)寄存器傳參,不是標(biāo)準(zhǔn)的調(diào)用約定,于是我就寫一個(gè)裸函數(shù) WrapperHookedAccessEntInfoList,將這三個(gè)寄存器push到棧里,保存其他寄存器,然后 jmp 到 HookedAccessEntInfoList。

HookedAccessEntInfoList 可以按正常函數(shù)的方式編程,定義局部變量都是可以的,返回的時(shí)候要先恢復(fù)寄存器,然后依次將棧里的值彈回給寄存器,然后執(zhí)行被替換的代碼。

hook 用到的工具函數(shù):

BOOL Internal::InlineHook(uintptr_t AddressToHook, size_t nByte, uintptr_t NewAddress) { #ifdef _WIN64InterlockedCompareExchange128return FALSE; #elseif (nByte < 5 || nByte > 8){return FALSE;}// 把原始的8字節(jié)拷貝過(guò)來(lái)BYTE Replace[8] = { 0 };memcpy(Replace, (BYTE*)AddressToHook, 8);Replace[0] = 0xE9;DWORD RelativeAddress = NewAddress - AddressToHook - 5;memcpy(Replace + 1, &RelativeAddress, 4);// 要 patch nByte 個(gè)字節(jié),前5字節(jié)是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 }

總結(jié)

以上是生活随笔為你收集整理的inline hook __usercall 函数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。