Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/141.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
获取虚拟成员函数的实际地址(或vTable中的索引) 在C++中,有没有办法获得成员函数的真地址< /强>,或者在VTAB.< /P>中索引< /强>?_C++_Member Functions - Fatal编程技术网

获取虚拟成员函数的实际地址(或vTable中的索引) 在C++中,有没有办法获得成员函数的真地址< /强>,或者在VTAB.< /P>中索引< /强>?

获取虚拟成员函数的实际地址(或vTable中的索引) 在C++中,有没有办法获得成员函数的真地址< /强>,或者在VTAB.< /P>中索引< /强>?,c++,member-functions,C++,Member Functions,更新: 我不知道vTable中的索引 我不知道地址 以下是我想知道的原因: 我想钩住DirectX的函数ID3DXFont->DrawText。如果我知道vTable中DrawText的索引,我可以替换它来执行挂钩。但是如何获得索引呢?如果它能够获得真实地址,我可以在vTable中搜索它以获得索引 而且不是特别的ID3DXFont->DrawText,将来可能还有其他一些函数,所以我尝试编写一个通用的钩子函数 以下是我迄今为止所尝试的: #include <iostream> usi

更新:

我不知道vTable中的索引 我不知道地址

以下是我想知道的原因:

我想钩住DirectX的函数ID3DXFont->DrawText。如果我知道vTable中DrawText的索引,我可以替换它来执行挂钩。但是如何获得索引呢?如果它能够获得真实地址,我可以在vTable中搜索它以获得索引

而且不是特别的ID3DXFont->DrawText,将来可能还有其他一些函数,所以我尝试编写一个通用的钩子函数

以下是我迄今为止所尝试的:

#include <iostream>
using namespace std;

struct cls {
    virtual int fn1() {
        cout << "fn1 called" << endl;
        return 1;
    }
    virtual int fn2() {
        cout << "fn2 called" << endl;
        return 2;
    }
};

template <typename fn_t>
DWORD fn_to_addr(fn_t fn) { // convert function to DWORD for printing
    union U {
        fn_t fn;
        DWORD addr;
    };
    U u;
    u.fn = fn;
    return u.addr;
}

int main() {
    cls c;

    DWORD addr = fn_to_addr(&cls::fn2);
    cout << hex << addr << endl;
}
两者都不是真实的地址。不管怎样,你想这么做吗

谢谢。

如本文所述:

每当一个类定义一个虚函数(或方法)时,大多数 编译器将一个隐藏的成员变量添加到指向 所谓的虚拟方法表(VMT或Vtable)。这个VMT基本上是 指向(虚拟)函数的指针数组


据我所知,您没有访问Vtable的权限,编译器甚至不知道表中的条目数

附近什么都没有。您尝试使用
&cls::fn2
无法工作,因为结果必须在特定情况下工作 类似于
(pCls->*fn)(
,即使
pCls
指向派生类 它将覆盖该函数。(指向成员函数的指针是 复杂的野兽,用于识别函数是否为 虚拟或非虚拟,并根据需要提供不同的信息 如果你在用MSC做实验,请注意 必须为指向要工作的成员函数的指针指定
/vmg
正确。)

即使对于给定的实现,也需要 正确的类型。鉴于此,如果你知道课堂布局 虚拟函数表的布局,您可以跟踪它。 通常,指向虚拟函数表的指针是 课堂上的第一个单词,尽管这不能保证。及 通常,函数将按其显示的顺序显示 宣布。但是,随着附加信息的增加,例如 指向RTTI的指针,以及可能需要的偏移量信息 在调用函数时修复
指针(尽管 许多编译器会为此使用蹦床)。对于64位g++ 在Windows(CygWin版本)下:

struct C
{
虚拟~C(){}

虚拟空间fn1()const{std::cout不要轻易放弃

虽然其他答案是正确的,因为C++语言不允许你以一种可移植的方式来做这件事,但是在你的特定情况下有一个重要的因素,这可能使这件事更合理。 <3>是ID3DXFooT是一个COM接口,以及那些工作是如何与访问它们的语言分开的精确二进制细节。因此,尽管C++没有说明在指针的另一端会发现什么,com确实表示有一个VTABLE,其中有一组函数指针,它们具有指定的顺序和一个SPECF。IED调用约定。这允许我告诉你,DRAWTEXT函数的索引是314(DrawTextA)或15(DRAWTEXW),而且在VisualC++ 28之后的许多年内,这仍然是正确的。或者在GCC 83.1中,因为COM是二进制接口规范,所有编译器都应该以同样的方式实现。(如果他们声称支持COM)

查看下面的第二个链接,使用两种不同的方法来实现COM函数挂钩。方法2最接近您所要求的,但我认为您可能会考虑第一个,而不是因为Vododo.

资料来源:

[ [
[

这是一个相当棘手的问题。由于您使用的是虚拟方法,它取决于您使用的编译器。通常不可能。但是,请阅读并解释您提出问题的原因……(为什么函数的机器地址对您很重要?)@aj3423术语“真实地址”是什么意思虚拟内存概念如何?我认为在下一个C++标准上添加它是很好的。为什么要这样?实际上,编译器比VoD知道更多的VToT布局。但是编译时编译器不知道VToT中的每个条目应该指向哪个函数,基类函数或派生类函数。ries是在运行时设置的。很明显,因为条目可以在不同的时间指向不同的函数。但是您甚至不知道哪个条目(如果有的话)与您感兴趣的函数相关。很抱歉,我没有解释为什么一开始,线程现在被更新了。如果我知道我可以获得地址,我也不知道索引。@aj3423索引将被更新根据不同的编译器而有所不同,正如我指出的,这可能是不够的。对于简单的情况,表中的条目是按照类中声明的虚拟函数的顺序排列的(任何虚拟函数都是先声明类的基类)。可能在开始或结束时有一些附加条目,每个条目可能包含一些附加信息。当然,成员函数的调用顺序可能不同于普通函数的调用顺序(例如MSC)。为什么在我的机器上vtable中的DrawText索引为14(win7 32位+vs2010+调试模式)@aj3抱歉,我假设函数在MSDN中是按接口顺序列出的,但它们只是按字母顺序排列的。您是对的:它是14(对于UTF-16版本是15)。答案已更新。但我向您保证,这不取决于您的计算机、编译器或编译器设置。
00401058   .    mov     eax, dword ptr [ecx] // get vptr
0040105A   .    jmp     dword ptr [eax+4] // jmp to the second function (fn2)
struct C
{
    virtual ~C() {}
    virtual void fn1() const { std::cout << "In C::fn1\n"; }
    virtual void fn2() const {}
};

void const*
fn1ToAddr( C const* pC )
{
    void const* const* vPtr = *reinterpret_cast<void const* const* const*>(pC);
    return vPtr[2];
}