Pregunta

Quiero desvío EndScene desde una aplicación arbitraria de DirectX 9 para crear una pequeña superposición. A modo de ejemplo, se puede tomar la superposición contador de cuadros de FRAPS, que se muestra en los juegos cuando se activa.

Yo sé los siguientes métodos para hacer esto:

  1. Creación de un nuevo d3d9.dll , que se copia en la ruta de juegos. Desde la carpeta actual se busca en primer lugar, antes de ir a system32 etc., mi DLL modificada se carga, la ejecución de mi código adicional.

    Desventaja: Tienes que ponerlo allí antes de iniciar el juego

    .
    • Igual que el primer método, pero sustituyendo la DLL en system32 directamente.

    Desventaja: No se puede agregar código específico de juego. No se puede excluir aplicaciones en las que no desea el archivo DLL se va a cargar.

    • Obtener la endScene compensado directamente de la DLL usando herramientas como IDA Pro 4.9 gratis. Dado que la DLL se carga como es, puede simplemente añadir este desplazamiento a la DLL dirección de inicio, cuando se asigna al juego, para conseguir compensar el real, y luego conectarlo.

    Desventaja:. El desplazamiento no es el mismo en todos los sistemas

    • El enganchar Direct3DCreate9 para obtener el D3D9, después enganchando D3D9-> CreateDevice para obtener el puntero del dispositivo y, a continuación, conectar Device-> endScene a través de la mesa virtual.

    Desventaja: El DLL no se puede inyectar, cuando el proceso ya se está ejecutando. Usted tiene que comenzar el proceso con la bandera CREATE_SUSPENDED para enganchar la inicial Direct3DCreate9 .

    • Creación de un nuevo dispositivo en una nueva ventana, tan pronto como el archivo DLL se inyecta. Entonces, conseguir el desplazamiento de este dispositivo EndScene y se enganche, lo que resulta en un gancho para el dispositivo que se utiliza por el juego.

    Desventaja:. a partir de cierta información que he leído, la creación de un segundo dispositivo puede interferir con el dispositivo existente, y que puede fastidiar con el modo de pantalla completa vs. ventana etc

    • Igual que el tercer método. Sin embargo, que va a hacer un patrón de escaneo para obtener EndScene.

    Desventaja: no se ve tan confiable

  2. .

¿Cómo puedo conectar EndScene de una DLL inyectado, que puede ser cargado cuando el juego ya está en marcha, sin tener que lidiar con diferentes d3d9.dll 's en otros sistemas, y con un método que es fiable? ¿Cómo FRAPS por ejemplo realizan ganchos es DirectX? La DLL no debe aplicarse a todos los juegos, sólo para procesos específicos en los que se inyecte a través de CreateRemoteThread.

¿Fue útil?

Solución

instalar un sistema de gancho ancho. (SetWindowsHookEx) Una vez hecho esto, se llega a ser cargado en cada proceso.

Ahora, cuando el gancho se llama, usted busca un d3d9.dll cargado.

Si uno está cargado, se crea un objeto D3D9 temporal, y caminar la viable para obtener la dirección del método endScene.

A continuación, se puede parchear la llamada endScene, con su propio método. (Vuelva a colocar la primera instrucción en endScene por una llamada a su método.

Cuando haya terminado, usted tiene que arreglar la parte posterior llamada, para llamar al método endScene originales. Y luego volver a instalar el parche.

Esta es la forma Fraps lo hace. ( Enlace )


Puede encontrar una dirección de función de la viable de una interfaz.

Así que usted puede hacer lo siguiente (Pseudo-Código):

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

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

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

EndSceneFunc hace ahora contiene un puntero a la función misma. Podemos ahora tampoco parchear todas las llamadas sitios o podemos arreglar la propia función.

Mira que todo esto depende de los conocimientos de la aplicación de COM-interfaces en Windows. Pero esto funciona en todas las versiones de Windows (32 o 64, no ambos al mismo tiempo).

Otros consejos

Un poco vieja pregunta que sé - pero en caso de que alguien está interesado en hacer esto con C #, aquí está mi ejemplo en enganchando la API Direct3D 9 usando C # . Esto se hace a EasyHook una fuente NET abierta que le permite 'segura' instalar ganchos de código administrado en funciones no administradas. (Nota: EasyHook se encarga de todas las cuestiones relacionadas con la inyección de DLL - por ejemplo, CREATE_SUSPENDED, ACL, 32 vs 64 bits y así sucesivamente)

I utilizar un enfoque Vtable similar a la mencionada por Christopher través de un pequeño C ++ helper DLL para determinar dinámicamente la dirección de las funciones IDirect3DDevice9 a gancho. Esto se hace mediante la creación de un identificador de ventana temporal, y la creación de un IDirect3Device9 de usar y tirar dentro de la asamblea antes de inyectarse después enganchando las funciones deseadas. Esto permite a su aplicación para enganchar un objetivo que ya se está ejecutando (Actualización: nota que esto es posible por completo dentro de C # también - véanse los comentarios sobre la página enlazada).

Actualizar : también hay una versión actualizada de enganchar Direct3D 9, 10 y 11 sigue utilizando EasyHook y con SharpDX en lugar de SlimDX

Sé que esta pregunta es antiguo, pero esto debería funcionar para cualquier programa usando DirectX 9, va a crear su propia instancia, básicamente, y luego conseguir el puntero a la viable, a continuación, sólo conectarlo. Necesitará desvíos 3.x por cierto:

//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();

Y entonces su función:

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

    //Call the original (if you want)
    return EndScene(pDevice);
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top