吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 16222|回复: 18
收起左侧

[其他转载] 【HOOK显卡厂商驱动】传说中的驱动显卡透视

[复制链接]
CS1516 发表于 2015-8-9 14:56

解:http://www.52pojie.cn/thread-397948-1-1.html

IDA,">本文要点:
介绍一种从显卡驱动入手的构造D3DHook的方法,DX9,DX9EX,DX10,DX11均试用,无需重启进程,注入即可使用。

以DX9为例。

前置知识:
1. API Hook的基础知识
2. DX绘图知识
3. 关于DX Hook 有很多种方法,传统的方法请自行查找资料。
4. Windows Display Driver 的基础知识

首先Vender驱动导出了一个叫做OpenAdapter的函数。
原型代码:
typedef HRESULT APIENTRY _OpenAdapter(D3DDDIARG_OPENADAPTER

*pAdapterData);
通过观察这个函数的参数可以发现这两个结构体
代码:
typedef struct _D3DDDIARG_OPENADAPTER{    HANDLE                         hAdapter;           // in/out:  Runtime handle/out: Driver handle    UINT                           Interface;          // in:  Interface version    UINT                           Version;            // in:  Runtime version    CONST D3DDDI_ADAPTERCALLBACKS* pAdapterCallbacks;  // in:  Pointer to runtime callbacks    D3DDDI_ADAPTERFUNCS*           pAdapterFuncs;      // out: Driver function table    UINT                           DriverVersion;      // out: D3D UMD interface version the                                                       //      driver was compiled with. Use                                                       //      D3D_UMD_INTERFACE_VERSION.} D3DDDIARG_OPENADAPTER;typedef struct _D3DDDI_ADAPTERFUNCS{    PFND3DDDI_GETCAPS                       pfnGetCaps;    PFND3DDDI_CREATEDEVICE                  pfnCreateDevice;    PFND3DDDI_CLOSEADAPTER                  pfnCloseAdapter;} D3DDDI_ADAPTERFUNCS;

HookOpenAdapter代码
代码:
BOOL DetourOpenAdapter(){OpenAdapter = (_OpenAdapter *)GetProcAddress(GetModuleHandleA("nvd3dum.dll"), "OpenAdapter");if (OpenAdapter == NULL){OpenAdapter = (_OpenAdapter *)GetProcAddress(GetModuleHandleA("aticfx32.dll"), "OpenAdapter");}if (OpenAdapter){DetourRestoreAfterWith();DetourTransactionBegin();DetourUpdateThread(GetCurrentThread());DetourAttach((void **)&OpenAdapter, WarpOpenAdapter);DetourTransactionCommit();}return OpenAdapter != NULL;}

通过Hook OpenAdapter 可以得到pfnCreateDevice;
代码如下
代码:
HRESULT APIENTRY WarpOpenAdapter(D3DDDIARG_OPENADAPTER *pAdapterData){    HRESULT ret = OpenAdapter(pAdapterData);    if (ret == S_OK && pAdapterData->pAdapterFuncs->pfnCreateDevice)    {        DdiCreateDevice = pAdapterData->pAdapterFuncs->pfnCreateDevice;        pAdapterData->pAdapterFuncs->pfnCreateDevice = WarpDdiCreateDevice;    }    return ret;}

pfnCreateDevice是Vender驱动上报给runtime的createDevice API.当APP调用CreateDevice最后会到厂商驱动的pfnCreateDevice; 替换厂商驱动上报给runtime的pfnCreateDevice函数指针,就可以实现Hook pfnCreateDevice。这样下次APP调用CreateDevice就会先进入我们的WarpDdiCreateDevice;
代码如下
代码:
HRESULT APIENTRY WarpDdiCreateDevice(    HANDLE hAdapter,    D3DDDIARG_CREATEDEVICE *pDeviceData){    // DdiCreateDevice must not be NULL if this path hit    HRESULT ret = DdiCreateDevice(hAdapter, pDeviceData);    if (pDeviceData->pDeviceFuncs->pfnPresent && gDetourFuncTable.DdiPresent.isAttatched == FALSE)    {        DdiPresent = pDeviceData->pDeviceFuncs->pfnPresent;        ULONG_PTR realTramponLine = DetourDDiPresent();        gDetourFuncTable.DdiPresent.isAttatched = TRUE;        gDetourFuncTable.DdiPresent.preFuncPtr = DdiPresent;        gDetourFuncTable.DdiPresent.TrampoLinePtr = (PFND3DDDI_PRESENT)realTramponLine;        gDetourFuncTable.DdiPresent.warpFuncPtr = WarpDdiPresent;    }    if (pDeviceData->pDeviceFuncs->pfnPresent1 && gDetourFuncTable.DdiPresent1.isAttatched == FALSE)    {        DdiPresent1 = pDeviceData->pDeviceFuncs->pfnPresent1;        ULONG_PTR realTramponLine = DetourDDiPresent1();        gDetourFuncTable.DdiPresent1.isAttatched = TRUE;        gDetourFuncTable.DdiPresent1.preFuncPtr = DdiPresent1;        gDetourFuncTable.DdiPresent1.TrampoLinePtr = (PFND3DDDI_PRESENT1)realTramponLine;        gDetourFuncTable.DdiPresent1.warpFuncPtr = WarpDdiPresent1;    }    DdiLock = pDeviceData->pDeviceFuncs->pfnLock;    DdiCreateResource = pDeviceData->pDeviceFuncs->pfnCreateResource;    DdiCreateResource2 = pDeviceData->pDeviceFuncs->pfnCreateResource2;    DdiUnlock = pDeviceData->pDeviceFuncs->pfnUnlock;    DdiBlt = pDeviceData->pDeviceFuncs->pfnBlt;    return ret;}typedef struct _D3DDDIARG_CREATEDEVICE{    HANDLE                          hDevice;                // in:  Runtime handle/out: Driver handle    UINT                            Interface;              // in:  Interface version    UINT                            Version;                // in:  Runtime Version    CONST D3DDDI_DEVICECALLBACKS*   pCallbacks;             // in:  Pointer to runtime callbacks    VOID*                           pCommandBuffer;         // in:  Pointer to the first command buffer to use.    UINT                            CommandBufferSize;      // in:  Size of the first command buffer to use.    D3DDDI_ALLOCATIONLIST*          pAllocationList;        // out: Pointer to the first allocation list to use.    UINT                            AllocationListSize;     // in:  Size of the allocation list that will be available                                                            //      when the first command buffer is submitted.    D3DDDI_PATCHLOCATIONLIST*       pPatchLocationList;     // out: Pointer to the first patch location list to use.    UINT                            PatchLocationListSize;  // in:  Size of the patch location list that will be available                                                            //      when the first command buffer is submitted.    D3DDDI_DEVICEFUNCS*             pDeviceFuncs;           // out: Driver function table    D3DDDI_CREATEDEVICEFLAGS        Flags;                  // in:  Flags#if (D3D_UMD_INTERFACE_VERSION >= D3D_UMD_INTERFACE_VERSION_WIN7)    D3DGPU_VIRTUAL_ADDRESS          CommandBuffer;          // out: GPU Virtual address to the command buffer to use. _ADVSCH_#endif // D3D_UMD_INTERFACE_VERSION} D3DDDIARG_CREATEDEVICE;

观察参数D3DDDIARG_CREATEDEVICE *pDeviceData不难发现 pDeviceFuncs中有我们需要的一切绘图API,这里用到的函数如下:
代码:
PFND3DDDI_CREATEDEVICE DdiCreateDevice = NULL;PFND3DDDI_PRESENT DdiPresent = NULL;PFND3DDDI_PRESENT1 DdiPresent1= NULL;PFND3DDDI_LOCK DdiLock = NULL;PFND3DDDI_CREATERESOURCE DdiCreateResource = NULL;PFND3DDDI_CREATERESOURCE2 DdiCreateResource2 = NULL;PFND3DDDI_UNLOCK DdiUnlock = NULL;PFND3DDDI_BLT DdiBlt = NULL;

代码如下
代码:
HRESULT APIENTRY WarpDdiCreateDevice(    HANDLE hAdapter,    D3DDDIARG_CREATEDEVICE *pDeviceData){    // DdiCreateDevice must not be NULL if this path hit    HRESULT ret = DdiCreateDevice(hAdapter, pDeviceData);    if (pDeviceData->pDeviceFuncs->pfnPresent && gDetourFuncTable.DdiPresent.isAttatched == FALSE)    {        DdiPresent = pDeviceData->pDeviceFuncs->pfnPresent;        ULONG_PTR realTramponLine = DetourDDiPresent();        gDetourFuncTable.DdiPresent.isAttatched = TRUE;        gDetourFuncTable.DdiPresent.preFuncPtr = DdiPresent;        gDetourFuncTable.DdiPresent.TrampoLinePtr = (PFND3DDDI_PRESENT)realTramponLine;        gDetourFuncTable.DdiPresent.warpFuncPtr = WarpDdiPresent;    }    if (pDeviceData->pDeviceFuncs->pfnPresent1 && gDetourFuncTable.DdiPresent1.isAttatched == FALSE)    {        DdiPresent1 = pDeviceData->pDeviceFuncs->pfnPresent1;        ULONG_PTR realTramponLine = DetourDDiPresent1();        gDetourFuncTable.DdiPresent1.isAttatched = TRUE;        gDetourFuncTable.DdiPresent1.preFuncPtr = DdiPresent1;        gDetourFuncTable.DdiPresent1.TrampoLinePtr = (PFND3DDDI_PRESENT1)realTramponLine;        gDetourFuncTable.DdiPresent1.warpFuncPtr = WarpDdiPresent1;    }    DdiLock = pDeviceData->pDeviceFuncs->pfnLock;    DdiCreateResource = pDeviceData->pDeviceFuncs->pfnCreateResource;    DdiCreateResource2 = pDeviceData->pDeviceFuncs->pfnCreateResource2;    DdiUnlock = pDeviceData->pDeviceFuncs->pfnUnlock;    DdiBlt = pDeviceData->pDeviceFuncs->pfnBlt;    return ret;}

到这里我们已经顺利拿到厂商的pfnPresent函数了,是不是有点兴奋呢?因为我们要做的任何绘图工作需要在pfnPresent之前完成。这样present才会把我们画的东西拷贝到屏幕上。
或许你会有一个疑问,APP已经在运行了,不会再调用CreateDevice了,这样我们的Hook不就无效了吗?
答案是这样的,既然APP调用CreateDevice,那我们就自己调用。我们来构造这样一个CreateDevice的条件,创建出来的d3dDevice还能在后面用来作为我们绘图的设备(OnRenderFrame).
代码:
BOOL TryInitD3D(HWND hWnd){    D3DPRESENT_PARAMETERS d3dpp;    HRESULT hResult = D3DERR_INVALIDCALL;    ZeroMemory(&d3dpp, sizeof(d3dpp));    d3dpp.Windowed = TRUE;    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;    pd3dInternal = Direct3DCreate9(D3D_SDK_VERSION);    if (pd3dInternal != NULL)    {        hResult = pd3dInternal->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,            D3DCREATE_SOFTWARE_VERTEXPROCESSING,            &d3dpp, &pd3dDevInternal);    }    return hResult == S_OK && pd3dDevInternal != NULL && InitDx();}

拿到pfnPresent之后做inlineHook
代码:
ULONG_PTR DetourDDiPresent1(){    ULONG_PTR realTrampoLine = NULL;    DetourRestoreAfterWith();    DetourTransactionBegin();    DetourUpdateThread(GetCurrentThread());    if (DdiPresent1)    {        DetourAttachEx((void **)&DdiPresent1, WarpDdiPresent1, (PDETOUR_TRAMPOLINE *)&realTrampoLine, NULL, NULL);    }    DetourTransactionCommit();    return realTrampoLine;}

然后在pfnPrsent的代{过}{滤}理函数中做我们自己的绘图操作。里面涉及的函数下面会有解释
我实现了一个简单的pfnPresent1代{过}{滤}理函数,在里面调用真正的pfnPresent1之前做我们的绘图(我是的WIN 8.1,WDDM1.3 所以就对pfnPresent1动手了)
代{过}{滤}理函数如下
代码:
HRESULT APIENTRY WarpDdiPresent1(    HANDLE hDevice,    CONST D3DDDIARG_PRESENT1 *pPresent1){    static HANDLE wrapDevice = NULL;    static HANDLE hDestSurf = NULL;    static UINT cachedWidth = 0;    static UINT cachedHeight = 0;    RECT rc = { 0 };    RECT destRC = { 0 };    RECT srcRC = { 0 };    IDirect3DSurface9 * pSrcSurf = NULL;    HRESULT hRet = S_OK;        //如果是运行中的app画图,就进入下面的流程进行我们的画图        //反之是我们的画图操作,直接放过,避免重入    if (hDevice == wrapDevice || wrapDevice == NULL)    {        wrapDevice = hDevice;        if (S_OK == onRenderFrame(&pSrcSurf, &rc))        {            if (rc.right - rc.left != cachedWidth ||                rc.bottom - rc.top != cachedHeight)            {                cachedWidth = rc.right - rc.left;                cachedHeight = rc.bottom - rc.top;                //TODO: destroy hDestSurf                hDestSurf = CreateSurfaceforWDDM1_3(hDevice, cachedWidth, cachedHeight);            }            if (hDestSurf != NULL)            {                destRC = srcRC = rc;                hRet = SurfaceBltInternal(hDevice, hDestSurf, destRC, pSrcSurf, srcRC);            }            if (hRet == S_OK)            {                BltToRTWDDM1_3(hDevice, hDestSurf, pPresent1,rc);            }        }    }    hRet = gDetourFuncTable.DdiPresent1.TrampoLinePtr(hDevice, pPresent1);    return hRet;}

HRESULT APIENTRY onRenderFrame(__out IDirect3DSurface9 ** pOutSurf, RECT * pOutRC)是我们的绘图函数,在这里实现我们要的东西,画到RenderTarget上,然后输出RenderTarget和它的大小。

代码:
HRESULT APIENTRY onRenderFrame(__out IDirect3DSurface9 ** pOutSurf, RECT * pOutRC){    HRESULT hr;    RECT rc;    pd3dDev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 0), 1.0f, 0);    if (S_OK == pd3dDev->BeginScene())    {        hr = pd3dDev->SetRenderTarget(NULL, pRTSurf);        //在这里画你需要的任何东西,没错 就是这么任性。        pd3dDev->EndScene();    }    if (hr == S_OK)    {        *pOutSurf = pRTSurf;        *pOutRC = rc;    }    else    {        *pOutSurf = NULL;        pOutRC->top = 0;        pOutRC->left = 0;        pOutRC->bottom = 0;        pOutRC->right = 0;    }    return hr;}

当在WarpDdiPresent1得到我们的绘图结果(RenderTarget和大小)之后,我们就能把画好的结果拿出来,然后通过调用厂商提供的pfnBlt函数 贴到present的SrcSurf上。

//用上面拿到的pfnCreateResource2 创建一张surface 用来保存我们的绘图结果。
代码:
HANDLE CreateSurfaceforWDDM1_3(HANDLE hDevice, UINT width, UINT height){    D3DDDIARG_CREATERESOURCE2 createResourceData2;    D3DDDI_SURFACEINFO surfList[1];    memset(surfList, 0, sizeof(surfList));    memset(&createResourceData2, 0, sizeof(createResourceData2));    surfList[0].Height = width;    surfList[0].Width = height;    surfList[0].Depth = 1;    surfList[0].pSysMem = NULL;    surfList[0].SysMemPitch = 0;    surfList[0].SysMemSlicePitch = 0;    createResourceData2.Format = D3DDDIFMT_A8R8G8B8;    createResourceData2.Pool = D3DDDIPOOL_NONLOCALVIDMEM;    createResourceData2.MultisampleType = D3DDDIMULTISAMPLE_NONE;    createResourceData2.MultisampleQuality = 0;    createResourceData2.pSurfList = surfList;    createResourceData2.SurfCount = 1;    createResourceData2.MipLevels = 0;    createResourceData2.Fvf = 0;    createResourceData2.VidPnSourceId = 0;    createResourceData2.RefreshRate.Denominator = 0;    createResourceData2.RefreshRate.Numerator = 0;    // use a particular handle that runtime do not use    createResourceData2.hResource = (HANDLE)0xfff00000;    createResourceData2.Flags.Value = 0;    createResourceData2.Rotation = D3DDDI_ROTATION_IDENTITY;    DdiCreateResource2(hDevice, &createResourceData2);    return createResourceData2.hResource;}

//把OnRenderFrame输出的RenderTarget的内容拷贝到创建的Surface
代码:
HRESULT SurfaceBltInternal(HANDLE hDevice, HANDLE hDestSurf, RECT destSurfRC, IDirect3DSurface9 * pSrcSurf, RECT srcSurfRC){    D3DDDIARG_LOCK lockdata;    D3DDDIARG_UNLOCK unlockData;    D3DLOCKED_RECT lockedRC;    HRESULT hr;    if (destSurfRC.right - destSurfRC.left < srcSurfRC.right - srcSurfRC.left ||        destSurfRC.bottom - destSurfRC.top < srcSurfRC.bottom - srcSurfRC.top)    {        hr = S_FALSE;    }    else    {        memset(&lockdata, 0, sizeof(lockdata));        memset(&unlockData, 0, sizeof(unlockData));        lockdata.hResource = hDestSurf;        lockdata.SubResourceIndex = 0;        lockdata.Area.left = 0;        lockdata.Area.right = destSurfRC.right - destSurfRC.left;        lockdata.Area.top = 0;        lockdata.Area.bottom = destSurfRC.bottom - destSurfRC.top;        hr = DdiLock(hDevice, &lockdata);        if (hr == S_OK)        {            hr = pSrcSurf->LockRect(&lockedRC, &srcSurfRC, NULL);            if (S_OK == hr)            {                CHAR *pDest = (CHAR*)lockdata.pSurfData;                CHAR *pSrc = (CHAR*)lockedRC.pBits;                for (UINT i = 0; i < destSurfRC.bottom - destSurfRC.top; i++)                {                    CopyMemory(pDest, pSrc, lockedRC.Pitch < lockdata.Pitch ? lockedRC.Pitch : lockdata.Pitch);                    pDest += lockdata.Pitch;                    pSrc += lockedRC.Pitch;                }            }            pSrcSurf->UnlockRect();            memset(&unlockData, 0, sizeof(unlockData));            unlockData.hResource = hDestSurf;            unlockData.SubResourceIndex = 0;            DdiUnlock(hDevice, &unlockData);        }    }    return hr;}

//调用厂商提供的pfnBLT把surafce上保存的图画 搬到 present的SrcSurf中,这样 present的时候 我们画的东西就展现出来了。
代码:
HRESULT BltToRTWDDM1_1(HANDLE hDevice, HANDLE hRes, CONST D3DDDIARG_PRESENT *pPresent){    D3DDDIARG_BLT bltData;    RECT srcRC;    RECT destRC;    memset(&bltData, 0, sizeof(bltData));    memset(&srcRC, 0, sizeof(srcRC));    memset(&destRC, 0, sizeof(destRC));        srcRC.left = 0;    srcRC.top = 0;    srcRC.right = 200;    srcRC.bottom = 200;    destRC.left = 0;    destRC.top = 0;    destRC.right = 200;    destRC.bottom = 200;    bltData.hDstResource = pPresent->hSrcResource;    bltData.DstSubResourceIndex = pPresent->SrcSubResourceIndex;    bltData.hSrcResource = hRes;    bltData.SrcSubResourceIndex = 0;    bltData.SrcRect = srcRC;    bltData.DstRect = destRC;    return DdiBlt(hDevice, &bltData);}



显卡驱动透视.rar

255.15 KB, 下载次数: 1039, 下载积分: 吾爱币 -1 CB

免费评分

参与人数 3热心值 +3 收起 理由
daohang + 1 谢谢@Thanks!
csx102501 + 1 完全看不懂
980359697 + 1 虽然看不懂还是要谢谢。

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| CS1516 发表于 2015-8-9 14:59
转的乱成这样 我晕
爸爸我要吃狼 发表于 2015-8-9 15:06
故人旧事 发表于 2015-8-9 15:08
表示你应该编译好程序再说怎么用,我是小白只会玩不会编译什么的
Aa1101200 发表于 2015-8-9 15:09
这个成品吗?
一块两毛五 发表于 2015-8-9 15:44
听说这是转来的?
不装能死 发表于 2015-8-9 15:50
不是成品.有什么用
858973926 发表于 2015-8-9 20:59
不错。。。
858973926 发表于 2015-8-9 21:02
怎么用 ?
980359697 发表于 2015-8-9 21:08
楼主说实话我看不懂。我这人实在。这又是源代码嘛?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-27 03:47

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表