从vc ++调用存储在堆中的代码

时间:2008-12-29 03:10:42

标签: c++ pointers assembly function-pointers opcode

想象一下,我正在做这样的事情:

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)。

谢谢

4 个答案:

答案 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是对的。您不应将代码填充到mallocnew获取的内存中。如果更改Windows分配的页面的页面属性,则会遇到问题。

这不是问题,因为使用VirtualAlloc()并且相关的WIn32 API非常简单:致电VirtualAlloc()并将flProtect设置为[PAGE_EXECUTE_READWRITE][2]

注意,您可能应该执行三个分配,一个保护页面,代码所需的页面,然后是另一个保护页面。这将为您提供一些不良代码保护。

还使用structured exception handling对生成的代码进行调用。

接下来,Windows X86 ABI(调用约定)没有很好地记录(我知道,我看过)。有一些信息hereherehere查看事物如何工作的最佳方法是查看编译器生成的代码。使用\FA switches(其中有四个)很容易做到这一点。

您可以找到64位呼叫约定here

此外,您仍然可以获得Microsoft的宏汇编程序MASM here。我建议在MASM中编写机器代码并查看其输出,然后让机器代码生成器执行类似的操作。

Intel'sAMD's处理器手册是很好的参考资料 - 如果您没有这些参考资料,请获取它们。

答案 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