Frage

Ich mag Umweg EndScene aus einer beliebigen Anwendung DirectX 9 ein kleines Overlay zu erstellen. Als ein Beispiel, können Sie den Bildzähler Overlay von FRAPS nehmen könnte, die in den Spielen gezeigt, wenn sie aktiviert sind.

ich die folgenden Methoden kennen, dies zu tun:

  1. Erstellen eines neuen d3d9.dll , die dann auf den Spielpfad kopiert. Da der aktuelle Ordner zuerst gesucht wird, bevor system32 usw. geht, wird meine modifizierte DLL geladen, meine zusätzlichen Code ausgeführt wird.

    Nachteil: Sie haben es dort zu setzen, bevor Sie das Spiel starten

    .
    • Wie bei dem ersten Verfahren, wobei jedoch das DLL in system32 direkt.

    Nachteil: Sie können nicht Spiel spezifischen Code hinzufügen. Sie können nicht ausschließen, Anwendungen, bei denen Sie Ihre DLL nicht geladen werden soll.

    • die EndScene Erste Offset direkt aus der DLL-Tools wie IDA Pro 4.9 kostenlos nutzen. Da die DLL geladen wird, wie es ist, können Sie einfach diese an die DLL Offsetzumischung Adresse beginnen, wenn es um das Spiel zugeordnet ist, bekommen die tatsächliche Offset und dann einhaken.

    Nachteil:. Der Offset ist nicht das gleiche auf jedem System

    • Anspannen Direct3DCreate9 erhalten die D3D9, dann Einhaken D3D9-> Create das Gerät Zeiger zu bekommen, und Einhaken dann Device-> EndScene durch die virtuelle Tabelle.

    Nachteil: Die DLL nicht injiziert werden kann, wenn der Prozess bereits ausgeführt wird. Sie haben den Prozess mit der CREATE_SUSPENDED Flagge beginnen die anfänglichen Haken Direct3DCreate9 .

    • ein neues Gerät in einem neuen Fenster erstellen, sobald die DLL injiziert wird. Dann die EndScene von diesem Gerät versetzt bekommen und Einhaken ihm, was zu einem Haken für das Gerät, die durch das Spiel verwendet wird.

    Nachteil:. als eine Information I gelesen habe, ein zweites Gerät zu schaffen mit dem vorhandenen Gerät stören kann, und es kann Fehler mit Fenstern vs. Vollbild-Modus etc

    • Wie bei der dritten Methode. Allerdings werden Sie ein Muster-Scan zu erhalten EndScene tun.

    Nachteil: sieht nicht so zuverlässig

  2. .

Wie kann ich EndScene von einem injizierten DLL Haken, die geladen werden können, wenn das Spiel bereits laufen, ohne mit unterschiedlichem umzugehen d3d9.dll 's auf anderen Systemen, und mit einem Verfahren das ist zuverlässig? Wie funktioniert FRAPS zum Beispiel durchführen, es ist DirectX Haken? Die DLL sollte nicht auf alle Spiele gelten nur für bestimmte Prozesse, bei denen ich spritze es über CreateRemoteThread.

War es hilfreich?

Lösung

installieren Sie eine systemweite Haken. (SetWindowsHookEx) Mit diesem getan, erhalten Sie in jeden Prozess geladen werden.

Nun, wenn der Haken genannt wird, suchen Sie eine geladene d3d9.dll.

Wenn man geladen wird, erstellen Sie ein temporäres D3D9 Objekt, und gehen Sie die VTable die Adresse der EndScene Methode zu erhalten.

Dann können Sie den EndScene Ruf-, mit Ihrer eigenen Methode. Ersetzen Sie (die erste Anweisung in EndScene durch einen Aufruf Ihrer Methode.

Wenn Sie fertig sind, müssen Sie den Anruf zurück patchen, das ursprüngliche EndScene Methode aufzurufen. Und dann Patch neu installiert werden.

Dies ist die Art und Weise Fraps es tut. ( Link-)


Sie können eine Funktion Adresse aus dem Vtable einer Schnittstelle finden.

So können Sie Folgendes ausführen können (Pseudo-Code):

IDirect3DDevice9* pTempDev = ...;
const int EndSceneIndex = 26 (?);

typedef HRESULT (IDirect3DDevice9::* EndSceneFunc)( void );

BYTE* pVtable = reinterpret_cast<void*>( pTempDev );
EndSceneFunc = pVtable + sizeof(void*) * EndSceneIndex;

EndSceneFunc enthält nun einen Zeiger auf die Funktion selbst. Wir können nun entweder alle Call-sites patchen oder wir können die Funktion selbst patchen.

Beachten Sie, dass dies alles hängt von der Kenntnis der Implementierung von COM-Schnittstellen in Windows. Aber das funktioniert auf allen Windows-Versionen (entweder 32 oder 64, nicht beide gleichzeitig).

Andere Tipps

Ein etwas alte Frage, die ich kenne - aber falls jemand in dies zu tun mit C # interessiert, hier ist mein Beispiel auf die Direct3D 9 API unter Verwendung von C # Einhaken. Dieses verwendet EasyHook eine Open-Source-.NET-Assembly, die Sie ‚sicher‘ installieren Haken von verwalteten Code in nicht verwalteten Funktionen ermöglicht. (Hinweis: EasyHook kümmert sich um alle Fragen rund um DLL-Injektion - zum Beispiel CREATE_SUSPENDED, ACL, 32 vs 64-Bit und so weiter)

Ich verwende einen ähnlichen VTable Ansatz wie von Christopher über eine kleine C ++ genannten Helfer DLL dynamisch die Adresse der IDirect3DDevice9 Funktionen Haken bestimmen. Dies wird durch die Schaffung eines temporären Fenster-Handle durchgeführt, und die Schaffung eines Wegwerf-IDirect3Device9 innerhalb der Baugruppe, bevor injiziert dann die gewünschten Funktionen Einhaken. Auf diese Weise können Sie Ihre Anwendung ein Ziel Haken, der bereits ausgeführt wird (Update: Beachten Sie, dass dies möglich ist, vollständig in C # auch - siehe Kommentar auf der verlinkten Seite).

Aktualisieren : Es gibt auch eine aktualisierte Version Einhaken Direct3D 9, 10 und 11 noch EasyHook verwenden und mit SharpDX statt SlimDX

Ich weiß, diese Frage ist alt, aber dies sollte für jedes Programm arbeitet mit DirectX9, Sie sind im Grunde Ihre eigene Instanz zu schaffen, und dann immer den Zeiger auf die VTable, dann nur Sie es Haken. Sie müssen Umwege 3.X btw:

//Just some typedefs:
typedef HRESULT (WINAPI* oEndScene) (LPDIRECT3DDEVICE9 D3DDevice);
static oEndScene EndScene;

//Do this in a function or whatever
HMODULE hDLL=GetModuleHandleA("d3d9");
LPDIRECT3D9(__stdcall*pDirect3DCreate9)(UINT) = (LPDIRECT3D9(__stdcall*)(UINT))GetProcAddress( hDLL, "Direct3DCreate9");

LPDIRECT3D9 pD3D = pDirect3DCreate9(D3D_SDK_VERSION);

D3DDISPLAYMODE d3ddm;
HRESULT hRes = pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm );
D3DPRESENT_PARAMETERS d3dpp; 
ZeroMemory( &d3dpp, sizeof(d3dpp));
d3dpp.Windowed = true;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = d3ddm.Format;

WNDCLASSEX wc = { sizeof(WNDCLASSEX),CS_CLASSDC,TempWndProc,0L,0L,GetModuleHandle(NULL),NULL,NULL,NULL,NULL,("1"),NULL};
RegisterClassEx(&wc);
HWND hWnd = CreateWindow(("1"),NULL,WS_OVERLAPPEDWINDOW,100,100,300,300,GetDesktopWindow(),NULL,wc.hInstance,NULL);

hRes = pD3D->CreateDevice( 
    D3DADAPTER_DEFAULT,
    D3DDEVTYPE_HAL,
    hWnd,
    D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_DISABLE_DRIVER_MANAGEMENT,
    &d3dpp, &ppReturnedDeviceInterface);

pD3D->Release();
DestroyWindow(hWnd);

if(pD3D == NULL){
    //printf ("WARNING: D3D FAILED");
    return false;
}
pInterface = (unsigned long*)*((unsigned long*)ppReturnedDeviceInterface);


EndScene = (oEndScene) (DWORD) pInterface[42];
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)EndScene, newEndScene);
DetourTransactionCommit();

Und dann Ihre Funktion:

HRESULT WINAPI D3D9Hook::newEndScene(LPDIRECT3DDEVICE9 pDevice)
{   
    //Do your stuff here

    //Call the original (if you want)
    return EndScene(pDevice);
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top