缓冲区溢出以后
我在CSDN发的一个帖子,很久没写日志了,拿来充数,也回顾一下。
C代码如下:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void func1(char *s)
{
char buf[12];
strcpy(buf,s);
}
void func2(void)
{
printf("Why I can be printed ?\n");
exit (0);
}
int main(void)
{
char badcode[]="abcdefghijklmnopqrstuvwxyz";
unsigned *p=(unsigned*)&badcode[16];
*p=(unsigned)func2;
func1(badcode);
return 0;
}
这段代码在有的编译器(比如VC6)编译后,运行会打印“Why I can be printed?"。
试分析原因:
概括说就是溢出的字符串覆盖了main函数中“保存fun1返回地址“的栈区,使程序跳转到fun2。
下面是cygwin下gcc反汇编的代码:
_mystrcpy:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl 8(%ebp), %eax
movl %eax, -4(%ebp)
L2:
movl 12(%ebp), %eax
movzbl (%eax), %edx
movl 8(%ebp), %eax
movb %dl, (%eax)
movl 8(%ebp), %eax
movzbl (%eax), %eax
testb %al, %al
setne %al
addl $1, 8(%ebp)
addl $1, 12(%ebp)
testb %al, %al
jne L2
movl -4(%ebp), %eax
leave
ret
.globl _func1
.def _func1; .scl 2; .type 32; .endef
_func1:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl 8(%ebp), %eax
movl %eax, 4(%esp)
leal -12(%ebp), %eax
movl %eax, (%esp)
call _mystrcpy
leave
ret
.section .rdata,"dr"
LC0:
.ascii "Why I can be printed ?\0"
.text
.globl _func2
.def _func2; .scl 2; .type 32; .endef
_func2:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl $LC0, (%esp)
call _puts
movl $0, (%esp)
call _exit
.def ___main; .scl 2; .type 32; .endef
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $36, %esp
call ___main
movl $825307441, -29(%ebp)
movl $842150450, -25(%ebp)
movl $858993459, -21(%ebp)
movl $875836468, -17(%ebp)
movl $892679477, -13(%ebp)
movb $0, -9(%ebp)
leal -29(%ebp), %eax
addl $16, %eax
movl %eax, -8(%ebp)
movl $_func2, %edx
movl -8(%ebp), %eax
movl %edx, (%eax)
leal -29(%ebp), %eax
movl %eax, (%esp)
call _func1
movl $0, %eax
addl $36, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
尤其需要注意的是fun1中的这几句。
pushl %ebp
保存main函数的栈帧,占用4个字节。
leal -12(%ebp), %eax
movl %eax, (%esp)
call _mystrcpy
这三句可知fun1为拷贝留出的缓冲区大小是12个字节。
再注意到fun2的入口地址在badcode中的偏移恰好是16个字节,由于字符串的拷贝由低地址向高地址进行,所以
fun2覆盖的地方恰好是fun1执行ret语句返回时应该取出的地址。
于是程序欢快滴跳转了。