作者descent (「雄辯是銀,沉默是金」)
看板C_and_CPP
標題[分享] gcc -fstack-protector 的實作
時間Mon May 6 09:22:22 2013
和大家分享, 若有什麼問題也麻煩幫忙指證。
我一直很好奇 check stack 有沒爆掉是怎麼做的, 一位朋友為我解惑, 就在 stack 底端
塞個值, 檢查他就好了, 我頓時茅塞頓開, 原來如此。 不過本著求證的心態, 來看看是
不是真的。
stack_pro.c
1
2 #include <stdio.h>
3 #include <string.h>
4
5 int main()
6 {
7
8 char string[10];
9
10 strcpy(string, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
11
12 }
gcc -m32 -g -static -fno-stack-protector stack_pro.c -o stack_pro.nosp
gcc -m32 -g -static -fstack-protector stack_pro.c -o stack_pro.sp
objdump -d stack_pro.sp
1 080482d0 <main>:
2 80482d0: 55 push %ebp
3 80482d1: 89 e5 mov %esp,%ebp
4 80482d3: 83 e4 f0 and $0xfffffff0,%esp
5 80482d6: 83 ec 20 sub $0x20,%esp
6 80482d9: 65 a1 14 00 00 00 mov %gs:0x14,%eax
7 80482df: 89 44 24 1c mov %eax,0x1c(%esp)
8 80482e3: 31 c0 xor %eax,%eax
9 80482e5: b8 dc 02 0b 08 mov $0x80b02dc,%eax
10 80482ea: c7 44 24 08 23 00 00 movl $0x23,0x8(%esp)
11 80482f1: 00
12 80482f2: 89 44 24 04 mov %eax,0x4(%esp)
13 80482f6: 8d 44 24 12 lea 0x12(%esp),%eax
14 80482fa: 89 04 24 mov %eax,(%esp)
15 80482fd: e8 ee 74 00 00 call 804f7f0 <memcpy>
16 8048302: 8b 54 24 1c mov 0x1c(%esp),%edx
17 8048306: 65 33 15 14 00 00 00 xor %gs:0x14,%edx
18 804830d: 74 05 je 8048314 <main+0x44>
19 804830f: e8 2c be 00 00 call 8054140 <__stack_chk_fail>
20 8048314: c9 leave
21 8048315: c3 ret
L6, 7, 16, 17 就是這些魔法施行的地方。string[10] 從 0x12(%esp) 開始,
長度 10, 所以這個魔法標記紀錄在 0x1c(%esp), 0x1c-0x12 = 0xa,
在做完 memcpy (為什麼 strcpy 變成 memcpy 就不用管他了) 之後,
再來檢查 0x1c(%esp) 值是不是之前保存 (從 %gs:0x14 得來的) 的即可,
如果不一樣, 就去執行 __stack_chk_fail。 在我測試時, 這個值是:
%gs:0x14: 0x944bc400 不過似乎會一直變化, 每次執行都不一樣,
不是固定值。
這是把 0x1c(%esp) dump 出來, 本來應該要是 0x00 0xc4 0x4b 0x94 (little
endian), 可是因為我們把 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" 覆蓋超過了
string[10], 所以就變成 0x41 0x41 0x41 0x41 ...
(gdb) x/32xb 0xffffd39c
0xffffd39c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffd3a4: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
這是執行結果, 沒有 -fstack-protector 的版本, 自然是發出 Segmentation fault。
stack protector 執行結果
1 *** stack smashing detected ***: ./stack_pro.sp terminated
2 ======= Backtrace: =========
3 [0x8054189]
4 [0x805414d]
5 [0x8048314]
6 [0x41414141]
7 ======= Memory map: ========
8 08048000-080cf000 r-xp 00000000 08:05 18620900
/home/descent/my-git/progs/stack_pro.sp
9 080cf000-080d1000 rw-p 00086000 08:05 18620900
/home/descent/my-git/progs/stack_pro.sp
10 080d1000-080d3000 rw-p 00000000 00:00 0
11 08f7b000-08f9d000 rw-p 00000000 00:00 0
[heap]
12 f77c9000-f77ca000 r-xp 00000000 00:00 0
[vdso]
13 ffdc2000-ffdd7000 rw-p 00000000 00:00 0
[stack]
14 Aborted
Emit extra code to check for buffer overflows, such as stack
smashing attacks. This is done by adding a guard variable to
functions with vulnerable objects. This includes functions that
call alloca, and functions with buffers larger than 8 bytes. The
guards are initialized when a function is entered and then checked
when the function exits. If a guard check fails, an error message
is printed and the program exits.
NOTE: In Ubuntu 6.10 and later versions this option is enabled by
default for C, C++, ObjC, ObjC++, if neither -fno-stack-protector
nor -nostdlib are found.
至於 man page 的 8 byte 我怎麼試都觀察不到, 就沒辦法分享這段的意思了。
stack overflow 有篇類似的, 可惜我找不到了。
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 59.125.239.46
→ scwg:有個至少 8 byte 的字元陣列 (buffer) 是加入 stack protecto 05/06 11:35
→ scwg:r 的條件. 把 string 改成 [4] 就不會加了. 05/06 11:36