[我想编写一个通过EXECVE(系统调用#0x3C)使用开关-al执行程序/ bin / ls的汇编程序。
手册页(man 2 execve)指出该调用需要三个值:
int execve(const char *filename, char *const argv[], char *const envp[]);
我不太了解如何建立这三个参数。据我所知,第一个参数输入RDI
,第二个参数输入RSI
,第三个参数输入RDX
。我相信设置第一个就足够了
push 0x736c2f2f ;sl//
push 0x6e69622f ;nib/
mov rdi, rsp
对于第三个,这很容易:
xor r11, r11
mov rdx, r11
我的问题是我不知道如何构建第二个参数,该参数应该是包含['/bin//ls', '-aal']
的数组
我需要为x86-64编写它,所以请不要int 0x80
建议。
您可以在NASM中写入push '/bin'
,以使字节按该顺序进入内存。 (用4个字节的零填充,以确保qword的总宽度;在64位模式下,无法进行dword推送。)无需手动编码ASCII字符。与某些汇编程序不同,NASM不会吸收多字符文字,可以使您的生活更轻松。
使用mov dword [rsp+4], '//ls'
存储上半部分。 (或者使它成为qword存储区,用mov r/m64, sign_extended_imm32
写入超过4个字节的零。或者用另一次推送将其终止为零。
或mov eax, '//ls'
; shl eax, 8
在准备存储的寄存器中获取EAX = "/ls\0"
,以生成8字节的0终止字符串。
或使用相同的技巧,在mov r64, imm64
之后移出一个字节(就像@prl的答案一样),而不是单独的push / mov。也可以使用mov rax, imm64
/not rax
/ push rax
,在寄存器中生成零,而在机器代码中不生成零。
您可以将argv
数组放入堆栈,并将其地址加载到rsi
中。 argv
的第一个成员是指向程序名称的指针,因此我们可以使用加载到rdi
中的相同地址。
xor edx, edx ; Load NULL to be used both as the third
; parameter to execve as well as
; to push 0 onto the stack later.
push "-aal" ; Put second argument string onto the stack.
mov rax, rsp ; Load the address of the second argument.
mov rcx, "/bin//ls" ; Load the file name string
push rdx ; and place a null character
push rcx ; and the string onto the stack.
mov rdi, rsp ; Load the address of "/bin//ls". This is
; used as both the first member of argv
; and as the first parameter to execve.
; Now create argv.
push rdx ; argv must be terminated by a NULL pointer.
push rax ; Second arg is a pointer to "-aal".
push rdi ; First arg is a pointer to "/bin//ls"
mov rsi, rsp ; Load the address of argv into the second
; parameter to execve.
将以下C示例(如果需要,进行修改)加载到Godbolt编译器资源管理器中,您可以看到各种编译器通常如何生成用于调用AMD64(或其他)体系结构上的execve
的程序集。