shellcode 在作为单独的代码单独运行时调用不同的系统调用,而 运行 C++ 代码

shellcode calls different syscall while runing alone as individiual code and while running with C++ code

我有这样一个代码 运行 的 shell:

BITS 64

global _start
_start:

  mov rax, 59

  jmp short file
  c1:
  pop rdi

  jmp short argv
  c2:
  pop rsi

  mov rdx, 0

  syscall

file:

  call c1
  db '/bin/sh',0

argv:

  call c2
  dq arg, 0

arg:

  db 'sh',0

以这种方式构建时它可以工作:

nasm -f elf64 shcode.asm
ld shcode.o -o shcode

尽管如此,当我将其转换为二进制形式时:

nasm -f bin shcode.asm

将其粘贴到以下 C++ 代码中:

int main(void)
{

  char kod[]="\xB8\x3B\x00\x00\x00\xEB\x0B\x5F\xEB\x15\x5E\xBA\x00\x00\x00\x00\x0F\x05\xE8\xF0\xFF\xFF\xFF\x2F\x62\x69\x6E\x2F\x73\x68\x00\xE8\xE6\xFF\xFF\xFF\x34\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x73\x68\x00";
  reinterpret_cast<void(*)()>(kod)();

  return 0;

}

用 clang++ 编译 texp.cpp -o texp.e -Wl,-z,execstack 并执行,shell 不是 运行ning.

运行与

结合后
strace ./texp.e

我看到了类似的东西(我用 ^C 停止了这个过程):

syscall_0xffffffffffffffda(0x7ffc23e0a297, 0x7ffc23e0a2a4, 0, 0x4a0, 0x7fe1ff3039b0, 0x7fe1ff69b960) = -1 ENOSYS (Nie zaimplementowana funkcja)
syscall_0xffffffffffffffda(0x7ffc23e0a297, 0x7ffc23e0a2a4, 0, 0x4a0, 0x7fe1ff3039b0, 0x7fe1ff69b960) = -1 ENOSYS (Nie zaimplementowana funkcja)
.
.
.
syscall_0xffffffffffffffda(0x7ffc23e0a297, 0x7ffc23e0a2a4, 0, 0x4a0, 0x7fe1ff3039b0, 0x7fe1ff69b960) = -1 ENOSYS (Nie zaimplementowana funkcja)
^Csyscall_0xffffffffffffffda(0x7ffc23e0a297, 0x7ffc23e0a2a4, 0, 0x4a0,  0x7fe1ff3039b0, 0x7fe1ff69b960strace: Process 2806 detached
 <detached ...>

Nie zaimplementowana funkcja - 功能未实现

所以程序(又名 shell代码)可能是 运行 不正确的系统调用。

在您的 C++ shellcode 调用程序中,strace 显示您的 execve 系统调用是

execve("/bin/sh", [0x34], NULL)         = -1 EFAULT (Bad address)

后面的 syscall_0xffffffffffffffda(...) = -1 ENOSYS 来自 RAX = -EFAULT 而不是 59 的无限循环,然后来自 RAX=- ENOSYS (同样不是有效的电话号码)。这个循环是由你的 call/pop.

创建的

大概是因为您从未链接的 .o 或 PIE 可执行文件中 hexdump 了 arg 的绝对地址,这就是您将 0x34 作为绝对地址的方式。

显然,如果要从随机堆栈地址 运行 没有重定位修复,那么在 shellcode 中嵌入绝对地址的整个方法都行不通。 dq arg, 0 与位置无关。

您至少需要使用指针自己构造 argv 数组(通常使用 push)。您还可以使用 push imm32 来构造 arg 本身。例如push 'shsh' / lea rax, [rsp+2].

或者最常见的技巧是利用 Linux 特定的 "feature":您可以将 argv=NULL(而不是指向 NULL 指针的指针)与 xor esi,esi.

(使用 mov reg,0 完全违背了避免零字节的 jmp/call/pop 技巧的目的。如果允许零字节,您还不如使用普通的 RIP 相关 LEA。但如果不允许,您可以向前跳转数据,然后使用具有负位移的 RIP 相关 LEA。)