在堆栈上为execve创建一个arg数组

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在堆栈上为execve创建一个arg数组相关的知识,希望对你有一定的参考价值。

[我想编写一个通过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的程序集。

以上是关于在堆栈上为execve创建一个arg数组的主要内容,如果未能解决你的问题,请参考以下文章

execv() 和 const-ness

如何在 Swift 上为堆栈声明“如果可选”

subprocess execv() arg 2 must contain only strings

subprocess.Popen execve()arg 3包含非字符串值

替换或删除后台堆栈上现有片段的代码不起作用

从后台堆栈恢复片段时的 savedInstanceState