C++ 动态调用成员方法c++;
我知道这已经讨论过好几次了,但我的情况有点不同 我有一个第三方dll导出一些类。不幸的是,头文件不可用。 仍然可以调用导出的函数。但我无法绕过传递正确的“this”指针(在RCX寄存器中传递) 首先,我使用dumpbin/exports来提取函数名(由于第三方库和函数名是机密的,所以会更改名称) 现在,API允许我注册接收指向ThirdPartyNamespace::ThirdPartyClass的指针的回调(只有ThirdPartyClass的前向声明) 下面是我如何尝试调用ThirdPartyNamespace::ThirdPartyClass::GetId(): 一切看起来都很好(即,如果我介入-i get inside ThirdPartyClass::GetId方法。但该指针不好。虽然ptr很好,如果在调试器中,我手动将rcx更改为ptr,则工作正常。但编译器由于某些原因未通过ptr。以下是反汇编:C++ 动态调用成员方法c++;,c++,dynamic,linker,getprocaddress,C++,Dynamic,Linker,Getprocaddress,我知道这已经讨论过好几次了,但我的情况有点不同 我有一个第三方dll导出一些类。不幸的是,头文件不可用。 仍然可以调用导出的函数。但我无法绕过传递正确的“this”指针(在RCX寄存器中传递) 首先,我使用dumpbin/exports来提取函数名(由于第三方库和函数名是机密的,所以会更改名称) 现在,API允许我注册接收指向ThirdPartyNamespace::ThirdPartyClass的指针的回调(只有ThirdPartyClass的前向声明) 下面是我如何尝试调用ThirdPart
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
而且它工作得很好
一些意见:
好的,我找到了一个解决方案,根据事件(因为我已经使用了类似的方法,它在稍微不同的情况下工作) 解决方案是通过定义一个伪类并通过指针调用成员方法来欺骗编译器,但假装它是指向已知(编译器)类的指针 也许,这并不重要,但我知道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
而且它工作得很好
一些意见:
很好。MSVC使用不同大小的指向成员函数的指针,具体取决于类,在64位平台上为8到24字节。请参阅链接感谢!它实际上有一个链接,并提供了完整的解释(自2015年以来仍然是实际的)。这真是令人兴奋。我很幸运,我的第三方类中只有一个继承。很好的捕获。MSVC使用不同大小的指向成员函数的指针,这取决于类,在64位平台上为8到24字节。请参阅感谢链接!它实际上有一个带有完整解释的链接(自2015年以来仍然是实际的).这真是令人兴奋。我很幸运,我的第三方类中只有一个继承。