• 用NVPerfHud4剖析Farcry的绘制过程








        NVPerfHud4是Nvidia推出的配合Geforce6系列显卡对DX9应用程序进行性能剖析的强大工具,通过它可以从宏观和微观两个角度剖析图形应用程序性能。宏观上可以看到整体绘制中CPU、GPU分别占用了多少时间,PS、VS分别占用了多少时间,CPU等待时间,GPU等待时间。微观上可以看到每一个DP调用的过程,显示每一个DP调用过程中PS、VS和光栅化分别占用了多少时间以及每个DP调用所使用的VS、PS代码,所用到的贴图和所有绘制状态。得到如此强大的功能对应用程序代码的修改却只需要一句,就是用下面的方式创建3D设备:
    g_pD3D->CreateDevice( g_pD3D->GetAdapterCount()-1, D3DDEVTYPE_REF, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice );
    其中最关键的参数是前两个,也就是说只要按照上面方法创建3D设备的应用程序都可以通过NVPerfHud进行剖析。要用NVPerfHud对Farcry进行剖析就是要在Farcry的二进制代码中找到CreateDevice()函数的调用位置,并将调用参数按要求修改。下面简单说说这个过程。

        用IDA打开Farcry的D3D9绘制模块XRenderD3D9.dll,在Strings窗口发现了我们感兴趣的字符串"Creating D3D device (Adapter format: %s, BackBuffer format: %s, Depth format: %s)",用右键菜单跳到引用这个字符串的地址发现如下代码:

    01 push    offset aCreatingD3dDev ; "Creating D3D device (Adapter format: %s"...
    02 .text:38054CF3                 push    ecx
    03 .text:38054CF4                 call    dword ptr [edi+8]
    04 .text:38054CF7                 mov     eax, dword_389E67D8
    05 .text:38054CFC                 add     esp, 14h
    06 .text:38054CFF                 test    eax, eax
    07 .text:38054D01                 jnz     short loc_38054D51
    08 .text:38054D03                 mov     al, [esi+1D650h]
    09 .text:38054D09                 test    al, al
    10 .text:38054D0B                 jz      short loc_38054D15
    11 .text:38054D0D                 mov     eax, [esi+1D65Ch]
    12 .text:38054D13                 jmp     short loc_38054D1B
    13 .text:38054D15
    14 .text:38054D15 loc_38054D15:                           ; CODE XREF: sub_38054B00+20Bj
    15 .text:38054D15                 mov     eax, [esi+1D694h]
    16 .text:38054D1B
    17 .text:38054D1B loc_38054D1B:                           ; CODE XREF: sub_38054B00+213j
    18 .text:38054D1B                 mov     ebp, [esp+21Ch+var_20C]
    19 .text:38054D1F                 mov     ecx, [eax]
    20 .text:38054D21                 mov     eax, [esi+1D620h]
    21 .text:38054D27                 mov     edx, [eax]
    22 .text:38054D29                 lea     edi, [esi+1E698h]
    23 .text:38054D2F                 push    edi
    24 .text:38054D30                 lea     ebx, [esi+1D6C0h]
    25 .text:38054D36                 push    ebx
    26 .text:38054D37                 push    ebp
    27 .text:38054D38                 mov     ebp, [esi+1F494h]
    28 .text:38054D3E                 mov     ebp, [ebp+0]
    29 .text:38054D41                 push    ebp
    30 .text:38054D42                 mov     ebp, [esp+22Ch+var_208]
    31 .text:38054D46                 mov     ebp, [ebp+4]
    32 .text:38054D49                 push    ebp
    33 .text:38054D4A                 push    ecx
    34 .text:38054D4B                 push    eax
    35 .text:38054D4C                 call    dword ptr [edx+40h]
    36 .text:38054D4F                 jmp     short loc_38054D8A
    37 .text:38054D51
    38 .text:38054D51 loc_38054D51:                           ; CODE XREF: sub_38054B00+201j
    39 .text:38054D51                 mov     ecx, [esp+21Ch+var_20C]
    40 .text:38054D55                 mov     edx, [esi+1F494h]
    41 .text:38054D5B                 mov     eax, [esi+1D620h]
    42 .text:38054D61                 mov     ebp, [eax]
    43 .text:38054D63                 lea     edi, [esi+1E698h]
    44 .text:38054D69                 push    edi
    45 .text:38054D6A                 lea     ebx, [esi+1D6C0h]
    46 .text:38054D70                 push    ebx
    47 .text:38054D71                 and     ecx, 0FFFFFFEFh
    48 .text:38054D74                 push    ecx
    49 .text:38054D75                 mov     ecx, [edx]
    50 .text:38054D77                 push    ecx
    51 .text:38054D78                 push    2
    52 .text:38054D7A                 push    eax
    53 .text:38054D7B                 call    dword ptr [ebp+10h]
    54 .text:38054D7E                 mov     edx, [esi+1D620h]
    55 .text:38054D84                 dec     eax
    56 .text:38054D85                 push    eax
    57 .text:38054D86                 push    edx
    58 .text:38054D87                 call    dword ptr [ebp+40h]

    第1行将我们感兴趣的字符串地址压入堆栈,第3行应该是输出日志之类的调用,下面应该离创建设备的调用(CreateDevice)不远了。再看看IDirect3D9接口的定义:

    DECLARE_INTERFACE_(IDirect3D9, IUnknown)
    {
        /*** IUnknown methods ***/
        STDMETHOD(QueryInterface)(THIS_ REFIID riid, void** ppvObj) PURE;
        STDMETHOD_(ULONG,AddRef)(THIS) PURE;
        STDMETHOD_(ULONG,Release)(THIS) PURE;

        /*** IDirect3D9 methods ***/
        STDMETHOD(RegisterSoftwareDevice)(THIS_ void* pInitializeFunction) PURE;
        STDMETHOD_(UINT, GetAdapterCount)(THIS) PURE;
        STDMETHOD(GetAdapterIdentifier)(THIS_ UINT Adapter,DWORD Flags,D3DADAPTER_IDENTIFIER9* pIdentifier) PURE;
        STDMETHOD_(UINT, GetAdapterModeCount)(THIS_ UINT Adapter,D3DFORMAT Format) PURE;
        STDMETHOD(EnumAdapterModes)(THIS_ UINT Adapter,D3DFORMAT Format,UINT Mode,D3DDISPLAYMODE* pMode) PURE;
        STDMETHOD(GetAdapterDisplayMode)(THIS_ UINT Adapter,D3DDISPLAYMODE* pMode) PURE;
        STDMETHOD(CheckDeviceType)(THIS_ UINT Adapter,D3DDEVTYPE DevType,D3DFORMAT AdapterFormat,D3DFORMAT BackBufferFormat,BOOL bWindowed) PURE;
        STDMETHOD(CheckDeviceFormat)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,DWORD Usage,D3DRESOURCETYPE RType,D3DFORMAT CheckFormat) PURE;
        STDMETHOD(CheckDeviceMultiSampleType)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SurfaceFormat,BOOL Windowed,D3DMULTISAMPLE_TYPE MultiSampleType,DWORD* pQualityLevels) PURE;
        STDMETHOD(CheckDepthStencilMatch)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,D3DFORMAT RenderTargetFormat,D3DFORMAT DepthStencilFormat) PURE;
        STDMETHOD(CheckDeviceFormatConversion)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SourceFormat,D3DFORMAT TargetFormat) PURE;
        STDMETHOD(GetDeviceCaps)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DCAPS9* pCaps) PURE;
        STDMETHOD_(HMONITOR, GetAdapterMonitor)(THIS_ UINT Adapter) PURE;
        STDMETHOD(CreateDevice)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,HWND hFocusWindow,DWORD BehaviorFlags,D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DDevice9** ppReturnedDeviceInterface) PURE;
       
        #ifdef D3D_DEBUG_INFO
        LPCWSTR Version;
        #endif
    };

        仔细数一数可以看到CreateDevice()是接口的第17个函数,也就是说它在虚函数表里的偏移量应该是0x40。再回头看上面的汇编代码,可以发现有两处"call    dword ptr [ebp+40h]"这样的函数调用,这应该就是对CreateDevice()函数的两次调用了。再看第53行还有这样一个调用"call    dword ptr [ebp+10h]",对照IDirect3D9接口定义我们知道这是GetAdapterCount()函数,第55行对函数GetAdapterCount()的返回值减一,这不正是我们需要的CreateDevice()函数的第一个参数吗,那再看看第二个参数是不是也是我们需要的D3DDEVTYPE_REF。第51行的指令"push    2"压入CreateDevice()函数的第二个参数,查找相关头文件我们发现D3DDEVTYPE_REF的值正好是2,这使我们相信第58行的CreateDevice()调用就是为NVPerfHud提供的,我们甚至都不需要修改调用参数,只需要把程序的执行路径引到这里就行了。

        将IDA的代码窗口切换到图形视图可以更容易地看到代码跳转路径。



        可以看到代码在最上面分为两叉,右边的绿色箭头指向我们需要的CreateDevice()调用,我们只需要把最上面那个框里的"jnz     short loc_38054D51"指令修改成"jz     short loc_38054D51",也就是取反条件判断,就能让代码走我们需要的执行路径。在十六进制编辑窗口找到相关代码,将75改为74(jnz改为jz),然后存盘就完成了对XRenderD3D9.dll的修改。

  • 相关阅读:
    abp架构中加载公共css样式表和公共js的文件目录位置
    angular中[hidden]="expression"注意事项
    angular中使用canvas画布做验证码
    AngularJs页面跳转
    Angular学习笔记【如何正确使用第三方组件】
    【JavaScript权威指南】——逻辑与(&&)
    angular学习笔记【ng2-charts】插件添加
    OpenLayers v4.2.0 -----地图延迟加载;
    Sharepoint 图片库字段名称(Title)和对应的内部名称(InternalName)
    Sharepoint JSCOM 列表操作
  • 原文地址:https://www.cnblogs.com/cproom/p/559287.html
Copyright © 2020-2023  润新知