将数组 (argv) 传递给程序集 x64 中的系统调用
Passing an array (argv) to a syscall in assembly x64
我正在学习创建 shell 代码并且玩得很开心。我基本上明白该怎么做。我可以创建实际生成 shell 的 asm 代码。但是,我打算通过尝试另一个系统调用来验证我的能力,即 cat
.
我正在使用从寄存器构建堆栈的方法。但是,我 运行 遇到了一个问题,我需要将数组传递给 'argv' 参数。这在做 shell 时很简单,我可以只传递堆栈上 /bin/sh
字符串的地址。但是对于 cat
我需要传递函数的名称 /bin/cat
和 cat
的参数,即 /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 时,这不会成为问题,因为它仍然可以通过您首先将它放入内存的任何方式写入。
我正在学习创建 shell 代码并且玩得很开心。我基本上明白该怎么做。我可以创建实际生成 shell 的 asm 代码。但是,我打算通过尝试另一个系统调用来验证我的能力,即 cat
.
我正在使用从寄存器构建堆栈的方法。但是,我 运行 遇到了一个问题,我需要将数组传递给 'argv' 参数。这在做 shell 时很简单,我可以只传递堆栈上 /bin/sh
字符串的地址。但是对于 cat
我需要传递函数的名称 /bin/cat
和 cat
的参数,即 /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 时,这不会成为问题,因为它仍然可以通过您首先将它放入内存的任何方式写入。