地址改写
将main函数的返回地址写入main函数的第一个参数在堆栈中的位置保证溢出返回后能返回到__lib_start_main函数使程序顺利结束
将foo 函数的返回地址写入main函数的返回地址,当main 函数执行结束返回时会跳转到foo函数中执行(溢出)
执行过程
1、__lib_start_main 为main函数创建好堆栈空间写好返回地址
2、main函数执行该地址输出now in main执行结束返回(跳转)到foo函数
3、foo函数输出jump here 执行shell结束返回到__lib_start_main函数调用main的下一条指令
4、__lib_start_main 函数继续执行,结束程序
说明
len可设置为1或2,编译时直接在栈顶开辟4个或8个字节的空间,
设置成其他值时在栈顶到数据结尾处会有一些字节的空间不容易得到函数的返回地址
汇编代码:
main函数
Dump of assembler code for function main:
0x8048568 <main>: push %ebp ;将旧ebp(__lib_start_main中)压栈
0x8048569 <main+1>: mov %esp,%ebp ;将esp值赋给ebp AT&T汇编模式
0x804856b <main+3>: sub $0x8,%esp ;为局部变量开辟空间,这里刚好是两个字节
0x804856e <main+6>: mov 0x4(%ebp),%eax ;ebp+4为main的返回地址,
0x8048571 <main+9>: mov %eax,0x8(%ebp) ;将main的返回地址写入其下面的单元,使溢出返回后能回到__lib_start_main中
0x8048574 <main+12>: movl $0x8048540,0x4(%ebp) ;将foo函数的入口地址写入main函数的返回地址中
0x804857b <main+19>: sub $0xc,%esp
0x804857e <main+22>: push $0x804861a
0x8048583 <main+27>: call 0x80483f4 <puts>
0x8048588 <main+32>: add $0x10,%esp
0x804858b <main+35>: mov $0x0,%eax
0x8048590 <main+40>: leave
0x8048591 <main+41>: ret
End of assembler dump.
foo函数
Dump of assembler code for function foo__Fv:
0x8048540 <foo__Fv>: push %ebp
0x8048541 <foo__Fv+1>: mov %esp,%ebp
0x8048543 <foo__Fv+3>: sub $0x8,%esp
0x8048546 <foo__Fv+6>: sub $0xc,%esp
0x8048549 <foo__Fv+9>: push $0x8048608
0x804854e <foo__Fv+14>: call 0x80483f4 <puts>
0x8048553 <foo__Fv+19>: add $0x10,%esp
0x8048556 <foo__Fv+22>: sub $0xc,%esp
0x8048559 <foo__Fv+25>: push $0x8048612
0x804855e <foo__Fv+30>: call 0x80483e4 <system>
0x8048563 <foo__Fv+35>: add $0x10,%esp
0x8048566 <foo__Fv+38>: leave
0x8048567 <foo__Fv+39>: ret
End of assembler dump.
执行到<main+6>时的堆栈结构为
esp --> offset+0 [ buf[0] ]
offset+1 [ buf[1] ]
ebp --> offset+2 [ 旧ebp(__lib_start_main中的) ]
offset+3 [ main 返回地址 ]
offset+4 [ argc = 1 main函数运行的参数 ]
执行到<foo_Fv+6>时的堆栈结构为
offset+0 [ 局部变量空间 ]
esp --> offset+1 [ 局部变量空间 ]
offset+2 [ 局部变量空间 ]
ebp --> offset+3 [ 旧ebp (main中的) ]
offset+4 [ main的返回地址 ]
源代码
#include <stdio.h>
#include <stdlib.h>
void foo(void)
{
puts("jump here");
system("/bin/sh");
}
#define len 2
int main()
{
int buf[len];
*(int *)(buf+len+2) = *(buf+len+1);
*(int *)(buf+len+1) =(int)((void(*)(void))foo);
puts("now in main");
return 0;
}
shell下执行过程
# g++ -g test.c
# ls
a.out test.c
# ./a.out
now in main
jump here
sh-2.05a# ls
a.out test.c
sh-2.05a# exit
exit
#