@TrollerCoaster
that was a nice try, but unfortunately, it will fail.
let me explain why.
you tried it on a __stdcall function, where stack is fixed by the callee
now, the ordinary function expects 2 parameters, but you passed 14 of them!
so the stack would look like
Code:
1500
500
uninitialized
uninitialized
uninitialized
uninitialized
uninitialized
uninitialized
uninitialized
uninitialized
uninitialized
uninitialized
uninitialized
uninitialized
when it returns, it pops only first two, leaving those uninitialized ints on stack, which would cause errors.
also, if you call a __cdecl function, it will leave everything except one parameter!
and if you try to call __thiscall or __fastcall, you wont be able to modify ecx and edx registers!
anyway i wrote a function that will do the job for you, hope you are good at asm!
Code:
enum CALLINGCONV
{
CALLINGONV_STDCALL,
CALLINGCONV_CDECL,
CALLINGCONV_THISCALL,
CALLINGCONV_FASTCALL,
};
int callsomething(void* func, CALLINGCONV cc, int* args, unsigned int count)
{
int retval;
if (cc == CALLINGCONV_THISCALL && count < 1) return 0; //__thiscall function must have at least one parameter (this pointer)
__asm
{
push ecx; //save original values
push esi;
push edi;
push eax; //calculate stack size
mov eax, 4;
mov ecx, count;
mul ecx;
mov ecx, eax;
pop eax;
sub esp, ecx; //put parameters on stack
mov esi, args;
mov edi, esp;
rep movs [edi], byte ptr [esi];
cmp cc, CALLINGCONV_THISCALL; //check if calling convention was __thiscall
jne not_thiscall;
pop ecx; //remove first parameter from stack and put it on ecx
not_thiscall:
cmp cc, CALLINGCONV_FASTCALL; //check if calling convention was __fastcall
jne neither;
mov esi, count; //check parameter count
cmp esi, 1; //make sure we have 1 parameters or more
jl neither;
pop ecx; //remove first parameter from stack and put it on ecx
mov esi, count; //check parameter count
cmp esi, 2; //make sure we have 1 parameters or more
jl neither;
pop edx; //remove second parameter from stack and put it on edx
neither:
call func; //lets call the function
mov retval, eax; //save return value
cmp cc, CALLINGCONV_CDECL; //if calling convention was __cdecl, perform a stack clean up
jne not_cdecl;
push eax;
mov eax, 4;
mov ecx, count;
mul ecx;
mov ecx, eax;
pop eax;
add esp, ecx;
not_cdecl:
pop edi; //restore original values
pop esi;
pop ecx;
}
return retval;
}
compile it in visual studio 
example:
Code:
void hey(int arg1, int arg2, int arg3, int arg4) //default calling convention is __cdecl
{
cout << arg1 << ", " << arg2 << ", " << arg3 << ", " << arg4 << endl;
}
void __fastcall hey2(int arg1, int arg2, int arg3, int arg4)
{
cout << arg1 << ", " << arg2 << ", " << arg3 << ", " << arg4 << endl;
}
class myclass
{
public:
int arg1;
void hey3(int arg2, int arg3, int arg4) //this one should be __thiscall
{
cout << arg1 << ", " << arg2 << ", " << arg3 << ", " << arg4 << endl;
}
};
//you cant convert &myclass::hey3 to void*, so i came up with this trick..
struct hack
{
typedef void (myclass::*myfunc)(int,int,int);
myfunc pp;
};
int main()
{
FARPROC func = GetProcAddress(LoadLibraryA("kernel32.dll"), "Beep");
myclass my;
my.arg1 = 5;
hack hk;
hk.pp = &myclass::hey3;
int beeparg[2] = {1500, 500};
int myargs[4] = {5, 10, 51, 11};
int thisargs[4] = {(int)&my, 10, 51, 11};
callsomething((void*)func, CALLINGONV_STDCALL, beeparg, 2);
callsomething((void*)hey, CALLINGCONV_CDECL, myargs, 4);
callsomething((void*)hey2, CALLINGCONV_FASTCALL, myargs, 4);
callsomething((void*)(*(int*)(&hk)), CALLINGCONV_THISCALL, thisargs, 4);
}
hope comments explained everything