我正在对 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无论如何都让我头疼)。
如果该类没有 vtable,原则上您可以在自己的代码中创建这样一个类,其中所有函数调用都会调用适当的实际实现。您可以通过将成员函数编写为包含指向实际实现的程序集跳转指令的裸函数来完成此操作。
如果类有 vtable,事情可能会变得更加复杂;您可能需要显式创建 vtable 作为函数指针的结构,并使函数存根调用它们。这意味着更复杂的垫片功能;带有跳转的简单裸函数可能还不够,使用真实函数可能会更好。但请记住,win32 上的成员函数使用不同的调用约定;这意味着普通的成员函数调用将不起作用。您可能能够摆脱构建指向成员函数的指针,但请记住它们有一个相当奇怪的结构,并且您需要将其与具有相同表示形式的东西相匹配vtable 指针。祝你好运!
您在这里进行逆向工程,因此(几乎,可能)在与现有代码交互时被迫降低。
我会使用纯汇编代码来调用这个函数。
如果 EXE 的基址是固定的那就更容易了。
示例代码:
void main()
{
int bar = 5;
int * cafebabe = &bar;
__asm
{
push [bar];
push [cafebabe];
mov eax, 123456; // address of the function
call eax;
}
}
只需检查原始代码如何调用此函数,即可了解需要按什么顺序推送参数。不要忘记某些参数可能需要通过寄存器传递!
我不完全确定我理解正确,但无论如何:我认为“手动定位”方法的最简单途径是使用函数指针。
C++ 没有定义任何类型的二进制接口,因此几乎不可能为 C++ 类实现任何类型的动态绑定。
您能做的最好的事情就是声明两个结构体 - 一个包含每个方法的 C 函数 typedef,另一个镜像类数据布局。
当然 - 因为类方法上的 __thiscall 通过 ecs 寄存器传递“this”,所以我不相信你实际上可以做出一个显式的 c 函数声明,它将具有相同的效果,因此你可能需要通过您在程序集中编写的自定义“CallThisCallMethodWithParameters”。