【问题标题】:Return from Shellcode instead of exit从 Shellcode 返回而不是退出
【发布时间】:2020-04-10 16:34:26
【问题描述】:

我正在为 uni 做一个共享的内存分配,我已经“借用”和“按摩”了一些我在我在这里和其他地方读过的帖子中看到的 shellcode。我已经能够构建一个在我的 MacBook (Mojave) 上运行的示例,并且几乎可以满足我的需求。

但是,由于我没有在 OS 环境(本例中为 MacOS)中进行汇编编程的经验,并且由于我不完全理解下面的汇编,因此我需要一些帮助来克服我的最后一个问题。

在我的 C 样板包装器中,我有一个循环定期调用我的 shellcode,但该循环只执行一次迭代。这使我得出结论,第二个syscall(在下面的代码中)正在执行exit 0,从而终止了进程。

如何将程序集修改为 return 而不是 exit

注意如果被问到,我可以发布有关我正在使用的包装器代码和工具的更多信息。

bits 64

Section .text
  global start

start:
  jmp       short MESSAGE     ;00000000  EB24              jmp short 0x26

GOBACK:
  mov       eax, 0x2000004    ;00000002  B804000002        mov eax,0x2000004  ; write
  mov       edi, 0x1          ;00000007  BF01000000        mov edi,0x1
  lea       rsi, [rel msg]    ;0000000C  488D3518000000    lea rsi,[rel 0x2b]
  mov       edx, 0xf          ;00000013  BA0F000000        mov edx,0xf
  syscall                     ;00000018  0F05              syscall

  mov       eax,0x2000001     ;0000001A  B801000002        mov eax,0x2000001  ;exit
  mov       edi,0x0           ;0000001F  BF00000000        mov edi,0x0
  syscall                     ;00000024  0F05              syscall


MESSAGE:
  call      GOBACK
  msg:      db      "Hello, world!", 0dh, 0ah
  .len:     equ     $ - msg

这是我的 C 样板代码,其中包括上面的 shellcode。

#include <string.h>
#include <sys/mman.h>
#include <unistd.h>

const char shellcode[] = "\xeb\x24\xb8\x04\x00\x00\x02\xbf\x01\x00\x00\x00\x48\x8d\x35\x18\x00\x00\x00\xba\x0f\x00\x00\x00\x0f\x05\xb8\x01\x00\x00\x02\xbf\x00\x00\x00\x00\x0f\x05\xe8\xd7\xff\xff\xff\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x21\x0d\x0a";

int main(int argc, char **argv)
{
  void *mem = mmap(0, sizeof(shellcode), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);

  memcpy(mem, shellcode, sizeof(shellcode));

  mprotect(mem, sizeof(shellcode), PROT_READ|PROT_WRITE|PROT_EXEC);

  for (int i = 0; i < 10; i++) {
    int (*func)();
    func = (int (*)())mem;
    (int)(*func)();
    sleep(5);
  }

  munmap(mem, sizeof(shellcode));

  return 0;
}

【问题讨论】:

  • 你知道你想return吗?
  • 如果你想从中ret,你只是在用机器代码而不是asm编写一个函数。如果您将此代码作为缓冲区溢出的一部分注入,这将不会起作用,因为它不会在堆栈上使用返回地址调用(除非您的有效负载包含额外的返回地址)。
  • @PeterCordes,是的,我明白你的意思。只是我有一段时间没有做任何汇编级编码,我不确定是否需要系统调用才能返回。
  • 查看编译器为整个函数生成的代码。这就是ret 指令的用途! How to remove "noise" from GCC/clang assembly output?(使用系统调用来修改你自己线程的架构状态,比如设置程序计数器 (RIP),会非常慢。)

标签: c macos assembly shellcode


【解决方案1】:

我有一个循环调用我的 shellcode

因此,如果它是一个实际的 call,那么您就可以开始了,您需要做的唯一更改是删除最后 3 条指令(movmovsyscall)并将它们替换为ret 因为返回地址已经在堆栈上。但是我们需要额外清理一下堆栈,因为文本字符串的地址是为了syscall而放在那里的,我们希望在返回之前将其删除。

此外,由于您的 shellcode 包含偏移量(第一个 jmp 操作码的值为 0x24),因此不删除任何内容(因为它会更改偏移量)而是替换为 NOP 会更安全。除非您修改 shellcode 的源代码并每次都生成它 - 否则删除东西是可以的。

所以我实际上建议做的是将构成最后 3 个操作码的字节替换为 0x90(NOP) 并将最后 2 个字节替换为 pop rax\ret 所以字节 0x58 和 @987654333 @。最终的 shellcode 可能如下所示:

const char shellcode[] = "\xeb\x24\xb8\x04\x00\x00\x02\xbf\x01\x00\x00\x00\x48\x8d\x35\x18\x00\x00\x00\xba\x0f\x00\x00\x00\x0f\x05\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x58\xc3\xe8\xd7\xff\xff\xff\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x21\x0d\x0a";

【讨论】:

  • 谢谢!在阅读了您的评论和回答后,我添加了样板来展示我如何执行 shellcode。这是通过函数调用。我会试着消化你的建议,看看我能取得什么成就。
  • 第一次打印 hello 后,使用您的第一个建议会导致 seg 错误。如何获取要返回的地址,是否需要在 shellcode 开始时将任何内容压入堆栈?
  • 感谢您的代码。我今天会检查并更新答案
  • 我已经更新了答案,应该没问题 - 尽管明天我可以在 MacOS 上验证这一点,除非它对你有用。
  • 是的,我正在使用 NASM 从汇编源代码生成 shellcode。我正在使用 Shellme.py 从目标文件中提取字节码。当objdump无法反汇编指令并使用标签&lt;unknown&gt;而不是助记符时,我不得不稍微修改一下Shellme。
猜你喜欢
  • 2013-10-15
  • 1970-01-01
  • 2012-05-15
  • 2019-11-06
  • 2021-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多