另:下一个程序就没运行成功...抓狂ing..找到栈底也不能定位环境变量阿....可能是我还不明白吧...希望有人指点指点!~
书中提到的第一个缓冲区溢出的测试程序,原文代码如下:
代码: 全选
#include <stdio.h>
#include <string.h>
char largebuff[] =
"1234512345123451234512345===ABCD";
int main (void)
{
char smallbuff[16];
strcpy (smallbuff,largebuff);
}
Program received signal SIGSEGV, Segmentation fault.
0x44434241 in ?? ()
正好是倒过来的ABCD,可是在ubuntu下按照例子调试确始终不得其解...于是有了此文...
一步一步来吧..先看看我开始调试时的问题:
先按照例子走:
代码: 全选
ojjou@ojjou-laptop:~$ gcc -o simple_overflow simple_overflow.c
ojjou@ojjou-laptop:~$ gdb simple_overflow
GNU gdb 6.6-debian
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".(后文用省略号代替.这里还是留着吧.)
(gdb) r
Starting program: /home/ojjou/simple_overflow
*** stack smashing detected ***: /home/ojjou/simple_overflow terminated
Program received signal SIGABRT, Aborted.
0xffffe410 in __kernel_vsyscall ()
却不是书上说的0x44434241 in ?? ()
这里是第一个问题了..于是:
代码: 全选
(gdb) disas main #得到如下代码
Dump of assembler code for function main:
0x080483d4 <main+0>: lea 0x4(%esp),%ecx
0x080483d8 <main+4>: and $0xfffffff0,%esp
0x080483db <main+7>: pushl 0xfffffffc(%ecx)
0x080483de <main+10>: push %ebp
0x080483df <main+11>: mov %esp,%ebp
0x080483e1 <main+13>: push %ecx
0x080483e2 <main+14>: sub $0x34,%esp
0x080483e5 <main+17>: mov %gs:0x14,%eax
0x080483eb <main+23>: mov %eax,0xfffffff8(%ebp)
0x080483ee <main+26>: xor %eax,%eax
0x080483f0 <main+28>: movl $0x8049620,0x4(%esp)
0x080483f8 <main+36>: lea 0xffffffe8(%ebp),%eax
0x080483fb <main+39>: mov %eax,(%esp)
0x080483fe <main+42>: call 0x8048308 <strcpy@plt>
0x08048403 <main+47>: mov 0xfffffff8(%ebp),%edx
0x08048406 <main+50>: xor %gs:0x14,%edx
0x0804840d <main+57>: je 0x8048414 <main+64>
0x0804840f <main+59>: call 0x8048318 <__stack_chk_fail@plt>
#看这一行..原文中是没有调用这个代码的,这是意思就像那函数名字一样:栈保护- -!
0x08048414 <main+64>: add $0x34,%esp
0x08048417 <main+67>: pop %ecx
0x08048418 <main+68>: pop %ebp
---Type <return> to continue, or q <return> to quit---Quit
(gdb)
于是:
代码: 全选
ojjou@ojjou-laptop:~$ gcc -fno-stack-protector -o simple_overflow simple_overflow.c
ojjou@ojjou-laptop:~$ gdb simple_overflow
......
......
(gdb) r
Starting program: /home/ojjou/simple_overflow
Program received signal SIGSEGV, Segmentation fault.
0x080483a0 in main () /*可是还是没有对阿!!哎.. 看下面代码知道执行到
0x080483a0 <main+44>: ret 时停住了*/
(gdb) disas main
Dump of assembler code for function main:
0x08048374 <main+0>: lea 0x4(%esp),%ecx
0x08048378 <main+4>: and $0xfffffff0,%esp
0x0804837b <main+7>: pushl 0xfffffffc(%ecx) #注意这一句!也是没有的!
0x0804837e <main+10>: push %ebp
0x0804837f <main+11>: mov %esp,%ebp
0x08048381 <main+13>: push %ecx /*这就是问题的关键!还是gcc的问题..
如果要覆盖返回地址...就会把ecx也覆盖
掉但是ecx却保存着esp的指向.于是
ret的时候就停了...esp的指向被
覆盖了*/
0x08048382 <main+14>: sub $0x24,%esp
0x08048385 <main+17>: movl $0x80495a0,0x4(%esp)
0x0804838d <main+25>: lea 0xffffffec(%ebp),%eax
0x08048390 <main+28>: mov %eax,(%esp)
0x08048393 <main+31>: call 0x80482c0 <strcpy@plt>
0x08048398 <main+36>: add $0x24,%esp
0x0804839b <main+39>: pop %ecx
0x0804839c <main+40>: pop %ebp
0x0804839d <main+41>: lea 0xfffffffc(%ecx),%esp /*由于ecx的值改变了
所以esp的值也会被
改变..于是下句ret就
出错了,eip的值仍然
没有被覆盖*/
0x080483a0 <main+44>: ret
End of assembler dump.
这也是gcc的问题.实践中发现..现在的gcc版本会把main函数的代码写成如下:
lea 0x4(%esp),%ecx
and $0xfffffff0,%esp
pushl 0xfffffffc(%ecx)
push %ebp
mov %esp,%ebp
push %ecx
而不是简单的写成:
push %ebp
mov %esp,%ebp /*无疑多了层溢出保护!!这样就算覆盖了返回地址也会必然覆盖esp.
导致指向不到那句:call *0x8(ebp) 意思就是让eip的值等
于ebp+8;*/
于是把程序修改成:
代码: 全选
#include <stdio.h>
#include <string.h>
char largebuff[] =
"1234512345123451234512345===ABCD";
void copyout(void)
{
char smallbuff[16];
strcpy (smallbuff,largebuff);
}
int main (void)
{
copyout(); #只是加了个嵌套而已..
}
ojjou@ojjou-laptop:~$ gcc -fno-stack-protector -o simple_overflow simple_overflow.c
ojjou@ojjou-laptop:~$ gdb simple_overflow
......
......
(gdb) r
Starting program: /home/ojjou/simple_overflow
Program received signal SIGSEGV, Segmentation fault.
0x34333231 in ?? () #虽然没有得到原文答案...但是已经溢出了!仔细看看这不就是"4321"么!
(gdb) i reg
eax 0xbfc2f3c8 -1077742648
ecx 0xb7be5e28 -1212260824
edx 0x80495c1 134518209
ebx 0xb7f56ff4 -1208651788
esp 0xbfc2f3e0 0xbfc2f3e0
ebp 0x35343332 0x35343332
esi 0xb7f86ce0 -1208455968
edi 0x0 0
eip 0x34333231 0x34333231 #eip已经修改!!!
eflags 0x210246 [ PF ZF IF RF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) disas main
Dump of assembler code for function main:
0x0804838f <main+0>: lea 0x4(%esp),%ecx
0x08048393 <main+4>: and $0xfffffff0,%esp
0x08048396 <main+7>: pushl 0xfffffffc(%ecx)
0x08048399 <main+10>: push %ebp
0x0804839a <main+11>: mov %esp,%ebp
0x0804839c <main+13>: push %ecx
0x0804839d <main+14>: sub $0x4,%esp
0x080483a0 <main+17>: call 0x8048374 <copyout>
0x080483a5 <main+22>: add $0x4,%esp
0x080483a8 <main+25>: pop %ecx
0x080483a9 <main+26>: pop %ebp
0x080483aa <main+27>: lea 0xfffffffc(%ecx),%esp
0x080483ad <main+30>: ret
End of assembler dump.
(gdb) disas copyout
Dump of assembler code for function copyout:
0x08048374 <copyout+0>: push %ebp
0x08048375 <copyout+1>: mov %esp,%ebp
0x08048377 <copyout+3>: sub $0x18,%esp #由于对齐不一样的缘故把和书
中不太一样
0x0804837a <copyout+6>: movl $0x80495a0,0x4(%esp)
0x08048382 <copyout+14>: lea 0xfffffff0(%ebp),%eax
0x08048385 <copyout+17>: mov %eax,(%esp)
0x08048388 <copyout+20>: call 0x80482c0 <strcpy@plt>
0x0804838d <copyout+25>: leave
0x0804838e <copyout+26>: ret
End of assembler dump.
(gdb) b *0x08048374
Breakpoint 1 at 0x8048374
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/ojjou/simple_overflow
Breakpoint 1, 0x08048374 in copyout ()
(gdb) display /i $pc
1: x/i $pc 0x8048374 <copyout>: push %ebp
(gdb) si
0x08048375 in copyout ()
1: x/i $pc 0x8048375 <copyout+1>: mov %esp,%ebp
(gdb)
0x08048377 in copyout ()
1: x/i $pc 0x8048377 <copyout+3>: sub $0x18,%esp
(gdb)
0x0804837a in copyout ()
1: x/i $pc 0x804837a <copyout+6>: movl $0x80495a0,0x4(%esp)
(gdb)
0x08048382 in copyout ()
1: x/i $pc 0x8048382 <copyout+14>: lea 0xfffffff0(%ebp),%eax
(gdb)
0x08048385 in copyout ()
1: x/i $pc 0x8048385 <copyout+17>: mov %eax,(%esp)
(gdb)
0x08048388 in copyout ()
1: x/i $pc 0x8048388 <copyout+20>: call 0x80482c0 <strcpy@plt>
(gdb) x/s 0x80495a0
0x80495a0 <largebuff>: "1234512345123451234512345===ABCD"
(gdb) i reg $eax
eax 0xbfd76d08 -1076400888
(gdb) i reg ebp
ebp 0xbfd76d18 0xbfd76d18
/*ebp-eax=0x10 故需要20个字节才能覆盖返回地址*/
原程序改为:
#include <stdio.h>
#include <string.h>
char largebuff[] =
"12345123451234512===ABCD";
void copyout(void)
{
char smallbuff[16];
strcpy (smallbuff,largebuff);
}
int main (void)
{
copyout();
}
代码: 全选
[ojjou@ojjou-laptop:~$ gcc -fno-stack-protector -o simple_overflow simple_overflow.c
[ojjou@ojjou-laptop:~$ gdb simple_overflowGNU gdb 6.6-debian
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
(gdb) r
Starting program: /home/ojjou/simple_overflow
Program received signal SIGSEGV, Segmentation fault.
0x44434241 in ?? ()
(gdb) i reg
eax 0xbfe9a638 -1075206600
ecx 0xb7e510ac -1209724756
edx 0x80495a5 134518181
ebx 0xb7f5fff4 -1208614924
esp 0xbfe9a650 0xbfe9a650
ebp 0x3d3d3d32 0x3d3d3d32
esi 0xb7f8fce0 -1208419104
edi 0x0 0
eip 0x44434241 0x44434241
eflags 0x210246 [ PF ZF IF RF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
代码: 全选
(gdb) disas main
Dump of assembler code for function main:
0x0804838f <main+0>: lea 0x4(%esp),%ecx
0x08048393 <main+4>: and $0xfffffff0,%esp
0x08048396 <main+7>: pushl 0xfffffffc(%ecx)
0x08048399 <main+10>: push %ebp
0x0804839a <main+11>: mov %esp,%ebp
0x0804839c <main+13>: push %ecx
0x0804839d <main+14>: sub $0x4,%esp
0x080483a0 <main+17>: call 0x8048374 <copyout>
0x080483a5 <main+22>: add $0x4,%esp
0x080483a8 <main+25>: pop %ecx
0x080483a9 <main+26>: pop %ebp
0x080483aa <main+27>: lea 0xfffffffc(%ecx),%esp
0x080483ad <main+30>: ret
End of assembler dump.
(gdb) disas copyout
Dump of assembler code for function copyout:
0x08048374 <copyout+0>: push %ebp
0x08048375 <copyout+1>: mov %esp,%ebp
0x08048377 <copyout+3>: sub $0x18,%esp
0x0804837a <copyout+6>: movl $0x804958c,0x4(%esp)
0x08048382 <copyout+14>: lea 0xfffffff0(%ebp),%eax
0x08048385 <copyout+17>: mov %eax,(%esp)
0x08048388 <copyout+20>: call 0x80482c0 <strcpy@plt>
0x0804838d <copyout+25>: leave
0x0804838e <copyout+26>: ret
End of assembler dump.
(gdb) b *0x08048374
Breakpoint 1 at 0x8048374
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/ojjou/simple_overflow
Breakpoint 1, 0x08048374 in copyout ()
(gdb) i reg
eax 0xbf91c974 -1080964748
ecx 0xbf91c8f0 -1080964880
edx 0x1 1
ebx 0xb7f4cff4 -1208692748
esp 0xbf91c8cc 0xbf91c8cc
ebp 0xbf91c8d8 0xbf91c8d8
esi 0xb7f7cce0 -1208496928
edi 0x0 0
eip 0x8048374 0x8048374 <copyout>
eflags 0x200282 [ SF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) x/x $esp
0xbf91c8cc: 0x080483a5
(gdb) x /2i 0x080483a5
0x80483a5 <main+22>: add $0x4,%esp
0x80483a8 <main+25>: pop %ecx
(gdb) x /2i 0x080483a5-5
0x80483a0 <main+17>: call 0x8048374 <copyout>
0x80483a5 <main+22>: add $0x4,%esp
代码: 全选
(gdb) display /i $pc
1: x/i $pc 0x8048374 <copyout>: push %ebp
(gdb) si
0x08048375 in copyout ()
1: x/i $pc 0x8048375 <copyout+1>: mov %esp,%ebp
(gdb)
0x08048377 in copyout ()
1: x/i $pc 0x8048377 <copyout+3>: sub $0x18,%esp
(gdb)
0x0804837a in copyout ()
1: x/i $pc 0x804837a <copyout+6>: movl $0x804958c,0x4(%esp)
gcc在编译的时候分配了0x18的空间(好像参数没有保持4字节的对齐...)
(gdb) si
0x08048382 in copyout ()
1: x/i $pc 0x8048382 <copyout+14>: lea 0xfffffff0(%ebp),%eax
(gdb)
0x08048385 in copyout ()
1: x/i $pc 0x8048385 <copyout+17>: mov %eax,(%esp)
(gdb)
0x08048388 in copyout ()
1: x/i $pc 0x8048388 <copyout+20>: call 0x80482c0 <strcpy@plt>
继续单步指令执行,"call 0x80482c0"指令实际就是调用strcpy函数,看看它push的两个参数:
(gdb) x/s 0x804958c
0x804958c <largebuff>: "12345123451234512===ABCD"
(gdb) i reg $eax
eax 0xbf91c8b8 -1080964936
压栈的第一个参数是largebuff的地址,第二个是smallbuff的地址,gcc给它分配的大小是0xbf91c8c8(ebp)-0xbf91c8b8=0x10,所以需要20个字节才能正好覆盖返回地址。
(gdb) b*0x0804838d
Breakpoint 2 at 0x804838d
(gdb) c
Continuing.
Breakpoint 2, 0x0804838d in copyout ()
1: x/i $pc 0x804838d <copyout+25>: leave
(gdb) x/20x $esp
0xbf91c8b0: 0xbf91c8b8 0x0804958c 0x34333231 0x33323135
0xbf91c8c0: 0x32313534 0x31353433 0x3d3d3d32 0x44434241
0xbf91c8d0: 0xb7f70700 0xbf91c8f0 0xbf91c948 0xb7e25ebc
0xbf91c8e0: 0xb7f7cce0 0x080483c0 0xbf91c948 0xb7e25ebc
0xbf91c8f0: 0x00000001 0xbf91c974 0xbf91c97c 0xb7f7d898
执行strcpy后,0xbf91c8cc已经被覆盖成0x44434241。
(gdb) i reg $esp $ebp
esp 0xbf91c8b0 0xbf91c8b0
ebp 0xbf91c8c8 0xbf91c8c8
(gdb) si
Cannot access memory at address 0x3d3d3d36
(gdb) i reg $esp $ebp
esp 0xbf91c8cc 0xbf91c8cc
ebp 0x3d3d3d32 0x3d3d3d32
代码: 全选
(gdb) si
0x44434241 in ?? ()
Disabling display 1 to avoid infinite recursion.
1: x/i $pc 0x44434241: Cannot access memory at address 0x44434241
(gdb) i reg $esp $ebp
esp 0xbf91c8d0 0xbf91c8d0
ebp 0x3d3d3d32 0x3d3d3d32
<完>
总结:
一、gcc的参数实在挺多的...应该去了解他的参数的用法.本文中用到了它的-fno-stack-protector参数..意思失去掉栈保护..还有-mpreferred-stack-boundary=n 按照2的n次对齐
有兴趣的朋友可以试试
二、由于gcc的版本原因..现编译函数对main进行了保护..使得在main下的溢出不太可能了(当然高手总是说nothing is impossible.希望高手来指教阿!)。
三、感谢《网络渗透技术》此书的所有作者和安焦团队..你们的文章实在太好了...也十分不好意思改动你们的文章,如果有什么写的不对的地方也请指正和谅解。感谢dorainm的一篇网上的文章《缓冲区溢出利用 的 简单例子》是这篇文章给我的启发。感谢google那些热心的朋友们。