Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/tfs/3.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
C++ 动态调用成员方法c++;_C++_Dynamic_Linker_Getprocaddress - Fatal编程技术网

C++ 动态调用成员方法c++;

C++ 动态调用成员方法c++;,c++,dynamic,linker,getprocaddress,C++,Dynamic,Linker,Getprocaddress,我知道这已经讨论过好几次了,但我的情况有点不同 我有一个第三方dll导出一些类。不幸的是,头文件不可用。 仍然可以调用导出的函数。但我无法绕过传递正确的“this”指针(在RCX寄存器中传递) 首先,我使用dumpbin/exports来提取函数名(由于第三方库和函数名是机密的,所以会更改名称) 现在,API允许我注册接收指向ThirdPartyNamespace::ThirdPartyClass的指针的回调(只有ThirdPartyClass的前向声明) 下面是我如何尝试调用ThirdPart

我知道这已经讨论过好几次了,但我的情况有点不同

我有一个第三方dll导出一些类。不幸的是,头文件不可用。 仍然可以调用导出的函数。但我无法绕过传递正确的“this”指针(在RCX寄存器中传递)

首先,我使用dumpbin/exports来提取函数名(由于第三方库和函数名是机密的,所以会更改名称)

现在,API允许我注册接收指向ThirdPartyNamespace::ThirdPartyClass的指针的回调(只有ThirdPartyClass的前向声明)

下面是我如何尝试调用ThirdPartyNamespace::ThirdPartyClass::GetId():

一切看起来都很好(即,如果我介入-i get inside ThirdPartyClass::GetId方法。但该指针不好。虽然ptr很好,如果在调试器中,我手动将rcx更改为ptr,则工作正常。但编译器由于某些原因未通过ptr。以下是反汇编:

long id = (ptr->*_pFnGetId)();
000000005C882362  movsxd      rax,dword ptr [rdi+30h]  
000000005C882366  test        eax,eax  
000000005C882368  jne         MyClass::MyCallback+223h (05C882373h)
000000005C88236A  movsxd      rcx,dword ptr [rdi+28h]  
000000005C88236E  add         rcx,rsi  
000000005C882371  jmp         MyClass::MyCallback+240h (05C882390h)  
000000005C882373  movsxd      r8,dword ptr [rdi+2Ch]  
000000005C882377  mov         rcx,rax  
000000005C88237A  mov         rax,qword ptr [r8+rsi]  
000000005C88237E  movsxd      rdx,dword ptr [rax+rcx]  
000000005C882382  movsxd      rcx,dword ptr [rdi+28h]  
000000005C882386  lea         rax,[r8+rdx]  
000000005C88238A  add         rcx,rax  
000000005C88238D  add         rcx,rsi  
000000005C882390  call        qword ptr [rdi+20h]  
000000005C882393  mov         ebp,eax  
在执行这些命令之前,rsi包含指向ThirdPartyClass(即ptr)对象的指针,但是没有直接将其传递到rcx中,而是对其执行了一些算术运算,因此,该指针完全错误

我不明白为什么编译器会这样做,因为它最终调用了非虚拟函数ThirdPartyClass::GetId():

在我看来,它应该像

long id = (ptr->*_pFnGetId)();
mov         rcx,rsi  
call        qword ptr [rdi+20h] 
mov         ebp,eax
如果我在调用qword ptr[rdi+20h]之前将rcx设置为rsi,它将返回我期望的值

我做错什么了吗?
提前感谢。

好的,我找到了一个解决方案,按事件(因为我已经使用了类似的方法,它在稍微不同的情况下工作)

解决方案是通过定义一个伪类并通过指针调用成员方法来欺骗编译器,但假装它是指向已知(编译器)类的指针

也许,这并不重要,但我知道ThirdPartyNamespace::ThirdPartyClass有虚拟函数,所以我也用虚拟函数声明假类

class FakeCall
{
private:
    FakeCall(){}
    virtual ~FakeCall(){}
};
其余部分与初始代码中的一样,除了一个小东西,我没有调用ptr->*\u pFnGetId(其中ptr是指向未知的、前向声明的类ThirdPartyNamespace::ThirdPartyClass的指针),而是假装在调用FakeCall类中的成员方法:

    FakeCall * fake = (FakeCall*)ptr;
    long sico = (fake->*_pFnGetId)();
拆解看起来与预期完全一样:

long sico = (fake->*_pFnGetSico)();
000000005A612096  mov         rcx,rax  
000000005A612099  call        qword ptr [r12+20h]  
000000005A61209E  mov         esi,eax 
而且它工作得很好

一些意见:

  • 正如我最初所想,成员方法指针只不过是一个普通的函数指针
  • 如果为未定义的类(即仅向前声明名称)调用成员方法,Microsoft编译器(至少VS2008)会发疯

  • 好的,我找到了一个解决方案,根据事件(因为我已经使用了类似的方法,它在稍微不同的情况下工作)

    解决方案是通过定义一个伪类并通过指针调用成员方法来欺骗编译器,但假装它是指向已知(编译器)类的指针

    也许,这并不重要,但我知道ThirdPartyNamespace::ThirdPartyClass有虚拟函数,所以我也用虚拟函数声明假类

    class FakeCall
    {
    private:
        FakeCall(){}
        virtual ~FakeCall(){}
    };
    
    其余部分与初始代码中的一样,除了一个小东西,我没有调用ptr->*\u pFnGetId(其中ptr是指向未知的、前向声明的类ThirdPartyNamespace::ThirdPartyClass的指针),而是假装在调用FakeCall类中的成员方法:

        FakeCall * fake = (FakeCall*)ptr;
        long sico = (fake->*_pFnGetId)();
    
    拆解看起来与预期完全一样:

    long sico = (fake->*_pFnGetSico)();
    000000005A612096  mov         rcx,rax  
    000000005A612099  call        qword ptr [r12+20h]  
    000000005A61209E  mov         esi,eax 
    
    而且它工作得很好

    一些意见:

  • 正如我最初所想,成员方法指针只不过是一个普通的函数指针
  • 如果为未定义的类(即仅向前声明名称)调用成员方法,Microsoft编译器(至少VS2008)会发疯

  • 很好。MSVC使用不同大小的指向成员函数的指针,具体取决于类,在64位平台上为8到24字节。请参阅链接感谢!它实际上有一个链接,并提供了完整的解释(自2015年以来仍然是实际的)。这真是令人兴奋。我很幸运,我的第三方类中只有一个继承。很好的捕获。MSVC使用不同大小的指向成员函数的指针,这取决于类,在64位平台上为8到24字节。请参阅感谢链接!它实际上有一个带有完整解释的链接(自2015年以来仍然是实际的).这真是令人兴奋。我很幸运,我的第三方类中只有一个继承。