这个 shellcode 中的栈指针有什么用?

What is the stack pointer used for in this shellcode?

https://www.exploit-db.com/exploits/46907

global _start
section .text
_start:
    xor rsi,rsi
    push rsi
    mov rdi,0x68732f2f6e69622f
    push rdi
    push rsp
    pop rdi
    push 59
    pop rax
    cdq
    syscall

一条指令是push %rsp,然后在rdi中弹出它。我很迷惑。根据文档,execve 系统调用中的 rdi 应该包含可执行文件的路径名。这里跟rsp有什么关系?其他 shellcode 不操纵 rsp.

在栈上构造数据,然后将栈指针复制到另一个reg,是完全正常的。许多 shellcode 操纵 RSP。

push rsp / pop rdi 只是 mov rdi, rsp 的 2 字节版本,它是在推入 0 和 8 字节的 ASCII 数据之后出现的。 (在 NASM 语法中可以写得更清楚,如 mov rdi, '/bin//sh')。

使用调试器单步执行 asm,并在 syscall 执行时查看 RDI 指向的内存,并向后工作以了解您是如何到达那里的。


奇怪的是,他们使用 push/pop 将 mov rdi,rsp 压缩到 2 个字节,但在异或归零指令中使用了 REX 前缀。 xor esi,esi 是等价的。 NASM 会将源优化为 xor esi,esi,但您的 link 显示反汇编。

此外,push 59 / pop rax 是寄存器中的 standard 3-byte way to construct a small constant (__NR_execve),不依赖于任何其他寄存器值。他们本可以完成 lea eax, [rsi+59] 这也是 3 个字节,并且还可以避免任何 0 字节。 (5 字节 mov eax, 59 将包含一个带有三个零字节的 imm32,这就是为什么大多数 shellcode 必须避免它的原因。)

cdq 只是设置 RDX=0 (envp=NULL),因为此时 EAX 的符号为正。与 xor edx,edx 相比,另一种节省字节的代码方式。在这种情况下,他们显然知道在编写 32 位 reg (EDX) 时利用完整 64 位 reg 的隐式归零,因此更奇怪的是,他们对 RSI 使用 64 位异或归零。也许他们对 x86-64 了解不多,甚至没有意识到 cqo 会显式使用 64 位操作数大小,将 RAX 符号扩展为 RDX:RAX,并打算使用 64 -到处都是,因为他们认为他们需要。