0


有点...我有一个 DLL,它从反汇编然后反编译的代码中导出唯一的单个函数 CreateInterface :

int __cdecl CreateInterface(const char *a1, int a2)
{
//many crazy things
}

这里它的返回类型为 int,但实际上它是指向某个结构的指针。从主 exe 加载这个库,然后以这种方式使用:

int (__stdcall *__cdecl Sys_GetFactory(int (__stdcall *hModule)()))()
{
  int (__stdcall *result)(); // eax@1

  result = hModule;
  if ( hModule )
    result = GetProcAddress(hModule, "CreateInterface");
  return result;
}

void some_funct()
{
    FARPROC net_interface =  Sys_GetFactory(pModule);
    int s_pClientNet = ((int (__cdecl *)(_DWORD, _DWORD))net_interface)("INetClient_003", 0);
}

并在初始化后以这种方式使用:

 int result = (*(int (__stdcall **)(int, int, int, int))(*(_DWORD *)s_pClientNet + 60))(
                 login,
                 password,
                 mw_account_struct,
                 mw_account_struct_size);

所以..回到结构。无论如何要恢复它,而不是通过如此疯狂的方式调用所需的函数?我的意思是 (s_pClientNet + 60)

PS 我肯定没有 dll 源、def 文件等,甚至不知道目标类/结构中可以包含哪些函数……我唯一知道的是一些调用像 s_pClientNet + 60 这样的功能

4

3 回答 3

3

嗯,这看起来可能是一个 C++ 类。有一个额外的间接级别,我敢打赌它是一个 vtable。s_pClientNet 绝对是一个指针,但 +60 发生取消引用它之后。vpointers 通常是类中的第一个元素,所以这是更多的证据。基本上不可能重新创建一个编译为相同布局的 C++ 类,除非你真的很幸运。但是您可以手动管理一些部分。

typedef int(*login_fcn_t)(int, int, int, int);

struct ClientInterfaceVtable
{
    _DWORD reserved[60];
    login_fcn_t login_fcn;
};

struct ClientInterface
{
    ClientInterfaceVtable *vpointer;
    /// other fields
};

现在,在将您s_pClientNet转换为 a之后ClientInterface *,您应该能够通过调用 login 方法s_pClientNet->vpointer->login_fcn(login, etc.);

在发现更多字段后,您总是可以尝试创建一个多态 C++ 类,看看是否可以推送定义直到找到匹配项,但这不会是可移植的。

编辑:

嗯,我刚刚意识到代码没有传递this指针。如果我对 vtable 没有完全错误,那么这表明这是一种静态方法,也许是某种工厂方法。

于 2012-06-12T17:07:16.137 回答
1

这很难甚至不可能,AFAIK 无法保证结构的布局和对齐方式,因此每个编译器可能会以不同的方式布局结构。即使是同一个编译器也可能通过修饰符和/或编译器选项具有不同的数据布局。

于 2012-06-12T16:09:17.020 回答
1

我不知道自动识别结构的任何方法,但是如果您使用 IDA,您可以在 IDA 内部定义结构,然后更改调用签名以显式使用它(将返回值更改为该结构类型和强制重新分析)。

这可能会帮助您更快地分析结构并了解程序行为,但最终将主要是手动分析。

可能有一些 IDA/OllyDbg 的脚本可以帮助解决这个问题,所以可能值得一看http://www.openrce.org/downloads/

于 2012-06-12T16:48:11.070 回答