我想在C中运行时生成一个函数。我的意思是我本来想分配一些内存,指向它并通过函数指针执行它。我意识到这是一个非常复杂的话题,我的问题是天真的。我也意识到有一些非常强大的库可以做到这一点(例如nanojit)。
但我想从基础开始学习这项技术。知识渊博的人能否在C中给我一个非常简单的例子?
编辑: 以下答案很棒,但以下是Windows的相同示例:
#include <Windows.h>
#define MEMSIZE 100*1024*1024
typedef void (*func_t)(void);
int main() {
HANDLE proc = GetCurrentProcess();
LPVOID p = VirtualAlloc(
NULL,
MEMSIZE,
MEM_RESERVE|MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
func_t func = (func_t)p;
PDWORD code = (PDWORD)p;
code[0] = 0xC3; // ret
if(FlushInstructionCache(
proc,
NULL,
0))
{
func();
}
CloseHandle(proc);
VirtualFree(p, 0, MEM_RELEASE);
return 0;
}
答案 0 :(得分:4)
如前面其他海报所说,你需要很好地了解你的平台。
忽略将对象指针强制转换为函数指针的问题,从技术上讲,UB,这是一个适用于x86 / x64 OS X(也可能是Linux)的示例。生成的所有代码都返回给调用者。
#include <unistd.h>
#include <sys/mman.h>
typedef void (*func_t)(void);
int main() {
/*
* Get a RWX bit of memory.
* We can't just use malloc because the memory it returns might not
* be executable.
*/
unsigned char *code = mmap(NULL, getpagesize(),
PROT_READ|PROT_EXEC|PROT_WRITE,
MAP_SHARED|MAP_ANON, 0, 0);
/* Technically undefined behaviour */
func_t func = (func_t) code;
code[0] = 0xC3; /* x86 'ret' instruction */
func();
return 0;
}
显然,这在不同平台上会有所不同,但它概述了所需的基础知识:获取内存的可执行部分,编写指令,执行指令。
答案 1 :(得分:3)
这需要您了解您的平台。例如,您平台上的C调用约定是什么?参数存储在哪里?什么寄存器保存返回值?必须保存和恢复哪些寄存器?一旦你知道了,你基本上可以编写一些C代码将代码组装到一个内存块中,然后将该内存转换为函数指针(虽然这在ANSI C中是技术上禁止的,并且如果你的平台标记了一些页面,它将无法工作内存为非可执行的又名NX位。)
简单的方法是编写一些代码,编译它,然后反汇编它,看看哪些字节对应哪些指令。您可以编写一些C代码,用该字节集填充已分配的内存,然后将其强制转换为相应类型的函数指针并执行。
最好先阅读架构和编译器的calling conventions。然后学习编写可以从C调用的程序集(即遵循调用约定)。
答案 2 :(得分:2)
如果您有工具,他们可以帮助您更轻松地完成某些工作。例如,我可以在C中编写代码,而不是尝试设计正确的函数prologue / epilogue:
int foo(void* Data)
{
return (Data != 0);
}
然后(Windows下的MicrosoftC)将其提供给“cl / Fa / c foo.c”。然后我可以看一下“foo.asm”:
_Data$ = 8
; Line 2
push ebp
mov ebp, esp
; Line 3
xor eax, eax
cmp DWORD PTR _Data$[ebp], 0
setne al
; Line 4
pop ebp
ret 0
我还可以使用“dumpbin / all foo.obj”来查看函数的确切字节:
00000000: 55 8B EC 33 C0 83 7D 08 00 0F 95 C0 5D C3
只需节省一些时间让字节完全正确......