繁体   English   中英

将 DX11 挂在游戏上

[英]Hook DX11 on a game

我发现这个例子可以挂钩 DirectX 11:

void MainThread( void* pHandle )
    {
        // Hook d3d
        if (HookD3D())
        {
            // END key to unload
            while (!GetAsyncKeyState( VK_END ));
        }
    
        CleanupD3D();
        WriteMem( ogPresent, ogBytes, PRESENT_STUB_SIZE );
        VirtualFree( (void*)ogPresentTramp, 0x1000, MEM_RELEASE );
        CreateThread( 0, 0, (LPTHREAD_START_ROUTINE)FreeLibrary, pHandle, 0, 0 );
    }
    
    BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved )
    {
        switch (fdwReason)
        {
            case DLL_PROCESS_ATTACH:
                DisableThreadLibraryCalls( hinstDLL );
                CreateThread( nullptr, 0, (LPTHREAD_START_ROUTINE)MainThread, hinstDLL, 0, nullptr );
                break;
            case DLL_PROCESS_DETACH:
    
                break;
        }
        return TRUE;
    }
    
    bool Hook( void* pSrc, void* pDst, size_t size )
    {
        DWORD dwOld;
        uintptr_t src = (uintptr_t)pSrc;
        uintptr_t dst = (uintptr_t)pDst;
    
        if (!VirtualProtect( pSrc, size, PAGE_EXECUTE_READWRITE, &dwOld ))
            return false;
    
        *(char*)src = (char)0xE9;
        *(int*)(src + 1) = (int)(dst - src - 5);
    
        VirtualProtect( pSrc, size, dwOld, &dwOld );
        return true;
    }
    
    bool WriteMem( void* pDst, char* pBytes, size_t size )
    {
        DWORD dwOld;
        if (!VirtualProtect( pDst, size, PAGE_EXECUTE_READWRITE, &dwOld ))
            return false;
    
        memcpy( pDst, pBytes, PRESENT_STUB_SIZE );
    
        VirtualProtect( pDst, size, dwOld, &dwOld );
        return true;
    }
    
    bool HookD3D()

        D3D_FEATURE_LEVEL featLevel;
        DXGI_SWAP_CHAIN_DESC sd{ 0 };
        sd.BufferCount = 1;
        sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
        sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
        sd.BufferDesc.Height = 800;
        sd.BufferDesc.Width = 600;
        sd.BufferDesc.RefreshRate = { 60, 1 };
        sd.OutputWindow = GetForegroundWindow();
        sd.Windowed = TRUE;
        sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
        sd.SampleDesc.Count = 1;
        sd.SampleDesc.Quality = 0;
        HRESULT hr = D3D11CreateDeviceAndSwapChain( nullptr, D3D_DRIVER_TYPE_REFERENCE, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, &sd, &pSwapchain, &pDevice, &featLevel, nullptr );
        if (FAILED( hr )) 
            return false;
    
        void** pVMT = *(void***)pSwapchain;
 
        ogPresent = (fnPresent)(pVMT[VMT_PRESENT]);
    

        safe_release( pSwapchain );
        safe_release( pDevice );
    
  jmp (important for x64)
        void* pLoc = (void*)((uintptr_t)ogPresent - 0x2000);
        void* pTrampLoc = nullptr;
        while (!pTrampLoc)
        {
            pTrampLoc = VirtualAlloc( pLoc, 1, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE );
            pLoc = (void*)((uintptr_t)pLoc + 0x200);
        }
        ogPresentTramp = (fnPresent)pTrampLoc;
    
        memcpy( ogBytes, ogPresent, PRESENT_STUB_SIZE );
        memcpy( pTrampLoc, ogBytes, PRESENT_STUB_SIZE );
        
        pTrampLoc = (void*)((uintptr_t)pTrampLoc + PRESENT_STUB_SIZE);
        
        *(char*)pTrampLoc = (char)0xE9;
        pTrampLoc = (void*)((uintptr_t)pTrampLoc + 1);
        uintptr_t ogPresRet = (uintptr_t)ogPresent + 5;
        *(int*)pTrampLoc = (int)(ogPresRet - (uintptr_t)pTrampLoc - 4);
        

        pTrampoline = pTrampLoc = (void*)((uintptr_t)pTrampLoc + 4);
    #ifdef _WIN64
        char pJmp[] = { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 };
        WriteMem( pTrampLoc, pJmp, ARRAYSIZE( pJmp ) );
        pTrampLoc = (void*)((uintptr_t)pTrampLoc + ARRAYSIZE( pJmp ));
        *(uintptr_t*)pTrampLoc = (uintptr_t)hkPresent;
    #else
        *(char*)pTrampLoc = (char)0xE9;
        pTrampLoc = (void*)((uintptr_t)pTrampLoc + 1);
        *(int*)pTrampLoc = (uintptr_t)hkPresent - (uintptr_t)pTrampLoc - 4;
    #endif
    
        return Hook(ogPresent, pTrampoline, PRESENT_STUB_SIZE);
    }
    

    bool InitD3DHook( IDXGISwapChain * pSwapchain )
    {
        HRESULT hr = pSwapchain->GetDevice( __uuidof(ID3D11Device), (void**)&pDevice );
        if (FAILED( hr ))
            return false;
    
        pDevice->GetImmediateContext( &pContext );
        pContext->OMGetRenderTargets( 1, &pRenderTargetView, nullptr );
    
        if (!pRenderTargetView)
        {
    
            ID3D11Texture2D* pBackbuffer = nullptr;
            hr = pSwapchain->GetBuffer( 0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&pBackbuffer) );
            if (FAILED( hr ))
                return false;
   
            hr = pDevice->CreateRenderTargetView( pBackbuffer, nullptr, &pRenderTargetView );
            pBackbuffer->Release();
            if (FAILED( hr ))
                return false;
    
            pContext->OMSetRenderTargets( 1, &pRenderTargetView, nullptr );
        }
        
        ID3D10Blob* pBlob = nullptr;
    
        if (!CompileShader( szShadez, "VS", "vs_5_0", &pBlob ))
            return false;
    
        hr = pDevice->CreateVertexShader( pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, &pVertexShader );
        if (FAILED( hr ))
            return false;
    
   
        D3D11_INPUT_ELEMENT_DESC layout[2] = {
        {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
        {"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0}
        };
        UINT numElements = ARRAYSIZE( layout );
    
        hr = pDevice->CreateInputLayout( layout, numElements, pBlob->GetBufferPointer(), pBlob->GetBufferSize(), &pVertexLayout );
        if (FAILED( hr ))
            return false;
    
        safe_release( pBlob );
    
        if (!CompileShader( szShadez, "PS", "ps_5_0", &pBlob ))
            return false;
    
        hr = pDevice->CreatePixelShader( pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, &pPixelShader );
        if (FAILED( hr ))
            return false;
    
        UINT numViewports = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
        float fWidth =  0;
        float fHeight = 0;
    

        pContext->RSGetViewports( &numViewports, pViewports );
        
    
        if (!numViewports || !pViewports[MAINVP].Width)
        {
        
            //HWND hWnd0 = FindWindowA( "W2ViewportClass", nullptr );
            HWND hWnd = FindMainWindow( GetCurrentProcessId() );
            RECT rc{ 0 };
            if (!GetClientRect( hWnd, &rc ))
                return false;
    
 
            fWidth = (float)rc.right;
            fHeight = (float)rc.bottom;
    
            pViewports[MAINVP].Width = (float)fWidth;
            pViewports[MAINVP].Height = (float)fHeight;
            pViewports[MAINVP].MinDepth = 0.0f;
            pViewports[MAINVP].MaxDepth = 1.0f;
    
            pContext->RSSetViewports( 1, pViewports );
        }
        else
        {
            fWidth = (float)pViewports[MAINVP].Width;
            fHeight = (float)pViewports[MAINVP].Height;
        }

        D3D11_BUFFER_DESC bd{ 0 };
        bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
        bd.ByteWidth = sizeof( ConstantBuffer );
        bd.Usage = D3D11_USAGE_DEFAULT;
        
        mOrtho = XMMatrixOrthographicLH( fWidth, fHeight, 0.0f, 1.0f );
        ConstantBuffer cb;
        cb.mProjection = mOrtho;
        
        D3D11_SUBRESOURCE_DATA sr{ 0 };
        sr.pSysMem = &cb;
        hr = pDevice->CreateBuffer( &bd, &sr, &pConstantBuffer );
        if (FAILED( hr ))
            return false;

        ZeroMemory( &bd, sizeof( bd ) );
        bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
        bd.Usage = D3D11_USAGE_DEFAULT;
        bd.ByteWidth = 3 * sizeof( Vertex );
        bd.StructureByteStride = sizeof( Vertex );
    
        float left = fWidth / -2;
        float top = fHeight / 2;
    
        float w = 50;
        float h = 50;

        float fPosX = -1 * left;
        float fPosY = top;
    
        Vertex pVerts[3] = {
            { XMFLOAT3( left + fPosX,           top - fPosY + h / 2,    1.0f ), XMFLOAT4( 1.0f, 0.0f, 0.0f, 1.0f ) },
            { XMFLOAT3( left + fPosX + w / 2,   top - fPosY - h / 2,    1.0f ), XMFLOAT4( 0.0f, 0.0f, 1.0f, 1.0f ) },
            { XMFLOAT3( left + fPosX - w / 2,   top - fPosY - h / 2,    1.0f ), XMFLOAT4( 0.0f, 1.0f, 0.0f, 1.0f ) },
        };    
    
        ZeroMemory( &sr, sizeof( sr ) );
        sr.pSysMem = &pVerts;
        hr = pDevice->CreateBuffer( &bd, &sr, &pVertexBuffer );
        if (FAILED( hr ))
            return false;
    
        ZeroMemory( &bd, sizeof( bd ) );
        ZeroMemory( &sr, sizeof( sr ) );
    
        UINT pIndices[3] = { 0, 1, 2 };
        bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
        bd.Usage = D3D11_USAGE_DEFAULT;
        bd.ByteWidth = sizeof( UINT ) * 3;
        bd.StructureByteStride = sizeof( UINT );
    
        sr.pSysMem = &pIndices;
        hr = pDevice->CreateBuffer( &bd, &sr, &pIndexBuffer );
        if (FAILED( hr ))
            return false;
    
        return true;
    }
    
    
    void Render()
    {   
        pContext->OMSetRenderTargets( 1, &pRenderTargetView, nullptr );
    
        ConstantBuffer cb;
        cb.mProjection = XMMatrixTranspose( mOrtho );
        pContext->UpdateSubresource( pConstantBuffer, 0, nullptr, &cb, 0, 0 );
        pContext->VSSetConstantBuffers( 0, 1, &pConstantBuffer );
    
        UINT stride = sizeof( Vertex );
        UINT offset = 0;
        pContext->IASetVertexBuffers( 0, 1, &pVertexBuffer, &stride, &offset );
        pContext->IASetInputLayout( pVertexLayout );
        pContext->IASetIndexBuffer( pIndexBuffer, DXGI_FORMAT_R32_UINT, 0 );
        pContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
        
        pContext->VSSetShader( pVertexShader, nullptr, 0 );
        pContext->PSSetShader( pPixelShader, nullptr, 0 );
    
        pContext->RSSetViewports( 1, pViewports );

        pContext->DrawIndexed( 3, 0, 0 );
    }
    
    HRESULT __stdcall hkPresent( IDXGISwapChain * pThis, UINT SyncInterval, UINT Flags )
    {
        pSwapchain = pThis;
    
        if (!pDevice)
        {
            if (!InitD3DHook( pThis ))
                return false;
        }
    
        Render();
        return ogPresentTramp( pThis, SyncInterval, Flags );
    }

代码正确显示了中心的三角形,但暂停游戏,直到我按下“结束”键。

简而言之,游戏开始通常会显示一个演示文稿,几秒钟后它应该显示另一个演示文稿,但不要什么都不做。

如果我按“结束”跳过所有 go 直接进入游戏菜单。

// Hook
if (HookD3D())
{
   // END key to unload
   while (!GetAsyncKeyState( VK_END ));
}


CleanupD3D();
WriteMem( ogPresent, ogBytes, PRESENT_STUB_SIZE );
VirtualFree( (void*)ogPresentTramp, 0x1000, MEM_RELEASE );
CreateThread( 0, 0, (LPTHREAD_START_ROUTINE)FreeLibrary, pHandle, 0, 0 );

调用“HookD3D”后游戏停止运行,只有当用户按下“结束”并调用“CleanupD3D()”时,游戏才能继续正常运行。

我的印象是这段代码是依赖于上下文的,如果它改变它就不再起作用了。

我问是否有办法在不停止游戏的情况下显示三角形。

谢谢 !

// Hook
if (HookD3D())
{
   // END key to unload
   while (!GetAsyncKeyState( VK_END ));
}

这是一个死锁循环。 它只会在当前线程中旋转,直到您按 END ,这正是您所描述的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM