Подключение DirectX EndScene из инъецированной DLL

Я хочу EndScene из произвольного приложения DirectX 9 для создания небольшого наложения. В качестве примера вы можете взять накладку счетчика кадров FRAPS, которая отображается в играх при активации.

Я знаю следующие методы для этого:

  1. Создаем новую d3d9.dll , которая затем копируется в игровой путь. Поскольку поиск текущей папки выполняется сначала, перед переходом на system32 и т. Д. Моя модифицированная DLL загружается, выполняя мой дополнительный код.

    Недостаток: вы должны положить его туда, прежде чем начать игру.

    • То же, что и первый метод, но напрямую заменяя DLL в system32.

    Недостаток: вы не можете добавить определенный код игры. Вы не можете исключать приложения, в которых вы не хотите, чтобы ваша DLL была загружена.

    • Получение смещения EndScene непосредственно из DLL с помощью таких инструментов, как IDA Pro 4.9 Free. Поскольку DLL загружается как есть, вы можете просто добавить это смещение к стартовому адресу DLL, когда он сопоставляется с игрой, чтобы получить фактическое смещение, а затем подключить его.

    Нижняя сторона: смещение не является одинаковым для каждой системы.

    • Подключив Direct3DCreate9, чтобы получить D3D9, затем подключите D3D9-> CreateDevice, чтобы получить указатель устройства, а затем подключите Device-> EndScene через виртуальную таблицу.

    Недостаток: DLL не может быть введена, когда процесс уже запущен. Вы должны запустить этот процесс с помощью флага CREATE_SUSPENDED чтобы подключить начальный Direct3DCreate9 .

    • Создание нового устройства в новом окне, как только будет загружена DLL. Затем, получив смещение EndScene от этого устройства и подключив его, вы EndScene крючок для устройства, которое используется в игре.

    Даунсайд: по некоторой информации, которую я прочитал, создание второго устройства может помешать существующему устройству, и оно может быть связано с оконным и полноэкранным режимами и т. Д.

    • То же, что и третий метод. Однако вы получите сканирование шаблонов, чтобы получить EndScene .

    Даунсайд: не выглядит так надежно.

Как я могу подключить EndScene из инъецированной DLL, которая может быть загружена, когда игра уже запущена, без необходимости иметь дело с различными d3d9.dll в других системах и с надежным методом? Как FRAPS, например, выполняют его DirectX-перехватчики? DLL не должна применяться ко всем играм, а также к конкретным процессам, где я ввожу их через CreateRemoteThread .

Вы устанавливаете системный крючок. (SetWindowsHookEx). При этом вы можете загрузиться в каждый процесс.

Теперь, когда вызывается hook, вы ищете загруженный файл d3d9.dll.

Если один из них загружен, вы создаете временный объект D3D9 и ходите по таблице vtable, чтобы получить адрес метода EndScene.

Затем вы можете исправить вызов EndScene своим собственным методом. (Замените первую команду в EndScene на вызов вашего метода.

Когда все будет готово, вам необходимо исправить звонок, чтобы вызвать оригинальный метод EndScene. Затем переустановите патч.

Это так делает FRAPS. ( Ссылка )


Вы можете найти адрес функции из таблицы vtable интерфейса.

Таким образом, вы можете сделать следующее (Псевдокод):

 IDirect3DDevice9* pTempDev = ...; const int EndSceneIndex = 26 (?); typedef HRESULT (IDirect3DDevice9::* EndSceneFunc)( void ); BYTE* pVtable = reinterpret_cast( pTempDev ); EndSceneFunc = pVtable + sizeof(void*) * EndSceneIndex; 

EndSceneFunc теперь содержит указатель на функцию. Теперь мы можем либо исправить все call-сайты, либо мы можем исправить эту функцию.

Помните, что все это зависит от знания реализации COM-интерфейсов в Windows. Но это работает во всех версиях Windows (32 или 64, не оба одновременно).

Немного старый вопрос, который я знаю, но если кто-то заинтересован в этом с C #, вот мой пример по подключению Direct3D 9 API с помощью C # . Это использует EasyHook сборку с открытым исходным кодом .NET, которая позволяет «безопасно» устанавливать крючки из управляемого кода в неуправляемые функции. (Примечание: EasyHook заботится обо всех проблемах, связанных с инъекцией DLL – например, CREATE_SUSPENDED, ACL, 32 против 64-битного и так далее)

Я использую аналогичный подход VTable, упомянутый Кристофером через небольшую DLL-помощницу C ++, чтобы динамически определить адрес функций IDirect3DDevice9 для подключения. Это делается путем создания временного дескриптора windows и создания отбрасываемого IDirect3Device9 внутри внедренной сборки, прежде чем подключать нужные функции. Это позволяет вашему приложению подключить уже запущенную цель (Update: обратите внимание, что это возможно и внутри C # – см. Комментарии на связанной странице).

Обновление : есть также обновленная версия для подключения Direct3D 9, 10 и 11, все еще использующая EasyHook и SharpDX вместо SlimDX

Я знаю, что этот вопрос старый, но это должно работать для любой программы, использующей DirectX9. Вы создаете свой собственный экземпляр в основном, а затем получаете указатель на VTable, а затем просто подключаете его. Вам понадобятся объездные пути 3.X кстати:

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

И тогда ваша функция:

 HRESULT WINAPI D3D9Hook::newEndScene(LPDIRECT3DDEVICE9 pDevice) { //Do your stuff here //Call the original (if you want) return EndScene(pDevice); } 
Interesting Posts

Получить HTML внутри iframe с помощью jQuery

Создайте переменную в файле .CSS для использования в этом файле .CSS

Доступ к заголовкам ответов HTTP в WebView?

Отслеживать массовые кампании электронной почты

C # HttpWebRequest типа «application / x-www-form-urlencoded» – как отправить символ «&» в теле контента?

Странное поведение командной строки Windows

Как добавить приложение для не-программных файлов в диалоговое окно OpenWith?

Ошибка шрифта Helvetica Neue – помеченные символы в Google Chrome для Mac

Не удается загрузить после изменения размера жесткого диска VHD в VirtualBox

Java: доступ к частному конструктору с параметрами типа

Службы Google Play устарели. Требуется 11011000, но найдено 10289574

Функция clearRect не очищает полотно

Как поместить данные, содержащие двойные кавычки в строковой переменной?

Как создать учетную запись пользователя для базовой проверки подлинности?

Смыкая свободную функцию

Давайте будем гением компьютера.