从注入的DLL挂钩DirectX EndScene [英] Hooking DirectX EndScene from an injected DLL

查看:1117
本文介绍了从注入的DLL挂钩DirectX EndScene的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想绕过 EndScene 从任意的DirectX 9应用程序创建一个小的覆盖。例如,您可以使用FRAPS的框架计数器重叠,这在游戏中显示。



我知道以下方法:


  1. 创建新的 d3d9.dll ,然后将其复制到游戏路径。因为首先搜索当前文件夹,在进入system32之前,我修改的DLL被加载,执行我的附加代码。



    下面


  2. 与第一种方法相同,但直接替换system32中的DLL。



    下限:您无法添加游戏专用代码。


  3. 使用IDA Pro 4.9免费版本的工具直接从DLL获取EndScene偏移。因为DLL被按原样加载,你可以只是添加这个偏移到DLL的起始地址,当它被映射到游戏,得到实际的偏移量,然后钩它。


    $ b $

    得到D3D9,然后挂上 D3D9-> CreateDevice 以获得设备指针,然后通过虚拟表挂上 Device-> EndScene



    下面:当进程已经运行时,无法注入DLL。您必须使用 CREATE_SUSPENDED 标志启动此流程,才能挂钩初始的 Direct3DCreate9


  4. 在注册DLL后立即在新窗口中创建新设备。然后,从此设备获取 EndScene 偏移量并挂钩,从而为游戏使用的设备创建一个挂钩。



    下面:从我读过的一些信息,创建第二个设备可能会干扰现有的设备,它可能会错误窗口化或全屏模式等。


  5. 与第三种方法相同。但是,您将执行模式扫描以获取 EndScene



    下层看起来不可靠。


如何从注入的DLL中挂起 EndScene ,这可以在游戏已经运行时加载,而无需处理不同的 d3d9.dll 在其他系统上,并使用可靠的方法? FRAPS如何执行它的DirectX钩子?
DLL不适用于所有游戏,只适用于通过 CreateRemoteThread 注入的特定进程。

解决方案

您安装了一个系统范围的钩子。 (SetWindowsHookEx)通过这样做,你将被加载到每个进程。



现在当钩子被调用时,你寻找一个加载的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 EndSceneFunc = pVtable + sizeof(void *)* EndSceneIndex;

EndSceneFunc现在包含一个指向函数本身的指针,现在我们可以修补所有调用点,或者我们可以修改函数本身。



注意这一切都取决于在Windows中实现COM接口的知识。但这适用于所有的Windows版本(32或64,而不是两个同时)。


I want to detour EndScene from an arbitrary DirectX 9 application to create a small overlay. As an example, you could take the frame counter overlay of FRAPS, which is shown in games when activated.

I know the following methods to do this:

  1. Creating a new d3d9.dll, which is then copied to the games path. Since the current folder is searched first, before going to system32 etc., my modified DLL gets loaded, executing my additional code.

    Downside: You have to put it there before you start the game.

  2. Same as the first method, but replacing the DLL in system32 directly.

    Downside: You cannot add game specific code. You cannot exclude applications where you don't want your DLL to be loaded.

  3. Getting the EndScene offset directly from the DLL using tools like IDA Pro 4.9 Free. Since the DLL gets loaded as is, you can just add this offset to the DLL starting address, when it is mapped to the game, to get the actual offset, and then hook it.

    Downside: The offset is not the same on every system.

  4. Hooking Direct3DCreate9 to get the D3D9, then hooking D3D9->CreateDevice to get the device pointer, and then hooking Device->EndScene through the virtual table.

    Downside: The DLL cannot be injected, when the process is already running. You have to start the process with the CREATE_SUSPENDED flag to hook the initial Direct3DCreate9.

  5. Creating a new Device in a new window, as soon as the DLL gets injected. Then, getting the EndScene offset from this device and hooking it, resulting in a hook for the device which is used by the game.

    Downside: as of some information I have read, creating a second device may interfere with the existing device, and it may bug with windowed vs. fullscreen mode etc.

  6. Same as the third method. However, you'll do a pattern scan to get EndScene.

    Downside: doesn't look that reliable.

How can I hook EndScene from an injected DLL, which may be loaded when the game is already running, without having to deal with different d3d9.dll's on other systems, and with a method which is reliable? How does FRAPS for example perform it's DirectX hooks? The DLL should not apply to all games, just to specific processes where I inject it via CreateRemoteThread.

解决方案

You install a system wide hook. (SetWindowsHookEx) With this done, you get to be loaded into every process.

Now when the hook is called, you look for a loaded d3d9.dll.

If one is loaded, you create a temporary D3D9 object, and walk the vtable to get the address of the EndScene method.

Then you can patch the EndScene call, with your own method. (Replace the first instruction in EndScene by a call to your method.

When you are done, you have to patch the call back, to call the original EndScene method. And then reinstall your patch.

This is the way FRAPS does it. (Link)


You can find a function address from the vtable of an interface.

So you can do the following (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 does now contain a pointer to the function itself. We can now either patch all call-sites or we can patch the function itself.

Beware that this all depends on the knowledge of the implementation of COM-Interfaces in Windows. But this works on all windows versions (either 32 or 64, not both at the same time).

这篇关于从注入的DLL挂钩DirectX EndScene的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆