Öffnet jetzt euer VC++ und legt ein neues Dynamic Link Library
Projekt an. Stellt sicher, dass ihr ein komplett leeres Projekt
bekommt. Dort fügt ihr dann folgenden Code ein:
Code:
int WINAPI DllMain(HINSTANCE hInst,DWORD reason,LPVOID reserved)
{
switch(reason)
{
case DLL_PROCESS_ATTACH:
// Hier kommt unser Code rein
break;
}
return true;
}
Das ist Standard für jede DLL die in ein Programm injected wird.
Sollte jeder von euch schon einmal gesehen haben. Unser Code wird
ausgeführt sobald die DLL an unseren Prozess angehängt wird.
Compilen können wir das so noch nicht, dazu müssen wir obendrüber
ersteinmal die wichtigsten Header mit einbinden.
Code:
#include <windows.h>
#include <cstdio>
#include <d3d9.h>
#include <d3dx9.h>
Jetzt habt ihr auch gleichzeitig die DirectX funktionen
includiert. Wenn ihr das SDK richtig in VC++ eingestellt habt
sollte das jetzt auch ohne Fehler zu compilen sein. Eventuell
müsst ihr folgendes noch obendrüber einfügen:
Code:
#pragma once
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
Das #pragma once sagt dem Compiler dass alles nur einmal
eingebunden wird. Ich bekomm sonst oft Fehler... Spätestens jetzt
sollte das fehlerfrei compilebar sein. Wenn nicht, guckt euch im
Internet um und stellt sicher, dass ihr das SDK richtig in VC++
eingestellt habt.
Jetzt können wir uns den Hook genauer anschauen. Am besten ist es,
wenn man das ganze in einem Thread macht, damit man sicher gehen
kann dass alles läuft. Also erstellen wir einen neuen Thread :
Code:
void InitHook()
{
HMODULE hModule = NULL;
while( !hModule )
{
hModule = GetModuleHandleA( "d3d9.dll" ); // Handle zur DLL holen
Sleep( 100 ); // 100ms warten
}
}
So da ist jetzt schon einiges vorweggenommen, aber es sollte klar
sein was hier passiert. Eigentlich brauchen wir das Handle nicht
mehr, aber so stellen wir sicher, dass die DLL auch wirklich
geladen wurde und dass D3D9 überhaupt läuft. An dieser Stelle
müssen wir jetzt die DetourFunction einfügen. Wer will kann die
von Microsoft benutzen, ich nehm die von GameDeception.
Code:
void *DetourFunc(BYTE *src, const BYTE *dst, const int len) // credits to gamedeception
{
BYTE *jmp = (BYTE*)malloc(len+5);
DWORD dwback;
VirtualProtect(src, len, PAGE_READWRITE, &dwback);
memcpy(jmp, src, len); jmp += len;
jmp[0] = 0xE9;
*(DWORD*)(jmp+1) = (DWORD)(src+len - jmp) - 5;
src[0] = 0xE9;
*(DWORD*)(src+1) = (DWORD)(dst - src) - 5;
VirtualProtect(src, len, dwback, &dwback);
return (jmp-len);
}
Bevor wir jetzt ans detouren gehen, gibt’s noch einiges
nachzuholen. Unser Thread muss natürlich auch gestartet werden.
Deswegen adden wir jetzt in DLLMain:
Code:
CreateThread(0, 0, (LPTHREAD_START_ROUTINE) InitHook, 0, 0, 0);
etzt aber zu unserer
EndScene Funktion. Als erstes brauchen wir
eine Typendefinition, damit der Compiler bei dem Detour später
nicht meckert. Die EndScene Funktion schaut folgendermaßen aus:
Code:
HRESULT __stdcall EndScene(LPDIRECT3DDEVICE9 pDevice)
Wir sehen hier auch, dass das Argument vom Typ LPDIRECT3DDEVICE9
ist. Hier können wir also auf den Pointer zum D3D Device
zugreifen. Ich nenn ihn jetzt einmal pDevice. Nähere Information
zu der Funktion gibt’s in der d3d9.h (dort ist sie deklariert)
oder im Internet.
Jetzt zurück zu unserem Typedef. Fügt folgendes in euer Projekt
ein:
Code:
typedef HRESULT(__stdcall* EndScene_t)(LPDIRECT3DDEVICE9);
EndScene_t pEndScene;
Wozu wir das brauchen wird gleich klar. Typedefs sind C-Standart,
ihr solltet wissen was diese zwei Zeilen bewirken (Wenn nicht: wie
immer -> Google).
Jetzt können wir die Funktion Detouren. Allgemein schaut das immer
so aus:
Code:
PointerOriginalFunktion = (TYPECAST) DetourFunc ( OffsetOriginalFunktion, UnsereFunktion, Länge );
Das ganze wird klar wenn ich das auf EndScene anwende. Bei der
Microsoft Detour variante brauchen wir keine Länge anzugeben. Hier
verwenden wir einfach immer 5, das ist das Minimum. Auf unsere
Funktion angewandt:
Code:
pEndScene = ( EndScene_t )DetourFunc((PBYTE) 0x4FDD71B0,(PBYTE)hkEndScene, 5);
Die Zeile fügt ihr in unseren Thread ein. Vergleicht sie dann mit
dem Typedef von gerade eben, dann versteht ihr das ganze gleich
besser. Allerdings taucht hier jetzt hkEndScene auf, und die ist
ja noch nirgendwo deklariert. Also holen wir das nach. Fügt am
Anfang die gehookte Funktion ein:
Code:
HRESULT __stdcall hkEndScene(LPDIRECT3DDEVICE9 pDevice)
{
return pEndScene(pDevice);
}
Das ist jetzt die Funktion in der wir Zeichnen können. Wie ihr
seht wird zur Originalfunktion returned. Aber das mit den Detours
ist ja längst klar ;D
An dieser Stelle sind wir eigentlich fertig, unser Ziel den D3D
DevicePointer zu bekommen haben wir hiermit erreicht. Jetzt wollen
wir aber gleich etwas Zeichnen um unseren Hook zu testen.