Assume I have a function
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;
}
Basically what I am trying to do is make a function which can be dynamically called to call any other function in the given DLL offset by function name. I know there are previous implementations of this via templates but people make multiple templates to take multiple parameters. What I am trying to figure out how to do is pass as many parameters I want to a function as needed and fill it accordingly.
Let's say I am calling MessageBoxA
For instance, I pass the following to this function
CallFunc(User32Address, "MessageBoxA", 4, (ULONG_PTR) NULL, (ULONG_PTR) "World", (ULONG_PTR) "Hello", (ULONG_PTR) NULL);
Now, you see that I have initialized a function type definition in the typedef within the function itself. I did this because I don't know how many parameters the function itself will take, if I knew then I would be able to initialize the typedef by only assigning the amount of parameters that I need (in this case, 4).
My question is this, after MessageBoxA
is loaded via GetProcAddress(Dll, Name)
and assigned to PVOID Function
. Using the function offset in Function
, how can I determine that MessageBoxA
contains 4 parameters so and then how can I initialize a typedef dynamically; knowing that I only need to have 4 ULONG_PTR arguments assigned to FuncPtr
?
I understand this question may appear confusing to some, but please let me know if I should clarify any aspect of it.
It is possible but difficult to do. What you are asking for cannot be done in straight C++, you would have to drop down to the Assembly layer instead. Assuming you are working with 32bit x86 (64bit x64 is harder to deal with), you would have to either:
PUSH
a duplicate of each argument value of CallFunc()
onto the call stack, then CALL
the pointed-to function, and then finally remove the duplicate arguments from the call stack if the pointed-to function uses the cdecl
(or similar) calling convention that requires the caller to perform call stack cleanup (which you would have to know ahead of time).
have CallFunc()
simply JMP
into the pointed-to function so it reads CallFunc()
arguments as if they were its own, and then let it RET
urn directly to the code that called CallFunc()
. However, CallFunc()
must use the exact same calling convention as the pointed-to function in order for this to work. So you will need to have multiple CallFunc()
style functions for different calling conventions.