这是在VC下编译的,也是利用VC中调试工具DEBUG查看到源程序的汇编代码.
如果是反汇编,结构和此处的几乎一样,就没有了源代码(粗体)。
文件从00401001处开始
从main函数开始分析(main函数位于内存00401090处)
00401001 int 3
00401002 int 3
00401003 int 3
00401004 int 3
@ILT+0(?verify_password@@YAHPAD@Z):
00401005 jmp verify_password (00401020)
@ILT+5(_main):
0040100A jmp main (00401090)
0040100F int 3
00401010 int 3
00401011 int 3
00401012 int 3
00401013 int 3
00401014 int 3
00401015 int 3
00401016 int 3
00401017 int 3
00401018 int 3
00401019 int 3
0040101A int 3
0040101B int 3
0040101C int 3
0040101D int 3
0040101E int 3
0040101F int 3
--- C:/Documents and Settings/Administrator/桌面/overflow/overflow.cpp ----------------------------------
1: #include<stdio.h>
2: #include<stdlib.h>
3: #include<string.h>
4:
5: #define PASSWORD "1234567"
6:
7: int verify_password(char *password){
00401020 push ebp
00401021 mov ebp,esp
00401023 sub esp,4Ch
00401026 push ebx
00401027 push esi
00401028 push edi
00401029 lea edi,[ebp-4Ch]
0040102C mov ecx,13h
00401031 mov eax,0CCCCCCCCh
00401036 rep stos dword ptr [edi]
//以上部分同main函数的前段代码,申请4ch的栈空间,其中authenticated和buffer【8】共占12个空间
8: int authenticated=0;
00401038 mov dword ptr [ebp-4],0
//设置authenticated为0
9: char buffer[8]; // add local buff to be overflowed
10: authenticated=strcmp(password,PASSWORD);
0040103F push offset string "1234567" (0042201c)
00401044 mov eax,dword ptr [ebp+8]
00401047 push eax
//把正确密码和输入密码分别压栈,输入密码存于password中,位于 [ebp+8]处
00401048 call strcmp (00401210)
//比较,对于cmp函数,如果正确密码大于输入密码则返回1,小于返回-1,等于返回0
0040104D add esp,8
00401050 mov dword ptr [ebp-4],eax
返回结果存于eax中,转到authenticated中
11: strcpy(buffer,password); //overflow is here !
00401053 mov ecx,dword ptr [ebp+8]
00401056 push ecx
00401057 lea edx,[ebp-0Ch]
0040105A push edx
0040105B call strcpy (00401120)
//此处把password拷贝到buffer数组,由于在栈中buffer数组下面是authenticated,
//然后就是main函数的ebp压栈处,再下面就是verify_password函数的返回地址
//所以只要传入的password大于buffer数组的大小,即8字节,
//就可以覆盖后面的authenticated和main函数的ebp以及verify_password函数的返回地址
//现在要使输入一个错误密码是也会pass----输入8位密码(要大于正确密码,这样cmp函数返回的就是00000001,否则就是FFFFFFFF(-1),不方便)
//比如qqqqqqqq,这样字符串后的结束符“0x00”就会覆盖authenticated中最后的"01”(Big-Indian),这样错误密码就会被认为是这正确的(cmp返回值被改为0)
//下面是那部分栈的内容:
0012FB10 CC CC CC CC 烫烫
0012FB14 CC CC CC CC 烫烫
0012FB18 71 71 71 71 qqqq
0012FB1C 71 71 71 71 qqqq
0012FB20 00 00 00 00 ....(此处原来是01 00 00 00,被覆盖成00)
0012FB24 80 FF 12 00 .... 这里是main函数的ebp保存于此
0012FB28 E2 10 40 00 ..@.这里是verify_password函数的返回地址
//在这里也可以覆盖返回地址从而使程序跳转到自己想执行的地方,也可插入自己的代码...
00401060 add esp,8
12: return authenticated;
00401063 mov eax,dword ptr [ebp-4]
13: }
00401066 pop edi
00401067 pop esi
00401068 pop ebx
00401069 add esp,4Ch
0040106C cmp ebp,esp
0040106E call __chkesp (004012a0)
00401073 mov esp,ebp
00401075 pop ebp
00401076 ret
..........
15: void main(){
00401090 push ebp
00401091 mov ebp,esp
//把调用main函数的函数栈帧的ebp压栈保存(当main函数结束时出栈恢复),
//现在栈是main的栈帧,把main函数的ebp设置在此处
00401093 sub esp,444h
//在栈中为变量保留444h的空间(其中4h是valid_flag的大小)
//而400h,1024B为password[1024]准备
//40h是VC对Debug版本的保护机制,设置对于堆栈操作溢出,故申请了40h空间
00401099 push ebx
0040109A push esi
0040109B push edi
//寄存器压栈,保存现场
0040109C lea edi,[ebp-444h]
//ebp-444h是战中变量部分顶部
004010A2 mov ecx,111h
//ecx计数,共111个栈单元(一个栈单元是4个内存单元)
004010A7 mov eax,0CCCCCCCCh
004010AC rep stos dword ptr [edi]
//循环ecx次数对变量部分填充cccccccch,即int 3
16:
17: int valid_flag=0;
004010AE mov dword ptr [ebp-4],0
18: char password[1024];
19:
20: printf("input the password : ");
004010B5 push offset string "input the password : " (0042300c)
//调用printf函数之前把输出内容的地址压栈传实参
004010BA call printf (004012e0)
//调用printf函数
004010BF add esp,4
//这个栈单元是调用printf函数时参数压栈,函数返回参数就没用了,直接跳过
21: scanf("%s",password);
004010C2 lea eax,[ebp-404h]
//把password数组的存储位置首地址压栈
004010C8 push eax
004010C9 push offset string "%s" (004228a0)
//再把另一个参数"%s"压栈(从右向左压参数)
004010CE call scanf (0040fa20)
004010D3 add esp,8
//此处同printf函数
22:
23: valid_flag=verify_password(password);
004010D6 lea ecx,[ebp-404h]
004010DC push ecx
//调用verify_password函数之前把参数首地址压栈,即数组password首地址
004010DD call @ILT+0(verify_password) (00401005)
004010E2 add esp,4
004010E5 mov dword ptr [ebp-4],eax
//函数返回时返回值保存在eax中,再把返回值保存在main函数中的变量valid_flag中
//ebp就是起到栈基址的作用
24:
25: if(valid_flag){
004010E8 cmp dword ptr [ebp-4],0
004010EC je main+6Dh (004010fd)
//比较valid_flag和0,如果相等(说明密码正确)
//则跳转到输出"Congratulations ! you have passed"
26: printf("incorrect passwprd !/n");
004010EE push offset string "incorrect passwprd !/n" (0042206c)
004010F3 call printf (004012e0)
004010F8 add esp,4
27: }
28: else{
004010FB jmp main+7Ah (0040110a)
29: printf("Congratulations ! you have passed the verification !/n/n");
004010FD push offset string "Congratulations ! you have passe"... (00422028)
00401102 call printf (004012e0)
00401107 add esp,4
30: }
31:
32: }
//下面是main函数返回时的恢复现场,寄存器出栈
0040110A pop edi
0040110B pop esi
0040110C pop ebx
0040110D add esp,444h
00401113 cmp ebp,esp
00401115 call __chkesp (004012a0)
0040111A mov esp,ebp
0040111C pop ebp