有时候用函数指针是很方便的,可是太多了以后,是不是觉得typedef看的烦啊?
要是能够直接调用任意函数就好了。下面就有一个这样的实现。(网上抄的,改了一点,觉得很实用)
还支持返回值的哦。
#include <windows.h>
#include <stdio.h>
BYTE code[] =
{
0x58,//POP EAX
0x87, 0x04, 0xE4,//XCHG DWORD PTR SS:[ESP],EAX
0x50,//PUSH EAX
0xC3//RETN
};
typedef int (WINAPIV *StdCall)(FARPROC, ...);
StdCall MyStdCall = (StdCall)code;//如果是Windows Server系列,还需要给code加上执行权限
int main()
{
HMODULE hModule = LoadLibraryA("User32.dll");
if (hModule)
{
FARPROC pfn;
pfn = GetProcAddress(hModule, "MessageBoxTimeoutA");
MyStdCall(pfn, 0, (char*)"这是一个定时关闭对话框!", (char*)"提示", 32,0,1000);
pfn = GetProcAddress(hModule, "MessageBoxA");
int x = MyStdCall(pfn, 0, (char*)"这是一个对话框!", (char*)"提示", 4);
printf("返回值:%d\n", x);
FreeLibrary(hModule);
}
system("pause");
}
执行过程分析:
就用MessageBoxA吧,如果是直接调用MessageBoxA会PUSH 4个参数,然后调用MyStdCall,则会多PUSH一个MessageBoxA的地址。
并且在call MyStdCall的时候,还会PUSH进去一个返回的地址。
现在看看code[]吧,首先取出栈顶的返回地址到EAX,这样MessageBoxA的地址就成了栈顶了。随后交换这两个地址。再次压入EAX(MessageBoxA地址),关键就在于此处了,此时堆栈中存放的地址分别为:MessageBoxA地址,主程序需要返回的地址,MessageBoxA的各个参数。我们知道,ret的作用就是把栈顶取出来JMP。
所以,看见现在的堆栈顺序,是不是和call MessageBoxA一样啦?