首页
社区
课程
招聘
[原创]简单讲解UE5游戏Dx12 虚表Hook的方法并实战演示
发表于: 2小时前 80

[原创]简单讲解UE5游戏Dx12 虚表Hook的方法并实战演示

2小时前
80

通过验证游戏是否加载了D3D12Core.dll来判断其是否使用Dx12,只有Release模式下生成这个dll,如果是debug模式生成的dll为:d3d12SDKLayers.dll。毕竟你玩的游戏确实有可能是debug模式下编译的。因为UE5都是单独编译D3D12Core.dll的,并没有使用系统目录下的dll,所以我们同样使用开源的UE5源码编译一个游戏后,在游戏目录下将D3D12Core.dll拖入IDA中分析,需要分析这个dll的主要原因是Dx12绘制流程中最重要的一步就是使用CommandQueue对象下的虚函数ExecuteCommandLists来提交所有需要绘制的内容,我们需要获取到CommandQueue对象,Hook这个对象实时调用的任意一个虚函数取rcx都可以达到目的。开源代码中基本都是Hook ExecuteCommandLists,那么我们只需要定位函数并获取到他的Index即可。
UE引擎下的 ExecuteCommandLists 特征码:

ExecuteCommandLists 在CommandQueue中的index=10。
你如果使用系统目录下的dll定位特征的话在游戏中可能是搜索不到的。
Dxgi.dll使用系统目录下的,拖入IDA中后,查找:

将其偏移记录,方便等等定位。
和Dx11一样,Hook代码基本就抄ImGui的源码即可,不需要什么技术含量。

接下来我们打开游戏,进行简单演示。我们定位到present函数,在头部下断。断下后查看堆栈返回。

这种堆栈是很常见的开启了GPU加速以及超分辨率模式,我们就不能像以前一样直接看上一层的代码了,我们需要直接定位到他返回到主模块的地址。你更换不同的超分辨模式这里加载的dll就是其他名称了,思路都是一样的直接找到主模块下的返回地址。漫xx雄与界xx潮都是一样的处理方式。

在mov rax, [rcx],调用时获取到rcx的值,替换成我们的虚表,即可完成对CDXGISwapChain对象的虚表的替换。那我们定位这里的特征码:

接下来在CE中搜索ExecuteCommandLists函数的特征码,定位到这个函数的头部下断,查看堆栈返回。

此时可以注意到函数的头部不是正常的头部,被经典5字节Hook了,我们进入这个函数查看:

这种情况其实对于这个游戏而言其实在多处使用到,比如FName::ToString、StaticFindObject等等很多函数都用到了。他就是简单看看是不是游戏自身调用的函数,如果是被Hook调用或者说是堆栈返回有异常的让你调用无效。他的内部肯定是要还原头部5字节的:

我们在堆栈中找到调用的返回处,往上滑:

我们定位到mov r9, [r12]的位置,调用时获取r12的值,替换CommandQueue对象的虚表。
获取到特征码:

基础数据我们获取完了,接下来我们使用硬件断点进行Hook就行。


Hook函数

48 89 ?? ?? ?? 48 89 ?? ?? ?? 48 89 ?? ?? ?? 57 48 ?? ?? ?? 48 8B ?? ?? ?? ?? ?? 48 8B E9 49 8B F8 8B F2 48 8D ?? ?? ?? ?? ?? E8 ?? ?? ?? ?? 4C 8B C7 8B D6 48 8B CD E8 ?? ?? ?? ?? 48 8D ?? ?? ?? ?? ?? 48 8B ?? ?? ?? 48 8B ?? ?? ?? 48 8B ?? ?? ?? 48 ?? ?? ?? 5F E9
48 89 ?? ?? ?? 48 89 ?? ?? ?? 48 89 ?? ?? ?? 57 48 ?? ?? ?? 48 8B ?? ?? ?? ?? ?? 48 8B E9 49 8B F8 8B F2 48 8D ?? ?? ?? ?? ?? E8 ?? ?? ?? ?? 4C 8B C7 8B D6 48 8B CD E8 ?? ?? ?? ?? 48 8D ?? ?? ?? ?? ?? 48 8B ?? ?? ?? 48 8B ?? ?? ?? 48 8B ?? ?? ?? 48 ?? ?? ?? 5F E9
__int64 __fastcall CDXGISwapChain::Present(CDXGISwapChain *this, unsigned int a2, unsigned int a3);
__int64 __fastcall CDXGISwapChain::Present(CDXGISwapChain *this, unsigned int a2, unsigned int a3);
48 8B 01 FF 50 40 45 85 FF 4C 8B 7C 24
48 8B 01 FF 50 40 45 85 FF 4C 8B 7C 24
4D 8B 0C 24 49 8B CC 4C 8B 44 24 48 8B 94
4D 8B 0C 24 49 8B CC 4C 8B 44 24 48 8B 94
long __fastcall hookPresentD3D12(IDXGISwapChain3* pSwapChain, UINT SyncInterval, UINT Flags)
{
    if (!init)
    {
        if (SUCCEEDED(pSwapChain->GetDevice(__uuidof(ID3D12Device), (void**)&d3d12Device))) {
            ImGui::CreateContext();
            D3dpSwapChain = pSwapChain;
            unsigned char* pixels;
            int width, height;
            ImGuiIO& io = ImGui::GetIO(); (void)io;
                 
            ImGui::GetIO().WantCaptureMouse || ImGui::GetIO().WantTextInput || ImGui::GetIO().WantCaptureKeyboard;
            io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
            ImGui::StyleColorsDark();
            io.Fonts->AddFontDefault();
            io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
            io.IniFilename = NULL;
             
            DXGI_SWAP_CHAIN_DESC sdesc;
            pSwapChain->GetDesc(&sdesc);
            sdesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
            sdesc.OutputWindow = Engine::hWnd;
            sdesc.Windowed = ((GetWindowLongPtr(Engine::hWnd, GWL_STYLE) & WS_POPUP) != 0) ? false : true;
 
            buffersCounts = sdesc.BufferCount;
            frameContext = new FrameContext[buffersCounts];
            memset(frameContext, 0, buffersCounts * sizeof(FrameContext));
             
            D3D12_DESCRIPTOR_HEAP_DESC descriptorBackBuffers = {};
            descriptorBackBuffers.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
            descriptorBackBuffers.NumDescriptors = buffersCounts;
            descriptorBackBuffers.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
            descriptorBackBuffers.NodeMask = 1;
            if (d3d12Device->CreateDescriptorHeap(&descriptorBackBuffers, IID_PPV_ARGS(&d3d12DescriptorHeapBackBuffers)) != S_OK)
                return Spoofer(Dx12SwapChainHook.GetOriginal<decltype(&hookPresentD3D12)>((8)), pSwapChain, SyncInterval, Flags);
             
            const auto rtvDescriptorSize = d3d12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
            D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = d3d12DescriptorHeapBackBuffers->GetCPUDescriptorHandleForHeapStart();
            for (size_t i = 0; i < buffersCounts; i++) {
                ID3D12Resource* pBackBuffer = nullptr;
 
                frameContext[i].main_render_target_descriptor = rtvHandle;
                pSwapChain->GetBuffer((UINT)i, IID_PPV_ARGS(&pBackBuffer));
                d3d12Device->CreateRenderTargetView(pBackBuffer, nullptr, rtvHandle);
                frameContext[i].main_render_target_resource = pBackBuffer;
                rtvHandle.ptr += rtvDescriptorSize;
            }
 
            D3D12_DESCRIPTOR_HEAP_DESC descriptorImGuiRender = {};
            descriptorImGuiRender.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
            descriptorImGuiRender.NumDescriptors = buffersCounts;
            descriptorImGuiRender.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
            if (d3d12Device->CreateDescriptorHeap(&descriptorImGuiRender, IID_PPV_ARGS(&d3d12DescriptorHeapImGuiRender)) != S_OK)
                return Spoofer(Dx12SwapChainHook.GetOriginal<decltype(&hookPresentD3D12)>((8)), pSwapChain, SyncInterval, Flags);
            g_pd3dSrvDescHeapAlloc.Create(d3d12Device, d3d12DescriptorHeapImGuiRender);
 
            for (UINT i = 0; i < buffersCounts; i++)
                if (d3d12Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&frameContext[i].commandAllocator)) != S_OK)
                    return Spoofer(Dx12SwapChainHook.GetOriginal<decltype(&hookPresentD3D12)>((8)), pSwapChain, SyncInterval, Flags);
            if (d3d12Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, frameContext[0].commandAllocator, NULL, IID_PPV_ARGS(&d3d12CommandList)) != S_OK ||
                d3d12CommandList->Close() != S_OK)
                return Spoofer(Dx12SwapChainHook.GetOriginal<decltype(&hookPresentD3D12)>((8)), pSwapChain, SyncInterval, Flags);
 
            g_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
            if (g_fenceEvent == nullptr)
                return false;
 
            pSwapChain->SetMaximumFrameLatency(buffersCounts);
            g_hSwapChainWaitableObject = pSwapChain->GetFrameLatencyWaitableObject();
 
            ImGui_ImplWin32_Init(Engine::hWnd);
            Menu::loadTheme();
            g_pd3dSrvDescHeapAlloc.Alloc(&my_texture_srv_cpu_handle, &my_texture_srv_gpu_handle);
            bRetGetTexture = ImGui_LoadImage::LoadTextureFromMemory((UCHAR*)logo, sizeof(logo), d3d12Device, my_texture_srv_cpu_handle, &my_texture, &my_image_width, &my_image_height);
            ImGui_ImplDX12_Init(d3d12Device, buffersCounts,
                DXGI_FORMAT_R8G8B8A8_UNORM, d3d12DescriptorHeapImGuiRender,
                d3d12DescriptorHeapImGuiRender->GetCPUDescriptorHandleForHeapStart(),
                d3d12DescriptorHeapImGuiRender->GetGPUDescriptorHandleForHeapStart());
            ImGui_ImplDX12_CreateDeviceObjects();
        }
        init = true;
    }
 
    if (init)
    {
        if (d3d12CommandQueue == nullptr)
        {
            return Spoofer(Dx12SwapChainHook.GetOriginal<decltype(&hookPresentD3D12)>((8)), pSwapChain, SyncInterval, Flags);
        }
 
        if (swapchainInit)
        {
            HDHook.UnHook();
            swapchainInit = false;
            commandQueueInit = false;
        }
 
        ImGui_ImplDX12_NewFrame();
        ImGui_ImplWin32_NewFrame();
        ImGui::NewFrame();
 
                Menu::get().Render();
 
        ImGui::Render();
 
        FrameContext& currentFrameContext = frameContext[pSwapChain->GetCurrentBackBufferIndex()];
        currentFrameContext.commandAllocator->Reset();
         
        FrameContext* frameCtx = WaitForNextFrameResources(buffersCounts);
        frameCtx->commandAllocator->Reset();
     
        D3D12_RESOURCE_BARRIER barrier = {};
        barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
        barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
        barrier.Transition.pResource = currentFrameContext.main_render_target_resource;
        barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
        barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
        barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
        d3d12CommandList->Reset(frameCtx->commandAllocator, nullptr);
        d3d12CommandList->ResourceBarrier(1, &barrier);
 
        d3d12CommandList->OMSetRenderTargets(1, &currentFrameContext.main_render_target_descriptor, FALSE, nullptr);
        d3d12CommandList->SetDescriptorHeaps(1, &d3d12DescriptorHeapImGuiRender);
        ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), d3d12CommandList);
        barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
        barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
        d3d12CommandList->ResourceBarrier(1, &barrier);
        d3d12CommandList->Close();
 
        d3d12CommandQueue->ExecuteCommandLists(1, reinterpret_cast<ID3D12CommandList* const*>(&d3d12CommandList));
    }
 
    return Spoofer(Dx12SwapChainHook.GetOriginal<decltype(&hookPresentD3D12)>((8)), pSwapChain, SyncInterval, Flags);
}
long __fastcall hookPresentD3D12(IDXGISwapChain3* pSwapChain, UINT SyncInterval, UINT Flags)
{
    if (!init)
    {
        if (SUCCEEDED(pSwapChain->GetDevice(__uuidof(ID3D12Device), (void**)&d3d12Device))) {
            ImGui::CreateContext();
            D3dpSwapChain = pSwapChain;
            unsigned char* pixels;
            int width, height;
            ImGuiIO& io = ImGui::GetIO(); (void)io;
                 
            ImGui::GetIO().WantCaptureMouse || ImGui::GetIO().WantTextInput || ImGui::GetIO().WantCaptureKeyboard;
            io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
            ImGui::StyleColorsDark();
            io.Fonts->AddFontDefault();
            io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
            io.IniFilename = NULL;
             
            DXGI_SWAP_CHAIN_DESC sdesc;
            pSwapChain->GetDesc(&sdesc);
            sdesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
            sdesc.OutputWindow = Engine::hWnd;
            sdesc.Windowed = ((GetWindowLongPtr(Engine::hWnd, GWL_STYLE) & WS_POPUP) != 0) ? false : true;
 
            buffersCounts = sdesc.BufferCount;
            frameContext = new FrameContext[buffersCounts];
            memset(frameContext, 0, buffersCounts * sizeof(FrameContext));
             
            D3D12_DESCRIPTOR_HEAP_DESC descriptorBackBuffers = {};
            descriptorBackBuffers.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
            descriptorBackBuffers.NumDescriptors = buffersCounts;
            descriptorBackBuffers.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
            descriptorBackBuffers.NodeMask = 1;
            if (d3d12Device->CreateDescriptorHeap(&descriptorBackBuffers, IID_PPV_ARGS(&d3d12DescriptorHeapBackBuffers)) != S_OK)
                return Spoofer(Dx12SwapChainHook.GetOriginal<decltype(&hookPresentD3D12)>((8)), pSwapChain, SyncInterval, Flags);
             
            const auto rtvDescriptorSize = d3d12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
            D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = d3d12DescriptorHeapBackBuffers->GetCPUDescriptorHandleForHeapStart();
            for (size_t i = 0; i < buffersCounts; i++) {
                ID3D12Resource* pBackBuffer = nullptr;
 
                frameContext[i].main_render_target_descriptor = rtvHandle;
                pSwapChain->GetBuffer((UINT)i, IID_PPV_ARGS(&pBackBuffer));
                d3d12Device->CreateRenderTargetView(pBackBuffer, nullptr, rtvHandle);
                frameContext[i].main_render_target_resource = pBackBuffer;
                rtvHandle.ptr += rtvDescriptorSize;
            }
 
            D3D12_DESCRIPTOR_HEAP_DESC descriptorImGuiRender = {};
            descriptorImGuiRender.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
            descriptorImGuiRender.NumDescriptors = buffersCounts;
            descriptorImGuiRender.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
            if (d3d12Device->CreateDescriptorHeap(&descriptorImGuiRender, IID_PPV_ARGS(&d3d12DescriptorHeapImGuiRender)) != S_OK)
                return Spoofer(Dx12SwapChainHook.GetOriginal<decltype(&hookPresentD3D12)>((8)), pSwapChain, SyncInterval, Flags);
            g_pd3dSrvDescHeapAlloc.Create(d3d12Device, d3d12DescriptorHeapImGuiRender);
 
            for (UINT i = 0; i < buffersCounts; i++)
                if (d3d12Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&frameContext[i].commandAllocator)) != S_OK)
                    return Spoofer(Dx12SwapChainHook.GetOriginal<decltype(&hookPresentD3D12)>((8)), pSwapChain, SyncInterval, Flags);
            if (d3d12Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, frameContext[0].commandAllocator, NULL, IID_PPV_ARGS(&d3d12CommandList)) != S_OK ||
                d3d12CommandList->Close() != S_OK)
                return Spoofer(Dx12SwapChainHook.GetOriginal<decltype(&hookPresentD3D12)>((8)), pSwapChain, SyncInterval, Flags);

[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

收藏
免费 3
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回