From 25284fb5bb6d929f56feb2fe9d0a38da1acc5d8b Mon Sep 17 00:00:00 2001 From: Nick Cano Date: Mon, 20 Apr 2015 09:12:03 -0700 Subject: [PATCH] Initial commit --- .gitignore | 16 + .../Chapter10_ResponsiveHacks.vcxproj | 91 +++++ .../main-responsiveHacks.cpp | 118 +++++++ .../Chapter4_CodeToMemory.filters | 22 ++ .../Chapter4_CodeToMemory.vcxproj | 91 +++++ Chapter4_CodeToMemory/main-codeToMemory.cpp | 159 +++++++++ ...5_AdvancedMemoryForensics_Scanning.vcxproj | 90 +++++ .../main-advancedMemoryForensics-Scanning.cpp | 169 +++++++++ .../Chapter6_AccessingMemory.vcxproj | 91 +++++ .../main-accessingMemory.cpp | 169 +++++++++ .../Chapter7_CodeInjection.vcxproj | 91 +++++ Chapter7_CodeInjection/main-codeInjection.cpp | 173 ++++++++++ .../Chapter7_CodeInjection_DLL.vcxproj | 79 +++++ ...Chapter7_CodeInjection_DLL.vcxproj.filters | 17 + Chapter7_CodeInjection_DLL/dllmain.cpp | 28 ++ Chapter8_AdobeAirHook/AdobeAirHook.cpp | 105 ++++++ Chapter8_AdobeAirHook/AdobeAirHook.h | 44 +++ Chapter8_AdobeAirHook/AdobeAirHook.vcxproj | 101 ++++++ .../AdobeAirHook.vcxproj.filters | 63 ++++ Chapter8_AdobeAirHook/AdobeAirHookCallbacks.h | 68 ++++ Chapter8_AdobeAirHook/DebugConsole.cpp | 109 ++++++ Chapter8_AdobeAirHook/DebugConsole.h | 41 +++ Chapter8_AdobeAirHook/ExecutableModule.cpp | 116 +++++++ Chapter8_AdobeAirHook/ExecutableModule.h | 71 ++++ Chapter8_AdobeAirHook/ThreadLock.h | 27 ++ Chapter8_AdobeAirHook/dllmain.cpp | 25 ++ .../Chapter8_ControlFlow.vcxproj | 91 +++++ Chapter8_ControlFlow/main-controlFlow.cpp | 321 ++++++++++++++++++ .../Chapter8_Direct3DApplication.vcxproj | 73 ++++ ...apter8_Direct3DApplication.vcxproj.filters | 22 ++ Chapter8_Direct3DApplication/main.cpp | 298 ++++++++++++++++ .../Chapter8_Direct3DHook.vcproj | 216 ++++++++++++ .../Chapter8_Direct3DHook.vcxproj | 114 +++++++ .../Chapter8_Direct3DHook.vcxproj.filters | 36 ++ Chapter8_Direct3DHook/DirectXHook.cpp | 257 ++++++++++++++ Chapter8_Direct3DHook/DirectXHook.h | 109 ++++++ Chapter8_Direct3DHook/DirectXHookCallbacks.h | 38 +++ Chapter8_Direct3DHook/main.cpp | 127 +++++++ Chapter8_Direct3DHook/memory.h | Bin 0 -> 3838 bytes GameHackingExamples.sln | 74 ++++ 40 files changed, 3950 insertions(+) create mode 100644 Chapter10_ResponsiveHacks/Chapter10_ResponsiveHacks.vcxproj create mode 100644 Chapter10_ResponsiveHacks/main-responsiveHacks.cpp create mode 100644 Chapter4_CodeToMemory/Chapter4_CodeToMemory.filters create mode 100644 Chapter4_CodeToMemory/Chapter4_CodeToMemory.vcxproj create mode 100644 Chapter4_CodeToMemory/main-codeToMemory.cpp create mode 100644 Chapter5_AdvancedMemoryForensics_Scanning/Chapter5_AdvancedMemoryForensics_Scanning.vcxproj create mode 100644 Chapter5_AdvancedMemoryForensics_Scanning/main-advancedMemoryForensics-Scanning.cpp create mode 100644 Chapter6_AccessingMemory/Chapter6_AccessingMemory.vcxproj create mode 100644 Chapter6_AccessingMemory/main-accessingMemory.cpp create mode 100644 Chapter7_CodeInjection/Chapter7_CodeInjection.vcxproj create mode 100644 Chapter7_CodeInjection/main-codeInjection.cpp create mode 100644 Chapter7_CodeInjection_DLL/Chapter7_CodeInjection_DLL.vcxproj create mode 100644 Chapter7_CodeInjection_DLL/Chapter7_CodeInjection_DLL.vcxproj.filters create mode 100644 Chapter7_CodeInjection_DLL/dllmain.cpp create mode 100644 Chapter8_AdobeAirHook/AdobeAirHook.cpp create mode 100644 Chapter8_AdobeAirHook/AdobeAirHook.h create mode 100644 Chapter8_AdobeAirHook/AdobeAirHook.vcxproj create mode 100644 Chapter8_AdobeAirHook/AdobeAirHook.vcxproj.filters create mode 100644 Chapter8_AdobeAirHook/AdobeAirHookCallbacks.h create mode 100644 Chapter8_AdobeAirHook/DebugConsole.cpp create mode 100644 Chapter8_AdobeAirHook/DebugConsole.h create mode 100644 Chapter8_AdobeAirHook/ExecutableModule.cpp create mode 100644 Chapter8_AdobeAirHook/ExecutableModule.h create mode 100644 Chapter8_AdobeAirHook/ThreadLock.h create mode 100644 Chapter8_AdobeAirHook/dllmain.cpp create mode 100644 Chapter8_ControlFlow/Chapter8_ControlFlow.vcxproj create mode 100644 Chapter8_ControlFlow/main-controlFlow.cpp create mode 100644 Chapter8_Direct3DApplication/Chapter8_Direct3DApplication.vcxproj create mode 100644 Chapter8_Direct3DApplication/Chapter8_Direct3DApplication.vcxproj.filters create mode 100644 Chapter8_Direct3DApplication/main.cpp create mode 100644 Chapter8_Direct3DHook/Chapter8_Direct3DHook.vcproj create mode 100644 Chapter8_Direct3DHook/Chapter8_Direct3DHook.vcxproj create mode 100644 Chapter8_Direct3DHook/Chapter8_Direct3DHook.vcxproj.filters create mode 100644 Chapter8_Direct3DHook/DirectXHook.cpp create mode 100644 Chapter8_Direct3DHook/DirectXHook.h create mode 100644 Chapter8_Direct3DHook/DirectXHookCallbacks.h create mode 100644 Chapter8_Direct3DHook/main.cpp create mode 100644 Chapter8_Direct3DHook/memory.h create mode 100644 GameHackingExamples.sln diff --git a/.gitignore b/.gitignore index b8bd026..9859b93 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,19 @@ *.exe *.out *.app + + +# VS stuff +*.suo +*.sdf +*.user + +#other directories +*/ipch/* +*/Debug/* +*/Release/* +*/BuildTemp/* +ipch/* +Debug/* +Release/* +BuildTemp/* diff --git a/Chapter10_ResponsiveHacks/Chapter10_ResponsiveHacks.vcxproj b/Chapter10_ResponsiveHacks/Chapter10_ResponsiveHacks.vcxproj new file mode 100644 index 0000000..456c809 --- /dev/null +++ b/Chapter10_ResponsiveHacks/Chapter10_ResponsiveHacks.vcxproj @@ -0,0 +1,91 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {E28E3DC6-2614-43B9-83E4-86D6F9A585B1} + Win32Proj + Chapter10_ResponsiveHacks + Chapter10_ResponsiveHacks + + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + true + $(SolutionDir)\BuildTemp\$(Configuration)\ + + + false + $(SolutionDir)\BuildTemp\$(ProjectName)_$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + 4Bytes + + + Console + true + false + + + + + Level3 + + + Disabled + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + 4Bytes + + + Console + true + true + true + + + false + + + + + + + + + \ No newline at end of file diff --git a/Chapter10_ResponsiveHacks/main-responsiveHacks.cpp b/Chapter10_ResponsiveHacks/main-responsiveHacks.cpp new file mode 100644 index 0000000..48415a9 --- /dev/null +++ b/Chapter10_ResponsiveHacks/main-responsiveHacks.cpp @@ -0,0 +1,118 @@ +#include +#include +#include + +// WARNING: if this code is killed mid-execute or you switch to another window (not the console) +// while it's executing, it may cause the system to think a modifier key is stuck. +// If this happens, you can tap shift, ctrl, and alt on the LEFT side of your keyboard to "unstick it" + + + + + +// SendInput() example code + void sendKeyWithSendInput(WORD key, bool up) + { + INPUT input = {0}; + input.type = INPUT_KEYBOARD; + input.ki.wVk = key; + input.ki.dwFlags = 0; + + if (up) + input.ki.dwFlags |= KEYEVENTF_KEYUP; + SendInput(1, &input, sizeof(input)); + } + + void sendModifiersWithSendInput(DWORD flags, bool up) + { + if (flags & 1) + sendKeyWithSendInput(VK_LSHIFT, up); + if (flags & 2) + sendKeyWithSendInput(VK_LCONTROL, up); + if (flags & 4) + sendKeyWithSendInput(VK_LMENU, up); + } + + void sendCharWithSendInput(char letter) + { + SHORT keyFlags = VkKeyScanA(letter); + + WORD key = keyFlags & 0xFF; + DWORD flags = (keyFlags >> 8) & 0xFF; + + sendModifiersWithSendInput(flags, false); + + sendKeyWithSendInput(key, false); + sendKeyWithSendInput(key, true); + + sendModifiersWithSendInput(flags, true); + } + + void typeStringWithSendInput(const char* string) + { + for (int i = 0; i < strlen(string); i++) + { + sendCharWithSendInput(string[i]); + Sleep(80); + } + } + +// SendMessage example code + void sendKeyWithSendMessage(HWND window, WORD key, char letter) + { + SendMessageA(window, WM_KEYDOWN, key, 0); + if (letter != 0) + SendMessageA(window, WM_CHAR, letter, 1); + SendMessageA(window, WM_KEYUP, key, 1); + } + + + void sendCharWithSendMessage(HWND window, char letter) + { + SHORT keyFlags = VkKeyScanA(letter); + + WORD key = keyFlags & 0xFF; + DWORD flags = (keyFlags >> 8) & 0xFF; + + sendKeyWithSendMessage(window, key, letter); + } + + void typeStringWithSendMessage(HWND window, const char* string) + { + for (int i = 0; i < strlen(string); i++) + { + sendCharWithSendMessage(window, string[i]); + Sleep(80); + } + } + + + + +DWORD WINAPI exampleThread(LPVOID lpParam) +{ + Sleep(500); + typeStringWithSendInput("Typing using SendInput()!\rHow does it look? :)\r\r"); + + auto window = FindWindowA(NULL, "Chapter10 Input Example"); + typeStringWithSendMessage(window, "Typing using SendMessage()!\rEffectively the same, but more powerful :-)\r\r"); + + return 0; +} + + +int main(void) +{ + std::cout << "WARNING: Don't switch between windows until this application is done typing" << std::endl; + system("pause"); + std::cout << "Everything below here is being programmatically typed using the keyboard" << std::endl << std::endl; + + SetConsoleTitleA("Chapter10 Input Example"); + + CreateThread(NULL, 0, exampleThread, 0, 0, NULL); + + char temp; + while (true) { + std::cin >> temp; + } +} \ No newline at end of file diff --git a/Chapter4_CodeToMemory/Chapter4_CodeToMemory.filters b/Chapter4_CodeToMemory/Chapter4_CodeToMemory.filters new file mode 100644 index 0000000..b449f95 --- /dev/null +++ b/Chapter4_CodeToMemory/Chapter4_CodeToMemory.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/Chapter4_CodeToMemory/Chapter4_CodeToMemory.vcxproj b/Chapter4_CodeToMemory/Chapter4_CodeToMemory.vcxproj new file mode 100644 index 0000000..b90f685 --- /dev/null +++ b/Chapter4_CodeToMemory/Chapter4_CodeToMemory.vcxproj @@ -0,0 +1,91 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {42D11C4C-AC06-47BD-B6CD-FC6DBAF54472} + Win32Proj + Chapter4_CodeToMemory + Chapter4_CodeToMemory + + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + true + $(SolutionDir)\BuildTemp\$(Configuration)\ + + + false + $(SolutionDir)\BuildTemp\$(ProjectName)_$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + 4Bytes + + + Console + true + false + + + + + Level3 + + + Disabled + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + 4Bytes + + + Console + true + true + true + + + false + + + + + + + + + \ No newline at end of file diff --git a/Chapter4_CodeToMemory/main-codeToMemory.cpp b/Chapter4_CodeToMemory/main-codeToMemory.cpp new file mode 100644 index 0000000..9573d87 --- /dev/null +++ b/Chapter4_CodeToMemory/main-codeToMemory.cpp @@ -0,0 +1,159 @@ +#include +#include + +/* numeric values */ +unsigned char ubyteValue = 0xFF; +char byteValue = 0xFE; + +unsigned short uwordValue = 0x4142; +short wordValue = 0x4344; + +unsigned int udwordValue = 0xDEADBEEF; +int dwordValue = 0xDEADBEEF; + +unsigned long long ulongLongValue = 0xEFCDAB8967452301; +long long longLongValue = 0xEFCDAB8967452301; + +float floatValue = 1337.7331; + +/* string values */ +char* thinStringP = "my_thin_terminated_value_pointer"; +char thinStringA[40] = "my_thin_terminated_value_array"; +wchar_t* wideStringP = L"my_wide_terminated_value_pointer"; +wchar_t wideStringA[40] = L"my_wide_terminated_value_array"; + +/* structures */ +struct MyStruct { + unsigned char ubyteValue; + char byteValue; + unsigned short uwordValue; + short wordValue; + unsigned int udwordValue; + int dwordValue; + unsigned long long ulongLongValue; + char interruptor; + long long longLongValue; + float floatValue; +}; + +/* classes with no VF tables */ +class bar { +public: + bar() : bar1(0x898989), bar2(0x10203040) {} + void myfunction() { bar1++; } + int bar1, bar2; +}; + +/* classes with VF tables */ +class foo { +public: + foo() : myValue1(0xDEADBEEF), myValue2(0xBABABABA) {} + int myValue1; + static int myStaticValue; + virtual void bar() { printf("foo::bar()\n"); } + virtual void baz() { printf("foo::baz()\n"); } + virtual void barbaz() {} + int myValue2; +}; +int foo::myStaticValue = 0x12121212; +class fooa : public foo { +public: + fooa() : foo() {} + virtual void bar() { printf("fooa::bar()\n"); } + virtual void baz() { printf("fooa::baz()\n"); } +}; +class foob : public foo { +public: + foob() : foo() { } + virtual void bar() { printf("foob::bar()\n"); } + virtual void baz() { printf("foob::baz()\n"); } +}; + +/* class protection */ +class baz { +public: + baz() : baz1(0x11111111), baz2(0x22222222), + baz3(0x33333333), baz4(0x44444444) {} + int baz1, baz2; + void printStuff() + { + printf("0x%x : baz->baz1\n", &this->baz1); + printf("0x%x : baz->baz2\n", &this->baz2); + printf("0x%x : baz->baz3\n", &this->baz3); + printf("0x%x : baz->baz4\n", &this->baz4); + } +private: + int baz3, baz4; +}; + +int main(void) +{ + /* just using global values so they don't get optimized away */ + ubyteValue = ubyteValue; + byteValue = byteValue; + wordValue = wordValue; + uwordValue = uwordValue; + udwordValue = udwordValue; + dwordValue = dwordValue; + ulongLongValue = ulongLongValue; + longLongValue = longLongValue; + floatValue = floatValue; + + thinStringP = thinStringP; + if (thinStringA){} + wideStringP = wideStringP; + if (wideStringA){} + + /* printing addresses so we can easily find the dumps */ + printf("0x%x : ubyteValue\n", &ubyteValue); + printf("0x%x : thinStringP\n", &thinStringP); + + /* showing structure arrangement */ + MyStruct* m = 0; + printf("Offsets: %d,%d,%d,%d,%d,%d,%d,%d,%d\n", + &m->ubyteValue, &m->byteValue, + &m->uwordValue, &m->wordValue, + &m->udwordValue, &m->dwordValue, + &m->ulongLongValue, &m->longLongValue, + &m->floatValue); + + /* union stuff */ + union { + BYTE byteValue; + struct { + WORD first; + WORD second; + } words; + DWORD value; + } dwValue; + dwValue.value = 0xDEADBEEF; + printf("Size %d; Addresses 0x%x,0x%x; Values 0x%x,0x%x\n", + sizeof(dwValue), &dwValue.value, &dwValue.words, + dwValue.words.first, dwValue.words.second); + + /* classes with no VF tables */ + bar _bar = bar(); + printf("Size %d; Address 0x%x : _bar\n", sizeof(_bar), &_bar); + + /* class VF call */ + foo* _testfoo = (foo*)new fooa(); + _testfoo->bar(); + + /* classes with VF tables */ + foo _foo = foo(); + fooa _fooa = fooa(); + foob _foob = foob(); + printf("0x%x : _foo\n", &_foo); + printf("0x%x : _fooa\n", &_fooa); + printf("0x%x : _foob\n", &_foob); + + _foo.barbaz(); + _fooa.bar(); + _foob.baz(); + + /* class protection */ + baz* _baz = 0; + _baz->printStuff(); + + system("pause"); +} \ No newline at end of file diff --git a/Chapter5_AdvancedMemoryForensics_Scanning/Chapter5_AdvancedMemoryForensics_Scanning.vcxproj b/Chapter5_AdvancedMemoryForensics_Scanning/Chapter5_AdvancedMemoryForensics_Scanning.vcxproj new file mode 100644 index 0000000..9601dcd --- /dev/null +++ b/Chapter5_AdvancedMemoryForensics_Scanning/Chapter5_AdvancedMemoryForensics_Scanning.vcxproj @@ -0,0 +1,90 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {6C658EF9-CCA4-4E18-8AD7-CEBDC04AB3AB} + Win32Proj + Chapter5_AdvancedMemoryForensics_Scanning + + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + true + $(SolutionDir)\BuildTemp\$(Configuration)\ + + + false + $(SolutionDir)\BuildTemp\$(ProjectName)_$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + 4Bytes + + + Console + true + false + + + + + Level3 + + + Disabled + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + 4Bytes + + + Console + false + true + true + + + false + + + + + + + + + \ No newline at end of file diff --git a/Chapter5_AdvancedMemoryForensics_Scanning/main-advancedMemoryForensics-Scanning.cpp b/Chapter5_AdvancedMemoryForensics_Scanning/main-advancedMemoryForensics-Scanning.cpp new file mode 100644 index 0000000..c34cea7 --- /dev/null +++ b/Chapter5_AdvancedMemoryForensics_Scanning/main-advancedMemoryForensics-Scanning.cpp @@ -0,0 +1,169 @@ +#include +#include +#include +#include +#include + +struct PlayerVital { + int current, maximum; +}; + +PlayerVital health = {450, 500}; + +std::vector vectorData; +std::list listData; + +typedef int keyInt; +typedef int valInt; +std::map mapData; + + +void printString(const char* text, int one, int two) +{ + printf(text, one, two); +} + +void printHealth() +{ + printString("Health: %d of %d\n", health.current, health.maximum); +} + +// VECTOR + +void readVector(DWORD vectorAddress) +{ + struct _vector + { + DWORD* begin; + DWORD* end; + DWORD* tail; + }; + + _vector* vec = (_vector*)vectorAddress; + + DWORD count = ((DWORD)vec->end - (DWORD)vec->begin) / sizeof(DWORD); + DWORD capacity = ((DWORD)vec->tail - (DWORD)vec->begin) / sizeof(DWORD); + + printf("Vector has %d items and %d capacity\n", count, capacity); + + for (int i = 0; i < count; i++) + printf("\tValue at %d is %d\n", i, vec->begin[i]); +} + +// LIST + +void readList(DWORD listAddress) +{ + struct listItem + { + listItem* next; + listItem* prev; + DWORD value; + }; + + struct _list + { + listItem* root; + DWORD size; + }; + + _list* list = (_list*)listAddress; + + printf("List has %d items\n", list->size); + + for (listItem* it = list->root->next; it != list->root; it = it->next) + printf("\tForward value is %d\n", it->value); + + for (listItem* it = list->root->prev; it != list->root; it = it->prev) + printf("\tReverse value is %d\n", it->value); +} + +// MAP + +struct mapItem { + mapItem* left; + mapItem* parent; + mapItem* right; + keyInt key; + valInt value; +}; +struct _map { + DWORD irrelevant; + mapItem* rootNode; + int size; +}; + +mapItem* findItem(keyInt key, mapItem* node, mapItem* root) +{ + if (node != root) { + if (key == node->key) + return node; + else if (key < node->key) + return findItem(key, node->left, root); + else + return findItem(key, node->right, root); + } + else + return root; +} + +mapItem* searchMap(keyInt key, _map* map) +{ + mapItem* ret = + findItem(key, map->rootNode->parent, map->rootNode); + if (ret == map->rootNode) return NULL; + return ret; +} + + +void iterateMap(mapItem* node, mapItem* root) +{ + if (node == root) return; + iterateMap(node->left, root); + printf("\tKey %d has value 0x%04x\n", node->key, node->value); + iterateMap(node->right, root); +} + +void readMap(DWORD mapAddress) +{ + _map* map = (_map*)mapAddress; + + printf("Nodes in map: %d\n", map->size); + iterateMap(map->rootNode->parent, map->rootNode); + + printf("\tMap search for 1 yields: 0x%04x\n", searchMap(1, map)->value); + printf("\tMap search for 2 yields: 0x%04x\n", searchMap(2, map)->value); + printf("\tMap search for 3 yields: 0x%04x\n", searchMap(3, map)->value); + printf("\tMap search for 5 yields: 0x%04x\n", searchMap(5, map)->value); +} + + +int main(void) +{ + vectorData.reserve(20); + vectorData.push_back(12345); + vectorData.push_back(54321); + + listData.push_back(123); + listData.push_back(321); + listData.push_back(121); + + mapData.insert(std::pair(1, 0x100)); + mapData.insert(std::pair(2, 0x200)); + mapData.insert(std::pair(3, 0x200)); + mapData.insert(std::pair(5, 0x500)); + + while (true) // stupid loop to keep anything needed for the example from being optimized away + { + auto something = &printString; + + printHealth(); + readVector((DWORD)&vectorData); + readList((DWORD)&listData); + readMap((DWORD)&mapData); + + health.current = (health.current == health.maximum) ? 1 : (health.current + 1); + health.maximum = 500; + system("pause"); + } +} \ No newline at end of file diff --git a/Chapter6_AccessingMemory/Chapter6_AccessingMemory.vcxproj b/Chapter6_AccessingMemory/Chapter6_AccessingMemory.vcxproj new file mode 100644 index 0000000..8e9b47b --- /dev/null +++ b/Chapter6_AccessingMemory/Chapter6_AccessingMemory.vcxproj @@ -0,0 +1,91 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {4C3B87D1-43D3-44DB-913E-E4A1D99909CB} + Win32Proj + Chapter6_AccessingMemory + Chapter6_AccessingMemory + + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + true + $(SolutionDir)\BuildTemp\$(Configuration)\ + + + false + $(SolutionDir)\BuildTemp\$(ProjectName)_$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + 4Bytes + + + Console + true + false + + + + + Level3 + + + Disabled + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + 4Bytes + + + Console + true + true + true + + + false + + + + + + + + + \ No newline at end of file diff --git a/Chapter6_AccessingMemory/main-accessingMemory.cpp b/Chapter6_AccessingMemory/main-accessingMemory.cpp new file mode 100644 index 0000000..4106c19 --- /dev/null +++ b/Chapter6_AccessingMemory/main-accessingMemory.cpp @@ -0,0 +1,169 @@ +#include +#include +#include + + +void printMyPid() +{ + wchar_t myTitle[1024]; + GetConsoleTitle(&myTitle[0], 1024); + + HWND myWindow = FindWindow(NULL, myTitle); + + DWORD pid; + GetWindowThreadProcessId(myWindow, &pid); + + printf("My pid is %d\n", pid); +} + +void printExplorerPid() +{ + PROCESSENTRY32 entry; + entry.dwSize = sizeof(PROCESSENTRY32); + + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); + + if (Process32First(snapshot, &entry) == TRUE) + { + while (Process32Next(snapshot, &entry) == TRUE) + { + std::wstring binaryPath = entry.szExeFile; + if (binaryPath.find(L"explorer.exe") != std::wstring::npos) + { + printf("Explorer's pid is %d\n", entry.th32ProcessID); + break; + } + } + } + + CloseHandle(snapshot); +} + +template +T readMemoryAPI(HANDLE process, LPVOID address) +{ + T value; + ReadProcessMemory(process, address, &value, sizeof(T), NULL); + return value; +} + +template +void writeMemoryAPI(HANDLE process, LPVOID address, T value) +{ + WriteProcessMemory(process, address, &value, sizeof(T), NULL); +} + +template +DWORD protectMemory(HANDLE process, LPVOID address, DWORD prot) +{ + DWORD oldProt; + VirtualProtectEx(process, address, sizeof(T), prot, &oldProt); + return oldProt; +} + +void readAndWriteMemoryAPI(HANDLE process, LPVOID address) +{ + DWORD value = readMemoryAPI(process, address); + + printf("Current mem value is %d\n", value); + value++; + + DWORD oldProt = protectMemory(process, address, PAGE_READWRITE); + writeMemoryAPI(process, address, value); + protectMemory(process, address, oldProt); + + + value = readMemoryAPI(process, address); + + printf("New mem value is %d\n", value); +} + +template +T readMemoryPointer(LPVOID address) +{ + return *((T*)address); +} + +template +void writeMemoryPointer(LPVOID address, T value) +{ + *((T*)address) = value; +} + +template +T* pointMemory(LPVOID address) +{ + return ((T*)address); +} +void readAndWriteMemoryMarshall(LPVOID address) +{ + DWORD value = readMemoryPointer(address); + + printf("Current mem value is %d\n", value); + value++; + + writeMemoryPointer(address, value); + value = readMemoryPointer(address); + + printf("New mem value is %d\n", value); +} + + +DWORD getMyBaseAddressGMH() +{ + return (DWORD)GetModuleHandle(NULL); +} + +DWORD getMyBaseAddressFS() +{ + DWORD newBase; + __asm + { + MOV EAX, DWORD PTR FS:[0x30] + MOV EAX, DWORD PTR DS:[EAX+0x8] + MOV newBase, EAX + } + return newBase; +} + +DWORD getMyBaseRemoteGMH(HANDLE Process) +{ + LPVOID TIB; + __asm + { + MOV EAX, DWORD PTR FS:[0x18] + ADD EAX, 0x30 + MOV TIB, EAX + } + // read 0x30 bytes past _the_game's_ TIB to get the PEB + DWORD PEB = readMemoryAPI(Process, TIB); + // read 0x8 bytes past _the_game's_ PEB to get the base + return readMemoryAPI(Process, (LPVOID)(PEB + 0x08)); +} + +void printMyBaseAddresses(HANDLE Process) +{ + DWORD base1 = getMyBaseAddressGMH(); + DWORD base2 = getMyBaseAddressFS(); + DWORD base3 = getMyBaseRemoteGMH(Process); + if (base1 != base2 || base2 != base3) + printf("Woah, this should be impossible!\n"); + else + printf("My base address is 0x%08x\n", base1); +} + +int main(void) +{ + HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId()); + + printMyBaseAddresses(proc); + printMyPid(); + printExplorerPid(); + + // lets do some memory stuff.. to ourself + DWORD someValue = 1234; + readAndWriteMemoryAPI(proc, &someValue); + readAndWriteMemoryMarshall(&someValue); + + system("pause"); +} \ No newline at end of file diff --git a/Chapter7_CodeInjection/Chapter7_CodeInjection.vcxproj b/Chapter7_CodeInjection/Chapter7_CodeInjection.vcxproj new file mode 100644 index 0000000..8a1c1f1 --- /dev/null +++ b/Chapter7_CodeInjection/Chapter7_CodeInjection.vcxproj @@ -0,0 +1,91 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {A20C8EDD-02C5-499E-8DB6-1CB8081FD62B} + Win32Proj + Chapter7_CodeInjection + Chapter7_CodeInjection + + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + true + $(SolutionDir)\BuildTemp\$(Configuration)\ + + + false + $(SolutionDir)\BuildTemp\$(ProjectName)_$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + 4Bytes + + + Console + true + false + + + + + Level3 + + + Disabled + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + 4Bytes + + + Console + true + true + true + + + false + + + + + + + + + \ No newline at end of file diff --git a/Chapter7_CodeInjection/main-codeInjection.cpp b/Chapter7_CodeInjection/main-codeInjection.cpp new file mode 100644 index 0000000..c824cc2 --- /dev/null +++ b/Chapter7_CodeInjection/main-codeInjection.cpp @@ -0,0 +1,173 @@ +#include +#include +#include + + +DWORD printStringManyTimes(int times, const char* string) +{ + for (int i = 0; i < times; i++) + printf(string); + return 0; +} + + +void injectCodeUsingThreadInjection(HANDLE process, LPVOID func, int times, const char* string) +{ + BYTE codeCave[20] = { + 0xFF, 0x74, 0x24, 0x04, // PUSH DWORD PTR[ESP+0x4] + 0x68, 0x00, 0x00, 0x00, 0x00, // PUSH 0 + 0xB8, 0x00, 0x00, 0x00, 0x00, // MOV EAX, 0x0 + 0xFF, 0xD0, // CALL EAX + 0x83, 0xC4, 0x08, // ADD ESP, 0x08 + 0xC3 // RETN + }; + + // copy values to the shellcode + memcpy(&codeCave[5], ×, 4); + memcpy(&codeCave[10], &func, 4); + + + // allocate memory for the coe cave + int stringlen = strlen(string) + 1; + int fulllen = stringlen + sizeof(codeCave); + LPVOID remoteString = VirtualAllocEx(process, NULL, fulllen, MEM_COMMIT, PAGE_EXECUTE); + LPVOID remoteCave = (LPVOID)((DWORD)remoteString + stringlen); + + // write the code cave + WriteProcessMemory(process, remoteString, string, stringlen, NULL); + WriteProcessMemory(process, remoteCave, codeCave, sizeof(codeCave), NULL); + + // run the thread + HANDLE thread = CreateRemoteThread(process, NULL, NULL, + (LPTHREAD_START_ROUTINE)remoteCave, + remoteString, NULL, NULL); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); +} + + +DWORD GetProcessThreadID(HANDLE Process) +{ + THREADENTRY32 entry; + entry.dwSize = sizeof(THREADENTRY32); + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + + if (Thread32First(snapshot, &entry) == TRUE) + { + DWORD PID = GetProcessId(Process); + while (Thread32Next(snapshot, &entry) == TRUE) + { + if (entry.th32OwnerProcessID == PID) + { + CloseHandle(snapshot); + return entry.th32ThreadID; + } + } + } + CloseHandle(snapshot); + return NULL; +} + + + +void injectCodeUsingThreadRedirection(HANDLE process, LPVOID func, int times, const char* string) +{ + BYTE codeCave[31] = { + 0x60, //PUSHAD + 0x9C, //PUSHFD + 0x68, 0x00, 0x00, 0x00, 0x00, // PUSH 0 + 0x68, 0x00, 0x00, 0x00, 0x00, // PUSH 0 + 0xB8, 0x00, 0x00, 0x00, 0x00, // MOV EAX, 0x0 + 0xFF, 0xD0, // CALL EAX + 0x83, 0xC4, 0x08, // ADD ESP, 0x08 + 0x9D, //POPFD + 0x61, //POPAD + 0x68, 0x00, 0x00, 0x00, 0x00, // PUSH 0 + 0xC3 // RETN + }; + + // allocate memory for the coe cave + int stringlen = strlen(string) + 1; + int fulllen = stringlen + sizeof(codeCave); + LPVOID remoteString = VirtualAllocEx(process, NULL, fulllen, MEM_COMMIT, PAGE_EXECUTE); + LPVOID remoteCave = (LPVOID)((DWORD)remoteString + stringlen); + + // suspend the thread and query its control context + DWORD threadID = GetProcessThreadID(process); + HANDLE thread = OpenThread((THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_SET_CONTEXT), false, threadID); + SuspendThread(thread); + + CONTEXT threadContext; + threadContext.ContextFlags = CONTEXT_CONTROL; + GetThreadContext(thread, &threadContext); + + // copy values to the shellcode (happens late because we need values from allocation) + memcpy(&codeCave[3], &remoteString, 4); + memcpy(&codeCave[8], ×, 4); + memcpy(&codeCave[13], &func, 4); + memcpy(&codeCave[25], &threadContext.Eip, 4); + + + // write the code cave + WriteProcessMemory(process, remoteString, string, stringlen, NULL); + WriteProcessMemory(process, remoteCave, codeCave, sizeof(codeCave), NULL); + + + //redirect the thread + threadContext.Eip = (DWORD)remoteCave; + threadContext.ContextFlags = CONTEXT_CONTROL; + SetThreadContext(thread, &threadContext); + ResumeThread(thread); + + //clean + CloseHandle(thread); +} + +DWORD WINAPI redirectionThread(LPVOID lpParam) +{ + injectCodeUsingThreadRedirection((HANDLE)lpParam, &printStringManyTimes, 2, "redirected\n"); + return 1; +} + + +void LoadDll(HANDLE process, const wchar_t* dllPath) +{ + // write the dll name to memory + int namelen = wcslen(dllPath) + 1; + LPVOID remoteString = VirtualAllocEx(process, NULL, namelen * 2, MEM_COMMIT, PAGE_EXECUTE); + WriteProcessMemory(process, remoteString, dllPath, namelen * 2, NULL); + + // get the address of GetModuleHandle() + HMODULE k32 = GetModuleHandleA("kernel32.dll"); + LPVOID funcAdr = GetProcAddress(k32, "LoadLibraryW"); + + // create the thread + HANDLE thread = + CreateRemoteThread(process, NULL, NULL, (LPTHREAD_START_ROUTINE)funcAdr, remoteString, NULL, NULL); + + // let the thread finish and clean up + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); +} + +int main(void) +{ + HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId()); + + // inject code into self using thread injection + injectCodeUsingThreadInjection(proc, &printStringManyTimes, 2, "injected\n"); + + // inject code into self using thread re-direction + // we need to do it from a secondary thread or else + // the redirection code would redirect itself.. which + // doesn't work + CreateThread(NULL, 0, redirectionThread, proc, 0, NULL); + + LoadDll(proc, L"Chapter7_CodeInjection_DLL.dll"); + + + while (true) // stay busy + { + Sleep(100); + } +} \ No newline at end of file diff --git a/Chapter7_CodeInjection_DLL/Chapter7_CodeInjection_DLL.vcxproj b/Chapter7_CodeInjection_DLL/Chapter7_CodeInjection_DLL.vcxproj new file mode 100644 index 0000000..3d2f4a5 --- /dev/null +++ b/Chapter7_CodeInjection_DLL/Chapter7_CodeInjection_DLL.vcxproj @@ -0,0 +1,79 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {37305F21-BB4B-4492-A713-DDD94653C16E} + Win32Proj + Chapter7_CodeInjection_DLL + + + + DynamicLibrary + true + Unicode + + + DynamicLibrary + false + true + Unicode + + + + + + + + + + + + + true + $(SolutionDir)\BuildTemp\$(Configuration)\ + + + false + $(SolutionDir)\BuildTemp\$(ProjectName)_$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;CHAPTER7_CODEINJECTION_DLL_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;CHAPTER7_CODEINJECTION_DLL_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/Chapter7_CodeInjection_DLL/Chapter7_CodeInjection_DLL.vcxproj.filters b/Chapter7_CodeInjection_DLL/Chapter7_CodeInjection_DLL.vcxproj.filters new file mode 100644 index 0000000..d7ef6a1 --- /dev/null +++ b/Chapter7_CodeInjection_DLL/Chapter7_CodeInjection_DLL.vcxproj.filters @@ -0,0 +1,17 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + \ No newline at end of file diff --git a/Chapter7_CodeInjection_DLL/dllmain.cpp b/Chapter7_CodeInjection_DLL/dllmain.cpp new file mode 100644 index 0000000..7f02844 --- /dev/null +++ b/Chapter7_CodeInjection_DLL/dllmain.cpp @@ -0,0 +1,28 @@ +#include + + +DWORD WINAPI nonTrivialSomething(LPVOID lpParam) +{ + + return 1; +} + + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + MessageBoxA(NULL, "DLL Attached!\n", "Game Hacking", MB_OK | MB_TOPMOST); + CreateThread(NULL, 0, &nonTrivialSomething, NULL, 0, NULL); + break; + case DLL_PROCESS_DETACH: + MessageBoxA(NULL, "DLL Detached!\n", "Game Hacking", MB_OK | MB_TOPMOST); + break; + } + return TRUE; +} + diff --git a/Chapter8_AdobeAirHook/AdobeAirHook.cpp b/Chapter8_AdobeAirHook/AdobeAirHook.cpp new file mode 100644 index 0000000..626b281 --- /dev/null +++ b/Chapter8_AdobeAirHook/AdobeAirHook.cpp @@ -0,0 +1,105 @@ +#include "AdobeAirHook.h" +#include "AdobeAirHookCallbacks.h" +#include "ExecutableModule.h" +#include "DebugConsole.h" +#include "ThreadLock.h" + + +AdobeAirHook* AdobeAirHook::instance = NULL; + +const char encodePattern[16] = {0x8B, 0xCE, 0xE8, 0xA6, 0xFF, 0xFF, 0xFF, 0x83, 0xF8, 0xFF, 0x74, 0x16, 0x03, 0xF8, 0x3B, 0xBE}; +const char decodePattern[12] = {0x8B, 0xCE, 0xE8, 0x7F, 0xF7, 0xFF, 0xFF, 0x83, 0xF8, 0xFF, 0x89, 0x86}; + + +AdobeAirHook::AdobeAirHook() +{ + this->airModule = new ExecutableModule(L"Adobe AIR.dll"); + this->socketLock = new ThreadLock(); + + this->socketLock->enter(); + this->socketLock->leave(); +} +AdobeAirHook::~AdobeAirHook() +{ + this->socketLock->enter(); + this->socketLock->leave(); + + delete this->airModule; + delete this->socketLock; +} + +void AdobeAirHook::execute() +{ + DebugConsole::getInstance(); + do + { + if (!this->airModule->isValid()) + { + printf("invalid module!\n"); + break; + } + + DWORD encodeAddress = this->airModule->findPattern(encodePattern, 16); + DWORD decodeAddress = this->airModule->findPattern(decodePattern, 12); + if (!encodeAddress || !decodeAddress) + { + printf("invalid encode/decode address!\n"); + break; + } + + encodeAddress += 2; decodeAddress += 2; //call is 2 bytes past start of each pattern + + encodeHookFunction = this->airModule->addCallHook("encode", encodeAddress, &myEncode); + if (!encodeHookFunction) + { + printf("encode hook failed!\n"); + break; + } + + decodeHookFunction = this->airModule->addCallHook("decode", decodeAddress, &myDecode); + if (!encodeHookFunction) + { + printf("encode hook failed!\n"); + break; + } + + printf("hooks installed!\n"); + return; //success + } while (0); + + //error is here + this->terminate(); +} +void AdobeAirHook::terminate() +{ + this->airModule->clearCallHooks(); + DebugConsole::deleteInstance(); +} + +DWORD AdobeAirHook::getEncodeHookFunction() +{ + return this->encodeHookFunction; +} + +DWORD AdobeAirHook::getDecodeHookFunction() +{ + return this->decodeHookFunction; +} + +void AdobeAirHook::encodeHookCallback(const unsigned char* buffer, unsigned int size) +{ + if (size == 0xFFFFFFFF) return; + + this->socketLock->enter(); + DebugConsole::getInstance()->dumpBuffer(buffer, size, "Outgoing packet collected"); + this->socketLock->leave(); +} + +void AdobeAirHook::decodeHookCallback(const unsigned char* buffer, unsigned int size) +{ + if (size == 0xFFFFFFFF) return; + + this->socketLock->enter(); + DebugConsole::getInstance()->dumpBuffer(buffer, size, "Incoming packet collected"); + this->socketLock->leave(); +} diff --git a/Chapter8_AdobeAirHook/AdobeAirHook.h b/Chapter8_AdobeAirHook/AdobeAirHook.h new file mode 100644 index 0000000..52a1773 --- /dev/null +++ b/Chapter8_AdobeAirHook/AdobeAirHook.h @@ -0,0 +1,44 @@ +#pragma once +#include + +class ExecutableModule; +class ThreadLock; +class PacketCollector; + +class AdobeAirHook +{ +public: + static AdobeAirHook* getInstance() + { + if (!AdobeAirHook::instance) + AdobeAirHook::instance = new AdobeAirHook(); + return AdobeAirHook::instance; + } + static void deleteInstance() + { + if (AdobeAirHook::instance) + { + delete AdobeAirHook::instance; + AdobeAirHook::instance = NULL; + } + } + + void execute(); + void terminate(); + + DWORD getEncodeHookFunction(); + DWORD getDecodeHookFunction(); + void encodeHookCallback(const unsigned char* buffer, unsigned int size); + void decodeHookCallback(const unsigned char* buffer, unsigned int size); + +private: + AdobeAirHook(); + ~AdobeAirHook(); + + static AdobeAirHook* instance; + + ExecutableModule* airModule; + ThreadLock* socketLock; + + DWORD encodeHookFunction, decodeHookFunction; +}; \ No newline at end of file diff --git a/Chapter8_AdobeAirHook/AdobeAirHook.vcxproj b/Chapter8_AdobeAirHook/AdobeAirHook.vcxproj new file mode 100644 index 0000000..6ea46a1 --- /dev/null +++ b/Chapter8_AdobeAirHook/AdobeAirHook.vcxproj @@ -0,0 +1,101 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {D041E046-6A67-413E-869B-14E3CE06A21B} + Win32Proj + Chapter8_AdobeAirHook + Chapter8_AdobeAirHook + + + + DynamicLibrary + true + Unicode + + + DynamicLibrary + false + true + Unicode + + + + + + + + + + + + + true + $(SolutionDir)\BuildTemp\$(Configuration)\ + + + false + $(SolutionDir)\BuildTemp\$(ProjectName)_$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;ADOBEAIRHOOK_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;ADOBEAIRHOOK_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + true + true + + + + + + + + + + + + + + + false + + + false + + + + + + + + + \ No newline at end of file diff --git a/Chapter8_AdobeAirHook/AdobeAirHook.vcxproj.filters b/Chapter8_AdobeAirHook/AdobeAirHook.vcxproj.filters new file mode 100644 index 0000000..9a2a7b5 --- /dev/null +++ b/Chapter8_AdobeAirHook/AdobeAirHook.vcxproj.filters @@ -0,0 +1,63 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {ec0c29ac-a76b-41e3-a066-77cd77437405} + + + {e2f43ad2-b882-46d5-ad16-5f30255ba5b5} + + + {1a0cd66b-65d6-498a-92a4-8dcf66820d1a} + + + {93221b58-954d-43c9-bdf5-2f94f2022512} + + + + + Header Files\Utils + + + Header Files\Utils + + + Header Files\Core + + + Header Files\Core + + + Header Files\Core + + + + + Source Files + + + Source Files\Utils + + + Source Files\Core + + + Source Files\Core + + + Source Files + + + \ No newline at end of file diff --git a/Chapter8_AdobeAirHook/AdobeAirHookCallbacks.h b/Chapter8_AdobeAirHook/AdobeAirHookCallbacks.h new file mode 100644 index 0000000..6325f1c --- /dev/null +++ b/Chapter8_AdobeAirHook/AdobeAirHookCallbacks.h @@ -0,0 +1,68 @@ +#include "AdobeAirHook.h" +#include +#include + + +DWORD __stdcall reportEncode(const unsigned char* buffer, unsigned int size, unsigned int loopCounter) +{ + if (loopCounter == 0) + AdobeAirHook::getInstance()->encodeHookCallback(buffer, size); + return AdobeAirHook::getInstance()->getEncodeHookFunction(); +} + +DWORD __stdcall getDecode() +{ + return AdobeAirHook::getInstance()->getDecodeHookFunction(); +} +void __stdcall reportDecode(const unsigned char* buffer, unsigned int size) +{ + AdobeAirHook::getInstance()->decodeHookCallback(buffer, size); +} + +void __declspec(naked) myEncode() +{ + __asm + { + MOV EAX, DWORD PTR SS:[ESP + 0x4] // get buffer + MOV EDX, DWORD PTR DS:[ESI + 0x3C58] // get full size + + PUSH ECX // store ecx + + PUSH EDI // push current pos + PUSH EDX // push size + PUSH EAX // push buffer + CALL reportEncode // report the encode call + + POP ECX // restore ecx + + JMP EAX // jump to original function (returned by reportEncode) + } +} + +void __declspec(naked) myDecode() +{ + __asm + { + MOV EAX, DWORD PTR SS:[ESP + 0x4] // get second arg + MOV EDX, DWORD PTR SS:[ESP + 0x8] // get first arg + + PUSH EDX // re-push first arg ------------------. + PUSH EAX // re-push second arg -----------------| + PUSH ECX // store ecx -----------------------. | + CALL getDecode // get the function to call | | + POP ECX // restore ecx ----------------------' | + CALL EAX // call the original function ---------' + + + MOV EDX, DWORD PTR SS:[ESP + 0x4] // get first arg, its the buffer now + + PUSH EAX // store eax ----------------------------. + PUSH ECX // store ecx --------------------------. | + PUSH EAX // push the size -------------------. | | + PUSH EDX // push the buffer -----------------| | | + CALL reportDecode // report the results now -' | | + POP ECX // restore ecx -------------------------' | + POP EAX // restore eax ---------------------------' + RETN 8 // return + } +} \ No newline at end of file diff --git a/Chapter8_AdobeAirHook/DebugConsole.cpp b/Chapter8_AdobeAirHook/DebugConsole.cpp new file mode 100644 index 0000000..0bded45 --- /dev/null +++ b/Chapter8_AdobeAirHook/DebugConsole.cpp @@ -0,0 +1,109 @@ +#include "DebugConsole.h" + +#include +#include +#include +#include + +DebugConsole* DebugConsole::instance = NULL;; + +DebugConsole::DebugConsole() +{ + this->show(); +} +DebugConsole::~DebugConsole() +{ + this->hide(); +} + +void DebugConsole::show() +{ + using namespace std; + + auto out = freopen("C:\\leaguelog.txt","w",stdout); + + return; + + static const WORD MAX_CONSOLE_LINES = 5000; + + int hConHandle; + long lStdHandle; + CONSOLE_SCREEN_BUFFER_INFO coninfo; + FILE *fp; + + // allocate a console for this app + AllocConsole(); + + // set the screen buffer to be big enough to let us scroll text + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo); + coninfo.dwSize.Y = MAX_CONSOLE_LINES; + SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize); + + // redirect unbuffered STDOUT to the console + lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen( hConHandle, "w" ); + *stdout = *fp; + setvbuf( stdout, NULL, _IONBF, 0 ); + + // redirect unbuffered STDIN to the console + lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen( hConHandle, "r" ); + *stdin = *fp; + setvbuf( stdin, NULL, _IONBF, 0 ); + + // redirect unbuffered STDERR to the console + lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen( hConHandle, "w" ); + *stderr = *fp; + setvbuf( stderr, NULL, _IONBF, 0 ); + + // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog + // point to console as well + ios::sync_with_stdio(); +} +void DebugConsole::hide() +{ + FreeConsole(); +} + +void DebugConsole::dumpBuffer(const char* buffer, unsigned int size, const char* title) +{ + printf("%s> %d bytes", title, size); + + for (unsigned int o = 0; o < ceil(size / 16.0f); o++) + { + printf("\n "); + for (unsigned int t = 0; t < 2; t++) + { + for (unsigned int i = 0; i < 16; i++) + { + unsigned char val = buffer[(o * 16) + i] & 0xFF; + if (t == 0) + { + if (i == 8) + printf("| "); + + if ((o * 16) + i < size) + printf("%02X ", val); + else + printf(" ", val); + } + else if ((o * 16) + i < size) + { + if (val > ' ' && val <= '~') + printf("%c", val); + else + printf("."); + } + else + printf(" "); + } + printf("|"); + } + } + + printf("\n"); +} \ No newline at end of file diff --git a/Chapter8_AdobeAirHook/DebugConsole.h b/Chapter8_AdobeAirHook/DebugConsole.h new file mode 100644 index 0000000..a6078e5 --- /dev/null +++ b/Chapter8_AdobeAirHook/DebugConsole.h @@ -0,0 +1,41 @@ +#pragma once +#include +#include + +#ifdef _DEBUG +#define LOG(message) printf("%s (%d): %s\n", __FUNCTION__, __LINE__, message) +#else +#define LOG(message) +#endif + +class DebugConsole +{ +public: + static DebugConsole* getInstance() + { + if (!DebugConsole::instance) + DebugConsole::instance = new DebugConsole(); + return DebugConsole::instance; + } + static void deleteInstance() + { + if (DebugConsole::instance) + { + delete DebugConsole::instance; + DebugConsole::instance = NULL; + } + } + void dumpBuffer(const char* buffer, unsigned int size, const char* title); + void dumpBuffer(char* buffer, unsigned int size, const char* title) { this->dumpBuffer((const char*)buffer, size, title); } + void dumpBuffer(unsigned char* buffer, unsigned int size, const char* title) { this->dumpBuffer((const char*)buffer, size, title); } + void dumpBuffer(const unsigned char* buffer, unsigned int size, const char* title) { this->dumpBuffer((const char*)buffer, size, title); } + +private: + static DebugConsole* instance; + + DebugConsole(); + ~DebugConsole(); + + void show(); + void hide(); +}; \ No newline at end of file diff --git a/Chapter8_AdobeAirHook/ExecutableModule.cpp b/Chapter8_AdobeAirHook/ExecutableModule.cpp new file mode 100644 index 0000000..fe12033 --- /dev/null +++ b/Chapter8_AdobeAirHook/ExecutableModule.cpp @@ -0,0 +1,116 @@ +#include "ExecutableModule.h" + +#include +#include + + +ExecutableModule::ExecutableModule(const wchar_t* moduleName) : name(moduleName), base(0), size(0), oldProtect(0) +{ + this->getModuleInformation(); +} + + +ExecutableModule::~ExecutableModule(void) +{ +} + +DWORD ExecutableModule::findPattern(const char* pattern, unsigned int patternLength, unsigned int occurance) +{ + unsigned int ocur = 0; + for (DWORD adr = this->base; adr < this->base + this->size - patternLength; adr++) + { + + if (memcmp((LPVOID)pattern, (LPVOID)adr, patternLength) == 0) + { + ocur++; + if (ocur == occurance) + return adr; + } + } + return 0; +} + +DWORD ExecutableModule::addCallHook(const char* name, DWORD address, LPVOID function) +{ + callHookInformation hook; + hook.hookAtAddress = address; + hook.newFuncAddress = (DWORD)function; + + if (this->readMemory(hook.hookAtAddress) != 0xE8) + { + printf("Hook %s is not on a valid opcode (saw 0x%02x at address 0x%08x)!\n", + name, + this->readMemory(hook.hookAtAddress), + hook.hookAtAddress); + return 0; + } + + bool hooked = true; + this->allowOPCodeModification(hook.hookAtAddress + 1, 4); + { + hook.oldFuncOffset = this->readMemory(hook.hookAtAddress + 1); + if (!this->writeMemory(hook.hookAtAddress + 1, hook.newFuncAddress - hook.hookAtAddress - 5)) + { + printf("Failed to write memory for hook %s!\n", name); + hooked = false; + } + } + this->disallowOPCodeModification(hook.hookAtAddress + 1, 4); + + if (!hooked) + return 0; + + this->callHooks.push_back(hook); + return hook.getOldFunctionAddress(); +} + +void ExecutableModule::clearCallHooks() +{ + for (auto hook = this->callHooks.begin(); hook != this->callHooks.end(); hook++) + { + this->allowOPCodeModification(hook->hookAtAddress + 1, 4); + this->writeMemory(hook->hookAtAddress + 1, hook->oldFuncOffset); + this->disallowOPCodeModification(hook->hookAtAddress + 1, 4); + } + this->callHooks.clear(); +} + +void ExecutableModule::getModuleInformation() +{ + MODULEENTRY32 entry; + entry.dwSize = sizeof(MODULEENTRY32); + + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, NULL); + + if (Module32First(snapshot, &entry) == TRUE) + { + while (Module32Next(snapshot, &entry) == TRUE) + { + std::wstring binaryPath = entry.szModule; + if (binaryPath.find(this->name) != std::wstring::npos) + { + this->size = (DWORD)entry.modBaseSize; + this->base = (DWORD)entry.modBaseAddr; + break; + } + } + } + + CloseHandle(snapshot); +} + + +void ExecutableModule::allowOPCodeModification(DWORD address, unsigned int size) +{ + this->oldProtect = this->setRegionProtection(address, size, PAGE_EXECUTE_READWRITE); +} +void ExecutableModule::disallowOPCodeModification(DWORD address, unsigned int size) +{ + this->setRegionProtection(address, size, (oldProtect) ? oldProtect : PAGE_WRITECOPY); +} +DWORD ExecutableModule::setRegionProtection(DWORD address, unsigned int size, DWORD protection) +{ + DWORD oldProtection; + VirtualProtect((LPVOID)address, size, protection, &oldProtection); + return oldProtection; +} \ No newline at end of file diff --git a/Chapter8_AdobeAirHook/ExecutableModule.h b/Chapter8_AdobeAirHook/ExecutableModule.h new file mode 100644 index 0000000..2aa6a45 --- /dev/null +++ b/Chapter8_AdobeAirHook/ExecutableModule.h @@ -0,0 +1,71 @@ +#pragma once +#include +#include + +class ExecutableModule +{ +public: + ExecutableModule(const wchar_t* moduleName); + ~ExecutableModule(); + + DWORD findPattern(const char* pattern, unsigned int patternLength, unsigned int occurance = 1); + DWORD addCallHook(const char* name, DWORD address, LPVOID function); + void clearCallHooks(); + + bool isValid() { return this->base > 0 && this->size > 0; } + + DWORD getBase() { return this->base; } + DWORD getSize() { return this->size; } + + template + T* pointMemory(DWORD address) + { + return (T*)address; + } + + template + T readMemory(DWORD address) + { + if (address < this->base || address > (this->base + this->size)) + { + T ret; + memset(&ret, 0, sizeof(T)); + return ret; + } + return *(T*)address; + } + + template + bool writeMemory(DWORD address, T value) + { + if (address < this->base || address > (this->base + this->size)) + return false; + *(T*)(address) = value; + return true; + } + +private: + struct callHookInformation + { + const char* name; + DWORD hookAtAddress; + DWORD newFuncAddress; + DWORD oldFuncOffset; + + DWORD getOldFunctionAddress() + { + return hookAtAddress + oldFuncOffset + 5; + } + }; + + const wchar_t* name; + DWORD base, size, oldProtect; + std::list callHooks; + + void getModuleInformation(); + + void allowOPCodeModification(DWORD address, unsigned int size); + void disallowOPCodeModification(DWORD address, unsigned int size); + DWORD setRegionProtection(DWORD address, unsigned int size, DWORD protection); +}; + diff --git a/Chapter8_AdobeAirHook/ThreadLock.h b/Chapter8_AdobeAirHook/ThreadLock.h new file mode 100644 index 0000000..832ffe7 --- /dev/null +++ b/Chapter8_AdobeAirHook/ThreadLock.h @@ -0,0 +1,27 @@ +#pragma once +#include + +class ThreadLock +{ +public: + ThreadLock() + { + InitializeCriticalSection(&cs); + } + + ~ThreadLock(){ + DeleteCriticalSection(&cs); + } + + void enter() + { + EnterCriticalSection(&cs); + } + + void leave() + { + LeaveCriticalSection(&cs); + } +private: + CRITICAL_SECTION cs; +}; \ No newline at end of file diff --git a/Chapter8_AdobeAirHook/dllmain.cpp b/Chapter8_AdobeAirHook/dllmain.cpp new file mode 100644 index 0000000..be85ed3 --- /dev/null +++ b/Chapter8_AdobeAirHook/dllmain.cpp @@ -0,0 +1,25 @@ +#include +#include "AdobeAirHook.h" +AdobeAirHook* hook; + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + AdobeAirHook::getInstance()->execute(); + break; + case DLL_PROCESS_DETACH: + AdobeAirHook::getInstance()->terminate(); + AdobeAirHook::deleteInstance(); + break; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + } + return TRUE; +} + diff --git a/Chapter8_ControlFlow/Chapter8_ControlFlow.vcxproj b/Chapter8_ControlFlow/Chapter8_ControlFlow.vcxproj new file mode 100644 index 0000000..de8d97e --- /dev/null +++ b/Chapter8_ControlFlow/Chapter8_ControlFlow.vcxproj @@ -0,0 +1,91 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {ACA1A8FF-6D8C-407A-983C-929D6F958D83} + Win32Proj + Chapter8_ControlFlow + Chapter8_ControlFlow + + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + true + $(SolutionDir)\BuildTemp\$(Configuration)\ + + + false + $(SolutionDir)\BuildTemp\$(ProjectName)_$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + 4Bytes + + + Console + true + false + + + + + Level3 + + + Disabled + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + 4Bytes + + + Console + true + true + true + + + false + + + + + + + + + \ No newline at end of file diff --git a/Chapter8_ControlFlow/main-controlFlow.cpp b/Chapter8_ControlFlow/main-controlFlow.cpp new file mode 100644 index 0000000..f50f4a0 --- /dev/null +++ b/Chapter8_ControlFlow/main-controlFlow.cpp @@ -0,0 +1,321 @@ +#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); + } + + +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 + NOPExample(); + callHookExample(); + VFHookExample(); + IATHookExample(); + + while (true) // stay busy + { + Sleep(100); + } +} \ No newline at end of file diff --git a/Chapter8_Direct3DApplication/Chapter8_Direct3DApplication.vcxproj b/Chapter8_Direct3DApplication/Chapter8_Direct3DApplication.vcxproj new file mode 100644 index 0000000..962f0fb --- /dev/null +++ b/Chapter8_Direct3DApplication/Chapter8_Direct3DApplication.vcxproj @@ -0,0 +1,73 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {E621BD23-8A39-4BA3-9DB0-191661BBF6C9} + Chapter8_Direct3DApplication + + + + Application + true + MultiByte + + + Application + false + true + MultiByte + + + + + + + + + + + + + $(SolutionDir)\BuildTemp\$(ProjectName)_$(Configuration)\ + + + $(SolutionDir)\BuildTemp\$(Configuration)\ + + + + Level3 + Disabled + + + true + + + + + Level3 + MaxSpeed + true + true + + + true + true + true + + + + + + + + + \ No newline at end of file diff --git a/Chapter8_Direct3DApplication/Chapter8_Direct3DApplication.vcxproj.filters b/Chapter8_Direct3DApplication/Chapter8_Direct3DApplication.vcxproj.filters new file mode 100644 index 0000000..8755a3a --- /dev/null +++ b/Chapter8_Direct3DApplication/Chapter8_Direct3DApplication.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/Chapter8_Direct3DApplication/main.cpp b/Chapter8_Direct3DApplication/main.cpp new file mode 100644 index 0000000..f7fc3f7 --- /dev/null +++ b/Chapter8_Direct3DApplication/main.cpp @@ -0,0 +1,298 @@ +/* + This is just a test application for the Direct3D hook proof-of-concept. + + The code for this application is from http://www.directxtutorial.com/ + The only thing I added was 'LoadLibrary("Chapter8_Direct3DHook.dll");' + to load the POC hook. +*/ +// include the basic windows header files and the Direct3D header file +#include +#include +#include +#include + +// define the screen resolution +#define SCREEN_WIDTH 800 +#define SCREEN_HEIGHT 600 + +// include the Direct3D Library files +#pragma comment (lib, "d3d9.lib") +#pragma comment (lib, "d3dx9.lib") + +// global declarations +LPDIRECT3D9 d3d; +LPDIRECT3DDEVICE9 d3ddev; +LPDIRECT3DVERTEXBUFFER9 v_buffer = NULL; +LPDIRECT3DINDEXBUFFER9 i_buffer = NULL; + +// function prototypes +void initD3D(HWND hWnd); +void render_frame(void); +void cleanD3D(void); +void init_graphics(void); +void init_light(void); // sets up the light and the material + +struct CUSTOMVERTEX {FLOAT X, Y, Z; D3DVECTOR NORMAL;}; +#define CUSTOMFVF (D3DFVF_XYZ | D3DFVF_NORMAL) + +// the WindowProc function prototype +LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + + +// the entry point for any Windows program +int WINAPI WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) +{ + HWND hWnd; + WNDCLASSEX wc; + + ZeroMemory(&wc, sizeof(WNDCLASSEX)); + + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = WindowProc; + wc.hInstance = hInstance; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.lpszClassName = "WindowClass"; + + RegisterClassEx(&wc); + + hWnd = CreateWindowEx(NULL, "WindowClass", "Our Direct3D Program", + WS_OVERLAPPEDWINDOW, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, + NULL, NULL, hInstance, NULL); + + ShowWindow(hWnd, nCmdShow); + + // set up and initialize Direct3D + initD3D(hWnd); + + // enter the main loop: + + MSG msg; + + while(TRUE) + { + while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + if(msg.message == WM_QUIT) + break; + + render_frame(); + } + + // clean up DirectX and COM + cleanD3D(); + + return msg.wParam; +} + + +// this is the main message handler for the program +LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case WM_DESTROY: + { + PostQuitMessage(0); + return 0; + } break; + } + + return DefWindowProc (hWnd, message, wParam, lParam); +} + + +// this function initializes and prepares Direct3D for use +void initD3D(HWND hWnd) +{ + d3d = Direct3DCreate9(D3D_SDK_VERSION); + + D3DPRESENT_PARAMETERS d3dpp; + + ZeroMemory(&d3dpp, sizeof(d3dpp)); + d3dpp.Windowed = TRUE; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = hWnd; + d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; + d3dpp.BackBufferWidth = SCREEN_WIDTH; + d3dpp.BackBufferHeight = SCREEN_HEIGHT; + d3dpp.EnableAutoDepthStencil = TRUE; + d3dpp.AutoDepthStencilFormat = D3DFMT_D16; + + // create a device class using this information and the info from the d3dpp stuct + d3d->CreateDevice(D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + hWnd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &d3dpp, + &d3ddev); + + init_graphics(); // call the function to initialize the cube + init_light(); // call the function to initialize the light and material + + d3ddev->SetRenderState(D3DRS_LIGHTING, TRUE); // turn on the 3D lighting + d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE); // turn on the z-buffer + d3ddev->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(15, 15, 15)); // ambient light + + + LoadLibrary("Chapter8_Direct3DHook.dll"); +} + + +// this is the function used to render a single frame +void render_frame(void) +{ + d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); + d3ddev->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); + + d3ddev->BeginScene(); + + // select which vertex format we are using + d3ddev->SetFVF(CUSTOMFVF); + + // set the view transform + D3DXMATRIX matView; + D3DXMatrixLookAtLH(&matView, + &D3DXVECTOR3 (0.0f, 8.0f, 25.0f), // the camera position + &D3DXVECTOR3 (0.0f, 0.0f, 0.0f), // the look-at position + &D3DXVECTOR3 (0.0f, 1.0f, 0.0f)); // the up direction + d3ddev->SetTransform(D3DTS_VIEW, &matView); + + // set the projection transform + D3DXMATRIX matProjection; + D3DXMatrixPerspectiveFovLH(&matProjection, + D3DXToRadian(45), + (FLOAT)SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT, + 1.0f, // the near view-plane + 100.0f); // the far view-plane + d3ddev->SetTransform(D3DTS_PROJECTION, &matProjection); + + // set the world transform + static float index = 0.0f; index+=0.03f; + D3DXMATRIX matRotateY; + D3DXMatrixRotationY(&matRotateY, index); + d3ddev->SetTransform(D3DTS_WORLD, &(matRotateY)); + + // select the vertex and index buffers to use + d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); + d3ddev->SetIndices(i_buffer); + + // draw the cube + d3ddev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 24, 0, 12); + + d3ddev->EndScene(); + + d3ddev->Present(NULL, NULL, NULL, NULL); +} + + +// this is the function that cleans up Direct3D and COM +void cleanD3D(void) +{ + v_buffer->Release(); + i_buffer->Release(); + d3ddev->Release(); + d3d->Release(); +} + + +// this is the function that puts the 3D models into video RAM +void init_graphics(void) +{ + // create the vertices using the CUSTOMVERTEX struct + CUSTOMVERTEX vertices[] = + { + { -3.0f, -3.0f, 3.0f, 0.0f, 0.0f, 1.0f, }, // side 1 + { 3.0f, -3.0f, 3.0f, 0.0f, 0.0f, 1.0f, }, + { -3.0f, 3.0f, 3.0f, 0.0f, 0.0f, 1.0f, }, + { 3.0f, 3.0f, 3.0f, 0.0f, 0.0f, 1.0f, }, + + { -3.0f, -3.0f, -3.0f, 0.0f, 0.0f, -1.0f, }, // side 2 + { -3.0f, 3.0f, -3.0f, 0.0f, 0.0f, -1.0f, }, + { 3.0f, -3.0f, -3.0f, 0.0f, 0.0f, -1.0f, }, + { 3.0f, 3.0f, -3.0f, 0.0f, 0.0f, -1.0f, }, + + { -3.0f, 3.0f, -3.0f, 0.0f, 1.0f, 0.0f, }, // side 3 + { -3.0f, 3.0f, 3.0f, 0.0f, 1.0f, 0.0f, }, + { 3.0f, 3.0f, -3.0f, 0.0f, 1.0f, 0.0f, }, + { 3.0f, 3.0f, 3.0f, 0.0f, 1.0f, 0.0f, }, + + { -3.0f, -3.0f, -3.0f, 0.0f, -1.0f, 0.0f, }, // side 4 + { 3.0f, -3.0f, -3.0f, 0.0f, -1.0f, 0.0f, }, + { -3.0f, -3.0f, 3.0f, 0.0f, -1.0f, 0.0f, }, + { 3.0f, -3.0f, 3.0f, 0.0f, -1.0f, 0.0f, }, + + { 3.0f, -3.0f, -3.0f, 1.0f, 0.0f, 0.0f, }, // side 5 + { 3.0f, 3.0f, -3.0f, 1.0f, 0.0f, 0.0f, }, + { 3.0f, -3.0f, 3.0f, 1.0f, 0.0f, 0.0f, }, + { 3.0f, 3.0f, 3.0f, 1.0f, 0.0f, 0.0f, }, + + { -3.0f, -3.0f, -3.0f, -1.0f, 0.0f, 0.0f, }, // side 6 + { -3.0f, -3.0f, 3.0f, -1.0f, 0.0f, 0.0f, }, + { -3.0f, 3.0f, -3.0f, -1.0f, 0.0f, 0.0f, }, + { -3.0f, 3.0f, 3.0f, -1.0f, 0.0f, 0.0f, }, + }; + + // create a vertex buffer interface called v_buffer + d3ddev->CreateVertexBuffer(24*sizeof(CUSTOMVERTEX), + 0, + CUSTOMFVF, + D3DPOOL_MANAGED, + &v_buffer, + NULL); + + VOID* pVoid; // a void pointer + + // lock v_buffer and load the vertices into it + v_buffer->Lock(0, 0, (void**)&pVoid, 0); + memcpy(pVoid, vertices, sizeof(vertices)); + v_buffer->Unlock(); + + // create the indices using an int array + short indices[] = + { + 0, 1, 2, // side 1 + 2, 1, 3, + 4, 5, 6, // side 2 + 6, 5, 7, + 8, 9, 10, // side 3 + 10, 9, 11, + 12, 13, 14, // side 4 + 14, 13, 15, + 16, 17, 18, // side 5 + 18, 17, 19, + 20, 21, 22, // side 6 + 22, 21, 23, + }; + + // create an index buffer interface called i_buffer + d3ddev->CreateIndexBuffer(36*sizeof(short), + 0, + D3DFMT_INDEX16, + D3DPOOL_MANAGED, + &i_buffer, + NULL); + + // lock i_buffer and load the indices into it + i_buffer->Lock(0, 0, (void**)&pVoid, 0); + memcpy(pVoid, indices, sizeof(indices)); + i_buffer->Unlock(); +} + +void init_light() +{ + D3DMATERIAL9 material; + + ZeroMemory(&material, sizeof(D3DMATERIAL9)); + material.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); + material.Ambient = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); + + d3ddev->SetMaterial(&material); +} diff --git a/Chapter8_Direct3DHook/Chapter8_Direct3DHook.vcproj b/Chapter8_Direct3DHook/Chapter8_Direct3DHook.vcproj new file mode 100644 index 0000000..6d5def7 --- /dev/null +++ b/Chapter8_Direct3DHook/Chapter8_Direct3DHook.vcproj @@ -0,0 +1,216 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Chapter8_Direct3DHook/Chapter8_Direct3DHook.vcxproj b/Chapter8_Direct3DHook/Chapter8_Direct3DHook.vcxproj new file mode 100644 index 0000000..b39a1e6 --- /dev/null +++ b/Chapter8_Direct3DHook/Chapter8_Direct3DHook.vcxproj @@ -0,0 +1,114 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + Chapter8_Direct3DHook + {784C482A-F6EC-4BCB-851E-07BE782BB040} + Chapter8_Direct3DHook + Win32Proj + + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)$(Configuration)\ + $(SolutionDir)\BuildTemp\$(Configuration)\ + true + $(SolutionDir)$(Configuration)\ + $(SolutionDir)\BuildTemp\$(ProjectName)_$(Configuration)\ + false + $(ExecutablePath) + $(ProjectName) + + + + Disabled + C:\Program Files (x86)\Microsoft Research\ms detours 1.5 src\src;C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;LOLORACLEHOOK_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + detours.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).dll + + + true + Windows + + + MachineX86 + + + + + MaxSpeed + true + C:\Program Files (x86)\Microsoft Research\ms detours 1.5 src\src;C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;LOLORACLEHOOK_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + + + %(AdditionalDependencies) + $(OutDir)$(ProjectName).dll + + + true + Windows + true + true + + + MachineX86 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Chapter8_Direct3DHook/Chapter8_Direct3DHook.vcxproj.filters b/Chapter8_Direct3DHook/Chapter8_Direct3DHook.vcxproj.filters new file mode 100644 index 0000000..92e74d2 --- /dev/null +++ b/Chapter8_Direct3DHook/Chapter8_Direct3DHook.vcxproj.filters @@ -0,0 +1,36 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/Chapter8_Direct3DHook/DirectXHook.cpp b/Chapter8_Direct3DHook/DirectXHook.cpp new file mode 100644 index 0000000..6ac14a1 --- /dev/null +++ b/Chapter8_Direct3DHook/DirectXHook.cpp @@ -0,0 +1,257 @@ +#include "DirectXHook.h" +#include "DirectXHookCallbacks.h" +#include "memory.h" + +DirectXHook* DirectXHook::instance = NULL; +unsigned char* DirectXHook::originalEndSceneCode = NULL; +DWORD DirectXHook::endSceneAddress = NULL; +LPDIRECT3DDEVICE9 DirectXHook::hookedDevice = NULL; + +_reset DirectXHook::origReset = NULL; +_endScene DirectXHook::origEndScene = NULL; +_drawPrimitive DirectXHook::origDrawPrimitive = NULL; +_drawIndexedPrimitive DirectXHook::origDrawIndexedPrimitive = NULL; + +bool DirectXHook::hookReady = false; +bool DirectXHook::hookReadyPre = false; + + +void DirectXHook::initialize() +{ + while (!GetModuleHandleA("d3d9.dll")) + Sleep(10); + + DirectXHook::endSceneAddress = this->locateEndScene(); + if (DirectXHook::endSceneAddress) + DirectXHook::originalEndSceneCode = hookWithJump(DirectXHook::endSceneAddress, (DWORD)&endSceneTrampoline); + + while (!DirectXHook::hookReadyPre) + Sleep(10); + + DirectXHook::hookReady = true; +} + +void DirectXHook::addDrawFrameCallback(_drawFrameCallback cb) +{ + if (!DirectXHook::hookReady) + this->drawFrameCallbacks.push_back(cb); +} +void DirectXHook::addDrawPrimitiveCallback(_drawPrimitiveCallback cb) +{ + if (!DirectXHook::hookReady) + this->drawPrimitiveCallbacks.push_back(cb); +} +void DirectXHook::addDrawIndexedPrimitiveCallback(_drawIndexedPrimitiveCallback cb) +{ + if (!DirectXHook::hookReady) + this->drawIndexedPrimitiveCallbacks.push_back(cb); +} + +LPDIRECT3DTEXTURE9 DirectXHook::addTexture(std::wstring imagePath) +{ + if (DirectXHook::hookReady) + { + LPDIRECT3DTEXTURE9 texture; + + if (D3DXCreateTextureFromFile(this->hookedDevice, imagePath.c_str(), &texture) < 0) + return NULL; + + return texture; + } + return NULL; +} + +int DirectXHook::addSpriteImage(std::wstring imagePath) +{ + if (DirectXHook::hookReady) + { + LPDIRECT3DTEXTURE9 texture; + LPD3DXSPRITE sprite; + D3DSURFACE_DESC desc; + + if (D3DXCreateTextureFromFile(this->hookedDevice, imagePath.c_str(), &texture) < 0) + return -1; + if(D3DXCreateSprite(this->hookedDevice, &sprite) < 0) + return -1; + texture->GetLevelDesc(0, &desc); + + this->imageBitmaps.push_back(texture); + this->imageSprites.push_back(sprite); + this->imageDescriptions.push_back(desc); + return this->imageBitmaps.size()-1; + } + + return -1; +} + +void DirectXHook::drawText(int x, int y, D3DCOLOR color, const char *text, ...) +{ + RECT rect; + va_list va_alist; + char buf[256] = {0}; + + va_start (va_alist, text); + _vsnprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), text, va_alist); + va_end (va_alist); + + rect.left=x+1; + rect.top=y+1; + rect.right=rect.left+1000; + rect.bottom=rect.top+1000; + + this->font->DrawTextA(NULL, buf, -1, &rect, 0, D3DCOLOR_ARGB(255, 10, 10, 10)); + rect.left--; + rect.top--; + this->font->DrawTextA(NULL, buf, -1, &rect, 0, color); +} + +void DirectXHook::drawSpriteImage(int imageID, int x, int y, int w, int h) +{ + if (imageID >= this->imageBitmaps.size() || imageID < 0) + return; + + D3DSURFACE_DESC desc = this->imageDescriptions[imageID]; + D3DXVECTOR2 scaleFactor; + if (h == -1 && w == -1) + { + scaleFactor = D3DXVECTOR2(1.0, 1.0); + } + else if (h == -1) + { + float scale = (float)w / (float)desc.Width; + scaleFactor = D3DXVECTOR2(scale, scale); + } + else if (w == -1) + { + float scale = (float)h / (float)desc.Height; + scaleFactor = D3DXVECTOR2(scale, scale); + } + else + scaleFactor = D3DXVECTOR2((float)w / (float)desc.Width, (float)h / (float)desc.Height); + + D3DXMATRIX spriteMatrix; + D3DXMatrixTransformation2D(&spriteMatrix, NULL, 0, &scaleFactor, NULL, 0, NULL); + + D3DXVECTOR3 imagepos((float)x * (1.0f / scaleFactor.x), (float)y * (1.0f / scaleFactor.y), 0); + this->imageSprites[imageID]->Begin(D3DXSPRITE_ALPHABLEND); + this->imageSprites[imageID]->SetTransform(&spriteMatrix); + this->imageSprites[imageID]->Draw(this->imageBitmaps[imageID], NULL, NULL, &imagepos, 0xFFFFFFFF); + this->imageSprites[imageID]->End(); +} + +DWORD DirectXHook::initHookCallback(LPDIRECT3DDEVICE9 device) +{ + DirectXHook::hookedDevice = device; + + while (DirectXHook::originalEndSceneCode == NULL){} + unhookWithJump(DirectXHook::endSceneAddress, originalEndSceneCode); + + D3DXCreateFont(DirectXHook::hookedDevice, 15, 0, FW_BOLD, 1, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial", &this->font); + + this->placeHooks(); + DirectXHook::hookReadyPre = true; + + return DirectXHook::endSceneAddress; +} + +DX_API DirectXHook::resetHookCallback(LPDIRECT3DDEVICE9 pDevice, D3DPRESENT_PARAMETERS* pPresentationParameters) +{ + auto result = origReset(pDevice, pPresentationParameters); + if (result == D3D_OK) + this->onLostDevice(); + return result; +} +DX_API DirectXHook::endSceneHookCallback(LPDIRECT3DDEVICE9 pDevice) +{ + for (int i = 0; i < drawFrameCallbacks.size(); i++) + drawFrameCallbacks[i](this, pDevice); + + auto result = origEndScene(pDevice); + this->placeHooks(); + return result; +} +DX_API DirectXHook::drawPrimitiveHookCallback(LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount) +{ + for (int i = 0; i < drawPrimitiveCallbacks.size(); i++) + drawPrimitiveCallbacks[i](this, pDevice, PrimitiveType, StartVertex, PrimitiveCount); + return origDrawPrimitive(pDevice, PrimitiveType, StartVertex, PrimitiveCount); +} +DX_API DirectXHook::drawIndexedPrimitiveHookCallback(LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE PrimType, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount) +{ + for (int i = 0; i < drawIndexedPrimitiveCallbacks.size(); i++) + drawIndexedPrimitiveCallbacks[i](this, pDevice, PrimType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount); + + return origDrawIndexedPrimitive(pDevice, PrimType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount); +} + + +void DirectXHook::placeHooks() +{ + static const DWORD VHHookCount = 4; + static VFHookInfo VFHooks[VHHookCount] = + { + VFHookInfo(16, (DWORD)&myReset, (DWORD*)&DirectXHook::origReset), + VFHookInfo(42, (DWORD)&myEndScene, (DWORD*)&DirectXHook::origEndScene), + VFHookInfo(81, (DWORD)&myDrawPrimitive, (DWORD*)&DirectXHook::origDrawPrimitive), + VFHookInfo(82, (DWORD)&myDrawIndexedPrimitive, (DWORD*)&DirectXHook::origDrawIndexedPrimitive), + }; + + for (int hook = 0; hook < VHHookCount; hook++) + { + DWORD ret = hookVF((DWORD)DirectXHook::hookedDevice, VFHooks[hook].index, VFHooks[hook].callback); + if (ret != VFHooks[hook].callback) + *VFHooks[hook].origFunc = ret; + } +} + +void DirectXHook::onLostDevice() +{ + if (this->font) + this->font->OnLostDevice(); + + for (int i = 0; i < this->imageSprites.size(); i++) + this->imageSprites[i]->OnLostDevice(); +} + + +DWORD DirectXHook::locateEndScene() +{ + WNDCLASSEXA wc = + { + sizeof(WNDCLASSEX), + CS_CLASSDC, + DefWindowProc, + 0L,0L, + GetModuleHandleA(NULL), + NULL, NULL, NULL, NULL, + "DX", NULL + }; + + RegisterClassExA(&wc); + HWND hWnd = CreateWindowA("DX",NULL,WS_OVERLAPPEDWINDOW,100,100,600,600,GetDesktopWindow(),NULL,wc.hInstance,NULL); + + LPDIRECT3D9 pD3D = Direct3DCreate9(D3D_SDK_VERSION); + + if (!pD3D) + return 0; + + D3DPRESENT_PARAMETERS d3dpp; + ZeroMemory( &d3dpp, sizeof(d3dpp) ); + d3dpp.Windowed = TRUE; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = hWnd; + + LPDIRECT3DDEVICE9 pd3dDevice; + HRESULT res = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pd3dDevice); + + if (FAILED(res)) + return 0; + + DWORD EndSceneAddress = getVF((DWORD)pd3dDevice, 42); + + pD3D->Release(); + pd3dDevice->Release(); + DestroyWindow(hWnd); + + return EndSceneAddress; +} \ No newline at end of file diff --git a/Chapter8_Direct3DHook/DirectXHook.h b/Chapter8_Direct3DHook/DirectXHook.h new file mode 100644 index 0000000..4d556eb --- /dev/null +++ b/Chapter8_Direct3DHook/DirectXHook.h @@ -0,0 +1,109 @@ +#pragma once + +#pragma once +#define WIN32_LEAN_AND_MEAN + +#include + +#include +#pragma comment(lib, "winmm.lib") +#include +#include + +#include +#include +#pragma comment(lib, "d3d9.lib") +#pragma comment(lib, "d3dx9.lib") + +#include + +#define DX_API HRESULT WINAPI + +typedef HRESULT (WINAPI* _reset)(LPDIRECT3DDEVICE9 pDevice, D3DPRESENT_PARAMETERS* pPresentationParameters); +typedef HRESULT (WINAPI* _endScene)(LPDIRECT3DDEVICE9 pDevice); +typedef HRESULT (WINAPI* _drawPrimitive)(LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount); +typedef HRESULT (WINAPI* _drawIndexedPrimitive)(LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE PrimType, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount); + + +class DirectXHook; +typedef void (*_drawFrameCallback)(DirectXHook* hook, LPDIRECT3DDEVICE9 pDevice); +typedef void (*_drawPrimitiveCallback)(DirectXHook* hook, LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount); +typedef void (*_drawIndexedPrimitiveCallback)(DirectXHook* hook, LPDIRECT3DDEVICE9 device, D3DPRIMITIVETYPE primType, INT baseVertexIndex, UINT minVertexIndex, UINT numVertices, UINT startIndex, UINT primCount); + +class DirectXHook +{ +public: + static _reset origReset; + static _endScene origEndScene; + static _drawPrimitive origDrawPrimitive; + static _drawIndexedPrimitive origDrawIndexedPrimitive; + + static DirectXHook* getInstance() + { + if (!DirectXHook::instance) + DirectXHook::instance = new DirectXHook(); + return DirectXHook::instance; + } + static void deleteInstance() + { + if (DirectXHook::instance) + { + delete DirectXHook::instance; + DirectXHook::instance = NULL; + } + } + void initialize(); + + void addDrawFrameCallback(_drawFrameCallback cb); + void addDrawPrimitiveCallback(_drawPrimitiveCallback cb); + void addDrawIndexedPrimitiveCallback(_drawIndexedPrimitiveCallback cb); + + LPDIRECT3DTEXTURE9 addTexture(std::wstring imagePath); + int addSpriteImage(std::wstring imagePath); + + void drawText(int x, int y, D3DCOLOR color, const char *text, ...); + void drawSpriteImage(int imageID, int x, int y, int w, int h); + + DWORD initHookCallback(LPDIRECT3DDEVICE9 device); + DX_API resetHookCallback(LPDIRECT3DDEVICE9 pDevice, D3DPRESENT_PARAMETERS* pPresentationParameters); + DX_API endSceneHookCallback(LPDIRECT3DDEVICE9 pDevice); + DX_API drawPrimitiveHookCallback(LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount); + DX_API drawIndexedPrimitiveHookCallback(LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE PrimType, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount); + + +private: + DirectXHook(void) {}; + ~DirectXHook(void) {}; + + + static DirectXHook* instance; + static unsigned char* originalEndSceneCode; + static DWORD endSceneAddress; + static LPDIRECT3DDEVICE9 hookedDevice; + + static bool hookReadyPre, hookReady; + + std::vector<_drawFrameCallback> drawFrameCallbacks; + std::vector<_drawPrimitiveCallback> drawPrimitiveCallbacks; + std::vector<_drawIndexedPrimitiveCallback> drawIndexedPrimitiveCallbacks; + + std::vector imageBitmaps; + std::vector imageDescriptions; + std::vector imageSprites; + + LPD3DXFONT font; + + void onLostDevice(); + + void placeHooks(); + DWORD locateEndScene(); + + + struct VFHookInfo + { + VFHookInfo(DWORD _index, DWORD cb, DWORD* _origFunc) : index(_index), callback(cb), origFunc(_origFunc) {} + DWORD index, callback; + DWORD* origFunc; + }; +}; + diff --git a/Chapter8_Direct3DHook/DirectXHookCallbacks.h b/Chapter8_Direct3DHook/DirectXHookCallbacks.h new file mode 100644 index 0000000..1d838b1 --- /dev/null +++ b/Chapter8_Direct3DHook/DirectXHookCallbacks.h @@ -0,0 +1,38 @@ +#include "DirectXHook.h" + + +DWORD __stdcall reportInitEndScene(LPDIRECT3DDEVICE9 discoveredDeviceAddress) +{ + return DirectXHook::getInstance()->initHookCallback(discoveredDeviceAddress); +} +__declspec(naked) void endSceneTrampoline() +{ + __asm + { + MOV EAX, DWORD PTR SS:[ESP + 0x4] + PUSH EAX + CALL reportInitEndScene + JMP EAX + } +} + + +DX_API myReset(LPDIRECT3DDEVICE9 pDevice, D3DPRESENT_PARAMETERS* pPresentationParameters) +{ + return DirectXHook::getInstance()->resetHookCallback(pDevice, pPresentationParameters); +} + +DX_API myEndScene(LPDIRECT3DDEVICE9 pDevice) +{ + return DirectXHook::getInstance()->endSceneHookCallback(pDevice); +} + +DX_API myDrawPrimitive(LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount) +{ + return DirectXHook::getInstance()->drawPrimitiveHookCallback(pDevice, PrimitiveType, StartVertex, PrimitiveCount); +} + +DX_API myDrawIndexedPrimitive(LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE PrimType, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount) +{ + return DirectXHook::getInstance()->drawIndexedPrimitiveHookCallback(pDevice, PrimType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount); +} \ No newline at end of file diff --git a/Chapter8_Direct3DHook/main.cpp b/Chapter8_Direct3DHook/main.cpp new file mode 100644 index 0000000..e08ae11 --- /dev/null +++ b/Chapter8_Direct3DHook/main.cpp @@ -0,0 +1,127 @@ +#include "DirectXHook.h" + +int primitivesDrawn = 0; +int gliderImage = 0; +bool initialized = false; + + +////////////////// CHAPTER 9 LIGTHACK STUFF ////////////////// +bool lightHack = false; +void enableLightHackDirectional(LPDIRECT3DDEVICE9 pDevice) +{ + D3DLIGHT9 light; + + ZeroMemory(&light, sizeof(light)); + light.Type = D3DLIGHT_DIRECTIONAL; + light.Diffuse = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f); + light.Direction = D3DXVECTOR3(-1.0f, -0.5f, -1.0f); + + pDevice->SetLight(0, &light); + pDevice->LightEnable(0, TRUE); + + lightHack = true; +} + +void enableLightHackAmbient(LPDIRECT3DDEVICE9 pDevice) +{ + pDevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(100, 100, 100)); + lightHack = true; +} + +void lightHackFrame(DirectXHook* hook, LPDIRECT3DDEVICE9 pDevice) +{ + if (!lightHack) + { + if (GetAsyncKeyState(VK_F1)) + enableLightHackDirectional(pDevice); + else if (GetAsyncKeyState(VK_F2)) + enableLightHackAmbient(pDevice); + } + + if (!lightHack) + hook->drawText(10, 188, D3DCOLOR_ARGB(255, 255, 0, 0), "There is currently no lighting. To enable light hack, press F1 for directional or F2 for ambient."); + else + hook->drawText(10, 188, D3DCOLOR_ARGB(255, 255, 0, 0), "Lighthack has been enabled, you should see the cube clearly now."); +} + + +////////////////// CHAPTER 9 WALLHACK STUFF ////////////////// +bool wallHack = false; +LPDIRECT3DTEXTURE9 redTexture = NULL; +void wallHackFrame(DirectXHook* hook, LPDIRECT3DDEVICE9 pDevice) +{ + if (!wallHack && GetAsyncKeyState(VK_F3)) + wallHack = true; + + if (!wallHack) + hook->drawText(10, 203, D3DCOLOR_ARGB(255, 255, 0, 0), "Wallhack example isnt running! Press F3 to enable."); + else + hook->drawText(10, 203, D3DCOLOR_ARGB(255, 255, 0, 0), "Wallhack is enabled! The cube should be drawn in red with no z-buffering now!"); +} + +void onDrawIndexedPrimitive(DirectXHook* hook, LPDIRECT3DDEVICE9 device, D3DPRIMITIVETYPE primType, INT baseVertexIndex, UINT minVertexIndex, UINT numVertices, UINT startIndex, UINT primCount) +{ + primitivesDrawn++; + + if (wallHack && numVertices == 24 && primCount == 12) + { + device->SetRenderState(D3DRS_ZENABLE, false); + if (redTexture) device->SetTexture(0, redTexture); + DirectXHook::origDrawIndexedPrimitive(device, primType, baseVertexIndex, minVertexIndex, numVertices, startIndex, primCount); + device->SetRenderState(D3DRS_ZENABLE, true); + } +} + + +////////////////// CHAPTER 8 STUFF ////////////////// +void initialize(LPDIRECT3DDEVICE9 pDevice) +{ + gliderImage = DirectXHook::getInstance()->addSpriteImage(L"glider.png"); + redTexture = DirectXHook::getInstance()->addTexture(L"red.png"); // CHAPTER 9 WALLHACK STUFF + + initialized = true; +} + +void onDrawFrame(DirectXHook* hook, LPDIRECT3DDEVICE9 pDevice) +{ + if (!initialized) initialize(pDevice); + + hook->drawText(10, 10, D3DCOLOR_ARGB(255, 255, 0, 0), "Direct3D hook working! Intercepted drawing of %d primitives!", primitivesDrawn); + hook->drawText(10, 25, D3DCOLOR_ARGB(255, 255, 0, 0), "Image drawn by hook:"); + hook->drawSpriteImage(gliderImage, 10, 40, 128, 128); + + lightHackFrame(hook, pDevice); // CHAPTER 9 LIGTHACK STUFF + wallHackFrame(hook, pDevice); // CHAPTER 9 WALLHACK STUFF + + primitivesDrawn = 0; +} + +void onDrawPrimitive(DirectXHook* hook, LPDIRECT3DDEVICE9 pDevice, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount) +{ + primitivesDrawn++; +} + + +DWORD WINAPI LoopFunction(LPVOID lpParam) +{ + DirectXHook::getInstance()->addDrawFrameCallback(&onDrawFrame); + DirectXHook::getInstance()->addDrawPrimitiveCallback(&onDrawPrimitive); + DirectXHook::getInstance()->addDrawIndexedPrimitiveCallback(&onDrawIndexedPrimitive); + DirectXHook::getInstance()->initialize(); + + return 0; +} + +BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpvReserved) +{ + if(dwReason == DLL_PROCESS_ATTACH) + { + CreateThread(0, 0, LoopFunction, 0, 0, 0); + } + else if(dwReason == DLL_PROCESS_DETACH) + { + + } + + return TRUE; +} \ No newline at end of file diff --git a/Chapter8_Direct3DHook/memory.h b/Chapter8_Direct3DHook/memory.h new file mode 100644 index 0000000000000000000000000000000000000000..fd04cc73fd87e5fd11d48956d3df33aef064c44c GIT binary patch literal 3838 zcmdT{TWb?R6h5yj_#XxelB6p2p$}p#RE<(mT1t#cC=#11Cf%}08nyV>)$g0hbZ2HS zCUt!fG0D!(oO9;8oSFXmxg(d7NKZyG!>5v1F63MWa#!xij!g8^RF=}mn3ATv*JFLm zTghA=%2*EcT+Ux$&J6LUh{WGbe160808x5)!wBv5{5F0k80jJMTYS$DF~RJbyg-g) zImNfqZ~J=Q9NFqR)3yGL^ymVWC5W!1ft58xZ(tTMoCtRf>aJW0<6o>Rr1tZ`8R00+*6ma-o^PAxN|3YQGD&V zGh*zxFDL74rus-aKrlhxrAEZQ9l#q4t+Y2-(Sc5nkS$akYnWsGciC|w5in3LtJ9gubflDl3;@qNX@)ebkMkyb z$gj;tOgl`PO`$`Y{ZzwC$lL`uSb-74U$M$V6hT1y{wP*908<+yK z2I)OuXr7w*CZc@W#Xr*rBXo*vU0uvMTSv(6`Ps}?VIigpxtP<}b&)qMKVcLyvxhUc zC68|+MFqFGVuw?ItmctE-LvZSYb^7*tutRoZk9hgJ-nx9`3U`;-ebvwb>q(zwfNEh;^K%Msd6XQoH-?#f#!|N2zY)jrSG HXchMx=BZ(S literal 0 HcmV?d00001 diff --git a/GameHackingExamples.sln b/GameHackingExamples.sln new file mode 100644 index 0000000..6e6c327 --- /dev/null +++ b/GameHackingExamples.sln @@ -0,0 +1,74 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chapter4_CodeToMemory", "Chapter4_CodeToMemory\Chapter4_CodeToMemory.vcxproj", "{42D11C4C-AC06-47BD-B6CD-FC6DBAF54472}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chapter5_AdvancedMemoryForensics_Scanning", "Chapter5_AdvancedMemoryForensics_Scanning\Chapter5_AdvancedMemoryForensics_Scanning.vcxproj", "{6C658EF9-CCA4-4E18-8AD7-CEBDC04AB3AB}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chapter6_AccessingMemory", "Chapter6_AccessingMemory\Chapter6_AccessingMemory.vcxproj", "{4C3B87D1-43D3-44DB-913E-E4A1D99909CB}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chapter7_CodeInjection", "Chapter7_CodeInjection\Chapter7_CodeInjection.vcxproj", "{A20C8EDD-02C5-499E-8DB6-1CB8081FD62B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chapter7_CodeInjection_DLL", "Chapter7_CodeInjection_DLL\Chapter7_CodeInjection_DLL.vcxproj", "{37305F21-BB4B-4492-A713-DDD94653C16E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chapter8_ControlFlow", "Chapter8_ControlFlow\Chapter8_ControlFlow.vcxproj", "{ACA1A8FF-6D8C-407A-983C-929D6F958D83}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chapter8_AdobeAirHook", "Chapter8_AdobeAirHook\AdobeAirHook.vcxproj", "{D041E046-6A67-413E-869B-14E3CE06A21B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chapter8_Direct3DApplication", "Chapter8_Direct3DApplication\Chapter8_Direct3DApplication.vcxproj", "{E621BD23-8A39-4BA3-9DB0-191661BBF6C9}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chapter8_Direct3DHook", "Chapter8_Direct3DHook\Chapter8_Direct3DHook.vcxproj", "{784C482A-F6EC-4BCB-851E-07BE782BB040}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chapter10_ResponsiveHacks", "Chapter10_ResponsiveHacks\Chapter10_ResponsiveHacks.vcxproj", "{E28E3DC6-2614-43B9-83E4-86D6F9A585B1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {42D11C4C-AC06-47BD-B6CD-FC6DBAF54472}.Debug|Win32.ActiveCfg = Debug|Win32 + {42D11C4C-AC06-47BD-B6CD-FC6DBAF54472}.Debug|Win32.Build.0 = Debug|Win32 + {42D11C4C-AC06-47BD-B6CD-FC6DBAF54472}.Release|Win32.ActiveCfg = Release|Win32 + {42D11C4C-AC06-47BD-B6CD-FC6DBAF54472}.Release|Win32.Build.0 = Release|Win32 + {6C658EF9-CCA4-4E18-8AD7-CEBDC04AB3AB}.Debug|Win32.ActiveCfg = Debug|Win32 + {6C658EF9-CCA4-4E18-8AD7-CEBDC04AB3AB}.Debug|Win32.Build.0 = Debug|Win32 + {6C658EF9-CCA4-4E18-8AD7-CEBDC04AB3AB}.Release|Win32.ActiveCfg = Release|Win32 + {6C658EF9-CCA4-4E18-8AD7-CEBDC04AB3AB}.Release|Win32.Build.0 = Release|Win32 + {4C3B87D1-43D3-44DB-913E-E4A1D99909CB}.Debug|Win32.ActiveCfg = Debug|Win32 + {4C3B87D1-43D3-44DB-913E-E4A1D99909CB}.Debug|Win32.Build.0 = Debug|Win32 + {4C3B87D1-43D3-44DB-913E-E4A1D99909CB}.Release|Win32.ActiveCfg = Release|Win32 + {4C3B87D1-43D3-44DB-913E-E4A1D99909CB}.Release|Win32.Build.0 = Release|Win32 + {A20C8EDD-02C5-499E-8DB6-1CB8081FD62B}.Debug|Win32.ActiveCfg = Debug|Win32 + {A20C8EDD-02C5-499E-8DB6-1CB8081FD62B}.Debug|Win32.Build.0 = Debug|Win32 + {A20C8EDD-02C5-499E-8DB6-1CB8081FD62B}.Release|Win32.ActiveCfg = Release|Win32 + {A20C8EDD-02C5-499E-8DB6-1CB8081FD62B}.Release|Win32.Build.0 = Release|Win32 + {37305F21-BB4B-4492-A713-DDD94653C16E}.Debug|Win32.ActiveCfg = Debug|Win32 + {37305F21-BB4B-4492-A713-DDD94653C16E}.Debug|Win32.Build.0 = Debug|Win32 + {37305F21-BB4B-4492-A713-DDD94653C16E}.Release|Win32.ActiveCfg = Release|Win32 + {37305F21-BB4B-4492-A713-DDD94653C16E}.Release|Win32.Build.0 = Release|Win32 + {ACA1A8FF-6D8C-407A-983C-929D6F958D83}.Debug|Win32.ActiveCfg = Debug|Win32 + {ACA1A8FF-6D8C-407A-983C-929D6F958D83}.Debug|Win32.Build.0 = Debug|Win32 + {ACA1A8FF-6D8C-407A-983C-929D6F958D83}.Release|Win32.ActiveCfg = Release|Win32 + {ACA1A8FF-6D8C-407A-983C-929D6F958D83}.Release|Win32.Build.0 = Release|Win32 + {D041E046-6A67-413E-869B-14E3CE06A21B}.Debug|Win32.ActiveCfg = Debug|Win32 + {D041E046-6A67-413E-869B-14E3CE06A21B}.Debug|Win32.Build.0 = Debug|Win32 + {D041E046-6A67-413E-869B-14E3CE06A21B}.Release|Win32.ActiveCfg = Release|Win32 + {D041E046-6A67-413E-869B-14E3CE06A21B}.Release|Win32.Build.0 = Release|Win32 + {E621BD23-8A39-4BA3-9DB0-191661BBF6C9}.Debug|Win32.ActiveCfg = Debug|Win32 + {E621BD23-8A39-4BA3-9DB0-191661BBF6C9}.Debug|Win32.Build.0 = Debug|Win32 + {E621BD23-8A39-4BA3-9DB0-191661BBF6C9}.Release|Win32.ActiveCfg = Release|Win32 + {E621BD23-8A39-4BA3-9DB0-191661BBF6C9}.Release|Win32.Build.0 = Release|Win32 + {784C482A-F6EC-4BCB-851E-07BE782BB040}.Debug|Win32.ActiveCfg = Debug|Win32 + {784C482A-F6EC-4BCB-851E-07BE782BB040}.Debug|Win32.Build.0 = Debug|Win32 + {784C482A-F6EC-4BCB-851E-07BE782BB040}.Release|Win32.ActiveCfg = Release|Win32 + {784C482A-F6EC-4BCB-851E-07BE782BB040}.Release|Win32.Build.0 = Release|Win32 + {E28E3DC6-2614-43B9-83E4-86D6F9A585B1}.Debug|Win32.ActiveCfg = Debug|Win32 + {E28E3DC6-2614-43B9-83E4-86D6F9A585B1}.Debug|Win32.Build.0 = Debug|Win32 + {E28E3DC6-2614-43B9-83E4-86D6F9A585B1}.Release|Win32.ActiveCfg = Release|Win32 + {E28E3DC6-2614-43B9-83E4-86D6F9A585B1}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal