如何在NASM汇编中正确使用execve系统调用执行cat命令输出文件?
正确调用x86_64 Linux下execve系统调用的方法
你的代码存在的核心问题
- 字符串带多余双引号:execve要求的是原始ASCII路径字符串,不需要shell的引号。你写的
"\"/bin/cat\""会让系统尝试寻找名为**"/bin/cat"(包含引号)**的程序,这显然不存在。 - 文件名拆分错误:你把
/file.txt拆成//file.t和xt,导致argv数组里的参数是两个无效的字符串指针,而非指向完整文件名的指针。 - 寄存器赋值错误:直接用
mov rdi, "\"/bin/cat\""是错误的——字符串字面量不能直接加载到64位寄存器,这行代码实际是把字符串的ASCII值当成64位整数加载,完全不是你需要的内存指针。 - argv数组构造错误:execve的第二个参数
rsi需要指向一个指针数组,每个元素是指向参数字符串的指针,最后必须以NULL指针结尾,你当前的栈结构完全不符合这个要求。
正确实现方式
方式1:使用.data段存储字符串(易读性高)
这种方式适合普通程序,把字符串和argv数组提前存在数据段:
section .data ; 程序路径,必须以NULL字节终止 cmd db "/bin/cat", 0 ; 要读取的文件路径,同样以NULL终止 arg1 db "/file.txt", 0 ; argv数组:[程序路径指针, 参数指针, NULL] argv dq cmd, arg1, 0 section .text global _start _start: mov rax, 59 ; x86_64 Linux下execve的系统调用号 mov rdi, cmd ; 第一个参数:指向程序路径的指针 mov rsi, argv ; 第二个参数:指向argv数组的指针 xor rdx, rdx ; 第三个参数:环境变量数组(传NULL表示继承当前环境) syscall
方式2:纯栈构造(适合shellcode等无.data段场景)
如果需要不依赖数据段,完全在栈上构造所有内容:
section .text global _start _start: xor rax, rax ; 清零rax,同时用来构造字符串的NULL终止符 ; 构造"/file.txt"字符串到栈上(栈向下增长,所以从字符串末尾往前压) push rax ; 压入NULL终止符 mov rbx, 0x7478742e656c6966 ; 小端序对应"txt.elif",即"file.txt"的后8字节 push rbx push byte 0x2f ; 压入"/",此时栈顶就是指向"/file.txt"的指针 mov rsi, rsp ; 暂存文件名指针到rsi ; 构造"/bin/cat"字符串到栈上 push rax ; 压入NULL终止符 mov rbx, 0x7461632f6e69622f ; 小端序对应"tac/nib/",即"/bin/cat" push rbx mov rdi, rsp ; 把程序路径指针存入rdi ; 构造argv数组:[程序路径指针, 文件名指针, NULL] push rax ; 压入NULL指针作为数组结尾 push rsi ; 压入文件名指针 push rdi ; 压入程序路径指针 mov rsi, rsp ; 让rsi指向argv数组的起始 mov al, 59 ; 加载execve系统调用号(rax高56位已为0,用al更高效) xor rdx, rdx ; 环境变量数组传NULL syscall
关键注意事项
- 字符串必须以NULL终止:execve依赖C风格字符串的NULL终止符来确定字符串长度,缺少会导致读取垃圾数据。
- x86_64系统调用参数约定:rax存系统调用号,rdi、rsi、rdx依次存前三个参数,这是Linux x86_64的固定规范。
- 栈构造的小端序问题:因为push操作是将64位值压入栈,所以字符串需要以逆序的64位值压入,才能保证栈中字节顺序正确。
内容的提问来源于stack exchange,提问作者flo456123
相关产品推荐
相关产品推荐

