VC6中新建工程,输入代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *getline()
{
char buf[8];
char *result;
gets(buf);
result = (char *) malloc(strlen(buf));
strcpy(result, buf);
return result;
}
int main(void)
{
getline();
return 0;
}
这个程序存在缓冲区溢出的问题,当 gets函数中输入的字符数大于7个字节,那么就会覆盖堆栈中的返回地址。
注意:
VC下并不包含alloc.h头文件,可以加上stdlib.h或malloc.h头文件,这两个头文件里面都有malloc函数的声明,以及free、realloc函数的声明。
按F10进入单步调试
然后右键,Go To Disassembly 转到汇编代码
汇编代码
-- c:/program files/microsoft visual studio/myprojects/asm/tt.c ---------------------------------------------------------
1: #include <stdio.h>
2: #include <stdlib.h>
3: #include <string.h>
4:
5:
6: char *getline()
7: {
00401020 55 push ebp
00401021 8B EC mov ebp,esp
00401023 83 EC 4C sub esp,4Ch ; Allocate 19*4 bytes on stack
00401026 53 push ebx
00401027 56 push esi
00401028 57 push edi
00401029 8D 7D B4 lea edi,[ebp-4Ch]
0040102C B9 13 00 00 00 mov ecx,13h
00401031 B8 CC CC CC CC mov eax,0CCCCCCCCh
00401036 F3 AB rep stos dword ptr [edi]
8: char buf[8];
9: char *result;
10: gets(buf);
00401038 8D 45 F8 lea eax,[ebp-8]
0040103B 50 push eax
0040103C E8 8F 21 00 00 call gets (004031d0)
00401041 83 C4 04 add esp,4
11: result = (char *) malloc(strlen(buf));
00401044 8D 4D F8 lea ecx,[ebp-8]
00401047 51 push ecx
00401048 E8 03 21 00 00 call strlen (00403150)
0040104D 83 C4 04 add esp,4
00401050 50 push eax
00401051 E8 7A 01 00 00 call malloc (004011d0)
00401056 83 C4 04 add esp,4
00401059 89 45 F4 mov dword ptr [ebp-0Ch],eax
12: strcpy(result, buf);
0040105C 8D 55 F8 lea edx,[ebp-8]
0040105F 52 push edx
00401060 8B 45 F4 mov eax,dword ptr [ebp-0Ch]
00401063 50 push eax
00401064 E8 77 00 00 00 call strcpy (004010e0)
00401069 83 C4 08 add esp,8
13:
14: return result;
0040106C 8B 45 F4 mov eax,dword ptr [ebp-0Ch]
15:
16: }
0040106F 5F pop edi
00401070 5E pop esi
00401071 5B pop ebx
00401072 83 C4 4C add esp,4Ch
00401075 3B EC cmp ebp,esp
00401077 E8 24 22 00 00 call __chkesp (004032a0)
0040107C 8B E5 mov esp,ebp
0040107E 5D pop ebp
0040107F C3 ret
--- No source file -------------------------------------------------------------------------------------------------------
Main函数:
--- C:/Program Files/Microsoft Visual Studio/MyProjects/asm/tt.c --------------------------------
12:
13: int main(void)
14: {
004010A0 55 push ebp ; Save old ebp
004010A1 8B EC mov ebp,esp ; Set ebp as frame pointer
004010A3 83 EC 40 sub esp,40h ; Allocate 16*4 bytes on stack
004010A6 53 push ebx ; Save ebx
004010A7 56 push esi ; Save esi
004010A8 57 push edi ; Save edi
004010A9 8D 7D C0 lea edi,[ebp-40h] ; Set edi to (ebp - 40h)
004010AC B9 10 00 00 00 mov ecx,10h
004010B1 B8 CC CC CC CC mov eax,0CCCCCCCCh ; cc = int 3 中断
004010B6 F3 AB rep stos dword ptr [edi] ; 上面分配的16 *4字节填上int3指令
15: getline();
004010B8 E8 48 FF FF FF call @ILT+0(_getline) (00401005) ; Debug的时侯才会出现@ILT (Incremental Link Table)
16: return 0;
004010BD 33 C0 xor eax,eax
17: }
004010BF 5F pop edi
004010C0 5E pop esi
004010C1 5B pop ebx
004010C2 83 C4 40 add esp,40h
004010C5 3B EC cmp ebp,esp ; 检查 esp 是否正确
004010C7 E8 D4 21 00 00 call __chkesp (004032a0) ; 同样是 Debug only
004010CC 8B E5 mov esp,ebp
004010CE 5D pop ebp
004010CF C3 ret
--- No source file ------------------------------------------------------------------------------
将分配的局部变量空间全部初始化成 int 3中断指令的目的在于,这些数据是不能当成指令来执行的,如果程序意
外的当成指令执行,那么int 3会造成中断。这样,我们就有机会了解到发生了不好的事情了。
用 Debug 选项编译程序才会出现这个 call @ILT+0(_getline) (00401005)