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

时间:2021-06-15 03:15:32

Imagine I am doing something like this:

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

void *p = malloc (1000);
*((char*)p) = some_opcode;
*((char*)p+1) = another_opcode; // for the sake of the example: the opcodes are ok

....
etc...

How can I define a function pointer to call p as if it was a function? (i'm using VC++ 2008 express).

如何定义一个函数指针来调用p,就像它是一个函数一样? (我使用的是VC ++ 2008 express)。

Thanks

4 个解决方案

#1


A comment wasn't enough space. Joe_Muc is correct. You should not stuff code into memory obtained by malloc or new. You will run into problems if you change the page properties of pages that Windows allocates.

评论的空间不够。 Joe_Muc是对的。你不应该将代码填充到malloc或new获得的内存中。如果更改Windows分配的页面的页面属性,则会遇到问题。

This isn't a problem becuase using VirtualAlloc() and the related WIn32 APIs is every easy: call VirtualAlloc() and set the flProtect to [PAGE_EXECUTE_READWRITE][2]

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

Note, you should probably do three allocations, one guard page, the pages you need for your code, then another guard page. This will give you a little protection from bad code.

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

Also wrap calls to your generated code with structured exception handling.

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

Next, the Windows X86 ABI (calling conventions) are not well documented (I know, I've looked). There is some info here, here, here The best way to see how things work is to look at code generated by the compiler. This is easy to do with the \FA switches ( there are four of them).

接下来,Windows X86 ABI(调用约定)没有很好的文档记录(我知道,我看过)。这里有一些信息,这里,这里查看工作原理的最佳方法是查看编译器生成的代码。这很容易用\ FA开关(有四个)。

You can find the 64-bit calling conventions here.

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

Also, you can still obtain Microsoft's Macro Assembler MASM here. I recommend writing your machine code in MASM and look at its output, then have your machine code generator do similar things.

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

Intel's and AMD's processor manuals are good references - get them if you don't have them.

英特尔和AMD的处理器手册是很好的参考 - 如果你没有它们,请拿到它们。

#2


Actually, malloc probably won't cut it. On Windows you probably need to call something like [VirtualAlloc](http://msdn.microsoft.com/en-us/library/aa366887(VS.85).aspx) in order to get an executable page of memory.

实际上,malloc可能不会削减它。在Windows上,您可能需要调用类似[VirtualAlloc](http://msdn.microsoft.com/en-us/library/aa366887(VS.85).aspx)的内容,以获取可执行的内存页面。

Starting small:

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)();
}

The next step for playing nice with your code is to preserve the EBP register. This is left as an exercise. :-)

使用代码的下一步是保留EBP寄存器。这是一个练习。 :-)

After writing this, I ran it with malloc and it also worked. That may be because I'm running an admin account on Windows 2000 Server. Other versions of Windows may actually need the VirtualAlloc call. Who knows.

写完之后,我用malloc运行它,它也有效。这可能是因为我在Windows 2000 Server上运行管理员帐户。其他版本的Windows实际上可能需要VirtualAlloc调用。谁知道。

#3


If you have the right opcodes in place, calling can be as simple as casting to a function pointer and calling it.

如果你有正确的操作码,调用就像转换为函数指针并调用它一样简单。

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)();

Note though that unless you mark the page as executable, your processor may not let you execute code generated on the heap.

请注意,除非您将页面标记为可执行文件,否则您的处理器可能无法执行堆上生成的代码。

#4


I'm also currently looking into executing generated code, and while the answers here didn't give me precisely what I needed, you guys sent me on the right track.

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

If you need to mark a page as executable on POSIX systems (Linux, BSD etc.), check out the mmap(2) function.

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

#1


A comment wasn't enough space. Joe_Muc is correct. You should not stuff code into memory obtained by malloc or new. You will run into problems if you change the page properties of pages that Windows allocates.

评论的空间不够。 Joe_Muc是对的。你不应该将代码填充到malloc或new获得的内存中。如果更改Windows分配的页面的页面属性,则会遇到问题。

This isn't a problem becuase using VirtualAlloc() and the related WIn32 APIs is every easy: call VirtualAlloc() and set the flProtect to [PAGE_EXECUTE_READWRITE][2]

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

Note, you should probably do three allocations, one guard page, the pages you need for your code, then another guard page. This will give you a little protection from bad code.

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

Also wrap calls to your generated code with structured exception handling.

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

Next, the Windows X86 ABI (calling conventions) are not well documented (I know, I've looked). There is some info here, here, here The best way to see how things work is to look at code generated by the compiler. This is easy to do with the \FA switches ( there are four of them).

接下来,Windows X86 ABI(调用约定)没有很好的文档记录(我知道,我看过)。这里有一些信息,这里,这里查看工作原理的最佳方法是查看编译器生成的代码。这很容易用\ FA开关(有四个)。

You can find the 64-bit calling conventions here.

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

Also, you can still obtain Microsoft's Macro Assembler MASM here. I recommend writing your machine code in MASM and look at its output, then have your machine code generator do similar things.

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

Intel's and AMD's processor manuals are good references - get them if you don't have them.

英特尔和AMD的处理器手册是很好的参考 - 如果你没有它们,请拿到它们。

#2


Actually, malloc probably won't cut it. On Windows you probably need to call something like [VirtualAlloc](http://msdn.microsoft.com/en-us/library/aa366887(VS.85).aspx) in order to get an executable page of memory.

实际上,malloc可能不会削减它。在Windows上,您可能需要调用类似[VirtualAlloc](http://msdn.microsoft.com/en-us/library/aa366887(VS.85).aspx)的内容,以获取可执行的内存页面。

Starting small:

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)();
}

The next step for playing nice with your code is to preserve the EBP register. This is left as an exercise. :-)

使用代码的下一步是保留EBP寄存器。这是一个练习。 :-)

After writing this, I ran it with malloc and it also worked. That may be because I'm running an admin account on Windows 2000 Server. Other versions of Windows may actually need the VirtualAlloc call. Who knows.

写完之后,我用malloc运行它,它也有效。这可能是因为我在Windows 2000 Server上运行管理员帐户。其他版本的Windows实际上可能需要VirtualAlloc调用。谁知道。

#3


If you have the right opcodes in place, calling can be as simple as casting to a function pointer and calling it.

如果你有正确的操作码,调用就像转换为函数指针并调用它一样简单。

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)();

Note though that unless you mark the page as executable, your processor may not let you execute code generated on the heap.

请注意,除非您将页面标记为可执行文件,否则您的处理器可能无法执行堆上生成的代码。

#4


I'm also currently looking into executing generated code, and while the answers here didn't give me precisely what I needed, you guys sent me on the right track.

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

If you need to mark a page as executable on POSIX systems (Linux, BSD etc.), check out the mmap(2) function.

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