Update Notes

Clean up DLL-Injector code
Fix Crash in DX8 EndScene Hook
Update Hook.c to change whole page protection instead of first few bytes
Add Hashtable parser and dumper
Add keyboard shortcut to toggle DX8 overlay
Add VMT Hooking (currently not working)
Add Cleanup function that gets called on DLL-Unload
This commit is contained in:
Daniel S. 2019-03-04 15:11:47 +01:00
parent 3976fdea37
commit 3a9ab54240
12 changed files with 275 additions and 100 deletions

View file

@ -65,7 +65,7 @@ Points to GameState struct
## Entity Hash Table ## Entity Hash Table
Hashfunction used: [strhash](http://www.cs.ecu.edu/karl/3300/spr16/Notes/DataStructure/hashtable.html) Hashfunction used: [PJW](https://en.wikipedia.org/wiki/PJW_hash_function) (Same parameters as the example implementation)
Entry format: Entry format:
@ -81,6 +81,7 @@ Data format:
| ------ | ----------- | -------------------- | | ------ | ----------- | -------------------- |
| 0x0 | void** | Virtual Method Table | | 0x0 | void** | Virtual Method Table |
| 0x4 | const char* | name as string | | 0x4 | const char* | name as string |
| 0x14 | void* | pointer to self |
| 0x28 | float[3] | Position | | 0x28 | float[3] | Position |
# File Formats # File Formats

View file

@ -156,7 +156,7 @@ bool Injected(DWORD PID)
return HasModule(PID, DLL_NAME); return HasModule(PID, DLL_NAME);
} }
void InjectDll(DWORD PID, bool do_resume = false) void InjectDll(DWORD PID)
{ {
HANDLE hRemThread, hProc; HANDLE hRemThread, hProc;
const char *dll_name = DLL_NAME; const char *dll_name = DLL_NAME;
@ -175,42 +175,34 @@ void InjectDll(DWORD PID, bool do_resume = false)
if (HasModule(PID, dll_name)) if (HasModule(PID, dll_name))
{ {
cout << "[*] DLL already Loaded" << endl; cout << "[*] DLL already Loaded" << endl;
} CloseHandle(hProc);
else return;
};
if (!fexists(dll_full_path))
{ {
if (!fexists(dll_full_path)) cout << "[!] DLL file not found!" << endl;
{ CloseHandle(hProc);
cout << "[!] DLL file not found!" << endl; return;
return;
}
HINSTANCE hK32 = LoadLibraryA("kernel32");
cout << "[*] Getting Address of LoadLibrary" << endl;
LPVOID LoadLibrary_Address = (LPVOID)GetProcAddress(hK32, "LoadLibraryA");
FreeLibrary(hK32);
cout << "[+] LoadLibrary is at " << LoadLibrary_Address << endl;
cout << "[*] Allocating " << strlen(dll_full_path) << " Bytes of Memory" << endl;
LPVOID mem = VirtualAllocEx(hProc, NULL, strlen(dll_full_path), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (mem == NULL)
{
cout << "[!] Could not Allocate Memory: " << GetLastErrorAsString() << endl;
return;
}
cout << "[*] Writing DLL Name to Process Memory at " << mem << endl;
WriteProcessMemory(hProc, mem, dll_full_path, strlen(dll_full_path), 0);
cout << "[*] Creating Thread to Load DLL" << endl;
if (do_resume)
{
hRemThread = CreateRemoteThread(hProc, 0, 0, (LPTHREAD_START_ROUTINE)LoadLibrary_Address, mem, CREATE_SUSPENDED, 0);
ResumeThread(hRemThread);
}
else
{
hRemThread = CreateRemoteThread(hProc, 0, 0, (LPTHREAD_START_ROUTINE)LoadLibrary_Address, mem, 0, 0);
}
cout << "[*] Waiting for DLL to load" << endl;
WaitForSingleObject(hRemThread, INFINITE);
CloseHandle(hRemThread);
} }
HINSTANCE hK32 = LoadLibraryA("kernel32");
cout << "[*] Getting Address of LoadLibrary" << endl;
LPVOID LoadLibrary_Address = (LPVOID)GetProcAddress(hK32, "LoadLibraryA");
FreeLibrary(hK32);
cout << "[+] LoadLibrary is at " << LoadLibrary_Address << endl;
cout << "[*] Allocating " << strlen(dll_full_path) << " Bytes of Memory" << endl;
LPVOID mem = VirtualAllocEx(hProc, NULL, strlen(dll_full_path), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (mem == NULL)
{
cout << "[!] Could not Allocate Memory: " << GetLastErrorAsString() << endl;
return;
}
cout << "[*] Writing DLL Name to Process Memory at " << mem << endl;
WriteProcessMemory(hProc, mem, dll_full_path, strlen(dll_full_path), 0);
cout << "[*] Creating Thread to Load DLL" << endl;
hRemThread = CreateRemoteThread(hProc, 0, 0, (LPTHREAD_START_ROUTINE)LoadLibrary_Address, mem, 0, 0);
cout << "[*] Waiting for DLL to load" << endl;
WaitForSingleObject(hRemThread, INFINITE);
CloseHandle(hRemThread);
cout << "[*] Closing Process Handle" << endl; cout << "[*] Closing Process Handle" << endl;
CloseHandle(hProc); CloseHandle(hProc);
return; return;

View file

@ -5,72 +5,89 @@ uintmax_t frame = 0;
DWORD* GetVTable(void* addr) { DWORD* GetVTable(void* addr) {
return (DWORD*)(*(DWORD*)addr); return (DWORD*)(*(DWORD*)addr);
} }
bool overlay = false;
LPD3DXFONT m_pFont;
HFONT hFont;
HBRUSH hBrush;
D3DCOLOR color = D3DCOLOR_XRGB(255, 0, 0);
RECT Rect = { 0,0,0,0 };
D3DRECT panel;
void Render(LPDIRECT3DDEVICE8 dev) { void Render(LPDIRECT3DDEVICE8 dev) {
char text[MAX_PATH]; if (!overlay) {
LPD3DXFONT m_pFont; return;
HFONT hFont;
RECT Rect={0,0,0,0};
D3DCOLOR color = D3DCOLOR_XRGB(255, 0, 0);
hFont = CreateFont(50, 0, 0, 0, FW_BOLD, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, "Verdana");
D3DXCreateFont(dev, hFont, &m_pFont);
snprintf(text, MAX_PATH, "Frame: %d", ++frame);
if (m_pFont) {
m_pFont->Begin();
m_pFont->DrawTextA(text, -1, &Rect, DT_CALCRECT, 0);
m_pFont->DrawTextA(text, -1, &Rect, DT_LEFT, color);
m_pFont->End();
m_pFont->Release();
m_pFont = nullptr;
} }
char text[MAX_PATH];
snprintf(text, MAX_PATH, "Frame: [%lld]\nTest", ++frame);
if (m_pFont == nullptr) {
D3DXCreateFont(dev, hFont, &m_pFont);
CloseHandle(hFont);
}
m_pFont->Begin();
m_pFont->DrawTextA(text, -1, &Rect, DT_CALCRECT, 0);
dev->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(25, 0, 0, 0),0.5,0);
m_pFont->DrawTextA(text, -1, &Rect, DT_LEFT, color);
m_pFont->End();
} }
HRESULT WINAPI H_EndScene(LPDIRECT3DDEVICE8 dev) { HRESULT WINAPI H_EndScene(LPDIRECT3DDEVICE8 dev) {
typedef HRESULT(WINAPI *t_func)(LPDIRECT3DDEVICE8); typedef HRESULT(WINAPI *t_func)(LPDIRECT3DDEVICE8);
shared_ptr<Hook> hook = Hook::get(H_EndScene); shared_ptr<Hook> hook = Hook::get(H_EndScene);
t_func func = reinterpret_cast<t_func>(hook->func()); _asm push esi;
_asm pushad;
Render(dev); Render(dev);
hook->disable(); hook->disable();
HRESULT ret = func(dev); HRESULT ret = hook->func<t_func>()(dev);
hook->enable(); hook->enable();
_asm popad;
_asm pop esi;
return ret; return ret;
} }
HRESULT WINAPI H_CreateDevice(void* pDirect3D, unsigned int uiAdapter, D3DDEVTYPE pDeviceType, HWND hFocusWindow, HRESULT WINAPI H_CreateDevice(void* pDirect3D, unsigned int uiAdapter, D3DDEVTYPE pDeviceType, HWND hFocusWindow,
unsigned long ulBehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, unsigned long ulBehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters,
LPDIRECT3DDEVICE8* ppReturnedDeviceInterface) { LPDIRECT3DDEVICE8* ppReturnedDeviceInterface) {
_asm push esi;
_asm pushad;
typedef HRESULT(WINAPI *t_func)(void*, unsigned int, D3DDEVTYPE, HWND, unsigned long, D3DPRESENT_PARAMETERS*, LPDIRECT3DDEVICE8*); typedef HRESULT(WINAPI *t_func)(void*, unsigned int, D3DDEVTYPE, HWND, unsigned long, D3DPRESENT_PARAMETERS*, LPDIRECT3DDEVICE8*);
shared_ptr<Hook> hook = Hook::get(H_CreateDevice); shared_ptr<Hook> hook = Hook::get(H_CreateDevice);
t_func func = reinterpret_cast<t_func>(hook->func());
hook->disable(); hook->disable();
HRESULT ret = func(pDirect3D, uiAdapter, pDeviceType, hFocusWindow, ulBehaviorFlags, pPresentationParameters, ppReturnedDeviceInterface); HRESULT ret = hook->func<t_func>()(pDirect3D, uiAdapter, pDeviceType, hFocusWindow, ulBehaviorFlags, pPresentationParameters, ppReturnedDeviceInterface);
cout << "Ret:" << ret << endl; cout << "CreateDevice ->" << ret << endl;
DWORD *vtable = GetVTable(ppReturnedDeviceInterface[0]); void* EndScene = reinterpret_cast<void*>(GetVTable(ppReturnedDeviceInterface[0])[35]);
cout << "Dev VTable @ " << vtable << endl; cout << "EndScene @ " << EndScene << endl; // EndScene
cout << "Dev VTable[35]: " << (void*)(vtable[35]) << endl; // EndScene Hook::addr(EndScene, H_EndScene);
Hook::addr((void*)vtable[35], H_EndScene);
Hook::drop(H_CreateDevice); Hook::drop(H_CreateDevice);
_asm popad;
_asm pop esi;
return ret; return ret;
} }
LPDIRECT3D8 WINAPI H_Direct3DCreate8(unsigned int SDKVersion) { LPDIRECT3D8 WINAPI H_Direct3DCreate8(unsigned int SDKVersion) {
typedef LPDIRECT3D8(_stdcall *t_func)(unsigned int); typedef LPDIRECT3D8(_stdcall *t_func)(unsigned int);
shared_ptr<Hook> hook = Hook::get(H_Direct3DCreate8); shared_ptr<Hook> hook = Hook::get(H_Direct3DCreate8);
t_func func = reinterpret_cast<t_func>(hook->func());
_asm push esi;
_asm pushad;
hook->disable(); hook->disable();
D3DPRESENT_PARAMETERS D3D_Present_Param = { 0,0,D3DFMT_UNKNOWN,0,D3DMULTISAMPLE_NONE,D3DSWAPEFFECT_DISCARD,0,1,0,D3DFMT_UNKNOWN,0,0,0 }; LPDIRECT3D8 ret = hook->func<t_func>()(SDKVersion);
LPDIRECT3D8 ret = func(SDKVersion);
cout << "D3D8-Create: " << SDKVersion << " -> " << ret << endl; cout << "D3D8-Create: " << SDKVersion << " -> " << ret << endl;
DWORD *vtable = GetVTable(ret); void *CreateDevice = reinterpret_cast<void*>(GetVTable(ret)[15]);
cout << "ID3D8 VTable @ " << vtable << endl; cout << "CreateDevice @ " << CreateDevice << endl; // CreateDevice
cout << "ID3D8 VTable[15]: " << (void*)(vtable[15]) << endl; // CreateDevice Hook::addr(CreateDevice, H_CreateDevice);
Hook::addr((void*)vtable[15], reinterpret_cast<void*>(H_CreateDevice));
Hook::drop(H_Direct3DCreate8); Hook::drop(H_Direct3DCreate8);
_asm popad;
_asm pop esi;
return ret; return ret;
} }
void hook_d3d8() { void hook_d3d8() {
hFont = CreateFont(20, 0, 0, 0, FW_BOLD, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, "Verdana");
hBrush = CreateSolidBrush(D3DCOLOR_ARGB(25, 0, 0, 0));
Hook::module("d3d8.dll","Direct3DCreate8", H_Direct3DCreate8); Hook::module("d3d8.dll","Direct3DCreate8", H_Direct3DCreate8);
} }

View file

@ -1,19 +1,18 @@
#pragma once #pragma once
#include <functional> #include <functional>
class Hook;
class Hook class Hook
{ {
private: private:
DWORD protect; MEMORY_BASIC_INFORMATION mbi;
void* orig; void* orig;
void* detour; void* detour;
bool enabled; bool enabled;
uint8_t orig_bytes[6]; uint8_t orig_bytes[6];
uint8_t jmp_bytes[6]; uint8_t jmp_bytes[6];
static map<uintptr_t, shared_ptr<Hook>> hooks; static map<uintptr_t, shared_ptr<Hook>> hooks;
public: public:
Hook(void* func, void* detour) { Hook(void* func, void* detour) {
uintptr_t dest = reinterpret_cast<uintptr_t>(detour); uintptr_t dest = reinterpret_cast<uintptr_t>(detour);
uintptr_t src = reinterpret_cast<uintptr_t>(func); uintptr_t src = reinterpret_cast<uintptr_t>(func);
@ -25,16 +24,18 @@ public:
this->jmp_bytes[3] = (dest >> 16) & 0xff; this->jmp_bytes[3] = (dest >> 16) & 0xff;
this->jmp_bytes[4] = (dest >> 24) & 0xff; this->jmp_bytes[4] = (dest >> 24) & 0xff;
this->jmp_bytes[5] = 0xC3; // ret this->jmp_bytes[5] = 0xC3; // ret
VirtualProtect(func, 16, PAGE_EXECUTE_READWRITE, &(this->protect)); VirtualQuery(func, &mbi, sizeof(mbi));
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &mbi.Protect);
memcpy(this->orig_bytes, this->orig, 1 + 4 + 1); memcpy(this->orig_bytes, this->orig, 1 + 4 + 1);
VirtualProtect(func, 16, this->protect, NULL); VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, NULL);
this->enabled = false; this->enabled = false;
} }
~Hook() { ~Hook() {
cout << "Unhooking: [" << this->orig << " <- " << this->detour << "]" << endl;
this->disable(); this->disable();
} }
static void addr(void* addr, void* detour) { static void addr(void* addr, void* detour) {
cout << "Hooking: [" << addr << " -> " << detour <<"]" << endl; cout << "Hooking: [" << addr << " -> " << detour <<"]" << endl;
uintptr_t key = reinterpret_cast<uintptr_t>(detour); uintptr_t key = reinterpret_cast<uintptr_t>(detour);
@ -72,31 +73,35 @@ public:
} }
static void clear() { static void clear() {
cout << "Clearing Hooks" << endl;
for (pair<uintptr_t,shared_ptr<Hook>> h : hooks) {
h.second->disable();
}
return hooks.clear(); return hooks.clear();
} }
void disable() { void disable() {
if (enabled) { if (enabled) {
//cout << "Disabling: [" << this->orig << " <- " << this->detour << "]" << endl; //cout << "Disabling: [" << this->orig << " <- " << this->detour << "]" << endl;
VirtualProtect(this->orig, 16, PAGE_EXECUTE_READWRITE, NULL); VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, NULL);
memcpy(this->orig, this->orig_bytes, 1 + 4 + 1); memcpy(this->orig, this->orig_bytes, 1 + 4 + 1);
VirtualProtect(this->orig, 16, this->protect, NULL); VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, NULL);
enabled = false; enabled = false;
} }
} }
void enable() { void enable() {
if (!enabled) { if (!enabled) {
//cout << "Enabling: [" << this->orig << " -> " << this->detour << "]" << endl; //cout << "Enabling: [" << this->orig << " -> " << this->detour << "]" << endl;
VirtualProtect(this->orig, 16, PAGE_EXECUTE_READWRITE, NULL); VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, NULL);
memcpy(this->orig, this->jmp_bytes, 1 + 4 + 1); memcpy(this->orig, this->jmp_bytes, 1 + 4 + 1);
VirtualProtect(this->orig, 16, this->protect, NULL); VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, NULL);
enabled = true; enabled = true;
} }
} }
void* func() { template<typename T>
return this->orig; T func() {
return reinterpret_cast<T>(this->orig);
} }
}; };

View file

@ -22,6 +22,7 @@ using namespace std;
#include "Structures.h" #include "Structures.h"
#include "Py_Utils.h" #include "Py_Utils.h"
#include "Hook.h" #include "Hook.h"
#include "VMT_Hook.h"
#include "D3D8_Hook.h" #include "D3D8_Hook.h"
HMODULE hD3D8Dll = 0; HMODULE hD3D8Dll = 0;
@ -30,29 +31,58 @@ bool initialized = false;
bool running = true; bool running = true;
HMODULE mod = 0; HMODULE mod = 0;
void dump_ht(HashTable* ht) {
size_t cnt = 0;
for (size_t i = 0; i < ht->size; ++i) {
HashTableEntry* ent = ht->chains[i];
if (ent != NULL) {
cout << i << ": ";
while (ent != NULL) {
++cnt;
cout << ent->name;
if (ent->next) {
cout << " -> ";
};
ent = ent->next;
}
cout << endl;
}
}
cout << cnt << " Entities" << endl;
return;
}
void MainLoop(HMODULE mod) void MainLoop(HMODULE mod)
{ {
Sleep(100); Sleep(100);
cout << "[*] Starting main Loop" << endl; cout << "[*] Starting main Loop" << endl;
cout << endl; cout << endl;
cout << "[F3 ] Unload ScrapHacks" << endl; cout << "[F3 ] Unload ScrapHacks" << endl;
cout << "[F5 ] Show Overlay" << endl;
cout << "[F6 ] Show Alarm status" << endl; cout << "[F6 ] Show Alarm status" << endl;
cout << "[F7 ] Set Money to 0x7fffffff" << endl; cout << "[F7 ] Set Money to 0x7fffffff" << endl;
cout << "[F8 ] Dump python modules" << endl; cout << "[F8 ] Dump python modules" << endl;
cout << "[F9 ] Dump Entity hashtable" << endl;
cout << "[F10] Enable python tracing" << endl; cout << "[F10] Enable python tracing" << endl;
cout << "[ F ] \"Handbrake\" (*Will* crash the game after some time!)" << endl; cout << "[ F ] \"Handbrake\" (*Will* crash the game after some time!)" << endl;
while (running) while (running)
{ {
Sleep(100); Sleep(100);
if (key_down_norepeat(VK_F10))
{
scrap_exec("dbg.settrace()");
}
while (key_down('F')) while (key_down('F'))
{ {
scrap_exec("dbg.brake()"); scrap_exec("dbg.brake()");
} }
if (key_down_norepeat(VK_F3))
{
break;
}
if (key_down_norepeat(VK_F5))
{
overlay = !overlay;
}
if (key_down_norepeat(VK_F6)) if (key_down_norepeat(VK_F6))
{ {
@ -75,17 +105,16 @@ void MainLoop(HMODULE mod)
} }
} }
} }
if (key_down_norepeat(VK_F3))
if (key_down_norepeat(VK_F9)) {
HashTable *ht = ptr<HashTable>(P_WORLD,O_HASHTABLE);
dump_ht(ht);
}
if (key_down_norepeat(VK_F10))
{ {
break; scrap_exec("dbg.settrace()");
} }
} }
SetConsoleCtrlHandler(NULL, false);
Hook::clear();
scrap_log(0xff0000, "ScrapHacks unloaded!\n");
cout << "[+] ScrapHacks unloaded, you can now close the console!" << endl;
FreeConsole();
PostQuitMessage(0);
FreeLibraryAndExitThread(mod, 0); FreeLibraryAndExitThread(mod, 0);
} }
@ -107,13 +136,12 @@ void handle_command(const char* cmd) {
int hooked_console(const char* cmd) { int hooked_console(const char* cmd) {
typedef int(_cdecl *t_func)(const char*); typedef int(_cdecl *t_func)(const char*);
shared_ptr<Hook> hook = Hook::get(hooked_console); shared_ptr<Hook> hook = Hook::get(hooked_console);
t_func func= reinterpret_cast<t_func>(hook->func());
if (cmd[0] == '$') { if (cmd[0] == '$') {
handle_command(++cmd); handle_command(++cmd);
return 0; return 0;
} }
hook->disable(); hook->disable();
int ret=func(cmd); int ret= hook->func<t_func>()(cmd);
hook->enable(); hook->enable();
return ret; return ret;
} }
@ -122,7 +150,6 @@ void hook_console() {
Hook::addr(reinterpret_cast<void*>(P_CON_HANDLER) , hooked_console); Hook::addr(reinterpret_cast<void*>(P_CON_HANDLER) , hooked_console);
} }
void DllPreInit(HMODULE _mod) { void DllPreInit(HMODULE _mod) {
char mfn[1024]; char mfn[1024];
InitConsole(); InitConsole();
@ -151,4 +178,14 @@ void DllInit(HMODULE _mod)
DispatchMessage(&msg); DispatchMessage(&msg);
} }
return; return;
}
void DllUnload(HMODULE _mod) {
SetConsoleCtrlHandler(NULL, false);
Hook::clear();
scrap_log(0xff0000, "ScrapHacks unloaded!\n");
cout << "[+] ScrapHacks unloaded, you can now close the console!" << endl;
FreeConsole();
PostQuitMessage(0);
return;
} }

View file

@ -154,6 +154,7 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="D3D8_Hook.h" /> <ClInclude Include="D3D8_Hook.h" />
<ClInclude Include="VMT_Hook.h" />
<ClInclude Include="Hook.h" /> <ClInclude Include="Hook.h" />
<ClInclude Include="Py_Utils.h" /> <ClInclude Include="Py_Utils.h" />
<ClInclude Include="Structures.h" /> <ClInclude Include="Structures.h" />

View file

@ -39,6 +39,9 @@
<ClInclude Include="D3D8_Hook.h"> <ClInclude Include="D3D8_Hook.h">
<Filter>Headerdateien</Filter> <Filter>Headerdateien</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="VMT_Hook.h">
<Filter>Headerdateien</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="stdafx.cpp"> <ClCompile Include="stdafx.cpp">

View file

@ -1,8 +1,10 @@
#pragma once #pragma once
//OFFSETS //OFFSETS
#define O_MONEY 0x2090 #define O_MONEY 0x2090
#define O_ALARM 0x1C6C #define O_ALARM 0x1C6C
#define O_ALARM_GROW 0x1C68 #define O_ALARM_GROW 0x1C68
#define O_HASHTABLE 0x4
//POINTERS //POINTERS
#define P_WORLD 0x7FE944 #define P_WORLD 0x7FE944

View file

@ -1,5 +1,5 @@
#pragma once #pragma once
struct HashTableEntry;
struct Vector3 { struct Vector3 {
float x; float x;
float y; float y;
@ -32,3 +32,19 @@ struct Module
PyMod *mod; PyMod *mod;
map<string, PyMethodDef*> methods; map<string, PyMethodDef*> methods;
}; };
struct Entity {
void* VMT;
};
struct HashTable {
uint32_t size;
HashTableEntry** chains;
};
struct HashTableEntry {
Entity* data;
const char* name;
HashTableEntry* next;
};

View file

@ -0,0 +1,91 @@
#pragma once
class VMT_Hook
{
private:
MEMORY_BASIC_INFORMATION mbi;
void* orig;
void* detour;
DWORD* vtable;
size_t ord;
bool enabled;
static map<uintptr_t, shared_ptr<VMT_Hook>> hooks;
static DWORD* GetVTable(void* addr) {
return (DWORD *)*(DWORD *)addr;
};
public:
VMT_Hook(void* obj, size_t ord, void* detour) {
this->vtable = GetVTable(obj);
this->detour = detour;
this->orig = reinterpret_cast<void*>(vtable[ord]);
this->ord = ord;
this->enabled = false;
VirtualQuery(&this->vtable[this->ord], &mbi, sizeof(mbi));
cout << "Hooking: " << this->vtable << "[" << this->ord << "]: (" << this->orig << " -> " << this->detour << ")" << endl;
}
~VMT_Hook() {
cout << "Unhooking: " << this->vtable << "[" << this->ord << "]: (" << this->orig << " -> " << this->detour << ")" << endl;
this->disable();
}
static void create(void* obj, size_t ord, void* detour) {
uintptr_t key = reinterpret_cast<uintptr_t>(detour);
hooks[key] = make_shared<VMT_Hook>(obj,ord, detour);
hooks[key]->enable();
}
static shared_ptr<VMT_Hook> get(void* func) {
uintptr_t addr = reinterpret_cast<uintptr_t>(func);
return VMT_Hook::get(addr);
}
static shared_ptr<VMT_Hook> get(uintptr_t addr) {
return hooks.at(addr);
}
static size_t drop(void* func) {
uintptr_t addr = reinterpret_cast<uintptr_t>(func);
return VMT_Hook::drop(addr);
}
static size_t drop(uintptr_t addr) {
return hooks.erase(addr);
}
static void clear() {
return hooks.clear();
}
void disable() {
if (enabled) {
cout << "Disabling: " << this->vtable << "[" << this->ord << "]: (" << this->orig << " -> " << this->detour<<")" << endl;
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, NULL);
this->vtable[ord] = reinterpret_cast<DWORD>(this->orig);
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, NULL);
enabled = false;
}
}
void enable() {
if (!enabled) {
cout << "Enabling: " << this->vtable << "[" << this->ord << "]: (" << this->orig << " -> " << this->detour <<")" << endl;
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, NULL);
this->vtable[ord] = reinterpret_cast<DWORD>(this->detour);
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, NULL);
enabled = true;
}
}
template<typename T>
T func() {
return reinterpret_cast<T>(this->orig);
}
};
map<uintptr_t, shared_ptr<VMT_Hook>> VMT_Hook::hooks;

View file

@ -2,6 +2,8 @@
#define DLL_EXPORT extern "C" __declspec(dllexport) #define DLL_EXPORT extern "C" __declspec(dllexport)
void DllInit(HMODULE); void DllInit(HMODULE);
void DllPreInit(HMODULE); void DllPreInit(HMODULE);
void DllUnload(HMODULE);
BOOL APIENTRY DllMain(HMODULE hModule, BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call, DWORD ul_reason_for_call,
@ -16,6 +18,8 @@ BOOL APIENTRY DllMain(HMODULE hModule,
hThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)DllInit, hModule, 0, 0); hThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)DllInit, hModule, 0, 0);
break; break;
case DLL_PROCESS_DETACH: case DLL_PROCESS_DETACH:
DllUnload(hModule);
break;
case DLL_THREAD_ATTACH: case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH: case DLL_THREAD_DETACH:
break; break;

View file

@ -9,24 +9,30 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Injector", "Injector\Inject
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64 Debug|x64 = Debug|x64
Debug|x86 = Debug|x86 Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64 Release|x64 = Release|x64
Release|x86 = Release|x86 Release|x86 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{72CB1B9E-50C7-4010-BEAD-82FACF87A87A}.Debug|Any CPU.ActiveCfg = Debug|Win32
{72CB1B9E-50C7-4010-BEAD-82FACF87A87A}.Debug|x64.ActiveCfg = Debug|x64 {72CB1B9E-50C7-4010-BEAD-82FACF87A87A}.Debug|x64.ActiveCfg = Debug|x64
{72CB1B9E-50C7-4010-BEAD-82FACF87A87A}.Debug|x64.Build.0 = Debug|x64 {72CB1B9E-50C7-4010-BEAD-82FACF87A87A}.Debug|x64.Build.0 = Debug|x64
{72CB1B9E-50C7-4010-BEAD-82FACF87A87A}.Debug|x86.ActiveCfg = Debug|Win32 {72CB1B9E-50C7-4010-BEAD-82FACF87A87A}.Debug|x86.ActiveCfg = Debug|Win32
{72CB1B9E-50C7-4010-BEAD-82FACF87A87A}.Debug|x86.Build.0 = Debug|Win32 {72CB1B9E-50C7-4010-BEAD-82FACF87A87A}.Debug|x86.Build.0 = Debug|Win32
{72CB1B9E-50C7-4010-BEAD-82FACF87A87A}.Release|Any CPU.ActiveCfg = Release|Win32
{72CB1B9E-50C7-4010-BEAD-82FACF87A87A}.Release|x64.ActiveCfg = Release|x64 {72CB1B9E-50C7-4010-BEAD-82FACF87A87A}.Release|x64.ActiveCfg = Release|x64
{72CB1B9E-50C7-4010-BEAD-82FACF87A87A}.Release|x64.Build.0 = Release|x64 {72CB1B9E-50C7-4010-BEAD-82FACF87A87A}.Release|x64.Build.0 = Release|x64
{72CB1B9E-50C7-4010-BEAD-82FACF87A87A}.Release|x86.ActiveCfg = Release|Win32 {72CB1B9E-50C7-4010-BEAD-82FACF87A87A}.Release|x86.ActiveCfg = Release|Win32
{72CB1B9E-50C7-4010-BEAD-82FACF87A87A}.Release|x86.Build.0 = Release|Win32 {72CB1B9E-50C7-4010-BEAD-82FACF87A87A}.Release|x86.Build.0 = Release|Win32
{7C91C225-D95C-4B7A-9251-0CE358BAF556}.Debug|Any CPU.ActiveCfg = Debug|Win32
{7C91C225-D95C-4B7A-9251-0CE358BAF556}.Debug|x64.ActiveCfg = Debug|x64 {7C91C225-D95C-4B7A-9251-0CE358BAF556}.Debug|x64.ActiveCfg = Debug|x64
{7C91C225-D95C-4B7A-9251-0CE358BAF556}.Debug|x64.Build.0 = Debug|x64 {7C91C225-D95C-4B7A-9251-0CE358BAF556}.Debug|x64.Build.0 = Debug|x64
{7C91C225-D95C-4B7A-9251-0CE358BAF556}.Debug|x86.ActiveCfg = Debug|Win32 {7C91C225-D95C-4B7A-9251-0CE358BAF556}.Debug|x86.ActiveCfg = Debug|Win32
{7C91C225-D95C-4B7A-9251-0CE358BAF556}.Debug|x86.Build.0 = Debug|Win32 {7C91C225-D95C-4B7A-9251-0CE358BAF556}.Debug|x86.Build.0 = Debug|Win32
{7C91C225-D95C-4B7A-9251-0CE358BAF556}.Release|Any CPU.ActiveCfg = Release|Win32
{7C91C225-D95C-4B7A-9251-0CE358BAF556}.Release|x64.ActiveCfg = Release|x64 {7C91C225-D95C-4B7A-9251-0CE358BAF556}.Release|x64.ActiveCfg = Release|x64
{7C91C225-D95C-4B7A-9251-0CE358BAF556}.Release|x64.Build.0 = Release|x64 {7C91C225-D95C-4B7A-9251-0CE358BAF556}.Release|x64.Build.0 = Release|x64
{7C91C225-D95C-4B7A-9251-0CE358BAF556}.Release|x86.ActiveCfg = Release|Win32 {7C91C225-D95C-4B7A-9251-0CE358BAF556}.Release|x86.ActiveCfg = Release|Win32