首页 > 解决方案 > shellcode 在两个循环而不是一个循环中执行

问题描述

我成功地构建了我的 shellcode。

[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调试代码时,设置参数和系统调用的整个过程会执行两次。我不知道它有什么问题。寄存器,翻录等看起来不错。最后,shell 在第二个循环后弹出。但是对于在堆栈上执行来说,这是一件很痛苦的事情,因为我的 /bin/sh 在第二个循环中搞砸了。

第一个系统调用返回 -14(错误地址)

我已经尝试了一些代码变体和 RTFM。帮助

先感谢您 :)

标签: linuxassemblyx86-64shellcode

解决方案


好吧,argv数组格式不正确。您将该参数设置为堆栈上的地址,但您没有放置空指针来终止它。

这是执行第一条指令时的堆栈(下部)_start

...
0
argN
...
arg0
argc <-- rsp

请注意,这些是您的程序的参数。另请注意,这<--意味着“指向”(或:包含的地址)。

何时back调用堆栈是:

...
0
argN
...
arg0
count
ptr to shell path <-- rsp

leas (顺便说一下,lea这种简单的寻址模式只是 a 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(检查)、envprdx(检查)和argvrsi(失败)读取可执行路径。
最后一个失败,因为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].
  • 自己推一个零。要么在寄存器中弹出返回地址,然后在推入零后将其推入,或者使用xchg或类似的。
  • 通过argvenvp作为NULL(即归零rsirdx)。在 Linux 上,这与您已经在执行的操作具有相同的效果(使用单个空指针传递数组)。
  • 如果你想将你的程序参数传递给 shell,你可以 double pop 然后推送返回地址或弹出返回地址并使用 amov覆盖count

推荐阅读