在挂钩函数中使用结构对象和构造函数

逆向工程 C++ 函数挂钩 代理人 api-reversing
2021-06-25 18:35:56

将尝试改写实际问题,因此希望它更具描述性并且更清楚我所追求的内容:

所以,有一个函数 main,我已经成功地钩住了。挂钩版本如下所示:

__int64 __fastcall gamemainHooked(gladius::Game* thisptr, int param_1, char** param_2, char** param_3)
    {       

        gladius::get().initialize(thisptr, param_1, param_2, param_3);

        gladius::gui::get().guiRun(*(GUI**)(thisptr + 0x28));

        gladius::get().quit(thisptr);

        return gladius::get().gamemain(thisptr, param_1, param_2, param_3);
    }

现在,看到有一个 Game* thisptr,它被传递给该函数。

当函数运行时,它会填充 Game* thisptr 实例

thisptr->GameConstructor (0x0x00000271704c6ec0)
thisptr->gamemain (0x00000271788a94f0)
thisptr->initialize(0x000002716d523b90)
thisptr->quit(0x000002716fdebdd0)

原始 main 函数和钩子函数有一个名为 guiRun 的函数,它采用thisptr + 0x28偏移量,从下面的代码中可以看出它是构造函数(游戏)的第 5 个元素。

Game * __thiscall gladius::Game::Game(Game *this)

{
  *(undefined8 *)this = 0;
  *(undefined8 *)(this + 8) = 0;
  *(undefined8 *)(this + 0x10) = 0;
  *(undefined8 *)(this + 0x18) = 0;
  *(undefined8 *)(this + 0x20) = 0;
  *(undefined8 *)(this + 0x28) = 0;
  *(undefined8 *)(this + 0x30) = 0;
  *(undefined8 *)(this + 0x38) = 0;
  *(undefined8 *)(this + 0x40) = 0;
  *(undefined8 *)(this + 0x48) = 0;
  *(undefined8 *)(this + 0x50) = 0;
  return this;
}

现在,扭转这种情况的最佳方法是什么,以便我可以处理 Game 实例的第 5 个元素?代码应该是什么样子,以便使用thisptr+0x28调用 guiRun成功。

我应该用里面的所有指针完全反转构造函数然后指向它吗?

关键是调用guiRun (thisptr + 0x28)不起作用,因为thisptr + 0x28没有指向 Game* 实例的第 5 个元素......

当前反转的 Game 结构如下所示:

 namespace gladius {
        struct Game {
            //virtual int __thiscall main(gladius::Game* thisptr, int param_1, char** param_2, char** param_3);
    
            using GameConstructor = Game * (__fastcall*) (Game* thisptr);
            GameConstructor gameConstructor;
    
            using GameMain = __int64(__fastcall*) (gladius::Game* thisptr, int param_1, char** param_2, char** param_3);
            GameMain gamemain;
    
            using Initialize = void(__fastcall*) (gladius::Game* thisptr, int a2, char** a3, char** a4);
            Initialize initialize;
    
            using Quit = void(__fastcall*) (gladius::Game* thisptr);
            Quit quit;
        };
    
        Game& get();
    
    } /

PS 似乎 guiRun 想要接受 * thisptr而不是thisptr但这意味着必须更改函数的原始签名。不确定这是否会导致挂钩无法正常工作。

1个回答

这已在此处解决:链接

所以,解决的办法是引入和原来一样功能的类结构,然后用原来的构造函数来填充它。

如果需要初始化其他类的对象,即作为上述结构的第 5 个元素的 GUI 对象,则 GUI 对象必须具有链接中描述的正确类构造函数。

您可能需要一个与那里描述的类似的结构来初始化您想要填充的任何对象。