1 | [bobo]$ cat gotover.c |
2 | #include <stdio.h> |
3 | #include <string.h> |
4 | |
5 | int evil_code(char *s) |
6 | { |
7 | printf("hi, I am here!/n"); |
8 | return 0; |
9 | } |
10 | |
11 | int main(int argc, char *argv[]) |
12 | { |
13 | long addr = *(long *)((long)strlen + 2); |
14 | |
15 | *(long *)addr = (long)evil_code; |
16 | |
17 | int len = strlen(argv[0]); |
18 | |
19 | printf("len = [%d]/n", len); |
20 | |
21 | return 0; |
22 | } |
23 | |
24 | [bobo]$ gcc gotover.c -o gotover |
25 | [bobo]$ ./gotover |
26 | hi, I am here! |
27 | len = [0] |
看了这篇帖子,理解了上面这段程序,直接修改栈内容。
详细内容可以参考 , 还有一篇alert7写的动态库符号解析过程
大概是这样的:
对于32位的x86,调用动态库中的函数,比如 printf(); 调用的其实是plt中的一小段代码,这一小段代码如:
address + 0: jmp *0xXXXXXXXX
address + 6 : push 一个常数
jmp 0xYYYYYYYY
第一次调用printf时地址0xXXXXXXXX中的值就是address + 6, 也就是第一次jmp会跳到 address + 6的地方,然后下一个jmp进行如号解析,然后在0xXXXXXXXX中写入真实的printf函数的地址,之后再调用printf时就会直接跳到printf函数去了。
我前面那个代码就是在0xXXXXXXXX中放入evil_code()函数的地址,address + 0: jmp *0xXXXXXXXX 这条指令占用6个字节,前面两个是操作码,后面就是地址,所以有代码中" + 2"
跑了帖子中更能清晰理解栈结构的例子,结果如下:
[S@fedora-1 test]$ cat test1.c
#include
int gi = 1;
f(char *fmt, int *p, int v)
{
int i;
for(i = 0; i < 8; i++) {
printf("%d %p %p/n", i, &i + i, *(&i+i));
}
printf("p = %p v = %d/n", p, v);
return;
for(i = 0; i < 256; i++) {
printf("addr = %p value = %d/n", &gi, gi);
}
}
main()
{
f("fmt", &gi, gi);
}
[S@fedora-1 test]$ ./a.out
0 0xbf8daf24 (nil)
1 0xbf8daf28 0xbf8daf48
2 0xbf8daf2c 0x8048469
3 0xbf8daf30 0x804855d
4 0xbf8daf34 0x80496d4
5 0xbf8daf38 0x1
6 0xbf8daf3c 0x80484a9
7 0xbf8daf40 0xa7add0
p = 0x80496d4 v = 1
程序中的局部数组溢出使用,就能改变栈,结果不可预料。打印出荒唐的信息。
摘自:http://bbs.chinaunix.net/viewthread.php?tid=1652842&extra=page%3D1%26amp;filter%3Ddigest&page=6