在 C++ 中使用未记录的类

发布于 2024-09-13 03:04:55 字数 626 浏览 2 评论 0原文

我正在对 Windows 可执行文件进行逆向工程。我从注入可执行文件(不同线程,自己的堆栈)的一些代码中找到了一个我想使用的类。给定方法地址和成员变量结构,我将如何声明这样一个类?

例如,假设我找到了一个名为 foo 的类,其构造函数为 @ 0x4012D30 ,函数为 doTheMario @ 40125D4。我还知道它保存着三个 DWORD 的私有数据。由于这两个方法都是 _thiscalls,所以我在代码中声明了一个这样的类:

class GuessedFoo {
    private:
        int bar;
        char *cafebabe;
        float deadbeef;
    public:
        GuessedFoo(int a, int b);
        void doTheMario();
};

现在,这是一个完美的花花公子的类,但是现在有什么方法可以让编译器/链接器将类方法绑定到我之前声明的两个地址吗?当然,我可以编写一个 asm 包装器,为我需要使用的每个方法将 stdcall 转换为 thiscall,然后使用结构而不是类,但必须有更好的方法。

我现在使用gcc/g++,但我可以切换到VC++(因为gcc的内联asm无论如何都让我头疼)。

I'm in the process of reverse-engineering a Windows executable. I found a class that I want to use from some code that I inject into the executable (different thread, own stack). How would I go about declaring such a class, given method addresses and member variables structure?

For instance, let's say I found a class called foo, with it's constructor @ 0x4012D30 and a function doTheMario @ 40125D4. I also know it holds three DWORDs of private data. Since both the methods are _thiscalls, I declare a class like so in my code:

class GuessedFoo {
    private:
        int bar;
        char *cafebabe;
        float deadbeef;
    public:
        GuessedFoo(int a, int b);
        void doTheMario();
};

Now, this is a perfectly dandy class, but now is there any way to make the compiler / linker bind the class methods to the two previous addresses I stated? Of course I can write an asm wrapper to convert an stdcall into a thiscall for every method that I need to use, and then use structs instead of classes, but there has to be a better way.

I use gcc/g++ at the moment, but I can switch to VC++ (since gcc's inline asm gives me headaches anyway).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

酒中人 2024-09-20 03:04:55

如果该类没有 vtable,原则上您可以在自己的代码中创建这样一个类,其中所有函数调用都会调用适当的实际实现。您可以通过将成员函数编写为裸函数 包含到实际实现的汇编跳转指令。

如果类有一个 vtable,事情可能会变得更加复杂;您可能需要显式创建 vtable 作为函数指针的结构,并使函数存根调用它们。这意味着更复杂的垫片功能;带有跳转的简单裸函数可能还不够,使用真实函数可能会更好。但请记住,win32 上的成员函数使用 不同的调用约定;这意味着普通的成员函数调用将不起作用。您也许能够构建指向成员函数的指针,但请记住它们有一个对它们来说是相当奇怪的结构,你需要将它与与 vtable 指针具有相同表示形式的东西相匹配。祝你好运!

If the class has no vtable, you could, in principle, create such a class in your own code, where all the function calls invoke the appropriate real implementations. You can do this by wring the member functions as naked functions containing an assembly jump instruction to the real implementation.

If the class has a vtable, things are likely to get much more complex; you'll likely need to explicitly create the vtable as a struct of function pointers, and make your function stubs call into them. This means more complex shim functions; a simple naked function with a jump may not be enough, and it may be better to go with a real function. Remember, though, that member functions on win32 use a different calling convention; this means that an ordinary member function call will not work. You may be able to get away with building pointers-to-member-functions, but keep in mind they have a rather strange structure to them, and you'll need to match it with something that has the same representation as the vtable pointers. Good luck!

流云如水 2024-09-20 03:04:55

您在这里进行逆向工程,因此(几乎,可能)在与现有代码交互时被迫降低。

我将使用纯汇编代码调用此函数。
如果 EXE 的基地址是固定的,那就更容易了。
示例代码:

void main()
{
    int bar = 5;
    int * cafebabe = &bar;
    __asm
    {
        push [bar];
        push [cafebabe];
        mov eax, 123456; // address of the function
        call eax;
    }
}

只需检查原始代码如何调用该函数,即可了解需要按什么顺序推送参数。不要忘记某些参数可能需要通过寄存器传递!

You're reverse-engineering here, hence (almost, probably) forced to get lower when it comes to interacting with existing code.

I'd call this function using pure assembly code.
If the EXE's base address is fixed it's even easier.
Example code:

void main()
{
    int bar = 5;
    int * cafebabe = &bar;
    __asm
    {
        push [bar];
        push [cafebabe];
        mov eax, 123456; // address of the function
        call eax;
    }
}

Simply check how this function is being called by original code to see in which order you need to push arguments. Don't forget that some arguments might need to be passed through registers!

¢好甜 2024-09-20 03:04:55

我不完全确定我是否正确理解你,但无论如何:我认为“手动定位”方法的最简单途径是使用函数指针。

I'm not entirely sure that I understand you correctly, but anyhow: I think the easiest route to "hand-locating" methods is by using function-pointers.

十年九夏 2024-09-20 03:04:55

C++ 没有定义任何类型的二进制接口,因此几乎不可能为 C++ 类实现任何类型的动态绑定。

你能做的最好的事情就是声明两个结构 - 一个包含每个方法的 C 函数 typedef,另一个镜像类数据布局。

当然 - 因为类方法上的 __thiscall 通过 ecs 寄存器传递“this”,所以我不相信您实际上可以做出具有相同效果的显式 c 函数声明,因此您可能需要通过自定义执行所有调用您在程序集中编写的“CallThisCallMethodWithParameters”。

C++ does not define any kind of binary interface making it all but impossible to implement any kind of dynamic binding for c++ classes.

the best you can do is to declare two structs - one containing c function typedefs for each method, the other mirrors the class data layout.

Of course - because __thiscall on a class method passes 'this' via the ecs register, I don't belive you can actually make an explicit c function declaration that will have the same effect so you might need to perform all the calls via a custom "CallThisCallMethodWithParameters" that you had write in assembly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文