今天在學習溢出時寫了個簡單程序,源代碼如下。
1
#include <stdio.h>
2
#include <stdlib.h>
3
4
int foo_normal(char*);
5
int foo_abnormal(char*);
6
7
int main()
8

{
9
int i;
10
char szTmp[] =
{
11
0x31, 0x31, 0x31, 0x31,
12
0x32, 0x32, 0x32, 0x32,
13
0x33, 0x33, 0x33, 0x33,
14
0x00, 0x40, 0x13, 0x45,
15
16
0x31, 0x31, 0x31, 0x31,
17
0x32, 0x32, 0x32, 0x32,
18
0x33, 0x33, 0x33, 0x33,
19
0x4e, 0x13, 0x40, 0x00
20
};
21
22
i = 0;
23
24
if (i == 0)
25
foo_normal(szTmp);
26
else
27
foo_abnormal(szTmp);
28
29
return(0);
30
}
31
32
33
int foo_normal(char* _sz)
34

{
35
char buffer[5];
36
memcpy(buffer, _sz, sizeof(char)*32);
37
printf("Application terminates normally.\n");
38
return(0);
39
}
40
int foo_abnormal(char* _sz)
41

{
42
char buffer[5];
43
memcpy(buffer, _sz, sizeof(char)*3);
44
printf("You should have never seen this.\n");
45
return (0);
46
}
打算通過foo_normal中的memcpy函數覆蓋棧中的EIP,改為調用foo_abnormal處的語句,來達到溢出攻擊的目的。按照正常情況看,在foo_normal中,棧里有4字節的CS和4字節的EIP,然后是5字節的字符串數組——對齊后是8字節,還有4字節的EBP。所以當往buffer中復制12字節數據就可以覆蓋掉EIP而達到溢出的目的。但實際上使用32字節的數據覆蓋buffer及其后的數據,才把EIP給照顧到。使用OllyDBG跟了一下:
1 004013F2 /$ 55 push ebp
2 004013F3 |. 89E5 mov ebp, esp
3 004013F5 |. 83EC 28 sub esp, 28
4 004013F8 |. C74424 08 050>mov dword ptr [esp+8], 5 ; ||
5 00401400 |. 8B45 08 mov eax, dword ptr [ebp+8] ; ||
6 00401403 |. 894424 04 mov dword ptr [esp+4], eax ; ||
7 00401407 |. 8D45 E8 lea eax, dword ptr [ebp-18] ; ||
8 0040140A |. 890424 mov dword ptr [esp], eax ; ||
9 0040140D |. E8 FE050000 call <jmp.&msvcrt.memcpy> ; |\memcpy
10 00401412 |. C70424 D01340>mov dword ptr [esp], 004013D0 ; |ASCII "Application terminates normally.",LF
11 00401419 |. E8 EA050000 call <jmp.&msvcrt.printf> ; \printf
12 0040141E |. B8 00000000 mov eax, 0
13 00401423 |. C9 leave
14 00401424 \. C3 retn
發現在進入函數的時候申請了28個字節的空間——除去12字節給memcpy的參數,比預想的多了6字節。看來使用的3.3.1版本的gcc是16字節對齊的。
……讓我抓狂了一個小時。