Solved D3D9 hooking

Hexui Undetected CSGO Cheats Sinkicheat PUBG Cheat

S22_UK

Newbie
Oct 2, 2016
3
32
0
Hi, everyone.

I'm new to programming and to hooking. I can re-route any win32 api by using microsoft's detours 3.0 library, which is realy easy to do.

however this does not work with directx, I've been seaching for example project's that I can learn from and I have not found one that worked for me.

I'm trying to capture screenshoot from AmaRecTV whic is a x86 'Video Capture Software for Direct Show', that uses D3D9.
I used apitrace which is for tracing OpenGL, OpenGL ES, Direct3D, and DirectDraw APIs calls to a file, and found it calls
IDirect3DSwapChain9Ex::present

can any one please share there example project that I can learn from, it can be c/c++ or c#.

thanks in advance.
 

Broihon

edgy 12 y/o
Escobar Tier VIP
Fleep Tier Donator
Dec 22, 2013
1,745
40,528
316
First of all just don't use Fleep'S tutorial(s) on d3d hooking. They aren't worth watching to be honest.

When hooking DirectX functions it always comes down to the problem that you don't know the address of the function you want to hook because they are member functions.
That means you can't just use a static function pointer in this case.
To get a pointer to the function you want you first have to create a instance of the object (in this IDirect3DSwapChain9, since Present is part of IDirect3DSwapChain9 interface and the IDirect3DSwapChain9Ex interface it's enough to use the IDirect3DSwapChain9 interface).

Here's some code on how to create this interface and how to get a pointer to one of the member functions:
C++:
D3DPRESENT_PARAMETERS D3DPP{ 0 };
D3DPP.Windowed		= TRUE;
D3DPP.SwapEffect	= D3DSWAPEFFECT_DISCARD;
D3DPP.hDeviceWindow = GetForegroundWindow();

pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if (!pD3D)
{
	printf("Direct3DCreate9 failed: 0x%X", (DWORD)GetLastError());
	return false;
}

HRESULT hr = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DPP.hDeviceWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &D3DPP, &pDevice);
if (FAILED(hr))
{
	printf("CreateDevice failed: 0x%X", (DWORD)hr);
	pD3D->Release();
	return false;
}

IDirect3DSwapChain9 * pSwapChain = nullptr;
hr = pDevice->GetSwapChain(0, &pSwapChain);
if (FAILED(hr))
{
	printf("GetSwapChain failed: 0x%X", (DWORD)hr);
	pDevice->Release();
	pD3D->Release();
	return false;
}
	
void ** VTable = *reinterpret_cast<void***>(pSwapChain);
printf("IDirect3DSwapChain9::Present 0x%p\n", VTable[3]);

pSwapChain->Release();
pDevice->Release();
pD3D->Release();

return true;
 

S22_UK

Newbie
Oct 2, 2016
3
32
0
thank you for both of your help.

I will try and see if I can have any success from trial and error.

so basicly I just need to get the directx functions address pointer and re-routed it to my function pointer.

Вroihon - if possible can you share one of your simple project file that I can learn from, I don't need to draw anything on screen, just need to capture screenshoot.

C++:
#include <windows.h>
#include <iostream>
#include <d3d9.h>
#pragma comment(lib, "d3d9.lib")

//functions
BOOL GetAddress();

// global variables
LPDIRECT3DDEVICE9 pDevice = NULL;

int main()
{
	printf("Before pDevice =  0x%p\n", pDevice);

	if(GetAddress())
		printf("After pDevice = 0x%p\n", pDevice);

	return 0;
}

BOOL GetAddress()
{
	D3DPRESENT_PARAMETERS D3DPP = { 0 };
	D3DPP.Windowed		= TRUE;
	D3DPP.SwapEffect	= D3DSWAPEFFECT_DISCARD;
	D3DPP.hDeviceWindow = GetForegroundWindow();

	LPDIRECT3D9 pD3D = Direct3DCreate9(D3D_SDK_VERSION);
	if (!pD3D)
	{
		printf("Direct3DCreate9 failed: 0x%X", (DWORD)GetLastError());
		return false;
	}

	HRESULT hr = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DPP.hDeviceWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &D3DPP, &pDevice);
	if (FAILED(hr))
	{
		printf("CreateDevice failed: 0x%X", (DWORD)hr);
		pD3D->Release();
		return false;
	}

	IDirect3DSwapChain9 * pSwapChain = nullptr;
	hr = pDevice->GetSwapChain(0, &pSwapChain);
	if (FAILED(hr))
	{
		printf("GetSwapChain failed: 0x%X", (DWORD)hr);
		pDevice->Release();
		pD3D->Release();
		return false;
	}

	void ** VTable = *reinterpret_cast<void***>(pSwapChain);
	printf("IDirect3DSwapChain9::Present 0x%p\n", VTable[3]);

	pSwapChain->Release();
	pDevice->Release();
	pD3D->Release();

	return true;
}
output
C++:
Before pDevice =  0x00000000
IDirect3DSwapChain9::Present 0x64DD781F
After pDevice = 0x01F889C0
 

Broihon

edgy 12 y/o
Escobar Tier VIP
Fleep Tier Donator
Dec 22, 2013
1,745
40,528
316
thank you for both of your help.

I will try and see if I can have any success from trial and error.

so basicly I just need to get the directx functions address pointer and re-routed it to my function pointer.

Вroihon - if possible can you share one of your simple project file that I can learn from, I don't need to draw anything on screen, just need to capture screenshoot.
//code
I actually never hooked IDirect3DSwapChain9::present in any of my projects. I just wrote that piece of code based on how I do my normal IDirect3DDevice9::EndScene hooks.
Furthermore I'm not sure if it's even necesarry to get a pointer to the IDirect3DSwapChain9 interface. To create a screenshot you need the IDirect3DDevice9 interface.
You can get that inside of IDirect3DSwapChain9::present by calling IDirect3DSwapChain9::GetDevice but it's probably easier to simply hook IDirect3DDevice9::present then.

What I'd do is this (enjoy some pseudo code):

C++:
void * GetPresent()
{
     //most of the code i posted
     void ** VTable = *reinterpret_cast<void***>(pDevice);
     return VTable[17];
}

typedef HRESULT(__stdcall * f_Present)(IDirect3DDevice9 * pDevice, RECT*, RECT*, HWND, RGNDATA); //present protype
f_Present pTrp_Present;

HRESULT __stdcall hk_Present(IDirect3DDevice9 * pDevice, RECT * sR, RECT * dR, HWND hWnd, RGNDATA pDirty)
{
     HRESULT hRet = pTrp_Present(pDevice, sR, dR, hWnd, pDirty);
     //screenshot magic
     return hRet;
}

void SetUpHooks()
{
     void * pD3D9Device_Present = GetPresent();
     pTrp_Present = Hook(pD3D9Device_Present, hk_Present); //detour trampoline hook
}
The easiest way to do a screenshot is to create a create another surface and copy the render target data to it.
Then you can (or probably should) use D3DXSaveSurfaceToFile from the d3d SDK. It's probably possible to do this without using the SDK but I don't know how.
This looks promising: https://stackoverflow.com/questions/30021274/capture-screen-using-directx
 

S22_UK

Newbie
Oct 2, 2016
3
32
0
sorry for the late update, due to work.

I still can't get it working, this is from apitrace
IDirect3DSwapChain9Ex::present(this = 0x6f5dc20, pSourceRect = [{left = 0, top = 0, right = 604, bottom = 339}], pDestRect = [{left = 0, top = 0, right = 604, bottom = 339}], hDestWindowOverride = 0x1e0ee4, pDirtyRegion = NULL, dwFlags = D3DPRESENT_DONOTWAIT) = D3D_OK

my dll code:
C++:
#include <Windows.h>
#include <d3d9.h>
#include "../detours/include/detours.h"

#pragma comment(lib, "../detours/lib.x86/detours.lib")
#pragma comment(lib, "d3d9.lib")

_declspec(dllexport) void exportfunc()
{
	return;
}

typedef HRESULT(__stdcall * f_Present)(IDirect3DDevice9 * pDevice, RECT*, RECT*, HWND, RGNDATA); //present protype
f_Present pTrp_Present;

HRESULT __stdcall hk_Present(IDirect3DDevice9 * pDevice, RECT * sR, RECT * dR, HWND hWnd, RGNDATA pDirty)
{
	HRESULT hRet = pTrp_Present(pDevice, sR, dR, hWnd, pDirty);

	MessageBox(NULL, "this is a test", "MessageBox caption", MB_OK);


	return hRet;
}

void *GetPresent()
{
	LPDIRECT3DDEVICE9 pDevice = NULL;
	D3DPRESENT_PARAMETERS D3DPP = { 0 };
	D3DPP.Windowed		= TRUE;
	D3DPP.SwapEffect	= D3DSWAPEFFECT_DISCARD;
	D3DPP.hDeviceWindow = GetForegroundWindow();

	LPDIRECT3D9 pD3D = Direct3DCreate9(D3D_SDK_VERSION);
	if (!pD3D)
	{
		MessageBox(NULL, "Direct3DCreate9 failed", "MessageBox caption", MB_OK);
		return false;
	}

	HRESULT hr = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DPP.hDeviceWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &D3DPP, &pDevice);
	if (FAILED(hr))
	{
		MessageBox(NULL, "CreateDevice failed", "MessageBox caption", MB_OK);
		pD3D->Release();
		return false;
	}

	IDirect3DSwapChain9 * pSwapChain = nullptr;
	hr = pDevice->GetSwapChain(0, &pSwapChain);
	if (FAILED(hr))
	{
		MessageBox(NULL, "GetSwapChain failed", "MessageBox caption", MB_OK);
		pDevice->Release();
		pD3D->Release();
		return false;
	}

    void ** VTable = *reinterpret_cast<void***>(pDevice);

    return VTable[17];
}

BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved)
{
    if (DetourIsHelperProcess())
	{
        return TRUE;
    }

	LONG error;

	if (DLL_PROCESS_ATTACH == fdwReason)
 	{
		DetourRestoreAfterWith();

		if(DetourTransactionBegin() == NO_ERROR)
		{
 			DetourUpdateThread(GetCurrentThread());

			//GetModuleHandleA("d3d9.dll");
			void * pD3D9Device_Present = GetPresent();

  			DetourAttach(&(PVOID&)pD3D9Device_Present, hk_Present);

  			error = DetourTransactionCommit();

			if(error != NO_ERROR)
				MessageBox(NULL, "Error", "MessageBox caption", MB_OK);
		}
 	}


	 return TRUE;
}
and this is my injedtor
C++:
#include <iostream>
#include <Windows.h>
#include "../detours/include/detours.h"
#pragma comment(lib, "../detours/lib.X86/detours.lib")

using namespace std;

int main() 
{
	STARTUPINFO si;
	PROCESS_INFORMATION pi;

	ZeroMemory(&si, sizeof(si));
	ZeroMemory(&pi, sizeof(pi));
	si.cb = sizeof(si);
	si.dwFlags = STARTF_USESHOWWINDOW;
	si.wShowWindow = SW_SHOW;

	if(DetourCreateProcessWithDllEx("C:\\Users\\UserX\\Videos\\AmaRecTV\\AmaRecTV.exe", NULL, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED, NULL, NULL, &si, &pi, "C:\\Users\\UserX\\Desktop\\AmaRecCap\\Release\\MyHook.dll", NULL))
	{
		ResumeThread(pi.hThread);
	}else cout << "Injection Failed\n" << endl;

    return EXIT_SUCCESS;
}
 
Last edited:
Attention! Before you post:

Read the How to Ask Questions Guide
99% of questions are answered in the Beginner's Guide, do it before asking a question.

No Hack Requests. Post in the correct section.  Search the forum first. Read the rules.

How to make a good post:

  • Fill out the form correctly
  • Tell us the game name & coding language
  • Post everything we need to know to help you
  • Ask specific questions, be descriptive
  • Post errors, line numbers & screenshots
  • Post code snippets using code tags
  • If it's a large project, zip it up and attach it

If you do not comply, your post may be deleted.  We want to help, please make a good post and we will do our best to help you.

Community Mods