我正在尝试使用WinAppDbg编写游戏插件,这涉及到钩子并调用该游戏中的现有功能。经过一些反向工程后,我得到了一些目标函数或类方法的RVA和签名。但是很快我发现WinAppDbg的文档仅告诉我如何挂钩现有函数而不是调用它们。此外,通常目标函数的地址是从Process.resolve_label获取的,但是我只有RVA。如何将函数与其RVA挂钩?谢谢!
------------------更新1 -----------------------
为了清楚说明我要做什么,请考虑以下情况:
bool Player::attack(this, Animal *some_animal)
中有一个称为some_game.exe
的类方法,当我攻击任何动物时都会调用该方法。我想监视攻击事件,并可能随时模拟/触发攻击事件。
[检查完'some_game.pdb'文件后,我发现目标函数的RVA即Player::attack
为0x00678840
。我制作了一个myplugin.dll
文件,该文件将在游戏过程中注入。
然后像这样在myplugin.dll
中调用此函数非常简单
#include <windows.h>
auto module_addr = reinterpret_cast<unsigned int>(GetModuleHandle(NULL));
attack_func = reinterpret_cast<void(*)(void*, void*)>(0x00678840+module_addr);
attack_func(...)
[通过首先定义一个辅助钩子函数Microsoft Detours library,钩子也很容易在void RegisterStaticHook(RVA sym, void* hook, void** org);
的帮助下:
#include <windows.h>
// Detours
#include <detours/detours.h>
typedef uint64_t VA;
typedef unsigned int RVA;
template<typename Type>
using Ptr = Type*;
enum class HookErrorCode {
ERR_SUCCESS,
ERR_TRANSACTION_BEGIN,
ERR_UPDATE_THREAD,
ERR_ATTACH,
ERR_DETACH,
ERR_TRANSACTION_COMMIT
};
template<typename T = Ptr<void>>
auto Hook(Ptr<T> p, T f) {
int error = DetourTransactionBegin();
if (error != NO_ERROR) {
return HookErrorCode::ERR_TRANSACTION_BEGIN;
}
error = DetourUpdateThread(GetCurrentThread());
if (error != NO_ERROR) {
return HookErrorCode::ERR_UPDATE_THREAD;
}
error = DetourAttach(
reinterpret_cast<Ptr<PVOID>>(p),
reinterpret_cast<PVOID>(f)
);
if (error != NO_ERROR) {
return HookErrorCode::ERR_ATTACH;
}
error = DetourTransactionCommit();
if (error != NO_ERROR) {
return HookErrorCode::ERR_TRANSACTION_COMMIT;
}
return HookErrorCode::ERR_SUCCESS;
}
void RegisterStaticHook(RVA sym, void* hook, void** org) {
auto base = reinterpret_cast<VA>(GetModuleHandle(NULL));
*org = reinterpret_cast<void*>(base + sym);
auto ret = Hook<void*>(org, hook);
if (ret != HookErrorCode::ERR_SUCCESS) {
std::cout << "[Error] ";
switch (ret) {
case HookErrorCode::ERR_TRANSACTION_BEGIN:
std::cout << "DetourTransactionBegin";
break;
case HookErrorCode::ERR_UPDATE_THREAD:
std::cout << "DetourUpdateThread";
break;
case HookErrorCode::ERR_ATTACH:
std::cout << "DetourAttach";
break;
case HookErrorCode::ERR_DETACH:
std::cout << "DetourDetach";
break;
case HookErrorCode::ERR_TRANSACTION_COMMIT:
std::cout << "DetourTransactionCommit";
break;
default:
break;
}
std::cout << "failed!" << std::endl;
}
}
然后用[RegisterStaticHook]钩住my_attack
:
void** org;
bool my_attack(void* player_this, void* animal){
...
}
RegisterStaticHook(0x00678840, my_attack, org);
我的问题是如何使用WinAppDbg。
TL; DR:WinAppDbg并不真正支持此功能,这样做有点困难。请改用Microsoft Detours。
详细说明:
WinAppDbg是调试器,这意味着要修补/挂钩等的目标程序正在与Python脚本不同的Windows进程中运行。它只能以Win32 API允许的方式与调试过的进程进行交互,不幸的是,没有在目标进程中执行功能的机制。
您可以通过一些工作来模拟此功能。基本上,这意味着要修改寄存器和堆栈以执行钩子函数的开头,确保堆栈中的所有指针实际上都指向该进程中的有效内存,并可能分配一些蹦床代码以使WinAppDbg一旦该函数中断执行已经回来了。由于体系结构的差异,必须对32位和64位都重新进行一次此操作。这基本上就是像GDB这样的调试器所做的。
另一方面,Detours的工作原理是将DLL直接注入到您要定位的进程的内存中-因此执行代码很容易,因为您不必处理怪异的Win32 API调用或映射内存流程。这也快得多了。但是您将不得不使用C而不是Python进行编码。