diff --git a/Chapter8_AdobeAirHook/AdobeAirHook.vcxproj b/Chapter8_AdobeAirHook/AdobeAirHook.vcxproj
index 6ea46a1..aefc419 100644
--- a/Chapter8_AdobeAirHook/AdobeAirHook.vcxproj
+++ b/Chapter8_AdobeAirHook/AdobeAirHook.vcxproj
@@ -82,7 +82,6 @@
-
diff --git a/Chapter8_ControlFlow/CallHookExample.cpp b/Chapter8_ControlFlow/CallHookExample.cpp
new file mode 100644
index 0000000..734b540
--- /dev/null
+++ b/Chapter8_ControlFlow/CallHookExample.cpp
@@ -0,0 +1,78 @@
+#include "main.h"
+
+// the function thaat we're going to hook
+DWORD functionToBeHooked(DWORD arg1, DWORD arg2, DWORD arg3)
+{
+ if (arg1 == arg2 && arg2 == 3 && arg3 == 4)
+ printf("Call hook worked! Parameters intercepted and changed!\n");
+ else
+ printf("Call hook failed!\n");
+ return 0;
+}
+
+// the hook will replace the call in this function
+// to call our hook
+void whereHookGoes()
+{
+ functionToBeHooked(0, 0, 0);
+}
+
+// I cannot hard-code any addresses from within this application,
+// as they may change upon re-compile. For this reason, I'll locate
+// the address of the CALL that I want to replace programatically
+// by scanning for the 'CALL' statement (bytes 0xE8)
+// somewhere within 1000 bytes of the start of the function
+DWORD getAddressForCallHook(DWORD functionStart)
+{
+ auto oldProtection = protectMemory(functionStart, PAGE_EXECUTE_READ); // make sure memory is readable, just incase
+ auto mem = pointMemory(functionStart);
+
+ DWORD ret = 0;
+ for (int i = 0; i < 1000; i++) {
+ if (mem[i] == 0xE8) {
+ ret = functionStart + i;
+ break;
+ }
+ }
+ protectMemory(functionStart, oldProtection); // restore old memory protection
+ return ret;
+}
+
+
+// this our our type-def that minmics the function type
+// of the function being hooked. This allows us to use a
+// clean call to the original function just knowing it's address
+typedef DWORD (__cdecl _origFunc)(DWORD arg1, DWORD arg2, DWORD arg3);
+_origFunc* originalFunction;
+
+// this is the function we re-direct the CALL to.
+// it simply throws out the orignal parameters
+// and passes new ones to the original function
+DWORD __cdecl someNewFunction(DWORD arg1, DWORD arg2, DWORD arg3)
+{
+ return originalFunction(3, 3, 4);
+}
+
+// this function is what actually places the hook
+DWORD callHook(DWORD hookAt, DWORD newFunc)
+{
+ DWORD newOffset = newFunc - hookAt - 5;
+
+ auto oldProtection = protectMemory(hookAt + 1, PAGE_EXECUTE_READWRITE);
+
+ DWORD originalOffset = readMemory(hookAt + 1);
+ writeMemory(hookAt + 1, newOffset);
+ protectMemory(hookAt + 1, oldProtection);
+
+ return originalOffset + hookAt + 5;
+}
+
+// This ties the entire example together
+void callHookExample()
+{
+ auto address = getAddressForCallHook((DWORD)&whereHookGoes);
+ if (address)
+ originalFunction = (_origFunc*)callHook(address, (DWORD)&someNewFunction);
+
+ whereHookGoes();
+}
\ No newline at end of file
diff --git a/Chapter8_ControlFlow/Chapter8_ControlFlow.vcxproj b/Chapter8_ControlFlow/Chapter8_ControlFlow.vcxproj
index de8d97e..512177f 100644
--- a/Chapter8_ControlFlow/Chapter8_ControlFlow.vcxproj
+++ b/Chapter8_ControlFlow/Chapter8_ControlFlow.vcxproj
@@ -83,7 +83,14 @@
+
+
+
+
+
+
+
diff --git a/Chapter8_ControlFlow/Chapter8_ControlFlow.vcxproj.filters b/Chapter8_ControlFlow/Chapter8_ControlFlow.vcxproj.filters
new file mode 100644
index 0000000..af256f2
--- /dev/null
+++ b/Chapter8_ControlFlow/Chapter8_ControlFlow.vcxproj.filters
@@ -0,0 +1,33 @@
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ {1ccf619e-78d1-4364-adcb-e255c0253713}
+
+
+ {00f1f1a3-3e5e-4f2c-8cbb-285f328f13d1}
+
+
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/Chapter8_ControlFlow/IATHookExample.cpp b/Chapter8_ControlFlow/IATHookExample.cpp
new file mode 100644
index 0000000..a74d3a8
--- /dev/null
+++ b/Chapter8_ControlFlow/IATHookExample.cpp
@@ -0,0 +1,74 @@
+#include "main.h"
+
+// this is the function that scans the import table and
+// overwrites the target function address with our hook
+// destination address
+DWORD hookIAT(const char* functionName, DWORD newFunctionAddress)
+{
+ DWORD baseAddress = (DWORD)GetModuleHandle(NULL);
+
+ auto dosHeader = pointMemory(baseAddress);
+ if (dosHeader->e_magic != 0x5A4D)
+ return 0;
+
+ auto optHeader = pointMemory(baseAddress + dosHeader->e_lfanew + 24);
+ if (optHeader->Magic != 0x10B)
+ return 0;
+
+ if (optHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size == 0 ||
+ optHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress == 0)
+ return 0;
+
+ IMAGE_IMPORT_DESCRIPTOR* importDescriptor = pointMemory(baseAddress + optHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); //what is the rule of adding them?
+ while (importDescriptor->FirstThunk)
+ {
+ int n = 0;
+ IMAGE_THUNK_DATA* thunkData = pointMemory(baseAddress + importDescriptor->OriginalFirstThunk);
+ while (thunkData->u1.Function)
+ {
+ char* importFunctionName = pointMemory(baseAddress + (DWORD)thunkData->u1.AddressOfData + 2);
+ if (strcmp(importFunctionName, functionName) == 0)
+ {
+ auto vfTable = pointMemory(baseAddress + importDescriptor->FirstThunk);
+
+ DWORD original = vfTable[n];
+
+ auto oldProtection = protectMemory((DWORD)&vfTable[n], PAGE_READWRITE);
+ vfTable[n] = newFunctionAddress;
+ protectMemory((DWORD)&vfTable[n], oldProtection);
+
+ return original;
+ }
+
+ n++;
+ thunkData++;
+ }
+ importDescriptor++;
+ }
+
+ return 0;
+}
+
+// this our our type-def that minmics the function type
+// of the function being hooked. This allows us to use a
+// clean call to the original function just knowing it's address
+typedef VOID (WINAPI _origSleep)(DWORD ms);
+_origSleep* originalSleep;
+
+// this is the function we re-direct any Sleep() call to.
+// it simply denies all Sleep calls that last for more than
+// 100 miliseconds, printing some text upon success
+VOID WINAPI newSleepFunction(DWORD ms)
+{
+ if (ms > 100)
+ printf("Sleep hook worked! Denied sleep for %d miliseconds.\n", ms);
+ else
+ originalSleep(ms);
+}
+
+// This is the function that ties everything together
+void IATHookExample()
+{
+ originalSleep = (_origSleep*)hookIAT("Sleep", (DWORD)&newSleepFunction);
+ Sleep(1234);
+}
\ No newline at end of file
diff --git a/Chapter8_ControlFlow/NOPExample.cpp b/Chapter8_ControlFlow/NOPExample.cpp
new file mode 100644
index 0000000..75940c5
--- /dev/null
+++ b/Chapter8_ControlFlow/NOPExample.cpp
@@ -0,0 +1,85 @@
+#include "main.h"
+
+// this is the simulated list of creatures in the game
+std::vector<_creature> creatures;
+int creaturesDrawn = 0;
+
+// this is the simulated function to draw creature names
+void drawHealthBar(int healthbar)
+{
+ creaturesDrawn++; // make a note that we drew it
+ Sleep(healthbar); // just an example, we're not really doing anything
+}
+
+// this is the function where we place the NOP.
+void drawCreatureHealthBarExample()
+{
+ for (int i = 0; i < creatures.size(); i++) {
+ auto c = creatures[i];
+ if (c.isEnemy && c.isCloaked)
+ {
+ // our NOP is esentially going to remove this continue statement,
+ // which will be a JUMP that evades the drawHealthBar car
+ continue;
+ }
+ drawHealthBar(c.healthBar);
+ }
+}
+
+// this is the function that actually does the NOP
+template
+void writeNop(DWORD address)
+{
+ auto oldProtection = protectMemory(address, PAGE_EXECUTE_READWRITE);
+ for (int i = 0; i < SIZE; i++)
+ writeMemory(address + i, 0x90);
+ protectMemory(address, oldProtection);
+}
+
+
+// I cannot hard-code any addresses from within this application,
+// as they may change upon re-compile. For this reason, I'll locate
+// the address of the JMP that I want to replace programatically
+// by scanning for the 'JMP -67' statement (bytes 0xEB 0xBD)
+// somewhere within 1000 bytes of the start of the function
+DWORD getAddressForNOP(DWORD functionStart)
+{
+ auto oldProtection = protectMemory(functionStart, PAGE_EXECUTE_READ); // make sure memory is readable, just incase
+ auto mem = pointMemory(functionStart);
+
+ DWORD ret = 0;
+ for (int i = 0; i < 999; i++) {
+ if (mem[i] == 0xEB && mem[i+1] == 0xBD) {
+ ret = functionStart + i;
+ break;
+ }
+ }
+ protectMemory(functionStart, oldProtection); // restore old memory protection
+ return ret;
+}
+
+// This ties the entire example together
+void NOPExample()
+{
+ creaturesDrawn = 0;
+
+ // nop it
+ auto address = getAddressForNOP((DWORD)&drawCreatureHealthBarExample);
+ if (address)
+ writeNop<2>(address);
+
+ // add some make creatures
+ creatures.push_back(_creature(0, true, true));
+ creatures.push_back(_creature(0, true, false));
+ creatures.push_back(_creature(0, false, true));
+ creatures.push_back(_creature(0, false, false));
+
+ //call the function
+ drawCreatureHealthBarExample();
+
+ //check if NOP worked
+ if (creaturesDrawn == 4)
+ printf("NOP worked! Drew all creatures!\n");
+ else
+ printf("NOP failed! :( Only drew %d/4 creatures.\n", creaturesDrawn);
+}
\ No newline at end of file
diff --git a/Chapter8_ControlFlow/VFHookExample.cpp b/Chapter8_ControlFlow/VFHookExample.cpp
new file mode 100644
index 0000000..a3ef1c8
--- /dev/null
+++ b/Chapter8_ControlFlow/VFHookExample.cpp
@@ -0,0 +1,76 @@
+#include "main.h"
+
+// This is a dummy base-class
+class someBaseClass
+{
+ public:
+ virtual DWORD someFunction(DWORD arg1) { return 0; }
+};
+
+// This is the class for which we'll
+// actually hook the VF table. It inherits
+// the dummy base-class to ensure that
+// someFunction() is in a virtual table.
+class someClass : public someBaseClass
+{
+ public:
+ virtual DWORD someFunction(DWORD arg1)
+ {
+ if (arg1 == 1)
+ printf(" VF Table hook worked! Parameters intercepted and changed!\n");
+ else
+ printf(" VF Table hook failed!\n");
+ return 0;
+ }
+};
+
+
+// This is where we re-direct the VF calls to
+DWORD originalVFFunction;
+DWORD __stdcall someNewVFFunction(DWORD arg1)
+{
+ // notice how we take ECX and store it in a variable..
+ // this is done because it stores the class instance pointer ("this")
+ // and we want to make sure our code doesn't overwrite it (the compiler
+ // doesn't understand that this is a VF hook, so it may think ECX is
+ // free for it to use)
+
+ static DWORD _this, _ret;
+ __asm MOV _this, ECX
+
+ printf("VFHook pre\n");
+ __asm {
+ PUSH 1
+ MOV ECX, _this
+ CALL [originalVFFunction]
+ MOV _ret, EAX
+ }
+ printf("VFHook Post\n");
+
+ __asm MOV ECX, _this
+ return _ret;
+}
+
+// This is the function that actually places the hook
+DWORD hookVF(DWORD classInst, DWORD funcIndex, DWORD newFunc)
+{
+ DWORD VFTable = readMemory(classInst);
+ DWORD hookAddress = VFTable + funcIndex * sizeof(DWORD);
+
+ auto oldProtection = protectMemory(hookAddress, PAGE_READWRITE);
+ DWORD originalFunc = readMemory(hookAddress);
+ writeMemory(hookAddress, newFunc);
+ protectMemory(hookAddress, oldProtection);
+
+ return originalFunc;
+}
+
+// This is the function that ties everything together
+void VFHookExample()
+{
+ someClass* inst = new someClass();
+
+ originalVFFunction = hookVF((DWORD)inst, 0, (DWORD)&someNewVFFunction);
+ inst->someFunction(0);
+ delete inst;
+}
\ No newline at end of file
diff --git a/Chapter8_ControlFlow/main-controlFlow.cpp b/Chapter8_ControlFlow/main-controlFlow.cpp
index f50f4a0..2f5e66f 100644
--- a/Chapter8_ControlFlow/main-controlFlow.cpp
+++ b/Chapter8_ControlFlow/main-controlFlow.cpp
@@ -1,314 +1,11 @@
-#include
-#include
-#include
-
-
-//helpers
- template
- T readMemory(DWORD address)
- {
- return *((T*)address);
- }
-
- template
- T* pointMemory(DWORD address)
- {
- return ((T*)address);
- }
-
- template
- void writeMemory(DWORD address, T value)
- {
- *((T*)address) = value;
- }
-
- template
- DWORD protectMemory(DWORD address, DWORD prot)
- {
- DWORD oldProt;
- VirtualProtect((LPVOID)address, sizeof(T), prot, &oldProt);
- return oldProt;
- }
-
-
-
-// NOP example code
- struct _creature
- {
- _creature(int hb, bool e, bool c) : healthBar(hb), isEnemy(e), isCloaked(c) {}
- int healthBar;
- bool isEnemy, isCloaked;
- };
- std::vector<_creature> creatures;
- int creaturesDrawn = 0;
-
- void drawHealthBar(int healthbar)
- {
- creaturesDrawn++; // make a note that we drew it
- Sleep(healthbar); // just an example, we're not really doing anything
- }
- void drawCreatureHealthBarExample()
- {
- for (int i = 0; i < creatures.size(); i++) {
- auto c = creatures[i];
- if (c.isEnemy && c.isCloaked) continue;
- drawHealthBar(c.healthBar);
- }
- }
-
- template
- void writeNop(DWORD address)
- {
- auto oldProtection = protectMemory(address, PAGE_EXECUTE_READWRITE);
- for (int i = 0; i < SIZE; i++)
- writeMemory(address + i, 0x90);
- protectMemory(address, oldProtection);
- }
-
- DWORD getAddressForNOP(DWORD functionStart)
- {
- // i cannot hard-code any addresses from within this application,
- // as they may change upon re-compile. For this reason, I'll locate
- // the address of the JMP that I want to replace programatically
- // by scanning for the 'JMP -67' statement (bytes 0xEB 0xBD)
- // somewhere within 1000 bytes of the start of the function
-
-
-
- auto oldProtection = protectMemory(functionStart, PAGE_EXECUTE_READ); // make sure memory is readable, just incase
- auto mem = pointMemory(functionStart);
-
- DWORD ret = 0;
- for (int i = 0; i < 999; i++) {
- if (mem[i] == 0xEB && mem[i+1] == 0xBD) {
- ret = functionStart + i;
- break;
- }
- }
- protectMemory(functionStart, oldProtection); // restore old memory protection
- return ret;
- }
-
- void NOPExample()
- {
- // nop it
- auto address = getAddressForNOP((DWORD)&drawCreatureHealthBarExample);
- if (address)
- writeNop<2>(address);
-
- // add some make creatures
- creatures.push_back(_creature(0, true, true));
- creatures.push_back(_creature(0, true, false));
- creatures.push_back(_creature(0, false, true));
- creatures.push_back(_creature(0, false, false));
-
- //call the function
- drawCreatureHealthBarExample();
-
- //check if NOP worked
- if (creaturesDrawn == 4)
- printf("NOP worked! Drew all creatures!\n");
- else
- printf("NOP failed! :( Only drew %d/4 creatures.\n", creaturesDrawn);
- }
-
-
-// call hook
- DWORD functionToBeHooked(DWORD arg1, DWORD arg2, DWORD arg3)
- {
- if (arg1 == arg2 && arg2 == 3 && arg3 == 4)
- printf("Call hook worked! Parameters intercepted and changed!\n");
- else
- printf("Call hook failed!\n");
- return 0;
- }
-
- void whereHookGoes()
- {
- functionToBeHooked(0, 0, 0);
- }
-
- DWORD getAddressForCallHook(DWORD functionStart)
- {
- // same story as with NOP, except we're looking for the first CALL (0xE8)
- auto oldProtection = protectMemory(functionStart, PAGE_EXECUTE_READ); // make sure memory is readable, just incase
- auto mem = pointMemory(functionStart);
-
- DWORD ret = 0;
- for (int i = 0; i < 1000; i++) {
- if (mem[i] == 0xE8) {
- ret = functionStart + i;
- break;
- }
- }
- protectMemory(functionStart, oldProtection); // restore old memory protection
- return ret;
- }
-
-
- typedef DWORD (__cdecl _origFunc)(DWORD arg1, DWORD arg2, DWORD arg3);
- _origFunc* originalFunction;
-
- DWORD __cdecl someNewFunction(DWORD arg1, DWORD arg2, DWORD arg3)
- {
- return originalFunction(3, 3, 4);
- }
-
-
- DWORD callHook(DWORD hookAt, DWORD newFunc)
- {
- DWORD newOffset = newFunc - hookAt - 5;
-
- auto oldProtection = protectMemory(hookAt + 1, PAGE_EXECUTE_READWRITE);
-
- DWORD originalOffset = readMemory(hookAt + 1);
- writeMemory(hookAt + 1, newOffset);
- protectMemory(hookAt + 1, oldProtection);
-
- return originalOffset + hookAt + 5;
- }
-
- void callHookExample()
- {
- auto address = getAddressForCallHook((DWORD)&whereHookGoes);
- if (address)
- originalFunction = (_origFunc*)callHook(address, (DWORD)&someNewFunction);
-
- whereHookGoes();
- }
-
-
-// vf table hook
- class someBaseClass
- {
- public:
- virtual DWORD someFunction(DWORD arg1) { return 0; }
- };
- class someClass : public someBaseClass
- {
- public:
- virtual DWORD someFunction(DWORD arg1)
- {
- if (arg1 == 1)
- printf(" VF Table hook worked! Parameters intercepted and changed!\n");
- else
- printf(" VF Table hook failed!\n");
- return 0;
- }
- };
-
-
- DWORD originalVFFunction;
- DWORD __stdcall someNewVFFunction(DWORD arg1)
- {
- static DWORD _this, _ret;
- __asm MOV _this, ECX
- printf("VFHook pre\n");
- __asm {
- PUSH 1
- MOV ECX, _this
- CALL [originalVFFunction]
- MOV _ret, EAX
- }
- printf("VFHook Post\n");
- __asm MOV ECX, _this
- return _ret;
- }
-
-
- DWORD hookVF(DWORD classInst, DWORD funcIndex, DWORD newFunc)
- {
- DWORD VFTable = readMemory(classInst);
- DWORD hookAddress = VFTable + funcIndex * sizeof(DWORD);
-
- auto oldProtection = protectMemory(hookAddress, PAGE_READWRITE);
- DWORD originalFunc = readMemory(hookAddress);
- writeMemory(hookAddress, newFunc);
- protectMemory(hookAddress, oldProtection);
-
- return originalFunc;
- }
-
- void VFHookExample()
- {
- someClass* inst = new someClass();
-
- originalVFFunction = hookVF((DWORD)inst, 0, (DWORD)&someNewVFFunction);
- inst->someFunction(0);
- delete inst;
- }
-
-// iat hook
- DWORD hookIAT(const char* functionName, DWORD newFunctionAddress)
- {
- DWORD baseAddress = (DWORD)GetModuleHandle(NULL);
-
- auto dosHeader = pointMemory(baseAddress);
- if (dosHeader->e_magic != 0x5A4D)
- return 0;
-
- auto optHeader = pointMemory(baseAddress + dosHeader->e_lfanew + 24);
- if (optHeader->Magic != 0x10B)
- return 0;
-
- if (optHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size == 0 ||
- optHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress == 0)
- return 0;
-
- IMAGE_IMPORT_DESCRIPTOR* importDescriptor = pointMemory(baseAddress + optHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); //what is the rule of adding them?
- while (importDescriptor->FirstThunk)
- {
- int n = 0;
- IMAGE_THUNK_DATA* thunkData = pointMemory(baseAddress + importDescriptor->OriginalFirstThunk);
- while (thunkData->u1.Function)
- {
- char* importFunctionName = pointMemory(baseAddress + (DWORD)thunkData->u1.AddressOfData + 2);
- if (strcmp(importFunctionName, functionName) == 0)
- {
- auto vfTable = pointMemory(baseAddress + importDescriptor->FirstThunk);
-
- DWORD original = vfTable[n];
-
- auto oldProtection = protectMemory((DWORD)&vfTable[n], PAGE_READWRITE);
- vfTable[n] = newFunctionAddress;
- protectMemory((DWORD)&vfTable[n], oldProtection);
-
- return original;
- }
-
- n++;
- thunkData++;
- }
- importDescriptor++;
- }
-
- return 0;
- }
-
- typedef VOID (WINAPI _origSleep)(DWORD ms);
- _origSleep* originalSleep;
-
- VOID WINAPI newSleepFunction(DWORD ms)
- {
- if (ms > 100)
- printf("Sleep hook worked! Denied sleep for %d miliseconds.\n", ms);
- else
- originalSleep(ms);
- }
-
- void IATHookExample()
- {
- originalSleep = (_origSleep*)hookIAT("Sleep", (DWORD)&newSleepFunction);
- Sleep(1234);
- }
-
+#include "main.h"
int main(void)
{
-
// due to differences in the way functions are compiled between
// DEBUG and RELEASE builds, this example will only work in RELEASE.
- // This is only because of the way I'm finding the address to be NOP'd
+ // This is only because of the way I'm finding the addresses of
+ // the NOP and CALL targets
NOPExample();
callHookExample();
VFHookExample();
diff --git a/Chapter8_ControlFlow/main.h b/Chapter8_ControlFlow/main.h
new file mode 100644
index 0000000..2224491
--- /dev/null
+++ b/Chapter8_ControlFlow/main.h
@@ -0,0 +1,46 @@
+#include
+#include
+#include
+
+/*
+ THIS IS JUST SOME BOILER-PLATE TO ALLOW THE EXAMPLE CODE TO WORK,
+ NOTHING INTERESTING HERE
+*/
+
+
+template
+T readMemory(DWORD address)
+{
+ return *((T*)address);
+}
+
+template
+T* pointMemory(DWORD address)
+{
+ return ((T*)address);
+}
+
+template
+void writeMemory(DWORD address, T value)
+{
+ *((T*)address) = value;
+}
+
+template
+DWORD protectMemory(DWORD address, DWORD prot)
+{
+ DWORD oldProt;
+ VirtualProtect((LPVOID)address, sizeof(T), prot, &oldProt);
+ return oldProt;
+}
+
+struct _creature
+{
+ _creature(int hb, bool e, bool c) : healthBar(hb), isEnemy(e), isCloaked(c) {}
+ int healthBar;
+ bool isEnemy, isCloaked;
+};
+void NOPExample();
+void callHookExample();
+void VFHookExample();
+void IATHookExample();
\ No newline at end of file
diff --git a/Chapter8_Direct3DHook/Chapter8_Direct3DHook.vcproj b/Chapter8_Direct3DHook/Chapter8_Direct3DHook.vcproj
index 6d5def7..87c3924 100644
--- a/Chapter8_Direct3DHook/Chapter8_Direct3DHook.vcproj
+++ b/Chapter8_Direct3DHook/Chapter8_Direct3DHook.vcproj
@@ -2,9 +2,9 @@
@@ -41,8 +41,8 @@