如何使用函数指针从其内存地址调用成员函数?
How to use function pointers to call member functions from its memory address?
我正在开发一个旧应用程序的补丁,该应用程序的所有者不再有 src 代码。
我在目标应用程序的 .exe 的 main() 之前将一个 dll 注入它。这个 dll 安装了我做的补丁。
该应用程序有一个 C++ 自定义类型(class 或结构),似乎是一个绘图字体管理器,它具有我需要通过其中一些补丁调用的功能。
我通常调用这些 "native" 成员函数的方式是创建一个包装函数,通过 asm 内联调用本机成员函数。我这样做是因为我找不到如何通过 C++ 函数指针来完成此操作。
我再次尝试以一种比创建大量臃肿的函数包装器更好的方式来完成此任务。这次我尝试使用 class/struct 作为该原生类型的虚拟包装器,但似乎我遗漏了一些我无法理解的与函数指针语法相关的内容。
这是我尝试做的示例:
/* NC for Native Class */
class NC_FontDevice
{
public:
typedef void(NC_FontDevice::*_UseTexturesTransparency)();
_UseTexturesTransparency *UseTexturesTransparency = reinterpret_cast<_UseTexturesTransparency*>(0x635FD0);
private:
NC_FontDevice(){}
};
NC_FontDevice* GetFontDevice()
{
NC_FontDevice* lpFontDevice = nullptr;
/*
This asm inline block is here to show more or less what I do in those wrappers I told.
I know this can be converted to a simple function pointer.
*/
__asm
{
mov eax, 0x0041FE10
call eax
mov lpFontDevice, eax
}
return lpFontDevice;
}
void foo()
{
auto lpFontDevice = GetFontDevice();
// Here I get and "identifier X is undefined"
(lpFontDevice->**UseTexturesTransparency)();
}
如果很清楚我想要什么,除了函数包装器之外还有更好的方法来实现它吗?
提前致谢。
您是否考虑过使用 std::bind 和 std::function 来代替? C++11 和 boost 都有。
std::function x = std::bind(&ClassName::function,this);
这将创建一个适用于您的对象的回调函数。
您的问题之一至少是您的代码与您的问题不匹配。你说的是函数指针,你却写void(NC_FontDevice::*_UseTexturesTransparency)()
。那是不是一个函数指针。这是指向成员函数 (PMF) 的指针。完全不同的野兽,你不能假设这些是简单的指针。它们通常甚至大小都不一样。
我怀疑您在 0x635FD0
找到了一个函数。该函数可能看起来像 void _UseTexturesTransparency(NC_FontDevice*)
。当然,它在编译时可能是(的一部分)成员函数,但这并不重要。这是黑客攻击,我们在这里很务实。如果我们可以将其视为普通函数指针,为什么还要处理 PMF 的复杂性?
[编辑]
根据评论,MSVC++ 将使用 ECX
作为成员函数中的 this
参数;碰巧它也支持常规函数的 __fastcall
调用约定,它将第一个 32 位参数放在 ECX
中。它不是完美的替代品; __fastcall
还使用 EDX 作为其第二个参数。如果现有代码需要堆栈上的更多参数,您可能需要一个虚拟参数。
您可以检查堆栈参数,因为根据成员函数的 __thiscall
调用约定,被调用方会清理堆栈。幸运的是,这符合 __fastcall
约定。
我正在开发一个旧应用程序的补丁,该应用程序的所有者不再有 src 代码。
我在目标应用程序的 .exe 的 main() 之前将一个 dll 注入它。这个 dll 安装了我做的补丁。
该应用程序有一个 C++ 自定义类型(class 或结构),似乎是一个绘图字体管理器,它具有我需要通过其中一些补丁调用的功能。
我通常调用这些 "native" 成员函数的方式是创建一个包装函数,通过 asm 内联调用本机成员函数。我这样做是因为我找不到如何通过 C++ 函数指针来完成此操作。
我再次尝试以一种比创建大量臃肿的函数包装器更好的方式来完成此任务。这次我尝试使用 class/struct 作为该原生类型的虚拟包装器,但似乎我遗漏了一些我无法理解的与函数指针语法相关的内容。
这是我尝试做的示例:
/* NC for Native Class */
class NC_FontDevice
{
public:
typedef void(NC_FontDevice::*_UseTexturesTransparency)();
_UseTexturesTransparency *UseTexturesTransparency = reinterpret_cast<_UseTexturesTransparency*>(0x635FD0);
private:
NC_FontDevice(){}
};
NC_FontDevice* GetFontDevice()
{
NC_FontDevice* lpFontDevice = nullptr;
/*
This asm inline block is here to show more or less what I do in those wrappers I told.
I know this can be converted to a simple function pointer.
*/
__asm
{
mov eax, 0x0041FE10
call eax
mov lpFontDevice, eax
}
return lpFontDevice;
}
void foo()
{
auto lpFontDevice = GetFontDevice();
// Here I get and "identifier X is undefined"
(lpFontDevice->**UseTexturesTransparency)();
}
如果很清楚我想要什么,除了函数包装器之外还有更好的方法来实现它吗?
提前致谢。
您是否考虑过使用 std::bind 和 std::function 来代替? C++11 和 boost 都有。
std::function x = std::bind(&ClassName::function,this);
这将创建一个适用于您的对象的回调函数。
您的问题之一至少是您的代码与您的问题不匹配。你说的是函数指针,你却写void(NC_FontDevice::*_UseTexturesTransparency)()
。那是不是一个函数指针。这是指向成员函数 (PMF) 的指针。完全不同的野兽,你不能假设这些是简单的指针。它们通常甚至大小都不一样。
我怀疑您在 0x635FD0
找到了一个函数。该函数可能看起来像 void _UseTexturesTransparency(NC_FontDevice*)
。当然,它在编译时可能是(的一部分)成员函数,但这并不重要。这是黑客攻击,我们在这里很务实。如果我们可以将其视为普通函数指针,为什么还要处理 PMF 的复杂性?
[编辑]
根据评论,MSVC++ 将使用 ECX
作为成员函数中的 this
参数;碰巧它也支持常规函数的 __fastcall
调用约定,它将第一个 32 位参数放在 ECX
中。它不是完美的替代品; __fastcall
还使用 EDX 作为其第二个参数。如果现有代码需要堆栈上的更多参数,您可能需要一个虚拟参数。
您可以检查堆栈参数,因为根据成员函数的 __thiscall
调用约定,被调用方会清理堆栈。幸运的是,这符合 __fastcall
约定。