能否编写纯机器码?精简Linux x86-64可执行文件从零编写
提取x86-64机器码并生成极简可执行文件的方法
为什么编译后会有大量零字节?
你用ld链接生成的ELF文件,会因为段对齐要求(默认按4KB页大小对齐)填充大量零字节,再加上ELF头部、节表等元数据,导致文件体积远超实际指令的大小。要提取纯指令机器码,完全可以跳过多余的填充和元数据。
步骤1:直接提取纯指令机器码
用nasm的二进制输出模式,直接生成仅包含指令字节的文件,无需链接:
nasm -f bin -o exit_raw.bin exit.asm
这个exit_raw.bin就是纯机器码,没有任何多余内容。用xxd查看十六进制:
xxd exit_raw.bin
对应你的指令,机器码如下:
mov rax, 60→48 c7 c0 3c 00 00 00mov rdi, 0→48 c7 c7 00 00 00 00syscall→0f 05
步骤2:生成可运行的极简ELF文件
Linux内核只识别ELF格式的可执行文件,纯指令二进制无法直接运行。你可以手动构造最小ELF头部,和指令拼接成可执行文件:
- 编写包含ELF头部的汇编文件(
minimal_exit.asm):
BITS 64 org 0x400000 ; ELF64 头部 ehdr: db 0x7f, "ELF", 2, 1, 1, 0 ; 魔数与标识 times 8 db 0 dw 2 ; 文件类型(可执行) dw 0x3e ; 架构(x86-64) dd 1 ; 版本 dq _start ; 程序入口地址 dq phdr - $$ ; 程序头部偏移 dq 0 ; 节表偏移(无节表) dd 0 ; 标志 dw ehdrsize ; 头部大小 dw phdrsize ; 程序头部条目大小 dw 1 ; 程序头部条目数量 dw 0 ; 节表条目大小(无) dw 0 ; 节表条目数量(无) dw 0 ; 节名字符串表索引(无) ehdrsize equ $ - ehdr ; 程序头部(描述代码段) phdr: dd 1 ; 类型(加载段) dd 5 ; 权限(读+执行) dq 0 ; 文件偏移 dq $$ ; 虚拟地址 dq $$ ; 物理地址 dq filesize ; 文件大小 dq filesize ; 内存大小 dq 0x1000 ; 对齐要求 phdrsize equ $ - phdr ; 核心指令 _start: mov rax, 60 mov rdi, 0 syscall filesize equ $ - $$
- 编译成可执行文件:
nasm -f bin -o minimal_exit minimal_exit.asm chmod +x minimal_exit
这个文件只有几十字节,没有多余零字节,直接运行即可退出。
步骤3:手动编写纯机器码
如果你想完全手动写十六进制字节,可以把ELF头部和指令的十六进制拼接,用xxd转成二进制:
- 创建
exit.hex文件,内容为ELF头部+指令的十六进制:
7f454c46020101000000000000000000 02003e00010000007800400000000000 40000000000000000000000000000000 00000000400038000100000005000000 00000000000040000000000000004000 18000000000000000010000000000000 48c7c03c00000048c7c7000000000f05
- 转换为可执行文件:
xxd -r -p exit.hex > exit_manual chmod +x exit_manual
内容的提问来源于stack exchange,提问作者avighnac
相关产品推荐
相关产品推荐

