C++ D3D Hooking

08/23/2009 16:37 asdasd4568#1
Hallo zusammen,

ich stehe gerade vor folgendem Problem:
ich habe eine DLL und einen Loader gecoded, jedoch will ich anstelle des Loader einen Injecter haben, sprich: das spiel, in das injected werden soll, soll schon laufen. Natürlich hab ich das ganze schon probiert, jedoch werden die D3D-funktionen nicht wirklich gehookt, da die DLL auf ein Direct3DCreate9 wartet. Da diese Funktion aber wahrscheinlich direkt beim Starten des "Opfer-Spiels" ausgeführt wird, werden deswegen die anderen funktionen nicht gehookt..

Hab schon diverse tutorials ausprobiert, ohne Erfolg jedoch...

EDIT: ich hooke Direct3DCreate9 mithilfe der Detour-library von microsoft

mfg
asdasd4568
08/23/2009 17:54 ms​#2
Du kannst Direct3DCreate9() ja in deinem eigenen Loader aufrufen und dann die Adresse der Funktion, die du hooken willst, aus der VTable des daraus entstehendem IDirect3D9-Objektes nehmen. Dann ziehst du von dieser Adresse die ImageBase der d3d9.dll ab und schon hast du das Offset der Funktion.
Dieses Offset kannst du dann anschließend zu der ImageBase der d3d9.dll in dem Zielprozesses addieren und schon hast du die Adresse, an der sich diese Funktion im Zielprozess befindet.
08/23/2009 18:04 asdasd4568#3
Quote:
Originally Posted by Disconnect View Post
Du kannst Direct3DCreate9() ja in deinem eigenen Loader aufrufen und dann die Adresse der Funktion, die du hooken willst, aus der VTable des daraus entstehendem IDirect3D9-Objektes nehmen. Dann ziehst du von dieser Adresse die ImageBase der d3d9.dll ab und schon hast du das Offset der Funktion.
Dieses Offset kannst du dann anschließend zu der ImageBase der d3d9.dll in dem Zielprozesses addieren und schon hast du die Adresse, an der sich diese Funktion im Zielprozess befindet.
Sorry, da steig ich nicht ganz durch. Könntest du mich eventuell mit etwas beispielcode versorgen? Und was meinst du mit VTables?

Ich sollte noch dazu erwähnen, bin erst kürzlich in den Bereich des D3D Hooking eingestiegen
08/23/2009 18:24 ms​#4
Code:
#include "stdafx.h"
#include <Windows.h>
#include <d3d8.h>

#pragma comment (lib, "d3d8.lib")

BOOL CALLBACK Dlgproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void DialogLoop(HWND hWnd);

BOOL CALLBACK Dlgproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg)
	{
		case WM_COMMAND:
			switch(LOWORD(wParam))
			{
			}
	}
	return FALSE;
}

void DialogLoop(HWND hWnd)
{
	ShowWindow(hWnd, SW_SHOW);
	MSG msg;
	while(GetMessage(&msg, hWnd, 0, 0) > 0)
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	HWND hWnd = CreateDialog(NULL, MAKEINTRESOURCE(IDD_DIALOG1), NULL, (DLGPROC)Dlgproc);
	CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)DialogLoop, hWnd, 0, NULL);

	IDirect3D8 *Direct3D8 = Direct3DCreate8(D3D_SDK_VERSION);

	D3DPRESENT_PARAMETERS D3DPresentParams;
	ZeroMemory(&D3DPresentParams, sizeof(D3DPRESENT_PARAMETERS));
		D3DPresentParams.Windowed=true;
		D3DPresentParams.BackBufferCount=1;
		D3DPresentParams.BackBufferWidth=800;
		D3DPresentParams.BackBufferHeight=600;
		D3DPresentParams.BackBufferFormat=D3DFMT_X8R8G8B8;
		D3DPresentParams.SwapEffect=D3DSWAPEFFECT_DISCARD;
		D3DPresentParams.hDeviceWindow=hWnd;

	IDirect3DDevice8 *pDirect3DDevice;
	Direct3D8->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,&D3DPresentParams, &pDirect3DDevice);

    DWORD* pVTable = (DWORD*)pDirect3DDevice;
    pVTable = (DWORD*)pVTable[0];

	DWORD EndSceneOffset = pVTable[42] - (DWORD)GetModuleHandle("d3d8.dll");

	pDirect3DDevice->BeginScene();
	pDirect3DDevice->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 255), 0, 0);
	pDirect3DDevice->EndScene();
	pDirect3DDevice->Present(0, 0, 0, 0);

	printf("IDirect3DDevice9::EndScene Offset:\n 0x%X\n\n", EndSceneOffset);
	system("pause");

	return 0;
}
Zuerst wird ein verstecktes Fenster erzeugt, worauf anschließend IDirect3D8::CreateDevice() benutzt wird. Aus der VTable des IDirect3DDevice8-Objektes wird dann die Adresse von IDirect3DDevice8::EndScene() ausgelesen und dann das Offset davon berechnet.
Das sollte in Direct3D9 genauso gehen, du musst nur alle 8er durch 9er ersetzen.
Der Teil, in dem diese Adresse aus der VTable ausgelesen wird habe ich ehrlich gesagt nicht selbst geschrieben, sondern aus einem anderen Forum genommen.
08/23/2009 18:52 asdasd4568#5
Danke für den Code, konnte das offset auslesen (0x20F67)

Jetzt frag ich mich nur noch, wie ich dem Loader beibring, Direct3DCreate9 auszuführen und zu injecten anstatt zu loaden.

EDIT: und das mit dem Direct3DCreate9 ausführen, würde das das spiel nicht etwas "verwirren"??
08/23/2009 19:08 ms​#6
Du kannst den Loader ja das Offset beispielsweise in eine .ini-Datei speichern lassen und dieses dann in der DLL wieder auslesen.
08/23/2009 20:06 asdasd4568#7
Quote:
Originally Posted by Disconnect View Post
Du kannst den Loader ja das Offset beispielsweise in eine .ini-Datei speichern lassen und dieses dann in der DLL wieder auslesen.
Sorry, jetzt hast du mich total durcheinander gebracht.
Das Offset hab ich doch jetzt, wozu muss ich das dann in einer datei speichern und dann von der dll lesen lassen?

Mein Ziel ist es einfach, dass ich a) einen injecter hab und b) eine dll und wenn ich den injecter ausführe soll die dll den ganzen kram den ich in EndScene hab ins game rendern...
08/23/2009 20:40 ms​#8
Weil das Offset von EndScene() von System zu System unterschiedlich ist. Wenn du das Offset in deine DLL hardcodest, dann funktioniert sie zwar auf deinem System und wahrscheinlich teilweise auch auf anderen System, doch bei sehr vielen anderen wird sie nicht funktionieren.
Wenn du deinen Loader aber so erweiterst, dass er nicht nur die DLL injiziert, sondern sich auch die Offsets holt, dann sollte es überall funktionieren.
08/23/2009 21:22 asdasd4568#9
Quote:
Originally Posted by Disconnect View Post
Weil das Offset von EndScene() von System zu System unterschiedlich ist. Wenn du das Offset in deine DLL hardcodest, dann funktioniert sie zwar auf deinem System und wahrscheinlich teilweise auch auf anderen System, doch bei sehr vielen anderen wird sie nicht funktionieren.
Wenn du deinen Loader aber so erweiterst, dass er nicht nur die DLL injiziert, sondern sich auch die Offsets holt, dann sollte es überall funktionieren.

Wieso muss der loader das denn erledigen, die DLL müsste das doch auch können?

und wie führe ich jetzt eigentlich Direct3DCreate9 aus?
08/24/2009 14:20 asdasd4568#11
Ich hab heute mal etwas rumgesucht und eine eventuelle einfachere möglichkeit gefunden..
Ich habe das offset des IDirect3DDevice9 pointers des spiels gefunden, könnte ich nicht einfach EndScene aus dem hooken?
08/24/2009 17:46 schlurmann#12
Quote:
Originally Posted by asdasd4568 View Post
Ich hab heute mal etwas rumgesucht und eine eventuelle einfachere möglichkeit gefunden..
Ich habe das offset des IDirect3DDevice9 pointers des spiels gefunden, könnte ich nicht einfach EndScene aus dem hooken?
Die Frage solltest du dir selbst beantworten können, sonst wirst du nicht weit kommen.
08/24/2009 18:30 link#13
4FDD0F30 /$ 8BFF MOV EDI,EDI
4FDD0F32 |. 56 PUSH ESI
4FDD0F33 |. 8BF1 MOV ESI,ECX
4FDD0F35 |. E8 065B0000 CALL d3d9.4FDD6A40
4FDD0F3A |. 33C0 XOR EAX,EAX
4FDD0F3C |. C706 286CD64F MOV [DWORD DS:ESI],d3d9.4FD66C28
4FDD0F42 |. 8986 40240000 MOV [DWORD DS:ESI+2440],EAX
;...

Hier kannst du die Adresse der Funktionstabelle auslesen und anhand der Offsets der Funktionsdeklarationen gelangst du dann zu den Adressen der Funktionen (s. d3d9.h)

Um das ganze revisionsunabhängiger zu machen, kannst du auch zur Laufzeit nach den Opcodes suchen und die hardgecodete Adresse auslesen.