DirectX 9.0 Hooking via Injection via C++
Ok, so beings that this was requested, I decided to write this up. I hope this helps someone and if not, sorry First and for most, this tutorial is strictly for DirectX 9 and I guarantee you it will not work for other versions without some major editing in the wrapper. At the end of this I will also include some instructions on how to turn this injected hook into a wrapper to the point where you can just compile it as d3d9.dll and drop it into your games directory and run it via that method too.
(I suggest the "wrapper" method as most cheat detections don't find it as a hack due to some machines needing the d3d9.dll in that folder to work.)
I am writing this tutorial to be used with C++ but you can translate it to what ever language you wish to program in as it's pretty basic and not too major. The wrapper is where the most work comes to play so you will need to do that on your own. Sorry, I don't know other languages outside of C++, MASM, and VB6 so you are on your own when translating.
Part 1. Introduction and Such
Before we begin, let me go over what this does and how it works. Firstly, this main tutorial method is via injection. What this does is creates a remote thread in the process as its starting up and injects your hook and calls its DllMain (or main function of the DLL) and hooks the Direct3D9Create function. From there, when the game, or DX app you are using calls Direct3D9Create, it will call your hooked function instead of the original. When that happens, instead of using the default DirectX functions, it will use your wrapper "proxy" functions that are modified to your need and such. This allows you to add to the game, or app, such as wireframe, colored primitives, etc. Such things you see in hacks and so on.
Along with that, it opens up the window for any other extra feature(s) you can come up with on your own. The boundaries are small, just what you are able to do and such.
This tutorial is going to explain how to do the basics, create the hook, show an example wrapper, and explain a few small things along with the hook. I will include a full example as well that I will find some random free program to show you how it works and such in as well. I will add wireframe mode to a toggle key to show you how to add some of your own code into the hook as well
Part 2. Tools Needed
This is a small list of the things you will need to be able to use this tutorial.
Microsoft Visual Studio 2005
You do not need the full version to create things, you can use the express edition as far as I know to compile things as long as they are non-commercial (from what I was told). If not, find the full version on a warez site or be nice and purchase it
Download
Microsoft Detours Library 1.5
Download from MS
Due to some unknown reason, the makers of the Detours library have removed the functions used in this tutorial from the new version. So you will need to download a precompiled version here
Microsoft DirectX 9.0c SDK
And again, another free download from Microsoft for developers. (Aren't they so nice to programmers? ^_^)
Download
Note: You need to have a real version of Windows for this download so if you don't, just google around for it. I don't think the version matters. I used the October 2006 update for most of my old projects, but have installed the June 2007 version and my stuff still compiles fine so either should be ok.
Misc Tools
A brain, patience, the willing to read and learn, coffee.
Part 3. Installing The Tools
Firstly, all the tools are in installers, so simply install them to their respected locations. BUT!! I suggest you install Visual Studio first, as some of the other tools may install variables and paths for you to easily include things into your project without lots of crap work and such. So, install VS2005 first, then the others.
VS2005 installs default to C:Program FilesMicrosoft Visual Studio 8
DX SDK installs default to C:Program FilesMicrosoft DirectX SDK (m/y)
Adding The Paths To VS2005
Next we need to add the paths to the extra used files in the detours and the DirectX SDK folders. This is so you don't have to have long ass include lines in your project, but instead the compiler will look inside the said folders for the included files in the project first. (But be warned, this can cause conflicts if you use more then 1 version of something that has the same file names!)
Open Visual Studio and goto Tools -> Options then click the + next to VC++ Directories. On the right, click the drop down box under "Show Directories For" and choose 'Include files'. Next click the folder icon and then the button that appears in the list box that says '. . .' and point it to the folder:
C:Program FilesMicrosoft DirectX SDK (October 2006)Include
(change the paths for either of these if they differ)
Next choose 'Library files' from the right drop down list and then click the folder icon again, then the '. . .' button and point it to:
C:Program FilesMicrosoft DirectX SDK (October 2006)Libx86
(change the paths if they differ)
Installing Detours
This is an updated step now due to an issue with Detours 2.1. To install Detours, you could put the detours.h and .lib files where ever you want on your system, just be sure to add their paths to the VS2005 IDE like you did for the DX SDK above. Or, as I will be using in this tutorial, make a new folder in your projects directory with the other source files (.h and .cpp files) and name it 'Detours' and place the files in there. This is probably going to be the easiest way to use them.
Now your IDE should be setup to use the DX SDK files with ease.
If you run into issues later on, just post the error and I will attempt to help you to the best of my abilities.
I'm not Jesus so don't expect me to fix every error.
Part 4. Creating The Hook
To start the hook, create a new DLL project in VS2005. To do that, open VS2005. Then goto File -> New -> Project. Select VC++ from the left box then on the right choose Win32 Project. Select a name for your project and a location for it.
Note: for this tutorial I will be calling mine dxhook and the location will be on my desktop. I also suggest leaving Create directory for solution checked.
Now the Win32 Application Wizard should come up. Click on Application Settings on the left, select DLL under Application Type, and choose Empty Project under Additional Options. Then click finish. You will be dumped into the IDE of VS2005 in a new blank solution.
Although we will have precompiled headers turned off, we are going to make stdafx.cpp/.h files anyway since they are nice to have for includes that multiple files will use. So lets go ahead and add the main files we will be using in this.
To add new files to the project, right click in the solution explorer and select Add then select New Item from the sub menu. You are going to want to add 2 cpp files and 1 header file. So:
Add->New Item-> Header File, name it stdafx.h
Add->New Item-> C++ File, name it stdafx.cpp
Add->New Item-> C++ File, name it main.cpp
So you should have 3 files in your solution now.
stdafx.cpp
Lets take care of the easier file first. Open stdafx.cpp by double clicking it in the solution explorer to open it in the code window in the center of the IDE. This file needs 1 line of code.
#include "stdafx.h"
Save and close that file now. You do not need to edit that file ever again.
stdafx.h
Next, lets take care of the basic needs inside the stdafx.h file that will be used for the start of this project. So double click on stdafx.h in the solution explorer and lets add some code.
The first thing we will want to do is to get rid of some rather annoying warnings. If you are like me, I have the compiler set to treat warnings as errors. I like things to be as perfect as possible.
The first line of code we will want to add to stdafx.h is:
#pragma once
This tells the compiler to only add this file once to the project instead of adding it each time its asked. This will be added first so no issues should arise while using this setting.
Next, we will want to tell the compiler what version of DXinput to use for the SDK as well as the windows version to stop annoying bullshit that happens when it's not auto-detected in the compiler. To do these add:
#define DIRECTINPUT_VERSION 0x0900
#define _WIN32_WINNT 0x0500
Now that we do not need anymore defines in this file, we are ready to add our includes. The first include is the standard windows include file which is used for most programs that require certain headers that are derived inside the windows.h file. Along with that, we will need tchar.h for some macros and to handle unicode strings. (Yes, I do my work in unicode.)
So the code we want to add is:
#include <windows.h>
#include <tchar.h>
Now, you could add the detours include and such in here, but since it is not used anywhere else but in 1 file, I suggest only adding it to the next file. No sense in giving everything access to it when only 1 thing needs it.
Save and close the stdafx.cpp file.
main.cpp
Next, open the main.cpp file. This is where the hooking happens. We will be using Detours for our hooking functions because it's free and easy to use. I will not guarantee that it will be undetected for your game so be careful when testing.
The first line of code we want to add to this file is to include the stdafx.h file as it has the includes that will be needed for this file. So add:
#include "stdafx.h"
Next we will need to add our include and library file for Detours. I myself prefer using the pragma param thats used with Visual Studio rather then adding the lib files to the project properties, but if you are not using VS2005 just remove the pragma line I'm about to show and add the lib file to the properties window in your compiler for the project to include when it links and compiles.
#pragma comment(lib, "Detours/detours.lib")
#include "Detours/detours.h"
Next I suggest adding this variable to the top under the includes for detours to keep track of the module handle incase you need it elsewhere in the code. I don't think anyone should ever really need it for their own thing and not be able to get it another method but this is just incase.
So we add:
HANDLE HookHandle = NULL;
Now we will want to add a trampoline for our hooked function, Direct3DCreate9. So firstly, you are probably saying wtf is a trampoline in coding? Its just like a code cave. When you hook something using Detours, the target functions code is placed in the trampoline and the trampolines address is placed into the targets pointer. As it says in the read me, we can either replace the target function entirely or simply add onto it.
The code for the trampoline looks like this:
DETOUR_TRAMPOLINE(IDirect3D9* WINAPI Real_Direct3DCreate9(UINT SDKVersion), Direct3DCreate9);
But because we need this function to remain usable after compiled we need to tell the compiler not to "mangle" the identifier. To do that we need to embrace our code with the extern "C" code. So our whole code block for the trampoline will be:
#ifdef __cplusplus
extern "C"
{
#endif
DETOUR_TRAMPOLINE(IDirect3D9* WINAPI Real_Direct3DCreate9(UINT SDKVersion), Direct3DCreate9);
#ifdef __cplusplus
}
#endif
The next step after creating the trampoline will be to create our new function for Direct3DCreate9. What we want the function to do instead of creating a normal instance of Direct3D is to create a new instance of our wrapper. (We haven't written the wrapper yet but thats next.) So what we are going to need to do is have the function think it's creating a normal instance of Direct3D but instead have it create a new instance of our wrapper.
IDirect3D9* WINAPI Mine_Direct3DCreate9(UINT SDKVersion)
{
IDirect3D9* Direct3D = Real_Direct3DCreate9( SDKVersion );
IDirect3D9* Mine_Direct3D = new Direct3D9Wrapper( Direct3D );
return Mine_Direct3D;
}
What this code does is creates a normal instance of Direct3D because we simply just want to wrap it and not recode everything. This will pass the handle of the newly created Direct3D interface to our wrapper which will then "proxy" the functions that Direct3D uses.
Now this next part is optional but I suggest doing it to keep the DllMain function nice, clean, and easy to read. I created to functions that are called from the DllMain which are: HookAPI and UnhookAPI. Both are simple void functions since they return nothing. For HookAPI we have:
void HookAPI()
{
DetourFunctionWithTrampoline( (PBYTE)Real_Direct3DCreate9, (PBYTE)Mine_Direct3DCreate9 );
}
And for UnhookAPI we have: Code:
void UnhookAPI()
{
DetourRemove( (PBYTE)Real_Direct3DCreate9, (PBYTE)Mine_Direct3DCreate9 );
}
Now for the last part of our main.cpp, we need the DllMain function. For those that are new to C++, every DLL has an entry point which is what is first called when the module is loaded. This entry point is called the DllMain function. (Some compilers will let you change the name of it but I use the standard.) Inside our DllMain entry we want the module, when its first loaded, to call HookAPI, and when its unloaded, to call UnhookAPI. This is very basic and very easy. To do it, we use:
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hModule);
HookHandle = hModule;
HookAPI();
}
else if (ul_reason_for_call == DLL_PROCESS_DETACH)
{
UnhookAPI();
}
return TRUE;
}
Also notice the HookHandle variable being used in there? We are storing the handle of the module to be used later on incase you need it else where. Along with that we have DisableThreadLibraryCalls in there as well. This removes the calls of DLL_THREAD_ATTACH and DLL_THREAD_DETACH to minimize the working code of the library. (Helps keep the size down.)
Now our main.cpp is done. But! We need to go back and edit stdafx.h. I left this code out to show you how to work with includes that you need and to add them when needed.
So lets reopen stdafx.h Under the last include which should be tchar.h we want to add the includes for DirectX 9. These will be used inside our wrapper as well as in the main.cpp as you can see from the above code. So we want to add:
#pragma comment(lib,"d3d9.lib")
#include <d3d9.h>
#include <d3dx9.h>
Again, I use #pragma cause it's fast and easy to add libraries to the project without having to fumble with the project properties. I don't think any compiler but Microsoft's supports this so you may need to do it a different method to add the library to the project.
Now we are done with that, save and close that file.
Part 5. The Wrapper
First and foremost we are going to need to add some new files to the project. Just like we did before you are going to want to create the following new files:
ID3D9Wrapper.h
ID3D9Wrapper.cpp
ID3D9Wrapper_Device.h
ID3D9Wrapper_Device.cpp
I suggest making a new filter in the solution explorer also (a new folder) to hold the wrapper files. Name it D3DWrapper or something easy to keep the solution organized and easy to find what you need to edit later on. Adding a lot of files can start to make it hard to find what you are looking for.
We are going to start with ID3D9Wrapper.h and .cpp these are the main Direct3D wrappers, where as the _Device files are for wrapping the device functions. (Read up on DirectX if you are unsure how everything with it works. I can't really explain everything cause that would be a whole other tutorial.)
ID3D9Wrapper.h
First we want to open notepad and open the file located at:
C:Program FilesMicrosoft DirectX SDK (October 2006)Included3d9.h
(Might differ for your version of the SDK but it will be called d3d9.h)
We are opening this because this file contains the functions that we need to add to our wrapper. This is where we get the info we need to understand what each part of DirectX does function wise. So scroll down in that file and you should find a few things we have already done above. Such as our new typedef, it's also used in this file as well as the function to create the instance of Direct3D. Keep scrolling till you find:
DECLARE_INTERFACE_(IDirect3D9, IUnknown)
This is the start of the main interface for Direct3D9. We want to use basically the exact code thats infront of us. First, lets create the class inside our code file. So inside of ID3D9Wrapper.h add:
#include "stdafx.h"
class Direct3D9Wrapper : public IDirect3D9
{
public:
Direct3D9Wrapper( LPDIRECT3D9 pDirect3D );
virual ~Direct3D9Wrapper();
IDirect3D9* Direct3D9;
};
This is the start of our class. We include stdafx.h because it includes the DirectX9 includes and such that we will need in this file and others soon to come. Next, back in the notepad window of d3d9.h lets copy and paste some lines.
/*** IUnknown methods ***/
STDMETHOD(QueryInterface)(THIS_ REFIID riid, void** ppvObj) PURE;
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
STDMETHOD_(ULONG,Release)(THIS) PURE;
/*** IDirect3D9 methods ***/
STDMETHOD(RegisterSoftwareDevice)(THIS_ void* pInitializeFunction) PURE;
STDMETHOD_(UINT, GetAdapterCount)(THIS) PURE;
STDMETHOD(GetAdapterIdentifier)(THIS_ UINT Adapter,DWORD Flags,D3DADAPTER_IDENTIFIER9* pIdentifier) PURE;
STDMETHOD_(UINT, GetAdapterModeCount)(THIS_ UINT Adapter,D3DFORMAT Format) PURE;
STDMETHOD(EnumAdapterModes)(THIS_ UINT Adapter,D3DFORMAT Format,UINT Mode,D3DDISPLAYMODE* pMode) PURE;
STDMETHOD(GetAdapterDisplayMode)(THIS_ UINT Adapter,D3DDISPLAYMODE* pMode) PURE;
STDMETHOD(CheckDeviceType)(THIS_ UINT Adapter,D3DDEVTYPE DevType,D3DFORMAT AdapterFormat,D3DFORMAT BackBufferFormat,BOOL bWindowed) PURE;
STDMETHOD(CheckDeviceFormat)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,DWORD Usage,D3DRESOURCETYPE RType,D3DFORMAT CheckFormat) PURE;
STDMETHOD(CheckDeviceMultiSampleType)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SurfaceFormat,BOOL Windowed,D3DMULTISAMPLE_TYPE MultiSampleType,DWORD* pQualityLevels) PURE;
STDMETHOD(CheckDepthStencilMatch)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,D3DFORMAT RenderTargetFormat,D3DFORMAT DepthStencilFormat) PURE;
STDMETHOD(CheckDeviceFormatConversion)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SourceFormat,D3DFORMAT TargetFormat) PURE;
STDMETHOD(GetDeviceCaps)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DCAPS9* pCaps) PURE;
STDMETHOD_(HMONITOR, GetAdapterMonitor)(THIS_ UINT Adapter) PURE;
STDMETHOD(CreateDevice)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,HWND hFocusWindow,DWORD BehaviorFlags,D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DDevice9** ppReturnedDeviceInterface) PURE;
And paste it into ID3D9Wrapper.h between the virtual function and the IDirect3D9* variable. If you pasted in the right spot the last thing in the wrapper should be:
IDirect3D9* Direct3D9; };
The next step we need to do is remove the PURE define from each function. Just delete the word PURE so the last thing on each line is ); An easy way to do this is hit CTRL+H, in Find What put: " PURE;" (without the quotes but with the space in the front) and in Replace With put: ";" (without the quotes) and make sure to select Current Document under Look In. Then hit replace all.
All done, save and close this file.
ID3D9Wrapper.cpp
Now for this file, I am not writing everything out that will be in it here on the forums because its a shit ton of code. You have to rewrite all the functions that we just added to the .h file. But don't worry its real easy. You are simply creating the functions to return the normal values as if it was the real Direct3D instance.
First, lets add our includes and create the class construct/deconstruct.
So inside ID3D9Wrapper.cpp the includes you will want are:
#include "ID3D9Wrapper.h"
Next we have our construct of the class. We want to store the Direct3D pointer to be used inside the class so we use:
Direct3D9Wrapper::Direct3D9Wrapper(LPDIRECT3D9 pDirect3D)
{
Direct3D9 = pDirect3D;
}
And under, our deconstruct doesn't need to do anything so:
Direct3D9Wrapper::~Direct3D9Wrapper() {}
Next is the functions. You can simply just walk down through each function and add them yourself easily. I will show you an example of how to do it yourself. (You can also look in the example if you don't understand.)
Our first function in the list was:
STDMETHOD(QueryInterface)(THIS_ REFIID riid, void** ppvObj);
To understand this, STDMETHOD is a macro that states anything inside the ( ) will return HRESULT. As for STDMETHOD_ this is like an extended version of the macro which states the first value inside the ( ) is the return type, and the second is the function name.
So looking at that line, we know QueryInterface returns HRESULT. So our function inside the .cpp file will look like:
HRESULT Direct3D9Wrapper::QueryInterface(const IID &riid, void **ppvObj)
{
return Direct3D9->QueryInterface(riid, ppvObj);
}
Simple isn't it?
An example of a function using STDMETHOD_ would be:
STDMETHOD_(ULONG,AddRef)(THIS);
So our function would be:
ULONG Direct3D9Wrapper::AddRef()
{
return Direct3D9->AddRef();
}
Once you get to CreateDevice, stop. This is the function we need to alter from its original code. This is because if we don't it will simply create a regular Direct3DDevice9 interface. Instead, we want it to create an instance of our Direct3DDevice9Wrapper class.
So our CreateDevice function will look like:
HRESULT Direct3D9Wrapper::CreateDevice(UINT Adapter, D3DDEVTYPE DeviceType,HWND hFocusWindow, DWORD BehaviorFlags,D3DPRESENT_PARAMETERS *pPresentationParameters,IDirect3DDevice9 **ppReturnedDeviceInterface)
{
IDirect3DDevice9* pDirect3DDevice9;
HRESULT hRes = Direct3D9->CreateDevice( Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, &pDirect3DDevice9 );
*ppReturnedDeviceInterface = new Direct3DDevice9Wrapper( pDirect3DDevice9, this, pPresentationParameters );
return hRes;
}
As you can see, instead of returning the regular device used in CreateDevice, we set our wrappers device pointer to the one used in ppReturnedDeviceInterface. This is so that it uses our wrapper instead of the normal Direct3DDevice functions.
And you are done with this file now. So you can save and close it.
ID3D9Wrapper_Device.h
Just like the other .h file for the wrapper, you need to find the functions that are used by the original Direct3DDevice9 interface. To do that, go back to your notepad that has d3d9.h open and scroll down further from the last spot we copied code from. Not much further down from where we just were in that file, you should find:
DECLARE_INTERFACE_(IDirect3DDevice9, IUnknown)
This is the start the Direct3DDevice9 interface which we will need the code from. As I said above, this is the file that contains the most code in this hook and tutorial. I will not show you everything to copy on here cause it will be way to long, but, I will show you where to start and stop:
Start copying at:
/*** IUnknown methods ***/
STDMETHOD(QueryInterface)(THIS_ REFIID riid, void** ppvObj) PURE;
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
STDMETHOD_(ULONG,Release)(THIS) PURE;
Copy everything, including what I just showed you above, down to, and including:
STDMETHOD(DrawTriPatch)(THIS_ UINT Handle,CONST float* pNumSegs,CONST D3DTRIPATCH_INFO* pTriPatchInfo) PURE;
STDMETHOD(DeletePatch)(THIS_ UINT Handle) PURE;
STDMETHOD(CreateQuery)(THIS_ D3DQUERYTYPE Type,IDirect3DQuery9** ppQuery) PURE;
Yea, it's a lot of things, but, it's easy to write them. They are just pass-through functions so you do not need to add any code inside them other then the returns unless you are modifying them for your needs.
Ok that being said, copy and paste that code into ID3D9Wrapper_Device.h then you will need to embrace these, just like the other header, in a class. First, we need our includes:
#pragma once
#include "stdafx.h"
Next, the class define:
class Direct3DDevice9Wrapper : public IDirect3DDevice9
{
public:
Next, the construct / deconstruct, to be added after the line that says public:
Direct3DDevice9Wrapper(IDirect3DDevice9* pDirect3DDevice9, IDirect3D9* pDirect3D9, D3DPRESENT_PARAMETERS *pPresentationParameters);
virtual ~Direct3DDevice9Wrapper();
Then at the end of the file, you will need the closing the of the class. But you will also need 3 variables that will be used inside this class. Which are the variables that hold the pointer to the device and a variable to track strides.
IDirect3DDevice9* Direct3DDevice9;
IDirect3D9* Direct3D9;
UINT m_Stride;
};
Next, you need to remove the PURE lines again. Just like before, hit CTRL+H, in the top box enter ' PURE;' including the space but not the quotes, and in the bottom, ';' not including the quotes. Then hit Replace All which should replace like 115-120 things. Now you are done with this file for now, so save and close.
ID3D9Wrapper_Device.cpp
Ah, the mother-load file. This file contains the most code as I said, but again as I said, it's just pass through functions at first until you add things yourself. So lets get started..
First, we need our includes for the file:
#include "ID3D9Wrapper_Device.h"
We only need this because the .h file already includes stdafx.h which contains the other includes that will be needed. Next, we need our construct / deconstruct of this class:
Direct3DDevice9Wrapper::Direct3DDevice9Wrapper(IDi rect3DDevice9 *pDirect3DDevice9, IDirect3D9 *pDirect3D9, D3DPRESENT_PARAMETERS *pPresentationParameters)
{
Direct3DDevice9 = pDirect3DDevice9;
Direct3D9 = pDirect3D9;
}
Direct3DDevice9Wrapper::~Direct3DDevice9Wrapper(){ }
In the construct, we are grabbing the pointer to the device and storing it to be used in this class, and then altering the returned device pointer with our hooked one so the system uses our wrapped functions.
Next, you need to go through the list of functions and write them out just like you did with the other file. Remember, STDMETHOD means the return type is HRESULT and STDMETHOD_ means the return type is the first variable in the parentheses.
Again heres some examples to help you out with this step:
HRESULT Direct3DDevice9Wrapper::QueryInterface(const IID &riid, void **ppvObj)
{
return Direct3DDevice9->QueryInterface( riid, ppvObj );
}
ULONG Direct3DDevice9Wrapper::AddRef()
{
return Direct3DDevice9->AddRef();
}
ULONG Direct3DDevice9Wrapper::Release()
{
return Direct3DDevice9->Release();
}
Now we need to make some edits to the code you just made. Nothing major, just some minor things. First, for the Stride logger, you want to alter SetStreamSource to look like this:
HRESULT Direct3DDevice9Wrapper::SetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9 *pStreamData, UINT OffsetInBytes, UINT Stride)
{
if( StreamNumber == 0 )
m_Stride = Stride;
return Direct3DDevice9->SetStreamSource(StreamNumber, pStreamData, OffsetInBytes, Stride);
}
Next, you need to alter GetDirect3D, instead of letting it setting the variable to the original pointer, we want it to set it to our wrappers, so we use:
HRESULT Direct3DDevice9Wrapper::GetDirect3D(IDirect3D9 **ppD3D9)
{
*ppD3D9 = Direct3D9;
return D3D_OK;
}
And another adjustment to QueryInterface:
HRESULT Direct3DDevice9Wrapper::QueryInterface(const IID &riid, void **ppvObj)
{
HRESULT hRes = Direct3DDevice9->QueryInterface(riid, ppvObj);
if( hRes == S_OK )
*ppvObj = this;
else
*ppvObj = NULL;
return hRes;
}
Ok now we should be done with this file as well. So save and close. Next, we need to go back and edit some of the first few files to handle the changes with the new wrapper. So, first lets open stdafx.h
At the bottom of stdafx.h you need to add another include:
#include "ID3D9Wrapper_Device.h"
Then you can save and close that file.
Next, in main.cpp, you need to add an include as well:
#include "ID3D9Wrapper.h"
This one should go under the include for stdafx.h (Order does matter in some cases.) Then save and close main.cpp.
Next we need to add a definition file to the project to make it so that Direct3DCreate9 is accessible to the program calling it and that its not all giberish when the compiler links it. This is another step that might need different work if you are not using VS2005. I do not know if .DEF files are standard for other compilers, but it should be. You might have to work different to compile one into your project though.
For people using VS2005, simply do the following:
- - In the solution explorer, right click on 'Source Files' and goto:
- Add -> New Item
- Select 'Module-definition' file from the popup and name it the same name as the project. In my case, it will be called, 'dxhook.def'
Now if the file doesn't open itself already, just double click it. This file is the export file that will contain any exports we need to allow other programs direct access to. In our case, the only one for now is Direct3DCreate9. But instead of just saying, export, we want it to set Direct3DCreate9 to our hooked function. So our DEF file code will be:
LIBRARY "dxhook"
EXPORTS
Direct3DCreate9 = Mine_Direct3DCreate9
Now, VS2005 should add the DEF file to the project properties automatically as long as you added it the way I showed above. Save and close that file now.
Congrats! The hook / wrapper are done! Take a breather for a few before we write up the quick launcher for this hook.
Part 6. The Injector
Ok first and foremost, let start with, this is a VERY BASIC injector. There are PLENTY of ways to rewrite this and such, and I HIGHLY suggest that you do. There are very nice libs you should use such as ForceLib, and a CRC32 rewriter to keep your hook undetected and such. This is just a small example to show you how to inject using Detours.
Detours comes with a function that wraps CreateProcessEx and injects the module you give it, for you. You can do this yourself as well by using CreateProcess/Ex then pausing the process, creating a new thread, and injecting your code into the thread, then calling the dllmain yourself and such. Again, theres many ways to do it, so you can choose which you want to use.
For this I will be using a simple console app. Nothing major, 1 file, not much code.
To start, lets make a new project so open another instance of VS2005 and goto: File -> New -> Project, select Win32 Project from the box, name it dxlauncher or what ever you want. Again keep "Create directory for solution" checked as it keeps things nice and tidy. Then click ok.
When the Application Wizard shows up, click on the Application Settings link on the left, then choose the following settings:
Application Type: Console Application
Additional options: Empty Project
Then click finish to open the new blank project. Next, right click in the solution explorer, and goto: Add -> New Item, Choose C++ File (.cpp) from the box, enter the name, 'main.cpp' and click add.
Now the new folder for this project should have been made. You will need to copy and paste the Detours folder into this projects directory as well cause we need them for this project too. Instead of really explaining things for this I'm just gunna post the code:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <atlbase.h>
#include <atlstr.h>
#pragma comment(lib,"Detours/detours.lib")
#include "Detours/detours.h"
int main()
{
CString strHookPath;
CString strINIPath;
////////////////////////////////////
// Get The Current Paths
////////////////////////////////////
_wfullpath(strHookPath.GetBuffer(MAX_PATH), L"dxhook.dll", MAX_PATH);
strHookPath.ReleaseBuffer();
_wfullpath(strINIPath.GetBuffer(MAX_PATH), L"settings.ini", MAX_PATH);
strINIPath.ReleaseBuffer();
////////////////////////////////////
// Check For Files
////////////////////////////////////
if( GetFileAttributes( strHookPath ) == 0xFFFFFFFF )
{
// Hook Was Not Found
return 0;
}
if( GetFileAttributes( strINIPath ) == 0xFFFFFFFF )
{
// INI File Was Not Found
return 0;
}
////////////////////////////////////
// Read INI For Game Path
////////////////////////////////////
CString strGamePath;
GetPrivateProfileString( _T("settings"), _T("Path"), _T(""), strGamePath.GetBuffer(MAX_PATH), MAX_PATH, strINIPath );
strGamePath.ReleaseBuffer();
////////////////////////////////////
// Create Game Path Variables
////////////////////////////////////
CString strGameExe = strGamePath + "\GAME_EXE_NAME.exe";
////////////////////////////////////
// Launch The Process
////////////////////////////////////
STARTUPINFO si = {sizeof(STARTUPINFO)};
PROCESS_INFORMATION pi = {0};
BOOL bResult = DetourCreateProcessWithDll( strGameExe, NULL, 0, 0, TRUE,
CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE, NULL,
strGamePath, &si, &pi, strHookPath, 0 );
if( !bResult )
{
// Process Failed To Launch
return 0;
}
////////////////////////////////////
// Done!
////////////////////////////////////
return 0;
}
Again, I do not recommend using this as your launcher. It is not secure and will be detectable. Along with that it wont work for some games that to late launching meaning 1 window launches another. You will need to make a process monitor style injector for that.
Now, compile both the launcher and the DLL and put them in the same folder. If you are using my launcher, create a new text file and rename it to 'settings.ini' and put inside of it:
[settings]
Path=C:/Path/To/Your/Game
Then launch the game and play.
Compiling
With Visual Studio 2005, you might run into issues with others using your programs after they are compiled. This is due to the runtime library thats set to default when compiled. This is, however, a simple adjustment. Open your project up in VS2005, and open the project properties by going to:
Project -> <Project Name> Properties
Once the project properties are open, expand the Configuration Properties tree item, then expand the C/C++ item. Then click on the 'Code Generation' item. On the right side, you should find an option labeled, 'Runtime Library', change this value to 'Multi-Threaded (/MT)' for your release build that will be distributed to others.
Notes
- Detours 2.1 has removed functions that are used for this hook so please use the link provided instead of the real Detours download.
Author: Wiccaan