将数组 (argv) 传递给程序集 x64 中的系统调用

Passing an array (argv) to a syscall in assembly x64

我正在学习创建 shell 代码并且玩得很开心。我基本上明白该怎么做。我可以创建实际生成 shell 的 asm 代码。但是,我打算通过尝试另一个系统调用来验证我的能力,即 cat .

我正在使用从寄存器构建堆栈的方法。但是,我 运行 遇到了一个问题,我需要将数组传递给 'argv' 参数。这在做 shell 时很简单,我可以只传递堆栈上 /bin/sh 字符串的地址。但是对于 cat 我需要传递函数的名称 /bin/catcat 的参数,即 /etc/issue.

我知道系统调用的布局是:

rax : syscall ID
rdi : arg0
rsi : arg1
rdx : arg2
r10 : arg3
r8 : arg4
r9 : arg5

我无法破译的是如何将 {"cat","/etc/issue"} 传递到单个寄存器,即 rsi。

我的程序集:

global _start
section .text
_start:
;third argument
xor rdx,rdx

;second array member
xor rbx,rbx
push rbx ;null terminator for upcoming string
;push string in 2 parts
mov rbx,6374652f ;python '/etc/issue'[::-1].encode().hex()
push rbx
xor rbx,rbx
mov rbx, 0x65757373692f
push rbx

;first array member
xor rcx,rcx ;null terminator for upcoming string
add rcx,0x746163 ;python 'cat'[::-1].encode().hex()
push rcx

;first argument
xor rdi,rdi
push rdi ;null terminator for upcoming string
add rdi,7461632f6e69622f ;python '/bin/cat'[::-1].encode().hex()
push rdi
mov rdi,rsp

;execve syscall
xor rax,rax
add rax,59

;exit call
xor rdi,rdi
xor rax,rax
add rax,60

它运行但(如预期的那样)当 NULL 作为 argv 传递时中止。

我什至尝试编写一个 C 应用程序来创建一个数组并退出并调试它,但我仍然不明白它在做什么来创建数组。

你使这种方式变得比你需要的更复杂。以下是您需要做的所有事情:

    jmp .afterdata
.pathname:
    db '/bin/' ; note lack of null terminator
.argv0:
    db 'cat'
.endargv0:
    db 1 ; we'll have to change the last byte to a null manually
.argv1:
    db '/etc/issue'
.endargv1:
    db 1 ; we'll have to change the last byte to a null manually
.afterdata:
    xor eax, eax ; the null terminator for argv and envp
    push rax
    mov rdx, rsp ; rdx = envp
    dec byte [rel .endargv1] ; change our 1 byte to a null byte
    lea rax, [rel .argv1]
    push rax
    dec byte [rel .endargv0] ; change our 1 byte to a null byte
    lea rax, [rel .argv0]
    push rax
    mov rsi, rsp ; rsi = argv
    lea rdi, [rel .pathname]
    xor eax, eax
    mov al, 59 ; SYS_execve
    syscall
    ; if you wanted to do an exit in case the execve fails, you could here, but for shellcode I don't see the point

您不需要手动对字符串进行任何十六进制编码或反转。你可以把你需要的字符串放在你的 shellcode 的末尾,然后使用 rip-relative 寻址将它们的地址压入堆栈。我们跳过的唯一环节是确保数据在使用它的指令之前,因此那里没有空字节,并且必须在运行时在字符串上添加空终止符。

此外,您通常希望 shellcode 很短。请注意我是如何指向 /bin/cat 的一部分的 cat 而不是让它有额外的时间,并在 argv 末尾为 envp.[=18 重用空值=]

顺便说一下,如果你想把它作为一个独立的程序来尝试,你需要将 -Wl,-N-static 传递给 GCC,因为它修改的字节将在 .text 部分(通常是只读的)。当您实际将它用作 shellcode 时,这不会成为问题,因为它仍然可以通过您首先将它放入内存的任何方式写入。