diff --git a/Chapter8_AdobeAirHook/AdobeAirHook.vcxproj b/Chapter8_AdobeAirHook/AdobeAirHook.vcxproj index 6ea46a1..aefc419 100644 --- a/Chapter8_AdobeAirHook/AdobeAirHook.vcxproj +++ b/Chapter8_AdobeAirHook/AdobeAirHook.vcxproj @@ -82,7 +82,6 @@ - diff --git a/Chapter8_ControlFlow/CallHookExample.cpp b/Chapter8_ControlFlow/CallHookExample.cpp new file mode 100644 index 0000000..734b540 --- /dev/null +++ b/Chapter8_ControlFlow/CallHookExample.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(functionStart, PAGE_EXECUTE_READ); // make sure memory is readable, just incase + auto mem = pointMemory(functionStart); + + DWORD ret = 0; + for (int i = 0; i < 1000; i++) { + if (mem[i] == 0xE8) { + ret = functionStart + i; + break; + } + } + protectMemory(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(hookAt + 1, PAGE_EXECUTE_READWRITE); + + DWORD originalOffset = readMemory(hookAt + 1); + writeMemory(hookAt + 1, newOffset); + protectMemory(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(); +} \ No newline at end of file diff --git a/Chapter8_ControlFlow/Chapter8_ControlFlow.vcxproj b/Chapter8_ControlFlow/Chapter8_ControlFlow.vcxproj index de8d97e..512177f 100644 --- a/Chapter8_ControlFlow/Chapter8_ControlFlow.vcxproj +++ b/Chapter8_ControlFlow/Chapter8_ControlFlow.vcxproj @@ -83,7 +83,14 @@ + + + + + + + diff --git a/Chapter8_ControlFlow/Chapter8_ControlFlow.vcxproj.filters b/Chapter8_ControlFlow/Chapter8_ControlFlow.vcxproj.filters new file mode 100644 index 0000000..af256f2 --- /dev/null +++ b/Chapter8_ControlFlow/Chapter8_ControlFlow.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + {1ccf619e-78d1-4364-adcb-e255c0253713} + + + {00f1f1a3-3e5e-4f2c-8cbb-285f328f13d1} + + + + + Header Files + + + \ No newline at end of file diff --git a/Chapter8_ControlFlow/IATHookExample.cpp b/Chapter8_ControlFlow/IATHookExample.cpp new file mode 100644 index 0000000..a74d3a8 --- /dev/null +++ b/Chapter8_ControlFlow/IATHookExample.cpp @@ -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(baseAddress); + if (dosHeader->e_magic != 0x5A4D) + return 0; + + auto optHeader = pointMemory(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(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(baseAddress + importDescriptor->OriginalFirstThunk); + while (thunkData->u1.Function) + { + char* importFunctionName = pointMemory(baseAddress + (DWORD)thunkData->u1.AddressOfData + 2); + if (strcmp(importFunctionName, functionName) == 0) + { + auto vfTable = pointMemory(baseAddress + importDescriptor->FirstThunk); + + DWORD original = vfTable[n]; + + auto oldProtection = protectMemory((DWORD)&vfTable[n], PAGE_READWRITE); + vfTable[n] = newFunctionAddress; + protectMemory((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); +} \ No newline at end of file diff --git a/Chapter8_ControlFlow/NOPExample.cpp b/Chapter8_ControlFlow/NOPExample.cpp new file mode 100644 index 0000000..75940c5 --- /dev/null +++ b/Chapter8_ControlFlow/NOPExample.cpp @@ -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 +void writeNop(DWORD address) +{ + auto oldProtection = protectMemory(address, PAGE_EXECUTE_READWRITE); + for (int i = 0; i < SIZE; i++) + writeMemory(address + i, 0x90); + protectMemory(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(functionStart, PAGE_EXECUTE_READ); // make sure memory is readable, just incase + auto mem = pointMemory(functionStart); + + DWORD ret = 0; + for (int i = 0; i < 999; i++) { + if (mem[i] == 0xEB && mem[i+1] == 0xBD) { + ret = functionStart + i; + break; + } + } + protectMemory(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); +} \ No newline at end of file diff --git a/Chapter8_ControlFlow/VFHookExample.cpp b/Chapter8_ControlFlow/VFHookExample.cpp new file mode 100644 index 0000000..a3ef1c8 --- /dev/null +++ b/Chapter8_ControlFlow/VFHookExample.cpp @@ -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(classInst); + DWORD hookAddress = VFTable + funcIndex * sizeof(DWORD); + + auto oldProtection = protectMemory(hookAddress, PAGE_READWRITE); + DWORD originalFunc = readMemory(hookAddress); + writeMemory(hookAddress, newFunc); + protectMemory(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; +} \ No newline at end of file diff --git a/Chapter8_ControlFlow/main-controlFlow.cpp b/Chapter8_ControlFlow/main-controlFlow.cpp index f50f4a0..2f5e66f 100644 --- a/Chapter8_ControlFlow/main-controlFlow.cpp +++ b/Chapter8_ControlFlow/main-controlFlow.cpp @@ -1,314 +1,11 @@ -#include -#include -#include - - -//helpers - template - T readMemory(DWORD address) - { - return *((T*)address); - } - - template - T* pointMemory(DWORD address) - { - return ((T*)address); - } - - template - void writeMemory(DWORD address, T value) - { - *((T*)address) = value; - } - - template - 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 - void writeNop(DWORD address) - { - auto oldProtection = protectMemory(address, PAGE_EXECUTE_READWRITE); - for (int i = 0; i < SIZE; i++) - writeMemory(address + i, 0x90); - protectMemory(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(functionStart, PAGE_EXECUTE_READ); // make sure memory is readable, just incase - auto mem = pointMemory(functionStart); - - DWORD ret = 0; - for (int i = 0; i < 999; i++) { - if (mem[i] == 0xEB && mem[i+1] == 0xBD) { - ret = functionStart + i; - break; - } - } - protectMemory(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(functionStart, PAGE_EXECUTE_READ); // make sure memory is readable, just incase - auto mem = pointMemory(functionStart); - - DWORD ret = 0; - for (int i = 0; i < 1000; i++) { - if (mem[i] == 0xE8) { - ret = functionStart + i; - break; - } - } - protectMemory(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(hookAt + 1, PAGE_EXECUTE_READWRITE); - - DWORD originalOffset = readMemory(hookAt + 1); - writeMemory(hookAt + 1, newOffset); - protectMemory(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(classInst); - DWORD hookAddress = VFTable + funcIndex * sizeof(DWORD); - - auto oldProtection = protectMemory(hookAddress, PAGE_READWRITE); - DWORD originalFunc = readMemory(hookAddress); - writeMemory(hookAddress, newFunc); - protectMemory(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(baseAddress); - if (dosHeader->e_magic != 0x5A4D) - return 0; - - auto optHeader = pointMemory(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(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(baseAddress + importDescriptor->OriginalFirstThunk); - while (thunkData->u1.Function) - { - char* importFunctionName = pointMemory(baseAddress + (DWORD)thunkData->u1.AddressOfData + 2); - if (strcmp(importFunctionName, functionName) == 0) - { - auto vfTable = pointMemory(baseAddress + importDescriptor->FirstThunk); - - DWORD original = vfTable[n]; - - auto oldProtection = protectMemory((DWORD)&vfTable[n], PAGE_READWRITE); - vfTable[n] = newFunctionAddress; - protectMemory((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(); diff --git a/Chapter8_ControlFlow/main.h b/Chapter8_ControlFlow/main.h new file mode 100644 index 0000000..2224491 --- /dev/null +++ b/Chapter8_ControlFlow/main.h @@ -0,0 +1,46 @@ +#include +#include +#include + +/* + THIS IS JUST SOME BOILER-PLATE TO ALLOW THE EXAMPLE CODE TO WORK, + NOTHING INTERESTING HERE +*/ + + +template +T readMemory(DWORD address) +{ + return *((T*)address); +} + +template +T* pointMemory(DWORD address) +{ + return ((T*)address); +} + +template +void writeMemory(DWORD address, T value) +{ + *((T*)address) = value; +} + +template +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(); \ No newline at end of file diff --git a/Chapter8_Direct3DHook/Chapter8_Direct3DHook.vcproj b/Chapter8_Direct3DHook/Chapter8_Direct3DHook.vcproj index 6d5def7..87c3924 100644 --- a/Chapter8_Direct3DHook/Chapter8_Direct3DHook.vcproj +++ b/Chapter8_Direct3DHook/Chapter8_Direct3DHook.vcproj @@ -2,9 +2,9 @@ @@ -41,8 +41,8 @@