Code:
template <class T> static bool MemoryTools::WriteMemory(void* pAddress, T tValue){
if (pAddress && IsReadableMemory(pAddress)){
DWORD dwOldProtect = 0;
if (VirtualProtect(pAddress, sizeof(T), PAGE_READWRITE, &dwOldProtect))
{
*(T*)pAddress = tValue;
if (dwOldProtect != PAGE_READWRITE)
VirtualProtect(pAddress, sizeof(T), dwOldProtect, &dwOldProtect);
return true;
}
}
return false;
}
//struct for handling API hooks
struct APIHookInfo{
unsigned long id;
PVOID pTarget; //api to be hooked;
PVOID pTrampoline; //trampoline for our API;
PVOID pDetour; //detour function;
unsigned long dwBackupSize; //size of overritten data;
BYTE IPs[0x10]; //overritten data;
APIHookInfo(){
static unsigned long nextid = 0;
id = ++nextid;
pTarget = pTrampoline = pDetour = nullptr;
dwBackupSize = NULL;
memset(IPs, 0, 0x10);
}
bool operator == (APIHookInfo i){
return (this->id == i.id);
}
};
#define MakePtr(ptr1, ptr2, type) (type)((DWORD_PTR)ptr1 + (DWORD_PTR)ptr2)
#define MakeDelta(ptr1, ptr2, type) (type)((DWORD_PTR)ptr1 - (DWORD_PTR)ptr2)
unsigned long APIHook::GetInstructionSize(PVOID lpInstruction){ //this function uses hde32 / hde64
if (lpInstruction && MemoryTools::IsReadableMemory(lpInstruction)){
hde_struct e = hde_struct();
return hde_disasm(lpInstruction, &e);
}
return 0;
}
PVOID APIHook::HookFunction(APIHook::APIHookInfo i){
PauseThreads();
DWORD dwOldProtect = 0; //Used for virtual protection.
if (i.dwBackupSize == NULL){
while (i.dwBackupSize < 5){
i.dwBackupSize += GetInstructionSize(MakePtr(i.pTarget, i.dwBackupSize, PVOID));
}
}
i.pTrampoline = new BYTE[i.dwBackupSize + 6]; //backup + jmp size + retn
VirtualProtect(i.pTarget, i.dwBackupSize, PAGE_READWRITE, &dwOldProtect);
memcpy(i.pTrampoline, i.pTarget,
i.dwBackupSize);
memcpy(i.IPs, i.pTarget,
i.dwBackupSize);
memset(i.pTarget, 0x90, i.dwBackupSize); //memset function
MemoryTools::WriteMemory<BYTE>(i.pTarget, 0xE9); //0xE9 (opcode for relative jmp)
MemoryTools::WriteMemory<DWORD>(MakePtr(i.pTarget, 1, PVOID), (unsigned long)i.pDetour - (unsigned long)i.pTarget - 5); //Sets the offset
VirtualProtect(i.pTarget, i.dwBackupSize, dwOldProtect, &dwOldProtect);
MemoryTools::WriteMemory<BYTE>(MakePtr(i.pTrampoline, i.dwBackupSize, PVOID), 0xE9);
MemoryTools::WriteMemory<DWORD>(MakePtr(i.pTrampoline, i.dwBackupSize + 1, PVOID),
(unsigned long)i.pTarget - (unsigned long)i.pTrampoline - 5);
MemoryTools::WriteMemory<BYTE>(MakePtr(i.pTrampoline, i.dwBackupSize + 5, PVOID), 0xC3);
FlushInstructionCache(GetCurrentProcess(), 0, 0);
hookList.push_back(i); //adds this hook to the "hook" list
ResumeThreads();
return i.pTrampoline;
}
PVOID APIHook::UnhookFunction(APIHook::APIHookInfo i){
PauseThreads();
DWORD dwOldProtect = 0; //Used for virtual protection.
if (i.dwBackupSize == NULL){
while (i.dwBackupSize < 5){
i.dwBackupSize += GetInstructionSize(MakePtr(i.pTarget, i.dwBackupSize, PVOID));
}
}
VirtualProtect(i.pTarget, i.dwBackupSize, PAGE_READWRITE, &dwOldProtect);
memcpy(i.pTarget, i.IPs, i.dwBackupSize);
VirtualProtect(i.pTarget, i.dwBackupSize, dwOldProtect, &dwOldProtect);
delete i.pTrampoline;
FlushInstructionCache(GetCurrentProcess(), 0, 0);
ResumeThreads();
for (std::vector<APIHookInfo>::iterator a = hookList.begin(); a < hookList.end(); a++){
if (*a == i){
hookList.erase(a);
break;
}
}
return i.pTarget;
}
PVOID APIHook::HookFunction(PVOID lpFunction, PVOID lpDetourFunction){
APIHookInfo i = APIHookInfo();
i.pTarget = lpFunction;
i.pDetour = lpDetourFunction;
return HookFunction(i);
}
PVOID APIHook::UnhookFunction(PVOID lpFunction){
for (auto &i : hookList){
if (i.pTarget == lpFunction) return UnhookFunction(i);
}
return nullptr;
}