如何在运行时在c中定义新函数?
在c语言中,您可以将代码复制为内存块,因此我想知道是否是由一些开发人员完成的,或者是将函数的代码复制到堆中分配的块中,在堆中更改函数的代码,然后(mprotect…)执行“复制和修改”函数,这是明智和安全的,从安全角度来看,让堆块保持可执行状态可能会产生什么后果。或者有没有一种方法可以运行运行时在c中定义的代码如何在运行时在c中定义新函数?,c,function,C,Function,在c语言中,您可以将代码复制为内存块,因此我想知道是否是由一些开发人员完成的,或者是将函数的代码复制到堆中分配的块中,在堆中更改函数的代码,然后(mprotect…)执行“复制和修改”函数,这是明智和安全的,从安全角度来看,让堆块保持可执行状态可能会产生什么后果。或者有没有一种方法可以运行运行时在c中定义的代码 void* handler(void* arg1, void* arg2, void* arg3) { typedef void* (*function)(void*, void
void* handler(void* arg1, void* arg2, void* arg3) {
typedef void* (*function)(void*, void*, void*, void*);
return ((function)FUNCTION_ADDRESS_TO_REPLACE)(SELF_ADDRESS_TO_REPLACE,
arg1,
arg2,
arg3);
}
void* allocate_new_function(void* function, void* self) {
void* (*fun) () = 0;
uint64_t size = (uint64_t) &allocate_new_function - (uint64_t) &handler; //48 byte
fun = malloc(size);
memcpy(fun, handler, size);
replace(fun, size, SELF_ADDRESS_TO_REPLACE, self);
replace(fun, size, FUNCTION_ADDRESS_TO_REPLACE, function);
char *to_mprotect = (char*) (((uint64_t) fun / PAGE_SIZE) * PAGE_SIZE);
uint64_t offset = (uint64_t) fun % PAGE_SIZE;
if (offset + size > PAGE_SIZE) {
mprotect(to_mprotect,
PAGE_SIZE,
PROT_READ | PROT_EXEC | PROT_WRITE);
mprotect(to_mprotect + PAGE_SIZE,
PAGE_SIZE,
PROT_READ | PROT_EXEC | PROT_WRITE);
} else {
mprotect(to_mprotect,
PAGE_SIZE,
PROT_READ | PROT_EXEC | PROT_WRITE);
}
return fun;
}
此处,分配的_函数将使用隐式参数self执行函数“function”。有没有更好的方法来做到这一点,或者这种方法可能是有效的
配置为:--prefix=/Applications/Xcode.app/Contents/Developer/usr--gxx include dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang版本12.0.0(clang-1200.0.32.29)
目标:x86_64-apple-darwin20.2.0
线程模型:posix
InstalledDir:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xToolchain/usr/bin
mprotect
不保证与通过mmap
获取的内存一起工作。因此,您最好通过mmap
调用分配内存,而不是new
。您还依赖于生成的对象文件中函数的特定顺序,但没有任何东西可以保证这一点。函数可以以编译器或链接器选择的任何顺序出现,因此您提取函数大小的方法存在严重缺陷。是的,这是事实,但偏移量必须是页面大小的倍数,因此如果多次调用allocate_new_函数,我将浪费大量内存,如果程序崩溃,页面将保持映射状态是的,我尝试过这样做,但是我可以假设函数的最大大小,而不是精确计算值,因为处理程序非常小,替换函数在找到第一个特殊地址时停止。无论如何,您必须为代码块设置一个专用页面,否则您将更改随机内存的权限。如果您不想浪费页面,您必须实现自己的分配器,它通过mmap请求内存并使用可用页面中的内存,直到用完为止。您正在做的事情是可以做到的——毕竟,这是任何JIT优化器正在做的事情——但它需要谨慎和深思熟虑的方法才能达到生产级。作为概念证明,您的代码很好。