通过 func ptr 间接将参数推送到函数

Push parameters to a function indirectly through func ptr

假设我有一个函数

inline PVOID CallFunc(PVOID Dll, PCHAR Name, INT nArgs, ...)
{
    va_list Args;
    va_start(Args, nArgs);
    ULONG_PTR *Params = (ULONG_PTR *) malloc(nArgs);

    for(INT n = 0; n < nArgs; ++n)
        Params[n] = va_arg(Args, ULONG_PTR);

    PVOID Func = (PVOID)GetProcAddress(Dll, Name);

    typedef PVOID (WINAPI *MyFunc)(ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR,
    ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR,
    ULONG_PTR, ULONG_PTR, ULONG_PTR, ULONG_PTR);

    MyFunc FuncPtr = (MyFunc)Func;

    va_end(Args);

    return ERROR;
}

基本上我想做的是制作一个可以动态调用的函数,以调用给定 DLL 中按函数名称偏移的任何其他函数。我知道以前有通过模板实现的,但是人们制作了多个模板来获取多个参数。我想弄清楚如何做的是根据需要将尽可能多的参数传递给函数并相应地填充它。

假设我打电话给 MessageBoxA

例如,我将以下内容传递给此函数

CallFunc(User32Address, "MessageBoxA", 4, (ULONG_PTR) NULL, (ULONG_PTR) "World", (ULONG_PTR) "Hello", (ULONG_PTR) NULL);

现在,您看到我已经在函数本身的 typedef 中初始化了一个函数类型定义。我这样做是因为我不知道函数本身将采用多少个参数,如果我知道那么我将能够通过仅分配我需要的参数数量(在本例中为 4)来初始化 typedef。

我的问题是,在 MessageBoxA 通过 GetProcAddress(Dll, Name) 加载并分配给 PVOID Function 之后。使用 Function 中的函数偏移量,如何确定 MessageBoxA 包含 4 个参数,然后如何动态初始化 typedef;知道我只需要将 4 个 ULONG_PTR 个参数分配给 FuncPtr?

我知道这个问题可能会让一些人感到困惑,但请让我知道是否需要澄清它的任何方面。

可能但很难做到。你所要求的不能直接用 C++ 完成,你必须下降到 Assembly 层。假设您正在使用 32 位 x86(64 位 x64 更难处理),您将不得不:

  1. PUSHCallFunc() 的每个参数值复制到调用堆栈,然后 CALL 指向的函数,最后删除重复项来自调用堆栈的参数,如果指向的函数使用 cdecl(或类似的)调用约定,要求调用者执行调用堆栈清理(您必须提前知道)。

  2. CallFunc() 简单地 JMP 放入指向的函数中,以便它读取 CallFunc() 参数,就好像它们是它自己的参数一样,然后让它 RETurn 直接转到调用 CallFunc() 的代码。但是,CallFunc() 必须使用与指向函数完全相同的调用约定才能使其工作。因此,您需要针对不同的调用约定使用多个 CallFunc() 样式函数。