c++ - shellcode 在单独运行时调用不同的系统调用

标签 c++ linux assembly nasm system-calls

我有这样一段运行 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 没有运行。

运行之后

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 - 功能未实现

所以程序(又名 shellcode)可能正在运行不正确的系统调用。

最佳答案

在您的 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 特定的“功能”:您可以使用 xor esi 传递 argv=NULL(而不是指向 NULL 指针的指针) ,esi.

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

关于c++ - shellcode 在单独运行时调用不同的系统调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57285839/

相关文章:

c++ - printf 末尾的不需要的字符

linux - 别名中的转义引号

c - ssize_t 在 Linux 中定义在哪里?

c - 用 C 语言编程 Arduino,中断 vector 会起作用吗?

assembly - 调用函数后内核出现三重错误

c++ - C/C++ 中空终止字符串的长度

c++ - 正确放置 "toCSV"函数 : In each object, 还是放在通用类中?

c++ - 枚举 HWND 属性 C++

linux - 带有 http get 参数的 wget 脚本

c - 函数返回后esp的值是多少?