// First get the raw pointer to the virtual function
auto myVirtualFuncPtr = &MyClass::myFunc;
void* myVirtualFuncPtrRaw = (void*&)myVirtualFuncPtr;
// Resolve the real function!
void* myFuncPtr = resolveVirtualFunctionAddress(myVirtualFuncPtrRaw);
...
static void* resolveVirtualFunctionAddress(void* address)
{
const int jumpInstructionSize = 5;
static ud_t ud_obj;
ud_init(&ud_obj);
ud_set_mode(&ud_obj, sizeof(void*) * 8);
ud_set_syntax(&ud_obj, UD_SYN_INTEL);
ud_set_pc(&ud_obj, (uint64_t)address);
ud_set_input_buffer(&ud_obj, (unsigned uint8_t*)address, jumpInstructionSize);
std::string jmpInstruction = "";
if (ud_disassemble(&ud_obj))
{
jmpInstruction += ud_insn_asm(&ud_obj);
}
// TODO: Implement startsWith and leftTrim yourself
if (startsWith(jmpInstruction, "jmp "))
{
std::string jumpAddressStr = leftTrim(jmpInstruction, "jmp ");
return hexToPointer(jumpAddressStr);
}
// If the jmp instruction was not found, then we just return the original address
return address;
}
static void* hexToPointer(std::string hexString)
{
void* address;
std::stringstream ss;
ss << std::hex << hexString;
ss >> address;
return address;
}
5条答案
按热度按时间v7pvogib1#
目前在C++中还没有标准的方法来做到这一点,尽管这些信息必须在某个地方可用。否则,程序如何调用函数?然而,GCC提供了一个扩展,允许我们检索虚函数的地址:
...假设成员函数的原型是
void func()
。当你想要缓存一个虚函数的地址或者在生成的代码中使用它时,这会非常有用。GCC会警告你这个构造,除非你指定-Wno-pmf-conversions
。它不太可能在任何其他编译器上工作。p4rjhz4m2#
指向成员函数的指针并不总是简单的内存地址。参见this article中的表,该表显示了不同编译器上成员函数指针的大小-有些高达20字节。
正如本文所述,成员函数指针实际上是一个实现定义的数据blob,用于帮助通过指针解析调用。您可以存储和调用它们,但如果您想打印它们,您打印什么?最好将其视为字节序列并通过
sizeof
获取其长度。lrl1mhuk3#
我找到了一种使用反汇编器(https://github.com/vmt/udis86)来实现这一点的方法。步骤如下:
1.通过普通C++代码获取虚函数指针
1.在该地址反汇编
jmp
指令1.从反汇编的字符串中解析出真实的地址
我是这样做的:
mf98qq944#
从我所知道的标准中,你唯一得到动态绑定的时候是在一个虚函数 * 调用 * 的时候。一旦你调用了一个函数,你就在执行函数中的语句(也就是说,你不能“中途停止”进入调用并获取地址。)
我认为这是不可能的。
wlzqhblo5#
对我来说没什么意义。如果你有正常的功能:
然后你可以把它的地址:
但是你不能获取函数call的地址,而这正是你想要做的。