我有一个代理dxgi.dll,并且我试图绕过原始dxgi.dll中的Present函数,以便在屏幕上呈现内容。 .dll已成功加载,并放置了弯路。但是,只要我的新Present被调用,绕道就会使程序崩溃。 请记住,.dll和程序是64位的。
下面是该功能在内存中的外观的图像修改之前(突出显示开始):
好的,所以我发现除非我有10个声誉,否则我不允许直接在此处发布图片,因此请使用此链接(代替DOT): https://imgur DOT com / a / Jf53dYc
我不确定它到底在哪里崩溃,我相信程序会继续运行一会儿,但是在绕行Present调用之后,它肯定会在中间/很快崩溃,我知道这是因为我可以将指针写到将SwapChain参数从“ Present”弯路内的文件崩溃之前清除。
我使用IDA找到了原始的Present函数地址。您可以在imgur画廊的图片上看到IDA所说的功能。
我一直在查看内存,并试图找出问题所在,当我使用作弊引擎跟踪跳转时,它们会指向正确的位置,但是绕道而行会使程序崩溃。被覆盖的操作码似乎也已被正确替换。
我试图在我的Present函数上更改调用约定和返回类型,我在dxgi挂钩指南中读到返回类型是HRESULT,我试图对此进行更改无济于事。至于调用约定,我已经尝试过WINAPI。
我还仔细研究了堆栈或寄存器是否因函数绕行而损坏。但是我对汇编不是很好,不能确定是否是这种情况。
我有一个名为Core的类来处理钩子,这是头文件,其中包含一些相关的定义:
#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();
};
Init通过获取相关地址开始该过程:
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
答案 0 :(得分:0)
已经有一段时间了,我一直在忙于其他事情,但是现在我已经使绕道功能成功运行了。
在查看了网络上的资源并进行了很多思考之后。答案很简单。在我的 FixAndReturn 汇编代码中,我要做的就是 jmp 绕行功能,不需要调用。 调用可能会不必要地更改我们不希望做的事情,并且绕行函数在参数方面与原始函数完全相同,因此它已从同一位置读取了参数原始函数调用将其放置。这意味着 jmp 可以很好地运行我们的绕行功能。组装时不需要额外的推动或弹出即可使它起作用。
以下是该过程的基本概述:
此函数调用使用的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