执行从C二进制机器code [英] execute binary machine code from C
问题描述
这的我已成功地生产出只有528个字节的指令在大小的a.out(当GCC main.c中给了我8539个字节开始大文件)。
main.c中是:
INT主(INT ARGC,字符** argv的){ 返回42;
}
但我的a.out从这个汇编文件,而不是建:
main.s:
; tiny.asm
BITS 64
GLOBAL _start
.text段
_开始:
MOV EAX,1
MOV EBX,42
INT 0x80的
与
我@#补偿NASM -f ELF64 tiny.s
我@#补偿GCC -Wall -s -nostartfiles -nostdlib tiny.o
我@#补偿./a.out;回声$?
42
我@#补偿WC -c的a.out
528的a.out
因为我需要机器code我做的:
objdump的-d的a.outa.out格式:文件格式ELF64,X86-64
.text段拆卸:00000000004000e0<的.text计算值:
4000e0:B8 01 00 00 00 $ MOV为0x1,%eax中
4000e5:BB 2A 00 00 00 $ MOV 0x2a,EBX%
4000ea:CD 80 INT 0x80的$>#objdump的-hrt的a.outa.out格式:文件格式ELF64,X86-64部分:
IDX名称大小VMA LMA文件ALGN关闭
0 .note.gnu.build-ID 00000024 00000000004000b0 00000000004000b0 000000b0 2 ** 2
内容ALLOC,LOAD,只读,DATA
1的.text 0000000c 00000000004000e0 00000000004000e0 000000e0 2 ** 4
内容ALLOC,LOAD,只读,code
符号表:
无符号
文件是小端约定:
我@#补偿-a readelf的a.out
ELF头:
魔术:7F 45 4C 46 02 01 01 00 00 00 00 00 00 00 00 00
类别:ELF64
数据:2的补,小尾数
版本:1(电流)
OS / ABI:UNIX - 系统V
ABI版本:0
类型:EXEC(可执行文件)
机床:Advanced Micro Devices公司X86-64
版本:为0x1
入口地址:0x4000e0
程序头开始:64(字节到文件)
节头的开始:272(字节到文件)
标志:为0x0
这个头的大小:64(字节)
程序头的尺寸:56(字节)
程序头数:2
节头的大小:64(字节)
节头数:4
节头字符串表指数:3
现在我想执行这个是这样的:
的#include<&unistd.h中GT;
//哪个版本(更多)是否正确?
//这可能(???)涉及到字节序
字符code [] =\\ X01 \\ XB8 \\ X00 \\ X00 \\ XBB \\ X00 \\ X00 \\ X2A \\ X00 \\ X00 \\ X80 \\ XCD \\ X00
字符code_v1 [] =\\ XB8 \\ X01 \\ X00 \\ X00 \\ X00 \\ XBB \\ X2A \\ X00 \\ X00 \\ X00 \\ XCD \\ X80 \\ X00INT主(INT ARGC,字符** argv的)
{
/ *创建一个函数指针* /
INT(* FUNC)();
FUNC =(INT(*)())code;
(INT)(* FUNC)();返回0;
}
但是我得到分段错误。 我的问题是:这个文本栏目
4000e0:B8 01 00 00 00 $ MOV为0x1,%eax中
4000e5:BB 2A 00 00 00 $ MOV 0x2a,EBX%
4000ea:CD 80 INT 0x80的$
(本机code)所有我真的需要吗我做的不对(字节序?),也许我只需要SIGSEGV以来以不同的方式来调用这个?
我得到了这个工作。在code必须是标记为可执行code。做到这一点的方法之一是这个二进制机器code复制到可执行的缓冲区。
的#include<&unistd.h中GT;
#包括LT&; SYS / mman.h>
#包括LT&;&string.h中GT;字符code [] = {0x55,0x48,0x89,0xe5,0x89,0x7d,0xFC有,0x48,
0x89,0x75,0xf0,0xb8,0x2a,0x00,0x00,0x00,0xc9,0xc3,0x00};
/ *
* 00000000004004b4<主> 55推%RBP
00000000004004b5<主+为0x1> 48 89 E5 MOV%RSP,RBP%
00000000004004b8<主+为0x4> 89 FC 7D MOV%EDI,-0x4(RBP%)
00000000004004bb<主+ 0x7的> 48 89 75 F0 MOV%RSI,-0x10(RBP%)
/NetBeansProjects/examples/tiny_c/tiny.c:15
返回42;
00000000004004bf<主+ 0XB> B8 2A 00 00 00 $ MOV 0x2a,EAX%
/NetBeansProjects/examples/tiny_c/tiny.c:16
}
00000000004004c4<主+ 0×10> C9 leaveq
00000000004004c5<主+ 0×11> C3 retq
* /
INT主(INT ARGC,字符** argv的)
{
无效* BUF; / *副本code到可执行的缓冲区* /
BUF = MMAP(0,sizeof的(code),PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANON,-1,0);
的memcpy(BUF,code,sizeof的(code)); / *运行code * /
INT I =((INT(*)(无效))BUF)();
的printf(完成这件事返回:%D,我);
返回0;
}
输出:
完成这件事。返回:42
成功运行(总时间:57ms)
块引用>following this instructions I have managed to produce only 528 bytes in size a.out (when gcc main.c gave me 8539 bytes big file initially).
main.c was:
int main(int argc, char** argv) { return 42; }
but I have built a.out from this assembly file instead:
main.s:
; tiny.asm BITS 64 GLOBAL _start SECTION .text _start: mov eax, 1 mov ebx, 42 int 0x80
with:
me@comp# nasm -f elf64 tiny.s me@comp# gcc -Wall -s -nostartfiles -nostdlib tiny.o me@comp# ./a.out ; echo $? 42 me@comp# wc -c a.out 528 a.out
because I need machine code I do:
objdump -d a.out a.out: file format elf64-x86-64 Disassembly of section .text: 00000000004000e0 <.text>: 4000e0: b8 01 00 00 00 mov $0x1,%eax 4000e5: bb 2a 00 00 00 mov $0x2a,%ebx 4000ea: cd 80 int $0x80 ># objdump -hrt a.out a.out: file format elf64-x86-64 Sections: Idx Name Size VMA LMA File off Algn 0 .note.gnu.build-id 00000024 00000000004000b0 00000000004000b0 000000b0 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 1 .text 0000000c 00000000004000e0 00000000004000e0 000000e0 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE SYMBOL TABLE: no symbols
file is in little endian convention:
me@comp# readelf -a a.out ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x4000e0 Start of program headers: 64 (bytes into file) Start of section headers: 272 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 2 Size of section headers: 64 (bytes) Number of section headers: 4 Section header string table index: 3
now I want to execute this like this:
#include <unistd.h> // which version is (more) correct? // this might be related to endiannes (???) char code[] = "\x01\xb8\x00\x00\xbb\x00\x00\x2a\x00\x00\x80\xcd\x00"; char code_v1[] = "\xb8\x01\x00\x00\x00\xbb\x2a\x00\x00\x00\xcd\x80\x00"; int main(int argc, char **argv) { /*creating a function pointer*/ int (*func)(); func = (int (*)()) code; (int)(*func)(); return 0; }
however I get segmentation fault. My question is: is this section of text
4000e0: b8 01 00 00 00 mov $0x1,%eax 4000e5: bb 2a 00 00 00 mov $0x2a,%ebx 4000ea: cd 80 int $0x80
(this machine code) all I really need? What I do wrong (endiannes??), maybe I just need to call this in different way since SIGSEGV?
解决方案I got this done. The code must be marked as executable code. One way to do it is to copy this binary machine code into executable buffer.
#include <unistd.h> #include <sys/mman.h> #include <string.h> char code[] = {0x55,0x48,0x89,0xe5,0x89,0x7d,0xfc,0x48, 0x89,0x75,0xf0,0xb8,0x2a,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) /NetBeansProjects/examples/tiny_c/tiny.c:15 return 42; 00000000004004bf <main+0xb> b8 2a 00 00 00 mov $0x2a,%eax /NetBeansProjects/examples/tiny_c/tiny.c:16 } 00000000004004c4 <main+0x10> c9 leaveq 00000000004004c5 <main+0x11> c3 retq */ int main(int argc, char **argv) { 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)); /* run code */ int i = ((int (*) (void))buf)(); printf("get this done. returned: %d", i); return 0; }
output:
get this done. returned: 42
RUN SUCCESSFUL (total time: 57ms)
这篇关于执行从C二进制机器code的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!