mirror of
https://github.com/GameHackingBook/GameHackingCode
synced 2026-06-08 11:08:54 +00:00
Updated some broken projects, cleaned up example code, and remove old artifacts
This commit is contained in:
@@ -82,7 +82,6 @@
|
||||
<ClInclude Include="ThreadLock.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\Chapter7_CodeInjection_DLL\dllmain.cpp" />
|
||||
<ClCompile Include="AdobeAirHook.cpp" />
|
||||
<ClCompile Include="DebugConsole.cpp" />
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
#include "main.h"
|
||||
|
||||
// the function thaat we're going to hook
|
||||
DWORD functionToBeHooked(DWORD arg1, DWORD arg2, DWORD arg3)
|
||||
{
|
||||
if (arg1 == arg2 && arg2 == 3 && arg3 == 4)
|
||||
printf("Call hook worked! Parameters intercepted and changed!\n");
|
||||
else
|
||||
printf("Call hook failed!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// the hook will replace the call in this function
|
||||
// to call our hook
|
||||
void whereHookGoes()
|
||||
{
|
||||
functionToBeHooked(0, 0, 0);
|
||||
}
|
||||
|
||||
// I cannot hard-code any addresses from within this application,
|
||||
// as they may change upon re-compile. For this reason, I'll locate
|
||||
// the address of the CALL that I want to replace programatically
|
||||
// by scanning for the 'CALL' statement (bytes 0xE8)
|
||||
// somewhere within 1000 bytes of the start of the function
|
||||
DWORD getAddressForCallHook(DWORD functionStart)
|
||||
{
|
||||
auto oldProtection = protectMemory<BYTE[1000]>(functionStart, PAGE_EXECUTE_READ); // make sure memory is readable, just incase
|
||||
auto mem = pointMemory<BYTE>(functionStart);
|
||||
|
||||
DWORD ret = 0;
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
if (mem[i] == 0xE8) {
|
||||
ret = functionStart + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
protectMemory<BYTE[1000]>(functionStart, oldProtection); // restore old memory protection
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// this our our type-def that minmics the function type
|
||||
// of the function being hooked. This allows us to use a
|
||||
// clean call to the original function just knowing it's address
|
||||
typedef DWORD (__cdecl _origFunc)(DWORD arg1, DWORD arg2, DWORD arg3);
|
||||
_origFunc* originalFunction;
|
||||
|
||||
// this is the function we re-direct the CALL to.
|
||||
// it simply throws out the orignal parameters
|
||||
// and passes new ones to the original function
|
||||
DWORD __cdecl someNewFunction(DWORD arg1, DWORD arg2, DWORD arg3)
|
||||
{
|
||||
return originalFunction(3, 3, 4);
|
||||
}
|
||||
|
||||
// this function is what actually places the hook
|
||||
DWORD callHook(DWORD hookAt, DWORD newFunc)
|
||||
{
|
||||
DWORD newOffset = newFunc - hookAt - 5;
|
||||
|
||||
auto oldProtection = protectMemory<DWORD>(hookAt + 1, PAGE_EXECUTE_READWRITE);
|
||||
|
||||
DWORD originalOffset = readMemory<DWORD>(hookAt + 1);
|
||||
writeMemory<DWORD>(hookAt + 1, newOffset);
|
||||
protectMemory<DWORD>(hookAt + 1, oldProtection);
|
||||
|
||||
return originalOffset + hookAt + 5;
|
||||
}
|
||||
|
||||
// This ties the entire example together
|
||||
void callHookExample()
|
||||
{
|
||||
auto address = getAddressForCallHook((DWORD)&whereHookGoes);
|
||||
if (address)
|
||||
originalFunction = (_origFunc*)callHook(address, (DWORD)&someNewFunction);
|
||||
|
||||
whereHookGoes();
|
||||
}
|
||||
@@ -83,7 +83,14 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="CallHookExample.cpp" />
|
||||
<ClCompile Include="IATHookExample.cpp" />
|
||||
<ClCompile Include="main-controlFlow.cpp" />
|
||||
<ClCompile Include="NOPExample.cpp" />
|
||||
<ClCompile Include="VFHookExample.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="main.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main-controlFlow.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NOPExample.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CallHookExample.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IATHookExample.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VFHookExample.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{1ccf619e-78d1-4364-adcb-e255c0253713}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{00f1f1a3-3e5e-4f2c-8cbb-285f328f13d1}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="main.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "main.h"
|
||||
|
||||
// this is the function that scans the import table and
|
||||
// overwrites the target function address with our hook
|
||||
// destination address
|
||||
DWORD hookIAT(const char* functionName, DWORD newFunctionAddress)
|
||||
{
|
||||
DWORD baseAddress = (DWORD)GetModuleHandle(NULL);
|
||||
|
||||
auto dosHeader = pointMemory<IMAGE_DOS_HEADER>(baseAddress);
|
||||
if (dosHeader->e_magic != 0x5A4D)
|
||||
return 0;
|
||||
|
||||
auto optHeader = pointMemory<IMAGE_OPTIONAL_HEADER>(baseAddress + dosHeader->e_lfanew + 24);
|
||||
if (optHeader->Magic != 0x10B)
|
||||
return 0;
|
||||
|
||||
if (optHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size == 0 ||
|
||||
optHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress == 0)
|
||||
return 0;
|
||||
|
||||
IMAGE_IMPORT_DESCRIPTOR* importDescriptor = pointMemory<IMAGE_IMPORT_DESCRIPTOR>(baseAddress + optHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); //what is the rule of adding them?
|
||||
while (importDescriptor->FirstThunk)
|
||||
{
|
||||
int n = 0;
|
||||
IMAGE_THUNK_DATA* thunkData = pointMemory<IMAGE_THUNK_DATA>(baseAddress + importDescriptor->OriginalFirstThunk);
|
||||
while (thunkData->u1.Function)
|
||||
{
|
||||
char* importFunctionName = pointMemory<char>(baseAddress + (DWORD)thunkData->u1.AddressOfData + 2);
|
||||
if (strcmp(importFunctionName, functionName) == 0)
|
||||
{
|
||||
auto vfTable = pointMemory<DWORD>(baseAddress + importDescriptor->FirstThunk);
|
||||
|
||||
DWORD original = vfTable[n];
|
||||
|
||||
auto oldProtection = protectMemory<DWORD>((DWORD)&vfTable[n], PAGE_READWRITE);
|
||||
vfTable[n] = newFunctionAddress;
|
||||
protectMemory<DWORD>((DWORD)&vfTable[n], oldProtection);
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
n++;
|
||||
thunkData++;
|
||||
}
|
||||
importDescriptor++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// this our our type-def that minmics the function type
|
||||
// of the function being hooked. This allows us to use a
|
||||
// clean call to the original function just knowing it's address
|
||||
typedef VOID (WINAPI _origSleep)(DWORD ms);
|
||||
_origSleep* originalSleep;
|
||||
|
||||
// this is the function we re-direct any Sleep() call to.
|
||||
// it simply denies all Sleep calls that last for more than
|
||||
// 100 miliseconds, printing some text upon success
|
||||
VOID WINAPI newSleepFunction(DWORD ms)
|
||||
{
|
||||
if (ms > 100)
|
||||
printf("Sleep hook worked! Denied sleep for %d miliseconds.\n", ms);
|
||||
else
|
||||
originalSleep(ms);
|
||||
}
|
||||
|
||||
// This is the function that ties everything together
|
||||
void IATHookExample()
|
||||
{
|
||||
originalSleep = (_origSleep*)hookIAT("Sleep", (DWORD)&newSleepFunction);
|
||||
Sleep(1234);
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
#include "main.h"
|
||||
|
||||
// this is the simulated list of creatures in the game
|
||||
std::vector<_creature> creatures;
|
||||
int creaturesDrawn = 0;
|
||||
|
||||
// this is the simulated function to draw creature names
|
||||
void drawHealthBar(int healthbar)
|
||||
{
|
||||
creaturesDrawn++; // make a note that we drew it
|
||||
Sleep(healthbar); // just an example, we're not really doing anything
|
||||
}
|
||||
|
||||
// this is the function where we place the NOP.
|
||||
void drawCreatureHealthBarExample()
|
||||
{
|
||||
for (int i = 0; i < creatures.size(); i++) {
|
||||
auto c = creatures[i];
|
||||
if (c.isEnemy && c.isCloaked)
|
||||
{
|
||||
// our NOP is esentially going to remove this continue statement,
|
||||
// which will be a JUMP that evades the drawHealthBar car
|
||||
continue;
|
||||
}
|
||||
drawHealthBar(c.healthBar);
|
||||
}
|
||||
}
|
||||
|
||||
// this is the function that actually does the NOP
|
||||
template<int SIZE>
|
||||
void writeNop(DWORD address)
|
||||
{
|
||||
auto oldProtection = protectMemory<BYTE[SIZE]>(address, PAGE_EXECUTE_READWRITE);
|
||||
for (int i = 0; i < SIZE; i++)
|
||||
writeMemory<BYTE>(address + i, 0x90);
|
||||
protectMemory<BYTE[SIZE]>(address, oldProtection);
|
||||
}
|
||||
|
||||
|
||||
// I cannot hard-code any addresses from within this application,
|
||||
// as they may change upon re-compile. For this reason, I'll locate
|
||||
// the address of the JMP that I want to replace programatically
|
||||
// by scanning for the 'JMP -67' statement (bytes 0xEB 0xBD)
|
||||
// somewhere within 1000 bytes of the start of the function
|
||||
DWORD getAddressForNOP(DWORD functionStart)
|
||||
{
|
||||
auto oldProtection = protectMemory<BYTE[1000]>(functionStart, PAGE_EXECUTE_READ); // make sure memory is readable, just incase
|
||||
auto mem = pointMemory<BYTE>(functionStart);
|
||||
|
||||
DWORD ret = 0;
|
||||
for (int i = 0; i < 999; i++) {
|
||||
if (mem[i] == 0xEB && mem[i+1] == 0xBD) {
|
||||
ret = functionStart + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
protectMemory<BYTE[1000]>(functionStart, oldProtection); // restore old memory protection
|
||||
return ret;
|
||||
}
|
||||
|
||||
// This ties the entire example together
|
||||
void NOPExample()
|
||||
{
|
||||
creaturesDrawn = 0;
|
||||
|
||||
// nop it
|
||||
auto address = getAddressForNOP((DWORD)&drawCreatureHealthBarExample);
|
||||
if (address)
|
||||
writeNop<2>(address);
|
||||
|
||||
// add some make creatures
|
||||
creatures.push_back(_creature(0, true, true));
|
||||
creatures.push_back(_creature(0, true, false));
|
||||
creatures.push_back(_creature(0, false, true));
|
||||
creatures.push_back(_creature(0, false, false));
|
||||
|
||||
//call the function
|
||||
drawCreatureHealthBarExample();
|
||||
|
||||
//check if NOP worked
|
||||
if (creaturesDrawn == 4)
|
||||
printf("NOP worked! Drew all creatures!\n");
|
||||
else
|
||||
printf("NOP failed! :( Only drew %d/4 creatures.\n", creaturesDrawn);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
#include "main.h"
|
||||
|
||||
// This is a dummy base-class
|
||||
class someBaseClass
|
||||
{
|
||||
public:
|
||||
virtual DWORD someFunction(DWORD arg1) { return 0; }
|
||||
};
|
||||
|
||||
// This is the class for which we'll
|
||||
// actually hook the VF table. It inherits
|
||||
// the dummy base-class to ensure that
|
||||
// someFunction() is in a virtual table.
|
||||
class someClass : public someBaseClass
|
||||
{
|
||||
public:
|
||||
virtual DWORD someFunction(DWORD arg1)
|
||||
{
|
||||
if (arg1 == 1)
|
||||
printf(" VF Table hook worked! Parameters intercepted and changed!\n");
|
||||
else
|
||||
printf(" VF Table hook failed!\n");
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// This is where we re-direct the VF calls to
|
||||
DWORD originalVFFunction;
|
||||
DWORD __stdcall someNewVFFunction(DWORD arg1)
|
||||
{
|
||||
// notice how we take ECX and store it in a variable..
|
||||
// this is done because it stores the class instance pointer ("this")
|
||||
// and we want to make sure our code doesn't overwrite it (the compiler
|
||||
// doesn't understand that this is a VF hook, so it may think ECX is
|
||||
// free for it to use)
|
||||
|
||||
static DWORD _this, _ret;
|
||||
__asm MOV _this, ECX
|
||||
|
||||
printf("VFHook pre\n");
|
||||
__asm {
|
||||
PUSH 1
|
||||
MOV ECX, _this
|
||||
CALL [originalVFFunction]
|
||||
MOV _ret, EAX
|
||||
}
|
||||
printf("VFHook Post\n");
|
||||
|
||||
__asm MOV ECX, _this
|
||||
return _ret;
|
||||
}
|
||||
|
||||
// This is the function that actually places the hook
|
||||
DWORD hookVF(DWORD classInst, DWORD funcIndex, DWORD newFunc)
|
||||
{
|
||||
DWORD VFTable = readMemory<DWORD>(classInst);
|
||||
DWORD hookAddress = VFTable + funcIndex * sizeof(DWORD);
|
||||
|
||||
auto oldProtection = protectMemory<DWORD>(hookAddress, PAGE_READWRITE);
|
||||
DWORD originalFunc = readMemory<DWORD>(hookAddress);
|
||||
writeMemory<DWORD>(hookAddress, newFunc);
|
||||
protectMemory<DWORD>(hookAddress, oldProtection);
|
||||
|
||||
return originalFunc;
|
||||
}
|
||||
|
||||
// This is the function that ties everything together
|
||||
void VFHookExample()
|
||||
{
|
||||
someClass* inst = new someClass();
|
||||
|
||||
originalVFFunction = hookVF((DWORD)inst, 0, (DWORD)&someNewVFFunction);
|
||||
inst->someFunction(0);
|
||||
delete inst;
|
||||
}
|
||||
@@ -1,314 +1,11 @@
|
||||
#include <iostream>
|
||||
#include <Windows.h>
|
||||
#include <vector>
|
||||
|
||||
|
||||
//helpers
|
||||
template<typename T>
|
||||
T readMemory(DWORD address)
|
||||
{
|
||||
return *((T*)address);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* pointMemory(DWORD address)
|
||||
{
|
||||
return ((T*)address);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void writeMemory(DWORD address, T value)
|
||||
{
|
||||
*((T*)address) = value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
DWORD protectMemory(DWORD address, DWORD prot)
|
||||
{
|
||||
DWORD oldProt;
|
||||
VirtualProtect((LPVOID)address, sizeof(T), prot, &oldProt);
|
||||
return oldProt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// NOP example code
|
||||
struct _creature
|
||||
{
|
||||
_creature(int hb, bool e, bool c) : healthBar(hb), isEnemy(e), isCloaked(c) {}
|
||||
int healthBar;
|
||||
bool isEnemy, isCloaked;
|
||||
};
|
||||
std::vector<_creature> creatures;
|
||||
int creaturesDrawn = 0;
|
||||
|
||||
void drawHealthBar(int healthbar)
|
||||
{
|
||||
creaturesDrawn++; // make a note that we drew it
|
||||
Sleep(healthbar); // just an example, we're not really doing anything
|
||||
}
|
||||
void drawCreatureHealthBarExample()
|
||||
{
|
||||
for (int i = 0; i < creatures.size(); i++) {
|
||||
auto c = creatures[i];
|
||||
if (c.isEnemy && c.isCloaked) continue;
|
||||
drawHealthBar(c.healthBar);
|
||||
}
|
||||
}
|
||||
|
||||
template<int SIZE>
|
||||
void writeNop(DWORD address)
|
||||
{
|
||||
auto oldProtection = protectMemory<BYTE[SIZE]>(address, PAGE_EXECUTE_READWRITE);
|
||||
for (int i = 0; i < SIZE; i++)
|
||||
writeMemory<BYTE>(address + i, 0x90);
|
||||
protectMemory<BYTE[SIZE]>(address, oldProtection);
|
||||
}
|
||||
|
||||
DWORD getAddressForNOP(DWORD functionStart)
|
||||
{
|
||||
// i cannot hard-code any addresses from within this application,
|
||||
// as they may change upon re-compile. For this reason, I'll locate
|
||||
// the address of the JMP that I want to replace programatically
|
||||
// by scanning for the 'JMP -67' statement (bytes 0xEB 0xBD)
|
||||
// somewhere within 1000 bytes of the start of the function
|
||||
|
||||
|
||||
|
||||
auto oldProtection = protectMemory<BYTE[1000]>(functionStart, PAGE_EXECUTE_READ); // make sure memory is readable, just incase
|
||||
auto mem = pointMemory<BYTE>(functionStart);
|
||||
|
||||
DWORD ret = 0;
|
||||
for (int i = 0; i < 999; i++) {
|
||||
if (mem[i] == 0xEB && mem[i+1] == 0xBD) {
|
||||
ret = functionStart + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
protectMemory<BYTE[1000]>(functionStart, oldProtection); // restore old memory protection
|
||||
return ret;
|
||||
}
|
||||
|
||||
void NOPExample()
|
||||
{
|
||||
// nop it
|
||||
auto address = getAddressForNOP((DWORD)&drawCreatureHealthBarExample);
|
||||
if (address)
|
||||
writeNop<2>(address);
|
||||
|
||||
// add some make creatures
|
||||
creatures.push_back(_creature(0, true, true));
|
||||
creatures.push_back(_creature(0, true, false));
|
||||
creatures.push_back(_creature(0, false, true));
|
||||
creatures.push_back(_creature(0, false, false));
|
||||
|
||||
//call the function
|
||||
drawCreatureHealthBarExample();
|
||||
|
||||
//check if NOP worked
|
||||
if (creaturesDrawn == 4)
|
||||
printf("NOP worked! Drew all creatures!\n");
|
||||
else
|
||||
printf("NOP failed! :( Only drew %d/4 creatures.\n", creaturesDrawn);
|
||||
}
|
||||
|
||||
|
||||
// call hook
|
||||
DWORD functionToBeHooked(DWORD arg1, DWORD arg2, DWORD arg3)
|
||||
{
|
||||
if (arg1 == arg2 && arg2 == 3 && arg3 == 4)
|
||||
printf("Call hook worked! Parameters intercepted and changed!\n");
|
||||
else
|
||||
printf("Call hook failed!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void whereHookGoes()
|
||||
{
|
||||
functionToBeHooked(0, 0, 0);
|
||||
}
|
||||
|
||||
DWORD getAddressForCallHook(DWORD functionStart)
|
||||
{
|
||||
// same story as with NOP, except we're looking for the first CALL (0xE8)
|
||||
auto oldProtection = protectMemory<BYTE[1000]>(functionStart, PAGE_EXECUTE_READ); // make sure memory is readable, just incase
|
||||
auto mem = pointMemory<BYTE>(functionStart);
|
||||
|
||||
DWORD ret = 0;
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
if (mem[i] == 0xE8) {
|
||||
ret = functionStart + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
protectMemory<BYTE[1000]>(functionStart, oldProtection); // restore old memory protection
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
typedef DWORD (__cdecl _origFunc)(DWORD arg1, DWORD arg2, DWORD arg3);
|
||||
_origFunc* originalFunction;
|
||||
|
||||
DWORD __cdecl someNewFunction(DWORD arg1, DWORD arg2, DWORD arg3)
|
||||
{
|
||||
return originalFunction(3, 3, 4);
|
||||
}
|
||||
|
||||
|
||||
DWORD callHook(DWORD hookAt, DWORD newFunc)
|
||||
{
|
||||
DWORD newOffset = newFunc - hookAt - 5;
|
||||
|
||||
auto oldProtection = protectMemory<DWORD>(hookAt + 1, PAGE_EXECUTE_READWRITE);
|
||||
|
||||
DWORD originalOffset = readMemory<DWORD>(hookAt + 1);
|
||||
writeMemory<DWORD>(hookAt + 1, newOffset);
|
||||
protectMemory<DWORD>(hookAt + 1, oldProtection);
|
||||
|
||||
return originalOffset + hookAt + 5;
|
||||
}
|
||||
|
||||
void callHookExample()
|
||||
{
|
||||
auto address = getAddressForCallHook((DWORD)&whereHookGoes);
|
||||
if (address)
|
||||
originalFunction = (_origFunc*)callHook(address, (DWORD)&someNewFunction);
|
||||
|
||||
whereHookGoes();
|
||||
}
|
||||
|
||||
|
||||
// vf table hook
|
||||
class someBaseClass
|
||||
{
|
||||
public:
|
||||
virtual DWORD someFunction(DWORD arg1) { return 0; }
|
||||
};
|
||||
class someClass : public someBaseClass
|
||||
{
|
||||
public:
|
||||
virtual DWORD someFunction(DWORD arg1)
|
||||
{
|
||||
if (arg1 == 1)
|
||||
printf(" VF Table hook worked! Parameters intercepted and changed!\n");
|
||||
else
|
||||
printf(" VF Table hook failed!\n");
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
DWORD originalVFFunction;
|
||||
DWORD __stdcall someNewVFFunction(DWORD arg1)
|
||||
{
|
||||
static DWORD _this, _ret;
|
||||
__asm MOV _this, ECX
|
||||
printf("VFHook pre\n");
|
||||
__asm {
|
||||
PUSH 1
|
||||
MOV ECX, _this
|
||||
CALL [originalVFFunction]
|
||||
MOV _ret, EAX
|
||||
}
|
||||
printf("VFHook Post\n");
|
||||
__asm MOV ECX, _this
|
||||
return _ret;
|
||||
}
|
||||
|
||||
|
||||
DWORD hookVF(DWORD classInst, DWORD funcIndex, DWORD newFunc)
|
||||
{
|
||||
DWORD VFTable = readMemory<DWORD>(classInst);
|
||||
DWORD hookAddress = VFTable + funcIndex * sizeof(DWORD);
|
||||
|
||||
auto oldProtection = protectMemory<DWORD>(hookAddress, PAGE_READWRITE);
|
||||
DWORD originalFunc = readMemory<DWORD>(hookAddress);
|
||||
writeMemory<DWORD>(hookAddress, newFunc);
|
||||
protectMemory<DWORD>(hookAddress, oldProtection);
|
||||
|
||||
return originalFunc;
|
||||
}
|
||||
|
||||
void VFHookExample()
|
||||
{
|
||||
someClass* inst = new someClass();
|
||||
|
||||
originalVFFunction = hookVF((DWORD)inst, 0, (DWORD)&someNewVFFunction);
|
||||
inst->someFunction(0);
|
||||
delete inst;
|
||||
}
|
||||
|
||||
// iat hook
|
||||
DWORD hookIAT(const char* functionName, DWORD newFunctionAddress)
|
||||
{
|
||||
DWORD baseAddress = (DWORD)GetModuleHandle(NULL);
|
||||
|
||||
auto dosHeader = pointMemory<IMAGE_DOS_HEADER>(baseAddress);
|
||||
if (dosHeader->e_magic != 0x5A4D)
|
||||
return 0;
|
||||
|
||||
auto optHeader = pointMemory<IMAGE_OPTIONAL_HEADER>(baseAddress + dosHeader->e_lfanew + 24);
|
||||
if (optHeader->Magic != 0x10B)
|
||||
return 0;
|
||||
|
||||
if (optHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size == 0 ||
|
||||
optHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress == 0)
|
||||
return 0;
|
||||
|
||||
IMAGE_IMPORT_DESCRIPTOR* importDescriptor = pointMemory<IMAGE_IMPORT_DESCRIPTOR>(baseAddress + optHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); //what is the rule of adding them?
|
||||
while (importDescriptor->FirstThunk)
|
||||
{
|
||||
int n = 0;
|
||||
IMAGE_THUNK_DATA* thunkData = pointMemory<IMAGE_THUNK_DATA>(baseAddress + importDescriptor->OriginalFirstThunk);
|
||||
while (thunkData->u1.Function)
|
||||
{
|
||||
char* importFunctionName = pointMemory<char>(baseAddress + (DWORD)thunkData->u1.AddressOfData + 2);
|
||||
if (strcmp(importFunctionName, functionName) == 0)
|
||||
{
|
||||
auto vfTable = pointMemory<DWORD>(baseAddress + importDescriptor->FirstThunk);
|
||||
|
||||
DWORD original = vfTable[n];
|
||||
|
||||
auto oldProtection = protectMemory<DWORD>((DWORD)&vfTable[n], PAGE_READWRITE);
|
||||
vfTable[n] = newFunctionAddress;
|
||||
protectMemory<DWORD>((DWORD)&vfTable[n], oldProtection);
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
n++;
|
||||
thunkData++;
|
||||
}
|
||||
importDescriptor++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef VOID (WINAPI _origSleep)(DWORD ms);
|
||||
_origSleep* originalSleep;
|
||||
|
||||
VOID WINAPI newSleepFunction(DWORD ms)
|
||||
{
|
||||
if (ms > 100)
|
||||
printf("Sleep hook worked! Denied sleep for %d miliseconds.\n", ms);
|
||||
else
|
||||
originalSleep(ms);
|
||||
}
|
||||
|
||||
void IATHookExample()
|
||||
{
|
||||
originalSleep = (_origSleep*)hookIAT("Sleep", (DWORD)&newSleepFunction);
|
||||
Sleep(1234);
|
||||
}
|
||||
|
||||
#include "main.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
// due to differences in the way functions are compiled between
|
||||
// DEBUG and RELEASE builds, this example will only work in RELEASE.
|
||||
// This is only because of the way I'm finding the address to be NOP'd
|
||||
// This is only because of the way I'm finding the addresses of
|
||||
// the NOP and CALL targets
|
||||
NOPExample();
|
||||
callHookExample();
|
||||
VFHookExample();
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#include <iostream>
|
||||
#include <Windows.h>
|
||||
#include <vector>
|
||||
|
||||
/*
|
||||
THIS IS JUST SOME BOILER-PLATE TO ALLOW THE EXAMPLE CODE TO WORK,
|
||||
NOTHING INTERESTING HERE
|
||||
*/
|
||||
|
||||
|
||||
template<typename T>
|
||||
T readMemory(DWORD address)
|
||||
{
|
||||
return *((T*)address);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* pointMemory(DWORD address)
|
||||
{
|
||||
return ((T*)address);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void writeMemory(DWORD address, T value)
|
||||
{
|
||||
*((T*)address) = value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
DWORD protectMemory(DWORD address, DWORD prot)
|
||||
{
|
||||
DWORD oldProt;
|
||||
VirtualProtect((LPVOID)address, sizeof(T), prot, &oldProt);
|
||||
return oldProt;
|
||||
}
|
||||
|
||||
struct _creature
|
||||
{
|
||||
_creature(int hb, bool e, bool c) : healthBar(hb), isEnemy(e), isCloaked(c) {}
|
||||
int healthBar;
|
||||
bool isEnemy, isCloaked;
|
||||
};
|
||||
void NOPExample();
|
||||
void callHookExample();
|
||||
void VFHookExample();
|
||||
void IATHookExample();
|
||||
@@ -2,9 +2,9 @@
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="LoLOracle Hook"
|
||||
Name="Direct3D Hook"
|
||||
ProjectGUID="{784C482A-F6EC-4BCB-851E-07BE782BB040}"
|
||||
RootNamespace="LoLOracleHook"
|
||||
RootNamespace="Direct3DHook"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
@@ -41,8 +41,8 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories=""C:\Program Files (x86)\Microsoft Research\ms detours 1.5 src\src";"C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include""
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LOLORACLEHOOK_EXPORTS"
|
||||
AdditionalIncludeDirectories=""C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include""
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
@@ -62,10 +62,10 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="detours.lib"
|
||||
OutputFile="$(OutDir)\loloracle.dll"
|
||||
AdditionalDependencies=""
|
||||
OutputFile="$(OutDir)\Chapter8_Direct3DHook.dll"
|
||||
LinkIncremental="2"
|
||||
AdditionalLibraryDirectories=""C:\Program Files (x86)\Microsoft Research\ms detours 1.5 src\lib""
|
||||
AdditionalLibraryDirectories=""
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
DataExecutionPrevention="0"
|
||||
@@ -120,8 +120,8 @@
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
AdditionalIncludeDirectories=""C:\Program Files (x86)\Microsoft Research\ms detours 1.5 src\src";"C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include""
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LOLORACLEHOOK_EXPORTS"
|
||||
AdditionalIncludeDirectories=";"C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include""
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
@@ -139,10 +139,10 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="detours.lib"
|
||||
OutputFile="$(OutDir)\loloracle.dll"
|
||||
AdditionalDependencies=""
|
||||
OutputFile="$(OutDir)\Chapter8_Direct3DHook.dll"
|
||||
LinkIncremental="1"
|
||||
AdditionalLibraryDirectories=""C:\Program Files (x86)\Microsoft Research\ms detours 1.5 src\lib""
|
||||
AdditionalLibraryDirectories=""
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
|
||||
Reference in New Issue
Block a user