то есть я внедрил длл в уже запущенную программу использующую Direct3D но поскольку создание интерфейса устройства происходит в начале подопытной программы... то мы не можем ставить хук на него потому как это произошло уже. вопрос вот в чём: можно ли получить указатель на IDirect3DDevice в уже запущенной программе?
А зачем тебе указатель на IDirect3DDevice? Достаточно перехватить его методы. И там уже делать все, что нужно. Тот же указатель можно получить сразу - он передается при вызове метода. Смотри сюда: http://www.wasm.ru/forum/viewtopic.php?id=10740
я просто не допонимаю как перехватить метод не зная указатель на интерфейс IDirect3DDevice. Игра к примеру уже запущена и в неё играют... функции Direct3DCreate9 и CreateDevice уже отработали, и тут встаёт вопрос как перехватить метод не зная указатель на интерфейс IDirect3DDevice. Надо ведь от чего то отталкиваться... объясните
Холод Интерфейс это vtbl. Когда ты получаешь указатель на него, то это указатель на vtbl, то есть таблицу методов этого интерфейса. Всё что тебе надо это изменить атрибут памяти vtbl (VirtualProtect) на write и поменять адреса в vtbl, на адреса своих функций, и все вызовы теперь будут перенаправляться тебе. З.Ы Да первый указатель в vtbl, это указатель this кома, то бишь его данные.
а оригинальную vtbl искать в памяти чтоли надо, создав клон интерфейса и сравнивая их. или что? мне бы пример какой или что-то похожее на пример... буду признателен за помощ
вкратце.... - вот запущенная игра, ребёнок играет 3 часа в неё. - по нажатии на горячую клавишу происходит внедрение длл в запущенную игру(это сделано). - теперь надо получить контекст запущенной игры(это надо сделать). собственно если запускать игру с лоадера проблем нет, просто перехватываются функции создания контекста и дальше по плану...
Холод vtbl искать не надо, получаешь интерфейс IDirect3DDevice, и патчишь его vtbl. vtbl всегда одна, так как это код. Только данные у всех разные. Патчишь vtbl, и перехват будет у всех экземпляров интерфейса данного процесса.
Холод vtbl это таблица адресов на методы. Меняешь эти адреса на адреса своих функций. А vtbl получаешь через указатель на интерфейс. Этот указатель и есть указатель на vtbl. Я этим делом занимался когда писал редиректор с джойстика на клаву и мышь, типо когда в игре нету джойстика, а нужно.
Вот меня интересует момнтент "...получаешь интерфейс IDirect3DDevice..." как его получать? В DLL делаю так: Код (Text): var direct3d_DEVICE: IDIRECT3DDEVICE9; D3D := Direct3DCreate9(D3D_SDK_VERSION); D3D.QueryInterface(IID_DIRECT3DDEVICE9, direct3d_DEVICE) direct3d_DEVICE - не возвращается... тоесть вы хотите сказать, что нужно создавать direct3d_DEVICE вручную незапраштвая его? делаю так(код внедряемой DLL в запущенное тестовое приложение. l_D3DPresentParameters у DLL и тестового приложения одинаковые): Код (Text): library game; uses SysUtils, Classes, Windows, Direct3D9, D3DX9, advApiHook; var D3DObj: IDirect3D9; direct3d_DEVICE: IDirect3DDevice9; l_D3DPresentParameters: TD3DPresentParameters; g_Font: ID3DXFont; var EndScene9Next: function(self: pointer): HResult stdcall = nil; function GetInterfaceMethod(const intf; methodIndex: DWORD): POINTER; begin RESULT := POINTER(POINTER(DWORD(POINTER(intf)^) + methodIndex * 4)^); end; function EndScene9Callback(self: pointer): HResult; stdcall; var TextRect: TRect; begin TextRect := RECT(0, 0, 100, 100); g_Font.DrawTextA(nil, PChar('test... ok installation...'), -1, @TextRect, DT_LEFT or DT_NOCLIP, D3DCOLOR_RGBA($FF, $FF, $FF, $FF)); Result := EndScene9Next(self); end; begin D3DObj := Direct3DCreate9(D3D_SDK_VERSION); FillChar(l_D3DPresentParameters, SizeOf(l_D3DPresentParameters), 0); l_D3DPresentParameters.Windowed := true; l_D3DPresentParameters.PresentationInterval := D3DPRESENT_INTERVAL_IMMEDIATE; l_D3DPresentParameters.MultiSampleType := D3DMULTISAMPLE_NONE; l_D3DPresentParameters.EnableAutoDepthStencil := true; l_D3DPresentParameters.BackBufferCount := 1; l_D3DPresentParameters.AutoDepthStencilFormat := D3DFMT_D16; l_D3DPresentParameters.SwapEffect := D3DSWAPEFFECT_DISCARD; l_D3DPresentParameters.Flags := D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; l_D3DPresentParameters.BackBufferWidth := 800; l_D3DPresentParameters.BackBufferHeight := 600; l_D3DPresentParameters.BackBufferFormat := D3DFMT_UNKNOWN; D3DObj.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GetForegroundWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, @l_D3DPresentParameters, direct3d_DEVICE); if direct3d_DEVICE <> nil then SetWindowText(getforegroundwindow, 'ok') else SetWindowText(getforegroundwindow, 'off'); D3DXCreateFont(direct3d_DEVICE, 30, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH or FF_DONTCARE, PChar('Lucida console'), g_Font); HookCode(GetInterfaceMethod(direct3d_DEVICE, 42), @EndScene9Callback, @EndScene9Next); end. результат нулевой... что посоветуете? P.S. Уважаемый Booster был бы рад увидеть ваш код редиректора, в виде выложенного архива.
Холод Понял в чём трабла. Я конечно делал перехват в самом начале, хукая Direct3DCreate9 и его метод CreateDevice. И уже когда программа их вызывала, хукал другие их методы. Скорее всего нету в нём этого интерфейса. А метод Direct3DCreate9.CreateDevice это фабрика интерфейса. Тут можно посоветовать всё же делать перехват в самом начале, например с помощью инфектора. Или попробовать получить ещё одно устройство, и патчить его методы. Методы ведь одни и теже для всех интерфейсов (vtbl всегда одна), а значит патчинг распространяется на все интерфейсы. Но не знаю, никогда не создавал несколько устройств в одном приложении.
кстати, хотелось бы узнать ответ на вопрос тот же самый fraps в состоянии впечатывать свои циферки в D3D приложение, даже если будет запущен после запуска приложения...
anticyclope По идее проблемы быть не должно. Вызываешь Direct3DCreate9.CreateDevice, получаешь интерфейс. И патчишь его. При вызове метода, первый параметр будет this того объекта для которого это вызывалось. Вообщем как со всеми другими комами. Единственно я не пробовал дважды вызывать CreateDevice в одном приложении, и незнаю можно ли дважды получить этот интерфейс. Раз fraps это умеет, значит возможно.
Кажется нашел, но не до конца понял http://forum.gamedeception.net/archive/index.php/t-10421.html upd: понял и реализовал. работает, будучи внедренным после создания D3D-устройства.