Free Pascal中执行字节数组作为函数触发访问冲突的技术问询
问题分析与解决方案
这种场景完全可行!你触发Access Violation的核心原因是内存页的执行权限限制:你从内存转储得到的字节数组,默认存储在普通的读写内存区域(比如全局数组或栈上),而现代操作系统的DEP(数据执行保护)机制会禁止CPU执行这类非可执行区域的代码,所以你赋值指针没问题,但调用时就会触发异常。
下面分平台给你具体的解决步骤:
Windows平台实现步骤
- 首先需要用
VirtualAlloc分配一块带有执行权限的内存区域,这是关键:#include <Windows.h> // 假设这是你转储得到的函数字节数组(示例为x86架构的int add(int a, int b)函数指令) unsigned char calcFuncBytes[] = { 0x55, 0x8B, 0xEC, 0x8B, 0x45, 0x08, 0x03, 0x45, 0x0C, 0x5D, 0xC3 }; int main() { size_t funcSize = sizeof(calcFuncBytes); // 分配可执行内存:MEM_COMMIT | MEM_RESERVE 标记,权限设为PAGE_EXECUTE_READWRITE void* execMemory = VirtualAlloc(NULL, funcSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (execMemory == NULL) { // 处理内存分配失败,比如打印GetLastError()排查问题 return 1; } - 把字节数组复制到这块可执行内存中:
memcpy(execMemory, calcFuncBytes, funcSize); - 将内存指针转换为对应的函数指针类型,然后就可以正常调用了:
// 定义函数指针类型,必须和原函数的签名完全匹配 typedef int(*CalcFunction)(int, int); CalcFunction callableCalc = (CalcFunction)execMemory; // 调用测试,这里应该返回30 int result = callableCalc(10, 20); - 使用完毕后记得释放内存:
VirtualFree(execMemory, 0, MEM_RELEASE); return 0; }
Linux/macOS平台实现步骤
- 用
mmap分配带执行权限的匿名内存:#include <sys/mman.h> #include <string.h> #include <stdio.h> // 示例为x86_64架构的int add(int a, int b)函数指令 unsigned char calcFuncBytes[] = { 0x55, 0x48, 0x89, 0xE5, 0x8B, 0x45, 0x10, 0x03, 0x45, 0x08, 0x5D, 0xC3 }; int main() { size_t funcSize = sizeof(calcFuncBytes); // 分配可执行内存:权限设为PROT_READ | PROT_WRITE | PROT_EXEC,使用MAP_PRIVATE | MAP_ANONYMOUS创建匿名映射 void* execMemory = mmap(NULL, funcSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (execMemory == MAP_FAILED) { perror("mmap failed"); return 1; } - 复制字节数组到可执行内存:
memcpy(execMemory, calcFuncBytes, funcSize); - 转换指针并调用:
typedef int(*CalcFunction)(int, int); CalcFunction callableCalc = (CalcFunction)execMemory; // 调用测试,这里应该返回40 int result = callableCalc(15, 25); printf("Result: %d\n", result); - 释放内存:
munmap(execMemory, funcSize); return 0; }
额外注意事项
- 确保你转储的字节数组和当前运行平台的指令集完全匹配:比如原函数是x64的,就不能在x86进程里执行这些字节,否则会触发非法指令异常。
- 如果你在更严格的安全环境下运行,建议先分配读写内存,写入字节后再修改权限为只读+执行(Windows用
VirtualProtect,Linux用mprotect),这样能避免内存被意外篡改,更安全。 - 因为你的函数是简单计算(无外部调用、无字符串操作),所以不需要处理重定位、导入表这些复杂问题,直接复制执行即可。
内容的提问来源于stack exchange,提问作者GrowingBrick
相关产品推荐
相关产品推荐

