11

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

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

4 回答 4

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 调用。谁知道。

于 2008-12-29T03:52:15.510 回答
12

评论空间不够。Joe_Muc 是正确的。您不应该将代码填充到由mallocor获得的内存中new。如果您更改 Windows 分配的页面的页面属性,您将遇到问题。

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

请注意,您可能应该进行三个分配,一个保护页面,您的代码需要的页面,然后是另一个保护页面。这将为您提供一些免受不良代码影响的保护。

还使用结构化异常处理包装对生成代码的调用。

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

您可以在此处找到 64 位调用约定。

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

英特尔AMD 的处理器手册是很好的参考资料——如果你没有它们,请获取它们。

于 2008-12-29T05:20:30.137 回答
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)();

请注意,除非您将页面标记为可执行,否则您的处理器可能不会让您执行在堆上生成的代码。

于 2008-12-29T03:14:15.743 回答
0

我目前也在研究执行生成的代码,虽然这里的答案并没有准确地告诉我我需要什么,但你们让我走上了正确的轨道。

如果您需要在 POSIX 系统(Linux、BSD 等)上将页面标记为可执行,请查看mmap(2) 函数

于 2012-01-12T22:28:43.797 回答