2010-01-03 13 views
28

Quiero que desviarse EndScene desde una aplicación arbitraria de DirectX 9 para crear una pequeña superposición. Como ejemplo, puede tomar la superposición del contador de fotogramas de FRAPS, que se muestra en los juegos cuando se activa.El enganchar DirectX endScene de una DLL inyectado

sé los siguientes métodos para hacer esto:

  1. Creación de una nueva d3d9.dll, que luego se copia en el camino 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 comenzar el juego.

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

    Desventaja: No se puede agregar el código específico del juego. No puede excluir aplicaciones donde no desea que se cargue su DLL.

    • Obteniendo la compensación de EndScene directamente desde 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 después enganchando 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 primera Direct3DCreate9.

    • Creando un nuevo dispositivo en una nueva ventana, tan pronto como se inyecta el DLL. A continuación, obtener la EndScene desplazamiento desde este dispositivo y conectarlo, lo que resulta en un gancho para el dispositivo que se utiliza por el juego.

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

    • Igual que la tercer método. Sin embargo, que va a hacer una exploración del patrón para obtener EndScene.

    Desventaja: no parece tan confiable.

Cómo puedo enganchar EndScene de una DLL inyectado, que puede ser cargado cuando el juego ya se está ejecutando, sin tener que tratar con diferentes d3d9.dll 's en otros sistemas, y con un método que ¿es confiable? ¿Cómo funciona, por ejemplo, FRAPS sus ganchos de DirectX? La DLL no debería aplicarse a todos los juegos, solo a procesos específicos en los que lo inyecté a través del CreateRemoteThread.

Respuesta

15

Instala un gancho de ancho de sistema. (SetWindowsHookEx) Una vez hecho esto, se debe cargar en cada proceso.

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

Si se carga uno, se crea un objeto temporal D3D9 y se recorre el vtable para obtener la dirección del método EndScene.

Luego puede aplicar un parche a 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 parchear la llamada de vuelta, para llamar al método endScene originales. Y luego volver a instalar el parche.

Esto es la forma en que lo hace FRAPS (Link)


se puede encontrar una dirección de función de la viable de una interfaz

para que pueda 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 ahora contiene un puntero a la función en sí. Ahora podemos parchear todos los sitios de llamadas o podemos parchear la función en sí.

Tenga en cuenta que todo esto depende del conocimiento de la implementación de COM-Interfaces en Windows. Pero esto funciona en todas las versiones de Windows (32 o 64, no ambas al mismo tiempo).

+1

la salida de este para más detalles: Windows a través de C/C++, Capítulo 22 - DLL de inyección y API que engancha, Inyectar una DLL con Windows Ganchos – whunmr

+0

Quiero inyectar el archivo DLL a través de 'CreateRemoteThread'. No quiero un gancho global, solo para juegos específicos. – Etan

+0

Luego solo deje caer el primer paso. – Christopher

4

Una pregunta un poco vieja que sé, pero en caso de que alguien esté interesado en hacer esto con C#, aquí está mi ejemplo en hooking the Direct3D 9 API using C#. Esto utiliza EasyHook, un ensamblado .NET de fuente abierta que le permite instalar ganchos de manera segura del código administrado en funciones no administradas. (Nota: EasyHook se encarga de todos los problemas relacionados con la inyección de DLL, por ejemplo, CREATE_SUSPENDED, ACL, 32 vs 64 bits y así sucesivamente)

Utilizo un enfoque VTable similar al mencionado por Christopher a través de un pequeño dll C++ helper para dinámicamente determinar la dirección de las funciones IDirect3DDevice9 para enganchar. Esto se hace creando un identificador de ventana temporal y creando un IDirect3Device9 desechable dentro del ensamblado inyectado antes de conectar las funciones deseadas. Esto permite que su aplicación enganche un objetivo que ya se está ejecutando (Actualización: tenga en cuenta que esto también es posible en C# - vea los comentarios en la página vinculada).

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

2

Sé que esta pregunta es viejo, pero esto debería funcionar para cualquier programa usando DirectX 9, va a crear su propia instancia básicamente, y luego obtener el puntero a la VTable, entonces simplemente lo engancha. Necesitarás desvíos 3.X 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); 
} 
+0

¿Por qué recibo una "aplicación de bloqueo" cuando devuelvo el EndScene original? – Duracell

+0

@Duracell realmente depende de cómo lo está usando. ¿Estás enganchando desde el hilo principal? Tal vez su puntero al EndScene original sea nulo. Necesito más información para poder ayudarte. – Fredaikis

+0

Estoy inyectando este código http://pastebin.com/ui0ezFyW en la aplicación (use d3d9), y recibo un mensaje en la consola "printf_s (" Hooked! ");" De la función "HRESULT WINAPI newEndScene (LPDIRECT3DDEVICE9 pDevice)" , pero luego cuando llamo "return EndScene (pDevice);" - Obtener la aplicación de bloqueo, por favor verifique mi error. – Duracell

Cuestiones relacionadas