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 或类似的。
  • argvenvp 作为 NULL 传递(即,将 rsirdx 归零)。在 Linux 上,这与您已经在做的事情具有相同的效果(传递带有单个空指针的数组)。
  • 如果你想将你的程序参数传递给shell,你可以双击弹出然后压入return地址或者弹出return地址并使用mov 覆盖 count.