shellcode 在两个循环而不是一个循环中执行
shellcode is executed in two loops instead of one
我已成功构建我的 shell代码。
[BITS 64]
segment .text
global _start
_start: jmp call
back: lea rsi, [rsp]
mov rdi, [rsi]
xor rax, rax
push rax
lea rdx, [rsp]
mov al, 0x3b
syscall
call: call back
db "/bin/sh",0
但是代码执行有些神秘。我仍然无法弄清楚问题出在哪里,也许有人可以提供帮助。
当我使用 radare2 调试代码时,设置参数和系统调用的整个过程执行了两次。我不知道它有什么问题。寄存器、rip 等看起来不错。最后, shell 在第二个循环后弹出。但是对于在堆栈上执行它是一个痛苦的屁股,因为我的 /bin/sh 在第二个循环中搞砸了。
第一个系统调用 returns -14(地址错误)
我已经尝试了一些代码变体和 RTFM。帮助
提前谢谢你:)
嗯,argv
数组格式不正确。
您将该参数设置为堆栈上的地址,但没有放置空指针来终止它。
这是执行 _start
的第一条指令时的(下部)堆栈:
...
0
argN
...
arg0
argc <-- rsp
请注意,这些是您的 程序的参数。另请注意,<--
表示“指向”(或:包含地址)。
调用back
时堆栈为:
...
0
argN
...
arg0
count
ptr to shell path <-- rsp
lea
之后(顺便说一句,具有这种简单寻址模式的lea
只是一个mov
)和xor
之后,堆栈是:
...
0
argN
...
arg0
count
ptr to shell path <-- rsp, rsi
rdi = ptr to shell path
然后就在 syscall
之前我们有:
...
0
argN
...
arg0
count
ptr to shell path <-- rsi
rdi = ptr to shell path
0 <-- rsp, rdx
然后 execve
将从 rdi
(检查)读取可执行路径,从 rdx
(检查)读取 envp
,以及 argv
来自 rsi
(失败)。
最后一个失败,因为 execve
将从 shell 的路径向上读取堆栈到第一个 0,但 count
不是有效指针(它可能是 1)。
如果系统调用失败,执行将进入 call back
,重复这些步骤,但这次来自上一次迭代的 0 将正确终止 argv
:
...
0
argN
...
arg0
count
ptr to shell path
0
ptr to shell path <-- rsi
rdi = ptr to shell path
0 <-- rsp, rdx
您可以:
- 什么也不做,就这样保留它作为调用 shell 的一种棘手方法(请注意,
count
的某些值可以解释为有效指针,从而使 shell一个论点)。
- 将
count
更改为零。您可以将 xor eax, eax
向上移动并使用 mov [rsp+8], rax
。只要您可以在 [rsp+8]
. 写入,这在其他情况下也适用
- 自己推一个零。在寄存器中弹出 return 地址,然后在压入零后压入它,或者使用
xchg
或类似的。
- 将
argv
和 envp
作为 NULL
传递(即,将 rsi
和 rdx
归零)。在 Linux 上,这与您已经在做的事情具有相同的效果(传递带有单个空指针的数组)。
- 如果你想将你的程序参数传递给shell,你可以双击弹出然后压入return地址或者弹出return地址并使用
mov
覆盖 count
.
我已成功构建我的 shell代码。
[BITS 64]
segment .text
global _start
_start: jmp call
back: lea rsi, [rsp]
mov rdi, [rsi]
xor rax, rax
push rax
lea rdx, [rsp]
mov al, 0x3b
syscall
call: call back
db "/bin/sh",0
但是代码执行有些神秘。我仍然无法弄清楚问题出在哪里,也许有人可以提供帮助。
当我使用 radare2 调试代码时,设置参数和系统调用的整个过程执行了两次。我不知道它有什么问题。寄存器、rip 等看起来不错。最后, shell 在第二个循环后弹出。但是对于在堆栈上执行它是一个痛苦的屁股,因为我的 /bin/sh 在第二个循环中搞砸了。
第一个系统调用 returns -14(地址错误)
我已经尝试了一些代码变体和 RTFM。帮助
提前谢谢你:)
嗯,argv
数组格式不正确。
您将该参数设置为堆栈上的地址,但没有放置空指针来终止它。
这是执行 _start
的第一条指令时的(下部)堆栈:
...
0
argN
...
arg0
argc <-- rsp
请注意,这些是您的 程序的参数。另请注意,<--
表示“指向”(或:包含地址)。
调用back
时堆栈为:
...
0
argN
...
arg0
count
ptr to shell path <-- rsp
lea
之后(顺便说一句,具有这种简单寻址模式的lea
只是一个mov
)和xor
之后,堆栈是:
...
0
argN
...
arg0
count
ptr to shell path <-- rsp, rsi
rdi = ptr to shell path
然后就在 syscall
之前我们有:
...
0
argN
...
arg0
count
ptr to shell path <-- rsi
rdi = ptr to shell path
0 <-- rsp, rdx
然后 execve
将从 rdi
(检查)读取可执行路径,从 rdx
(检查)读取 envp
,以及 argv
来自 rsi
(失败)。
最后一个失败,因为 execve
将从 shell 的路径向上读取堆栈到第一个 0,但 count
不是有效指针(它可能是 1)。
如果系统调用失败,执行将进入 call back
,重复这些步骤,但这次来自上一次迭代的 0 将正确终止 argv
:
...
0
argN
...
arg0
count
ptr to shell path
0
ptr to shell path <-- rsi
rdi = ptr to shell path
0 <-- rsp, rdx
您可以:
- 什么也不做,就这样保留它作为调用 shell 的一种棘手方法(请注意,
count
的某些值可以解释为有效指针,从而使 shell一个论点)。 - 将
count
更改为零。您可以将xor eax, eax
向上移动并使用mov [rsp+8], rax
。只要您可以在[rsp+8]
. 写入,这在其他情况下也适用
- 自己推一个零。在寄存器中弹出 return 地址,然后在压入零后压入它,或者使用
xchg
或类似的。 - 将
argv
和envp
作为NULL
传递(即,将rsi
和rdx
归零)。在 Linux 上,这与您已经在做的事情具有相同的效果(传递带有单个空指针的数组)。 - 如果你想将你的程序参数传递给shell,你可以双击弹出然后压入return地址或者弹出return地址并使用
mov
覆盖count
.