1、看《揭秘java虚拟机》,其中提到C中用函数指针直接执行二进制代码,如下:
#include <stdio.h>
char code[] = {0x55,0x48,0x89,0xe5,0x89,0x7d,0xfc,0x48,
0x89,0x75,0xf0,0xb8,0x5a,0x00,0x00,0x00,0xc9,0xc3,0x00};
int main(){
int (*fun)();
fun = (void*)code;
int i = fun();
printf("get this done. returned: %d \n", i);
return 0;
}
编译后报错segmentation fault, google到答案大概是说这段二进制会保存在程序的数据段,没有可执行权限,然后编译的时候加上选项gcc -z execstack,可以解决.
2、不过还有另外一个思路,(Another way to do it without making everything executable is to copy this binary machine code into an executable buffer.)就是把这段二进制代码放到可执行buffer里,如下,不加参数编译后可以正常执行。
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <stdio.h>
char code[] = {0x55,0x48,0x89,0xe5,0x89,0x7d,0xfc,0x48,
0x89,0x75,0xf0,0xb8,0x5a,0x00,0x00,0x00,0xc9,0xc3,0x00};
/*
00000000004004b4 <main> 55 push %rbp
00000000004004b5 <main+0x1> 48 89 e5 mov %rsp,%rbp
00000000004004b8 <main+0x4> 89 7d fc mov %edi,-0x4(%rbp)
00000000004004bb <main+0x7> 48 89 75 f0 mov %rsi,-0x10(%rbp)
----------- 00000000004004bf <main+0xb> b8 5a 00 00 00 mov $0x2a,%eax 'return 90;'
00000000004004c4 <main+0x10> c9 leaveq
00000000004004c5 <main+0x11> c3 retq
*/
int main()
{
void *buf;
/* copy code to executable buffer */
buf = mmap (0,sizeof(code),PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_ANON,-1,0);
memcpy (buf, code, sizeof(code));
__builtin___clear_cache(buf, buf+sizeof(code)-1); // on x86 this just stops memcpy from optimizing away as a dead store
/* run code */
int (*fun)();
fun = (void*)buf;
int i = fun();
printf("get this done. returned: %d \n", i);
return 0;
}