0

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.

  • 2
    The answer is simple: you cannot know the number of parameters a functions needs by having only the function pointer. – Jabberwocky Dec 05 '16 at 07:11
  • Okay, I'd assume that is the answer a scholar would give. Can anyone provide an answer that a "hacker" would give? – Robert Peterson Dec 05 '16 at 07:13
  • Regarding the actual problem you are trying to solve, [this](http://stackoverflow.com/questions/8696653/dynamically-load-a-function-from-a-dll/23763255#23763255) might be the solution. Strictly speaking not well-defined behavior but works in practice on all Windows computers. As such, it is a hack, so it might be the answer a "hacker" would give. – Lundin Dec 05 '16 at 07:14
  • @Lundin I'm aware of how to load api's dynamically through their type definition. The actual problem I am trying to solve is figuring out how to assign the number of parameters needed to the typedef by using the Function pointer obtained from `GetProcAddress`. So instead of defining a typedef for every single API I wish to use. I can simply pass the parameters to this one function and it will resolve the API for me on-the-go AND define the appropriate number of parameters to its typedef accordingly, without all that extra (manual) work! – Robert Peterson Dec 05 '16 at 07:18
  • The point is, you shouldn't mix loading functions from the DLL with calling them. Those are two different things. You need to load all functions in advance, to ensure that the DLL is found and correct. And once you have loaded all functions, by using the method given in the link, you have all the function signatures available and you can treat them like any other function. – Lundin Dec 05 '16 at 07:21
  • @Lundin I know how to treat a function loaded from a DLL. I don't understand what you're trying to say. I am aware of how to call a function pointer by dynamically importing its respective function already (`LoadLibrary` -> `GetModuleHandle` -> `GetProcAddress` or vice versa, assuming the DLL is already loaded in the given process instance you can just resort to `GetModuleHandle` directly followed by `GetProcAddress` and obtain the address of the function pointer you are trying to resolve). But this doesn't answer my question. The specifics are clearly explained in my previous reply to you. – Robert Peterson Dec 05 '16 at 07:25
  • 1
    @RobertPeterson If you know how to do it properly, then why resort to ugly meta programming with va_list, which throws all the type safety out the door? Variable-argument lists should be avoided at all costs. – Lundin Dec 05 '16 at 07:29
  • @Lundin Because I'm the one that will be assigning the parameters to the desired functions I will be calling so I don't have to worry about type-safety as the debugging portion is all on my hands. Also, the reason I resort to them is because in my scenario I am unaware how many parameters the given function will have and what data types are provided. This way I can just call them on my own and cast them as ULONG_PTR which will give me the virtual address to the parameters passed in any given function. – Robert Peterson Dec 05 '16 at 07:32
  • Since `typedef` is just a way of giving a name to a type during compilation, you cannot dynamically modify one. – rici Dec 05 '16 at 07:53
  • This wheel has been invented. It's libffi. – David Heffernan Dec 05 '16 at 08:16
  • 1
    What you are asking for is impossible. A module's export table consists of symbol names and their offsets into the module. There is no type information available. The type information **must** be provided by the developer, at compile time (that's what your `typedef` does). Assuming `__stdcall` with functions exported using their decorated names, you could deduce the number of bytes a function's arguments take. This doesn't tell you the number of arguments, or their type, though. You are trying to solve the impossible. This is futile. – IInspectable Dec 05 '16 at 15:34
  • Why would you ever on earth need to do that? To me, it sounds like you're trying simplify something which is already simplified. I cannot see any situation where this would be useful - don't try to make C act like an interpreted language. If you want to accomplish this, just do this in python and have your C program call the python script. If you are convinced what you are doing is necessary (I would argue it isn't), you can try and write this in Assembly and combine it with your C code - which is going to be very annoying - having to assume functions are stdcall – Zach P Dec 06 '16 at 06:58

1 Answers1

0

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:

  1. 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).

  2. have CallFunc() simply JMP into the pointed-to function so it reads CallFunc() arguments as if they were its own, and then let it RETurn 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.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Rather than writing an ffi library you could use an existing one which makes the task trivially easy – David Heffernan Dec 06 '16 at 07:40
  • `1` won't work for functions with variable argument lists, because only the callee will know, how many arguments there are. And I'm not entirely sure, how well `2` performs once the optimizer kicks in. Although you surprised me again, with creativity, I'm not entirely convinced this time around, that this is indeed possible. In general, anyway. – IInspectable Dec 06 '16 at 15:59
  • @IInspectable 1 works because `CallFunc()` is the caller of the pointed-to function and knows how many arguments it is pushing and thus may need to pop. 2 is not subject to optimization if you write `CallFunc()` in pure assembly (which you should do anyway for a task like this). I've written code like this before that proxies calls from one function to another at the assembly level, even switching calling conventions where possible. It is not trivial, but it does work. – Remy Lebeau Dec 06 '16 at 16:06
  • But `1` cannot possibly know, how many arguments its caller pushed onto the stack. As an example, consider that `CallFunc` needs to call `printf`. As for `2`, I understand that inline assembly disables optimizations. But if you move one level up, are optimizations disabled for `CallFunc` as well? – IInspectable Dec 06 '16 at 16:22
  • @IInspectable: `CallFunc()` has an `nArgs` argument, it knows exactly how many arguments are being passed to it. But yes, if `nArgs` is removed, then 1 becomes more problematic and 2 is needed. What optimizations are you worried about exactly? – Remy Lebeau Dec 06 '16 at 18:22
  • Any optimization, that passes arguments in an unpredictable way (e.g. in registers for x86 code). – IInspectable Dec 07 '16 at 13:15
  • @IInspectable how parameters are passed is dictated by the calling convention, not the optimizer. – Remy Lebeau Dec 07 '16 at 16:35
  • As long as the optimizer doesn't violate the as-if rule, it can choose any way it feels fit to pass arguments. If it determines that `CallFunc` doesn't rely on parameters being passed on the stack, the optimizer can choose to pass them in registers instead (or not pass them altogether). – IInspectable Dec 07 '16 at 16:50
  • I managed to get it working following what you said in `1`, it's the answer I was looking for. Thank-you very much! – Robert Peterson Dec 09 '16 at 05:02