首页
论坛
课程
招聘
Hook显卡厂商驱动(draw whatever you want)
2014-12-21 02:16 49409

Hook显卡厂商驱动(draw whatever you want)

2014-12-21 02:16
49409
作者:hhstudy
博客: http://hi.baidu.com/hhstudy
转载请在文章开头注明出处

本文要点:
介绍一种从显卡驱动入手的构造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);
}
如有错误之处,还请各位指正。欢迎各位大牛小牛牛牛拍砖了。

2021 KCTF 秋季赛 防守篇-征题倒计时(11月14日截止)!

收藏
点赞0
打赏
分享
最新回复 (44)
雪    币: 177
活跃值: 活跃值 (256)
能力值: (RANK:290 )
在线值:
发帖
回帖
粉丝
viphack 活跃值 4 2014-12-21 02:19
2
0
我是来学习的
雪    币: 376
活跃值: 活跃值 (51)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
蛋蛋好疼 活跃值 2014-12-21 07:28
3
0
楼主不错啊,都注释那么详细,好多人发都只是丢一段代码出来新手都看不懂
雪    币: 238
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
封心锁爱 活跃值 2014-12-21 09:11
4
0
学习下d3dhook
雪    币: 8670
活跃值: 活跃值 (777)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
cvcvxk 活跃值 10 2014-12-21 09:37
5
0
显卡种类太多了xxxx.dll!OpenAdapter的hook方法不好。比较科学的方式是读注册表读出DLL名称,然后走起~

DDIHook有个小问题就是有些东西跟操作系统版本太贴了~好处是没几个人关注这个hook点~

PS:
好文章顶了~
雪    币: 114
活跃值: 活跃值 (159)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
topofall 活跃值 2014-12-21 10:12
6
0
围观和学习的。。。。
雪    币: 153
活跃值: 活跃值 (252)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
人在塔在 活跃值 2014-12-21 12:46
7
0
mark谢谢分享
雪    币: 60
活跃值: 活跃值 (145)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
hhstudy 活跃值 1 2014-12-21 15:01
8
0
恩,感谢V大提醒。
DDIHook需要处理WDDM1.0-WDDM1.3 就能兼容目前所有的微软还支持的OS了。
等下一代Windows出来再处理WDDM2.0就好了。
雪    币: 78
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
一盏清茗 活跃值 2014-12-22 11:37
9
0
最好来个小应用实例。。比如透视这类的
雪    币: 276
活跃值: 活跃值 (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Kernal 活跃值 2014-12-22 12:29
10
0
好文章,支持一下!
雪    币: 69
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Maiunjour 活跃值 2014-12-22 16:30
11
0
看着很不错的呢!
雪    币: 1267
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
suiyu 活跃值 2014-12-22 16:48
12
0
额,支持学习,以前一直是通过找D3D的接口函数进行挂钩的
雪    币: 291
活跃值: 活跃值 (92)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cavan 活跃值 2014-12-24 22:36
13
0
mark
雪    币: 273
活跃值: 活跃值 (627)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
sxpp 活跃值 1 2014-12-25 01:30
14
0
mark
雪    币: 269
活跃值: 活跃值 (77)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
WinDos2K 活跃值 2014-12-25 01:49
15
0
可否把ATI驱动*.sys上载?
雪    币: 44
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
romero 活跃值 2014-12-25 03:35
16
0
great project!
雪    币: 111
活跃值: 活跃值 (15)
能力值: ( LV2,RANK:140 )
在线值:
发帖
回帖
粉丝
kingsdows 活跃值 3 2014-12-25 06:09
17
0
貌似需要nt6以上才能支持吧
雪    币: 6122
活跃值: 活跃值 (1336)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zhczf 活跃值 2014-12-25 15:32
18
0
楼主辛苦了,

虽然我看不懂,但总有人看得懂的
雪    币: 60
活跃值: 活跃值 (145)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
hhstudy 活跃值 1 2014-12-25 22:51
19
0
是的,XP上UMD Driver在 R0, 已经放弃, WDDM 1.0 以后才支持.
雪    币: 188
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
JackJoker 活跃值 2014-12-26 12:32
20
0
学习楼主大牛。
雪    币: 111
活跃值: 活跃值 (15)
能力值: ( LV2,RANK:140 )
在线值:
发帖
回帖
粉丝
kingsdows 活跃值 3 2014-12-27 03:04
21
0
我之前也听说过这个, 虽然nt6之后有了个这样的东西,但是既然在R3层,你可以改,游戏也可以查,只能说可以虐虐那些还没查的游戏。
雪    币: 272
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
AASSMM 活跃值 2014-12-27 05:26
22
0
即将加入TP猥琐检测豪华大餐
雪    币: 8670
活跃值: 活跃值 (777)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
cvcvxk 活跃值 10 2014-12-27 11:47
23
0
早检测了~只是权重比例小于D3D~呵呵~
雪    币: 60
活跃值: 活跃值 (145)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
hhstudy 活跃值 1 2014-12-28 10:58
24
0
更正一个错误
原帖贴的是BltToRTWDDM1_1 这个适合WIN7,大同小异。
HRESULT BltToRTWDDM1_3(HANDLE hDevice, HANDLE hRes, CONST D3DDDIARG_PRESENT1 *pPresent1, RECT rc)
{
        D3DDDIARG_BLT bltData;
        RECT srcRC;
        RECT destRC;
        HRESULT ret = S_OK;

        memset(&bltData, 0, sizeof(bltData));
        memset(&srcRC, 0, sizeof(srcRC));
        memset(&destRC, 0, sizeof(destRC));

        srcRC = destRC = rc;
        bltData.hDstResource = pPresent1->phSrcResources[0].hResource;
        bltData.DstSubResourceIndex = pPresent1->phSrcResources[0].SubResourceIndex;
        bltData.hSrcResource = hRes;
        bltData.SrcSubResourceIndex = 0;
        bltData.SrcRect = srcRC;
        bltData.DstRect = destRC;
        bltData.Flags.SrcColorKey = 1;
        bltData.ColorKey = 0;
        return DdiBlt(hDevice, &bltData);
}
雪    币: 201
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
善良屠夫 活跃值 2014-12-28 18:55
25
0
mark
游客
登录 | 注册 方可回帖
返回