从 VC++ 代码调用 __thiscall DLL 函数

问题描述 投票:0回答:1

我有一个 DLL 文件需要进行逆向工程,我想直接在我的 x86 C++ 代码中调用它的函数之一(即类构造函数)。原因是我不知道类的结构是什么,而且我也没有头文件。该函数的

calling convention
__thiscall
。我有兴趣从我的代码和我在
MSDN
页面、here 中阅读的内容访问 this 指针,
this
指针位于
ecx
寄存器中。

Microsoft 特定的 __thiscall 调用约定用于 x86 架构上的 C++ 类成员函数。

...

this 指针通过寄存器 ECX 传递,而不是在堆栈上。

如果我想从五次调用加载的函数中获得五个不同的对象,我期望获得五个不同的

this
指针,但从我下面的代码来看,它们都是相同的值。

#include <iostream>
#include <Windows.h>

int main()
{
    typedef void (__thiscall* CTOR)(void);

    HMODULE dll = LoadLibraryA(R"(MYDLL.dll)");
    if (!dll)
        std::cout << "can not load dll error: " << GetLastError() << std::endl;
    else
    {       
        void* default_ctor_this_pointer = ::operator new(4);

        if (default_ctor_this_pointer)
        {
            for (std::size_t i = 0; i < 5; i++)
            {
                std::memset(default_ctor_this_pointer, 0, 4);

                CTOR default_ctor = (CTOR)(GetProcAddress(dll, "??0TestClass@@QAE@XZ"));
                std::cout << "\t[+]TestClass::TestClass() = 0x" << default_ctor << " --> error: " << GetLastError() << std::endl;
                std::cout << "\t\t[-]this_pointer before call: 0x" << std::hex << *(unsigned*)default_ctor_this_pointer << std::dec << std::endl;       
                _asm {mov ecx, default_ctor_this_pointer};
                default_ctor();
                _asm {mov default_ctor_this_pointer, ecx};
                std::cout << "\t\t[-]this_pointer after call: 0x" << std::hex << *(unsigned*)default_ctor_this_pointer << std::dec << std::endl;
            }
        }
    }

    return 0;
}

这就是我得到的输出

[+]TestClass::TestClass() = 0x62995440 --> error: 0
    [-]this_pointer before call: 0x0
    [-]this_pointer after call: 0x62a7d8d8
[+]TestClass::TestClass() = 0x62995440 --> error: 0
    [-]this_pointer before call: 0x0
    [-]this_pointer after call: 0x62a7d8d8
[+]TestClass::TestClass() = 0x62995440 --> error: 0
    [-]this_pointer before call: 0x0
    [-]this_pointer after call: 0x62a7d8d8
[+]TestClass::TestClass() = 0x62995440 --> error: 0
    [-]this_pointer before call: 0x0
    [-]this_pointer after call: 0x62a7d8d8
[+]TestClass::TestClass() = 0x62995440 --> error: 0
    [-]this_pointer before call: 0x0
    [-]this_pointer after call: 0x62a7d8d8

我期望检索五个不同的

this
值,但正如您所看到的,它们是相同的值。我是不是操作方法不对?

visual-c++ reverse-engineering dllimport class-constructors
1个回答
0
投票

您不能仅使用 4 字节分配来调用构造函数 - 您需要首先在

ecx
指向的地址处提供足够的存储空间。据您所知,构造函数可能因任何原因失败。


如果构造成功,你应该在寄存器

eax
中找到构造对象的地址。
ecx
的内容未定义,它是一个易失性寄存器(未保存被调用者!)。

仔细看看

__thiscall
构造函数调用的最小示例 (https://godbolt.org/z/zhfEexcEE):

class Foo {
    public:
    __thiscall Foo() : x(nullptr) {
    }
    void* x;
};

组装大部分是不言自明的:

_this$ = -4                                   ; size = 4
Foo::Foo(void) PROC                           ; Foo::Foo, COMDAT
        // `ebp` and `esp` are non-volatile, and have to be saved by the callee.
        push    ebp
        mov     ebp, esp
        // Compiler quirk - MSVC writes `this` to the stack ... twice.
        push    ecx
        mov     DWORD PTR _this$[ebp], ecx
        // Member initialization
        mov     eax, DWORD PTR _this$[ebp]
        mov     DWORD PTR [eax], 0
        // Here comes the ret val
        mov     eax, DWORD PTR _this$[ebp]
        // Restore non-volatile registers
        mov     esp, ebp
        pop     ebp
        ret     0
Foo::Foo(void) ENDP                           ; Foo::Foo
© www.soinside.com 2019 - 2024. All rights reserved.