协程4 --- 一个特殊的栈溢出例子
代码
先看下面这个程序流程:
有个长度位24的字符数组
buffer
,前面16个字符初始化。
把attack
函数的地址复制到后面8个字符(编译成64位程序,指针大小为8Byte)。
打印信息:do Something
调用doSomething
,函数内调用了copy
函数拷贝到temp
变量中,但是注意temp
变量长度只有16。
打印信息:do next
提问:do next
会打印出来吗
#include <stdio.h>
#include <stdlib.h>
#define BUFFER_LEN 24
void attack()
{
printf("Hello. I will close your program.\n");
exit(1);
}
void copy(char* src, char* dest, int n)
{
for (int i = 0; i < n; ++i)
{
dest[i] = src[i];
}
}
void doSomething(char* str, int n)
{
// 字符串拷贝
char temp[16];
copy(str, temp, n);
}
int main()
{
char buffer[BUFFER_LEN] =
{
'w', 'o', 'l', 'd',
'a', 'b', 'a', 'b', 'a', 'b',
'a', 'b', 'a', 'b', 'a', 'b'
};
// 将函数注册到字符串最后八个字节
int n = BUFFER_LEN - 8;
for (int i = 0; i < 8; ++i)
{
buffer[n+i] = (char)((((long)(&attack)) >> (i*8)) & 0xff);
}
printf("do Something\n");
// 运行程序
doSomething(buffer, BUFFER_LEN);
// 继续往下执行
printf("do next\n");
return 0;
}
运行结果
注意这边用了-O1
优化,-fno-stack-protector
禁用堆栈保护。
分析
分析之前先普及一下几点知识
三个寄存器:
rip
指向要运行的代码
rbp
指向栈底
rsp
指向栈顶
程序运行时候的内存分布(当然这个大概是Linux 0.11的,现在的不长这样,不过大体是类似的):
这边注意一下栈是往下生长的
objdump -d stackattack
看一下汇编
gcc -O1 -o stackattack stackattack.c -g -fno-stack-protector
objdump -d stackattack
000000000040117f <main>:
40117f: 48 83 ec 28 sub $0x28,%rsp // 栈中开辟临时变量空间
401183: 48 c7 44 24 10 00 00 movq $0x0,0x10(%rsp)
40118a: 00 00
40118c: c6 04 24 77 movb $0x77,(%rsp)
401190: c6 44 24 01 6f movb $0x6f,0x1(%rsp)
401195: c6 44 24 02 6c movb $0x6c,0x2(%rsp)
40119a: c6 44 24 03 64 movb $0x64,0x3(%rsp)
40119f: c6 44 24 04 61 movb $0x61,0x4(%rsp)
4011a4: c6 44 24 05 62 movb $0x62,0x5(%rsp)
4011a9: c6 44 24 06 61 movb $0x61,0x6(%rsp)
4011ae: c6 44 24 07 62 movb $0x62,0x7(%rsp)
4011b3: c6 44 24 08 61 movb $0x61,0x8(%rsp)
4011b8: c6 44 24 09 62 movb $0x62,0x9(%rsp)
4011bd: c6 44 24 0a 61 movb $0x61,0xa(%rsp)
4011c2: c6 44 24 0b 62 movb $0x62,0xb(%rsp)
4011c7: c6 44 24 0c 61 movb $0x61,0xc(%rsp)
4011cc: c6 44 24 0d 62 movb $0x62,0xd(%rsp)
4011d1: c6 44 24 0e 61 movb $0x61,0xe(%rsp)
4011d6: c6 44 24 0f 62 movb $0x62,0xf(%rsp) // 赋值
4011db: b8 00 00 00 00 mov $0x0,%eax
4011e0: be 32 11 40 00 mov $0x401132,%esi // attack函数地址
4011e5: 8d 0c c5 00 00 00 00 lea 0x0(,%rax,8),%ecx // i*8
4011ec: 48 89 f2 mov %rsi,%rdx
4011ef: 48 d3 fa sar %cl,%rdx // 算数右移
4011f2: 88 54 04 10 mov %dl,0x10(%rsp,%rax,1) // dl就是rdx & 0xff 写入目标字符串
4011f6: 48 83 c0 01 add $0x1,%rax // ++i
4011fa: 48 83 f8 08 cmp $0x8,%rax
4011fe: 75 e5 jne 4011e5 <main+0x66>
401200: bf 30 20 40 00 mov $0x402030,%edi
401205: e8 26 fe ff ff callq 401030 <puts@plt> // printf
40120a: be 18 00 00 00 mov $0x18,%esi // 参数n
40120f: 48 89 e7 mov %rsp,%rdi // 参数str
401212: e8 55 ff ff ff callq 40116c <doSomething> // 调用doSomething
401217: bf 3d 20 40 00 mov $0x40203d,%edi
40121c: e8 0f fe ff ff callq 401030 <puts@plt> // printf
401221: b8 00 00 00 00 mov $0x0,%eax
401226: 48 83 c4 28 add $0x28,%rsp
40122a: c3 retq
40122b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
000000000040116c <doSomething>:
40116c: 48 83 ec 10 sub $0x10,%rsp // 栈中开辟临时变量空间
401170: 89 f2 mov %esi,%edx // 参数 n
401172: 48 89 e6 mov %rsp,%rsi // desc
401175: e8 d0 ff ff ff callq 40114a <copy> // 调用copy
40117a: 48 83 c4 10 add $0x10,%rsp
40117e: c3 retq
000000000040114a <copy>:
40114a: 85 d2 test %edx,%edx
40114c: 7e 1d jle 40116b <copy+0x21> // 如果参数n是0 直接返回
40114e: 8d 4a ff lea -0x1(%rdx),%ecx // 参数n-1 因为从0开始循环
401151: b8 00 00 00 00 mov $0x0,%eax // i = 0
401156: eb 03 jmp 40115b <copy+0x11>
401158: 48 89 d0 mov %rdx,%rax
40115b: 0f b6 14 07 movzbl (%rdi,%rax,1),%edx // src[n] -> 寄存器
40115f: 88 14 06 mov %dl,(%rsi,%rax,1) // 寄存器 -> desc[n]
401162: 48 8d 50 01 lea 0x1(%rax),%rdx // ++i
401166: 48 39 c8 cmp %rcx,%rax
401169: 75 ed jne 401158 <copy+0xe>
40116b: c3 retq
-fno-stack-protector
:禁用堆栈保护- 如果不优化用
O0
,不仅会push rip
还会push rbp
。 - 第一行
sub $0x28,%rsp
在栈中开辟临时变量空间,其中0x28
中是 (字符串长度24,16字节对齐到0x20
) + (printf的0x8
) printf
会在第一次调用的时候用malloc
申请缓冲区,malloc
会在分配的地址前预留2*sizeof(size_t)
的空间维护malloc_chunk
信息 。
如果看不懂汇编的可以看这个堆栈变换的示意图:
一开始attack
函数的地址被放在buffer
数组后8位,调用了doSomething
后压栈了rip
和temp
数组变量,结果字符串copy
后buffer
数组比temp数组长的后8位也被拷贝过去了,由于关闭了栈保护,把原来的rip
覆盖了。doSomething
函数结束后就调用到attack
函数了。
原文地址:https://blog.csdn.net/qq_40571533/article/details/126973920
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!