如何写一个缓冲区溢出的GCC,Windows XP中,利用x86的? [英] How to write a buffer-overflow exploit in GCC,windows XP,x86?

查看:159
本文介绍了如何写一个缓冲区溢出的GCC,Windows XP中,利用x86的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  void函数(INT A,INT B,INT C){
   炭缓冲器1 [5];
   炭缓冲器2 [10];
   INT * RET;   RET =缓冲器1 + 12;
   (* RET)+ = 8; //为什么是8?
}无效的主要(){
  INT X;  X = 0;
  函数(1,2,3);
  X = 1;
  的printf(%d个\\ N,X);
}

上面演示就是从这里开始:

http://insecure.org/stf/smashstack.html

但它不会在这里工作:

  D:\\试验>的gcc -Wall -Wextra hw.cpp&放大器;&安培; A.EXE
hw.cpp:在函数'void函数(INT,INT,INT):
hw.cpp:6:警告:未使用的变量'缓冲器2'
hw.cpp:在全球范围内:
hw.cpp:4:警告:​​未使用的参数'A'
hw.cpp:4:警告:​​未使用的参数'B'
hw.cpp:4:警告:​​未使用的参数'C'
1

和我不明白为什么这是8,虽然笔者认为:


  

一个小的数学告诉我们的距离
  8个字节。


我的GDB转储为名为:

 汇编code的转储为主要功能:
0x004012ee<主+ 0计算值:推%EBP
0x004012ef<主+ 1计算值:MOV%ESP,EBP%
0x004012f1<主+3 ;:子$为0x18,ESP%
0x004012f4<主+ 6计算值:和$ 0xfffffff0,ESP%
0x004012f7<主+ 9计算值:MOV $为0x0,%eax中
0x004012fc<主+ 14计算值:加$ 0xF的,EAX%
0x004012ff<主+ 17计算值:加$ 0xF的,EAX%
0x00401302<主+ 20计算值:SHR $为0x4,%eax中
0x00401305<主+ 23计算值:SHL $为0x4,%eax中
0x00401308<主+ 26计算值:MOV EAX%,0xfffffff8(%EBP)
0x0040130b<主+ 29计算值:MOV 0xfffffff8(%EBP),EAX%
0x0040130e<主+ 32计算值:调用0x401b00<&_alloca GT;
0x00401313<主+ 37计算值:调用0x4017b0< __主>
0x00401318<主+ 42计算值:MOVL $ 0x0,0xfffffffc(EBP%)
0x0040131f<主+ 49计算值:MOVL $ 0x3,0x8(%ESP)
0x00401327<主+ 57计算值:MOVL $ 0x2,0x4(%ESP)
0x0040132f<主+ 65计算值:MOVL $为0x1(%ESP)
0x00401336<主+ 72计算值:调用0x4012d0<作用>
0x0040133b<主+ 77计算值:MOVL $ 0x1,0xfffffffc(EBP%)
0x00401342<主+ 84计算值:MOV 0xfffffffc(%EBP),EAX%
0x00401345<主+ 87计算值:MOV EAX%,为0x4(%ESP)
0x00401349<主+ 91计算值:MOVL $ 0x403000(%ESP)
0x00401350<主+ 98计算值:调用0x401b60< printf的>
0x00401355<主+ 103计算值:离开
0x00401356<主+ 104计算值:RET
0x00401357<主+ 105计算值:NOP
0x00401358<主+ 106计算值:添加%人(%EAX)
0x0040135a<主+ 108计算值:添加%人(%EAX)
0x0040135c<主+ 110 GT ;:添加%人(%EAX)
0x0040135e<主+ 112 GT ;:添加%人(%EAX)
汇编转储结束。汇编code的功能函数的转储:
0x004012d0<作用+ 0计算值:推%EBP
0x004012d1<作用+ 1计算值:MOV%ESP,EBP%
0x004012d3<作用+3 ;:子$ 0x38,%尤
0x004012d6<作用+ 6计算值:LEA 0xffffffe8(EBP%),%EAX
0x004012d9<作用+ 9计算值:加$ 0xC的,EAX%
0x004012dc<作用+ 12计算值:MOV EAX%,0xffffffd4(EBP%)
0x004012df<作用+ 15计算值:MOV 0xffffffd4(EBP%),EDX%
0x004012e2<作用+ 18计算值:MOV 0xffffffd4(EBP%),%EAX
0x004012e5<作用+ 21计算值:movzbl(%EAX),EAX%
0x004012e8<作用+ 24计算值:加$ 0x5的,%人
0x004012ea<作用+ 26计算值:MOV%人(%EDX)
0x004012ec<作用+ 28计算值:离开
0x004012ed<作用+ 29计算值:RET

在我的情况下,距离应该是 - ?= 5,右,但它似乎不工作。

为什么函数需要局部变量 56 字节?(子$ 0x38,%ESP


解决方案

作为<一个href=\"http://stackoverflow.com/questions/2543725/how-to-write-a-buffer-overflow-exploit-in-gcc-windows-xp-x86/2546653#2546653\">joveha指出,EIP值由调用保存在堆栈中(返回地址)需要用 7 字节递增指令( 0x00401342 - 0x0040133b = 7 ),以跳过 X = 1; 指令( MOVL $ 0x1,0xfffffffc(EBP%)

您是正确的,56字节被预留给本地变量(子$ 0x38,%ESP ),所以缺少的部分是多少字节过去缓冲器1 是保存的EIP。


测试code和内联汇编的一点告诉我,魔法值 28 作为我的测试。我不能提供一个明确的答案,为什么它是28,但我会假设编译器添加填充和/或的栈金丝雀的。


  

以下code,采用GCC 3.4.5(MinGW的)编制和Windows XP SP3(x86)的测试。


 
无符号长get_ebp(){
   __asm​​ __(流行的%ebp \\ n \\ t的
           MOVL%EBP,EAX%\\ n \\ t的
           推的%ebp \\ n \\ t的);
}void函数(INT A,INT B,INT C){
   炭缓冲器1 [5];
   炭缓冲器2 [10];
   INT * RET;   / *从缓冲器1字节距离堆栈上返回地址* /
   的printf(测试%d个\\ N,((get_ebp()+ 4) - (无符号长)缓冲器1));   RET =(INT *)(缓冲器1 + 28);   (* RET)+ = 7;
}无效的主要(){
   INT X;   X = 0;
   函数(1,2,3);
   X = 1;
   的printf(%d个\\ N,X);
}

我可以很容易地用gdb来确定此值。

(编译瓦特/ -g 来包括调试符号)

 (GDB)暂停功能
...
(GDB)运行
...
(GDB)p $ EBP
$ 1 =(无效*)0x22ff28
(GDB)P和;缓冲器1
$ 2 =(炭(*)[5])0x22ff10
(GDB)退出

0x22ff28 + 4) - 0x22ff10 = 28

(EBP值+字的大小) - 缓冲器1的地址=字节数


除了砸堆栈的乐趣和利润,我会建议读一些的我在<一提到文章href=\"http://stackoverflow.com/questions/2533261/is-there-a-buffer-overflow-helloworld-for-c/2533901#2533901\">my回答你的previous 的问题和/或其他材料上的问题。具有这种类型的究竟是如何利用作品有很好的理解应该可以帮助您编写更安全的code

void function(int a, int b, int c) {
   char buffer1[5];
   char buffer2[10];
   int *ret;

   ret = buffer1 + 12;
   (*ret) += 8;//why is it 8??
}

void main() {
  int x;

  x = 0;
  function(1,2,3);
  x = 1;
  printf("%d\n",x);
}

The above demo is from here:

http://insecure.org/stf/smashstack.html

But it's not working here:

D:\test>gcc -Wall -Wextra hw.cpp && a.exe
hw.cpp: In function `void function(int, int, int)':
hw.cpp:6: warning: unused variable 'buffer2'
hw.cpp: At global scope:
hw.cpp:4: warning: unused parameter 'a'
hw.cpp:4: warning: unused parameter 'b'
hw.cpp:4: warning: unused parameter 'c'
1

And I don't understand why it's 8 though the author thinks:

A little math tells us the distance is 8 bytes.

My gdb dump as called:

Dump of assembler code for function main:
0x004012ee <main+0>:    push   %ebp
0x004012ef <main+1>:    mov    %esp,%ebp
0x004012f1 <main+3>:    sub    $0x18,%esp
0x004012f4 <main+6>:    and    $0xfffffff0,%esp
0x004012f7 <main+9>:    mov    $0x0,%eax
0x004012fc <main+14>:   add    $0xf,%eax
0x004012ff <main+17>:   add    $0xf,%eax
0x00401302 <main+20>:   shr    $0x4,%eax
0x00401305 <main+23>:   shl    $0x4,%eax
0x00401308 <main+26>:   mov    %eax,0xfffffff8(%ebp)
0x0040130b <main+29>:   mov    0xfffffff8(%ebp),%eax
0x0040130e <main+32>:   call   0x401b00 <_alloca>
0x00401313 <main+37>:   call   0x4017b0 <__main>
0x00401318 <main+42>:   movl   $0x0,0xfffffffc(%ebp)
0x0040131f <main+49>:   movl   $0x3,0x8(%esp)
0x00401327 <main+57>:   movl   $0x2,0x4(%esp)
0x0040132f <main+65>:   movl   $0x1,(%esp)
0x00401336 <main+72>:   call   0x4012d0 <function>
0x0040133b <main+77>:   movl   $0x1,0xfffffffc(%ebp)
0x00401342 <main+84>:   mov    0xfffffffc(%ebp),%eax
0x00401345 <main+87>:   mov    %eax,0x4(%esp)
0x00401349 <main+91>:   movl   $0x403000,(%esp)
0x00401350 <main+98>:   call   0x401b60 <printf>
0x00401355 <main+103>:  leave
0x00401356 <main+104>:  ret
0x00401357 <main+105>:  nop
0x00401358 <main+106>:  add    %al,(%eax)
0x0040135a <main+108>:  add    %al,(%eax)
0x0040135c <main+110>:  add    %al,(%eax)
0x0040135e <main+112>:  add    %al,(%eax)
End of assembler dump.

Dump of assembler code for function function:
0x004012d0 <function+0>:        push   %ebp
0x004012d1 <function+1>:        mov    %esp,%ebp
0x004012d3 <function+3>:        sub    $0x38,%esp
0x004012d6 <function+6>:        lea    0xffffffe8(%ebp),%eax
0x004012d9 <function+9>:        add    $0xc,%eax
0x004012dc <function+12>:       mov    %eax,0xffffffd4(%ebp)
0x004012df <function+15>:       mov    0xffffffd4(%ebp),%edx
0x004012e2 <function+18>:       mov    0xffffffd4(%ebp),%eax
0x004012e5 <function+21>:       movzbl (%eax),%eax
0x004012e8 <function+24>:       add    $0x5,%al
0x004012ea <function+26>:       mov    %al,(%edx)
0x004012ec <function+28>:       leave
0x004012ed <function+29>:       ret

In my case the distance should be - = 5,right?But it seems not working..

Why function needs 56 bytes for local variables?( sub $0x38,%esp )

解决方案

As joveha pointed out, the value of EIP saved on the stack (return address) by the call instruction needs to be incremented by 7 bytes (0x00401342 - 0x0040133b = 7) in order to skip the x = 1; instruction (movl $0x1,0xfffffffc(%ebp)).

You are correct that 56 bytes are being reserved for local variables (sub $0x38,%esp), so the missing piece is how many bytes past buffer1 on the stack is the saved EIP.


A bit of test code and inline assembly tells me that the magic value is 28 for my test. I cannot provide a definitive answer as to why it is 28, but I would assume the compiler is adding padding and/or stack canaries.

The following code was compiled using GCC 3.4.5 (MinGW) and tested on Windows XP SP3 (x86).


unsigned long get_ebp() {
   __asm__("pop %ebp\n\t"
           "movl %ebp,%eax\n\t"
           "push %ebp\n\t");
}

void function(int a, int b, int c) {
   char buffer1[5];
   char buffer2[10];
   int *ret;

   /* distance in bytes from buffer1 to return address on the stack */
   printf("test %d\n", ((get_ebp() + 4) - (unsigned long)&buffer1));

   ret = (int *)(buffer1 + 28);

   (*ret) += 7;
}

void main() {
   int x;

   x = 0;
   function(1,2,3);
   x = 1;
   printf("%d\n",x);
}

I could have just as easily used gdb to determine this value.

(compiled w/ -g to include debug symbols)

(gdb) break function
...
(gdb) run
...
(gdb) p $ebp
$1 = (void *) 0x22ff28
(gdb) p &buffer1
$2 = (char (*)[5]) 0x22ff10
(gdb) quit

(0x22ff28 + 4) - 0x22ff10 = 28

(ebp value + size of word) - address of buffer1 = number of bytes


In addition to Smashing The Stack For Fun And Profit, I would suggest reading some of the articles I mentioned in my answer to a previous question of yours and/or other material on the subject. Having a good understanding of exactly how this type of exploit works should help you write more secure code.

这篇关于如何写一个缓冲区溢出的GCC,Windows XP中,利用x86的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆