如何在macOS系统中使用汇编代码执行/bin/ls类可执行文件?
问题解答
1. 路径倒序写入的原因
x86架构默认采用小端序存储数据,同时栈的生长方向是从高内存地址向低内存地址延伸。我们需要在栈中构造C风格的正序字符串/bin//ls(额外加的/是为了凑4字节对齐,不影响路径解析),就需要从字符串的尾部开始倒序压入四字节数据:
- 字符串
/bin//ls的字节序列为0x2f 0x62 0x69 0x6e 0x2f 0x2f 0x6c 0x73,末尾需要加0x00作为字符串终止符 - 小端序下,压入四字节数值
0x736c2f2f时,内存中从低到高会存储为0x2f 0x2f 0x6c 0x73,对应//ls - 再压入四字节数值
0x6e69622f,内存中从低到高存储为0x2f 0x62 0x69 0x6e,对应/bin - 之前压入的
eax(值为0)刚好作为字符串终止符,最终栈中从低地址开始的内容就是完整的正序字符串/bin//ls\0
2. 适配macOS的汇编代码修改
你提到的规则是对的:macOS的系统调用号需要加0x2000000前缀,且参数传递规则和Linux不同。注意现在新的macOS版本已经停止支持32位程序,下面分别提供32位兼容版本和常用的64位版本实现:
2.1 32位x86 macOS版本
macOS 32位系统调用采用栈传递参数,参数按照从右到左的顺序压栈,系统调用号存入eax后触发int 0x80:
global start start: xor eax, eax ; 构造 /bin//ls 字符串,末尾补0 push eax push 0x736c2f2f ; 对应 //ls push 0x6e69622f ; 对应 /bin mov ebx, esp ; path参数:字符串地址 ; 构造argv数组:argv[0] = path, argv[1] = NULL push eax push ebx mov ecx, esp ; argv参数:数组地址 xor edx, edx ; envp参数:空环境变量 ; 系统调用号:execve编号为59,加macOS前缀 mov eax, 0x200003b ; 按从右到左顺序压入三个参数 push edx push ecx push ebx int 0x80
编译运行(仅支持旧版macOS):
nasm -f macho32 exec_ls.s -o exec_ls.o ld -o exec_ls exec_ls.o -arch i386 -lSystem ./exec_ls
2.2 64位x86_64 macOS版本
现在主流macOS均为64位,系统调用采用寄存器传递参数,顺序为rdi、rsi、rdx、r10、r8、r9,对应第一到第六个参数,系统调用号存入rax后触发syscall指令,要求栈16字节对齐:
global start start: xor rax, rax ; 构造 /bin//ls 字符串,末尾补0 push rax push 0x736c2f2f ; 对应 //ls push 0x6e69622f ; 对应 /bin mov rdi, rsp ; 第一个参数:path路径地址 ; 构造argv数组 push rax push rdi mov rsi, rsp ; 第二个参数:argv数组地址 xor rdx, rdx ; 第三个参数:envp空环境变量 ; 系统调用号 mov rax, 0x200003b syscall
编译运行:
nasm -f macho64 exec_ls.s -o exec_ls.o ld -o exec_ls exec_ls.o -macosx_version_min 10.15 -lSystem ./exec_ls
内容的提问来源于stack exchange,提问作者l4x3
相关产品推荐
相关产品推荐

