编写用于syscall 59的NASM汇编char*数组时遇命令未找到问题
64位NASM汇编执行
/bin/bash -c "echo hello; ls -la"的问题 我尝试编写64位NASM汇编程序,启动时执行命令:/bin/bash -c "echo hello; ls -la",当前的汇编代码如下:
section .text global _start _start: BITS 64 jmp short two one: pop rbx mov [rbx+34], rbx xor al, al mov [rbx+9], al mov [rbx+12], al mov [rbx+33], al xor rdx, rdx mov [rbx+66], rdx mov rcx, rbx add rcx, 10 mov [rbx+42], rcx add rcx, 3 mov [rbx+50], rcx add rcx, 53 mov [rbx+58], rcx mov rdi, rbx lea rsi, [rbx+34] mov rax, 59 syscall two: call one db '/bin/bash', 0xFF db '-c', 0xFF db '"echo hello; ls -la"', 0xFF db 'AAAAAAAA' db 'BBBBBBBB' db 'CCCCCCCC' db 'DDDDDDDD' db 'FFFFFFFF'
作为汇编新手,我的理解是只需将多个指针连续存放在内存中,因此把实际参数的指针存入占位的AAAAAAAA至FFFFFFFF内存区域,并在syscall前将首个引用地址移入rsi。但程序运行报错,结束时rsi指向0x4000e9,对应的内存数据如下:
0x4000c7: 0x2f 0x62 0x69 0x6e 0x2f 0x62 0x61 0x73 0x4000cf: 0x68 0x00 0x2d 0x63 0x00 0x22 0x65 0x63 0x4000d7: 0x68 0x6f 0x20 0x68 0x65 0x6c 0x6c 0x6f 0x4000df: 0x3b 0x20 0x6c 0x73 0x20 0x2d 0x6c 0x61 0x4000e7: 0x22 0x00 0xc7 0x00 0x40 0x00 0x00 0x00 0x4000ef: 0x00 0x00 0xd1 0x00 0x40 0x00 0x00 0x00 0x4000f7: 0x00 0x00 0xd4 0x00 0x40 0x00 0x00 0x00 0x4000ff: 0x00 0x00 0x09 0x01 0x40 0x00 0x00 0x00 0x400107: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
gdb猜测的参数如下:
Guessed arguments: arg[0]: 0x4000c7 ("/bin/bash") arg[1]: 0x4000e9 --> 0x4000c7 ("/bin/bash") arg[2]: 0x0 arg[3]: 0x400109 --> 0x0
程序运行时的错误信息:
: echo hello; ls -la: command not found
问题根源
- 字符串多余双引号:
-c参数不需要外层双引号,你在字符串中加入的"会被bash当成命令的一部分,导致它尝试执行"echo这个不存在的命令。 - argv数组构造错误:execve要求argv数组以NULL结尾,你代码中给最后一个元素设置了无效指针,而非0,导致bash收到错误的参数列表。
- 指针计算失误:构造第三个参数指针时错误地给rcx加了53,这完全偏离了目标字符串的起始地址。
修正后的代码
section .text global _start _start: BITS 64 jmp short two one: pop rbx ; rbx指向字符串起始位置 ; 将各字符串的终止符替换为0(Linux C风格字符串要求) xor al, al mov [rbx+9], al ; /bin/bash的终止符(共9字节) mov [rbx+12], al ; -c的终止符(/bin/bash+终止符共10字节,-c占2字节) mov [rbx+33], al ; echo hello; ls -la的终止符(起始于rbx+13,长度20) ; 构造argv数组:[&"/bin/bash", &"-c", &"echo hello; ls -la", NULL] mov [rbx+34], rbx ; argv[0] = /bin/bash的地址 mov rcx, rbx add rcx, 10 ; rcx指向"-c"的起始地址 mov [rbx+42], rcx ; argv[1] = -c的地址 add rcx, 3 ; rcx指向命令字符串起始地址(-c+终止符共3字节) mov [rbx+50], rcx ; argv[2] = 命令字符串地址 xor rdx, rdx mov [rbx+58], rdx ; argv[3] = NULL,数组终止 ; 调用execve系统调用 mov rdi, rbx ; rdi = 程序路径地址 lea rsi, [rbx+34] ; rsi = argv数组地址 xor rdx, rdx ; rdx = envp(设为NULL) mov rax, 59 ; execve的系统调用号 syscall two: call one db '/bin/bash', 0xFF db '-c', 0xFF db 'echo hello; ls -la', 0xFF ; argv数组占位空间(4个8字节指针,共32字节) db 'AAAAAAAA' db 'BBBBBBBB' db 'CCCCCCCC' db 'DDDDDDDD'
修正点说明
- 移除命令字符串的外层双引号,直接传递
echo hello; ls -la作为-c的参数。 - 将argv数组最后一个元素设为NULL,确保参数列表正确终止。
- 修正第三个参数的指针计算,指向命令字符串的正确起始位置。
- 将envp参数设为NULL,让bash继承当前环境变量。
运行修正后的代码即可正确执行目标命令,输出hello和当前目录的文件列表。
内容的提问来源于stack exchange,提问作者Jimmyboy
相关产品推荐
相关产品推荐

