我有一个代理dxgi.dll,并且试图绕过原始dxgi.dll中的Present函数,以便在屏幕上呈现内容。 .dll已成功加载,并放置了弯路。但是,一旦我的新Present被调用,绕道就会使程序崩溃。 请记住,.dll和程序是64位的。
下图显示了在修改之前该函数在内存中的外观(开始突出显示):
好的,所以我才知道除非我有10个声誉,否则不允许直接在此处发布图像,因此请使用此链接(代替DOT):
https://imgur DOT com / a / Jf53dYc
我不确定它到底在哪里崩溃,我相信程序会继续运行一会儿,但是它在绕行Present调用后肯定会在中间/很快崩溃,我知道这是因为我可以将指向SwapChain参数的指针写入崩溃之前从“Present”改道内部获取一个文件。
我使用IDA找到了原始的Present函数地址。您可以在imgur画廊中的图片上看到IDA所说的功能。
我一直在查看内存,并试图找出问题所在,当我使用Cheat引擎跟踪跳转时,它们会指向正确的位置,但是绕道而行会使程序崩溃。被覆盖的操作码似乎也已被正确替换。
我试图在我的Present函数上更改调用约定和返回类型,我在dxgi挂钩指南中读到返回类型是HRESULT,我试图对此进行更改无济于事。至于调用约定,我已经尝试了WINAPI。
我还仔细研究了堆栈或寄存器是否因函数绕行而损坏。但是我对汇编不是很好,我不能肯定是否是这种情况。
我有一个名为Core的类来处理钩子(Hook),这是头文件,具有一些相关的定义:
#pragma once
#include <iostream>
#include <Windows.h>
#include <intrin.h>
#include <dxgi.h>
#include <fstream>
// Seems my C++ doesn't have QWORD predefined, defining it myself
typedef unsigned __int64 QWORD;
// Definition of the structure of the DXGI present function
typedef __int64 (__fastcall* PresentFunction)(IDXGISwapChain *pSwapChain, UINT SyncInterval, UINT Flags);
class Core
{
private:
QWORD originalDllBaseAddress;
QWORD originalPresentFunctionOffset;
public:
void Init();
bool Hook(PresentFunction originalFunction, void* newFunction, int bytes);
~Core();
};
初始化通过获取相关地址来启动该过程:
void Core::Init()
{
originalDllBaseAddress = (QWORD)GetModuleHandleA("dxgi_.dll");
originalPresentFunctionOffset = 0x5070;
originalPresentFunction = (PresentFunction)(originalDllBaseAddress + (QWORD)originalPresentFunctionOffset);
Hook(originalPresentFunction, FixAndReturn, 14);
}
Hook试图在目标地址中跳转,我坚信问题就在这里,(注释现在改变了我的主意,它可能与汇编,寄存器或堆栈有关),更具体地说是originalFunction:
bool Core::Hook(PresentFunction originalFunction, void* newFunction, int length)
{
DWORD oldProtection;
VirtualProtect(originalFunction, length, PAGE_EXECUTE_READWRITE, &oldProtection);
memset(originalFunction, 0x90, length);
// Bytes are flipped (because of endianness), could alternatively use _byteswap_uint64()
*(QWORD*)originalFunction = 0x0000000025FF;
// The kind of jump I'm doing here seems to only use 6 bytes,
// and then grabs the subsequent memory address,
// I'm not quite sure if I'm doing this right
*(QWORD*)((QWORD)originalFunction + 6) = (QWORD)newFunction;
DWORD temp;
VirtualProtect(originalFunction, length, oldProtection, &temp);
originalPresentFunction = (PresentFunction)((QWORD)originalFunction + length);
presentAddr = (QWORD)Present;
jmpBackAddr = (QWORD)originalPresentFunction;
return true;
}
在将字节写入内存时,我已经尝试了很多方法,但是都没有解决我的问题。
函数结尾处对“originalPresentFunction”的分配是绕行路线将尝试跳回的地址。
这是位于Core.cpp中的绕行功能的定义:
__int64 __fastcall Present(IDXGISwapChain *pSwapChain, UINT SyncInterval, UINT Flags)
{
//The program crashes with and without these file writes.
std::ofstream file;
file.open("HELLO FROM PRESENT.txt");
file << pSwapChain;
file.close();
return originalPresentFunction(pSwapChain, SyncInterval, Flags);
}
该函数在调用时会导致崩溃。如您所见,我在此处将pSwapChain参数写入文件。我这样做是为了测试是否从原始函数传递了参数。写入成功,文件的内容看起来像一个有效的指针。因此,崩溃发生在此写入之后。 FixAndReturn()是一个汇编函数。includelib legacy_stdio_definitions.lib
.data
extern presentAddr : qword
extern jmpBackAddr : qword
; This performs instructions originally performed by dxgi.dll in the
; memory that we've replaced, and then returns
.code
FixAndReturn PROC
call [presentAddr]
mov [rsp+10h],rbx
mov [rsp+20h],rsi
push rbp
push rdi
push r14
jmp qword ptr [jmpBackAddr]
FixAndReturn ENDP
end
如果需要更多代码,我已将整个代码上传到Github:
https://github.com/techiew/KenshiDXHook
最佳答案
已经有一段时间了,我一直在忙于其他事情,但是现在我使绕道功能成功了。
在查看了网络上的资源并做了很多思考之后。答案很简单。在我的 FixAndReturn 汇编代码中,我要做的就是将,jmp 应用于绕行功能,不需要调用。 调用可能会不必要地更改我们不想做的事情,并且绕行函数在参数和其他方面与原始函数相同,因此它已经从与原始函数调用相同的位置读取了参数他们。这意味着 jmp 将可以很好地运行我们的绕行功能。组装时不需要额外的 push 或弹出即可使它起作用。
这是该过程的基本概述:
该函数调用使用的typedef与我们所钩住的原始函数相同。看起来像这样:
typedef HRESULT (__fastcall* PresentFunction)(IDXGISwapChain *pSwapChain, UINT SyncInterval, UINT Flags);
使用typedef返回函数的过程是这样的,使用原始参数值:
return ((PresentFunction)coreRef->newPresentReturn)(swapChain, syncInterval, flags);
基本上,这里发生的是指向我们绕行函数的第二个汇编代码 jmp 指令之后紧随其后的地址被返回并作为函数调用,因此我们要跳至绕行,跳回并执行原始代码。 (coreRef-> newPresentReturn包含 jmp 指令之后的地址)。
现在,我们遵循原始Present函数的调用约定,并且将传入的参数放在正确的位置,寄存器和堆栈以及任何不会以任何方式损坏的内容。
使用的资源:Guidedhacking.com - D3D11 barebones hook
完整代码在我的Github上:https://github.com/techiew/KenshiHook