想象一下,我正在做这样的事情:
void *p = malloc (1000);
*((char*)p) = some_opcode;
*((char*)p+1) = another_opcode; // for the sake of the example: the opcodes are ok
....
etc...
如何定义一个函数指针来调用p,好像它是一个函数? (我使用的是VC ++ 2008 express)。
谢谢
答案 0 :(得分:12)
实际上,malloc可能不会削减它。在Windows上,您可能需要调用[VirtualAlloc](http://msdn.microsoft.com/en-us/library/aa366887(VS.85).aspx)之类的东西才能获得可执行的内存页面。
从小处开始:
void main(void)
{
char* p = (char*)VirtualAlloc(NULL, 4096, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
p[0] = (char)0xC3; // ret
typedef void (*functype)();
functype func = (functype)p;
(*func)();
}
与您的代码玩得很好的下一步是保留EBP寄存器。这是一个练习。 : - )
写完之后,我用malloc运行它,它也有效。这可能是因为我在Windows 2000 Server上运行管理员帐户。其他版本的Windows实际上可能需要VirtualAlloc调用。谁知道呢。
答案 1 :(得分:12)
评论空间不够。 Joe_Muc是对的。您不应将代码填充到malloc
或new
获取的内存中。如果更改Windows分配的页面的页面属性,则会遇到问题。
这不是问题,因为使用VirtualAlloc()并且相关的WIn32 API非常简单:致电VirtualAlloc()并将flProtect
设置为[PAGE_EXECUTE_READWRITE][2]
注意,您可能应该执行三个分配,一个保护页面,代码所需的页面,然后是另一个保护页面。这将为您提供一些不良代码保护。
还使用structured exception handling对生成的代码进行调用。
接下来,Windows X86 ABI(调用约定)没有很好地记录(我知道,我看过)。有一些信息here,here,here查看事物如何工作的最佳方法是查看编译器生成的代码。使用\FA
switches(其中有四个)很容易做到这一点。
您可以找到64位呼叫约定here。
此外,您仍然可以获得Microsoft的宏汇编程序MASM here。我建议在MASM中编写机器代码并查看其输出,然后让机器代码生成器执行类似的操作。
答案 2 :(得分:6)
如果你有正确的操作码,那么调用就像转换为函数指针并调用它一样简单。
typedef void (*voidFunc)();
char *p = malloc (1000);
p[0] = some_opcode;
p[1] = another_opcode; // for the sake of the example: the opcodes are ok
p[n] = // return opcode...
((voidFunc)p)();
请注意,除非您将页面标记为可执行文件,否则您的处理器可能无法执行堆上生成的代码。
答案 3 :(得分:0)
我目前正在考虑执行生成的代码,虽然这里的答案并没有准确地告诉我我需要什么,但是你们让我走上正轨。
如果您需要在POSIX系统(Linux,BSD等)上将页面标记为可执行文件,请查看mmap(2) function。