基于缓冲区溢出的HelloWorld
基于缓冲区溢出的HelloWorld
CPP代码
#include "stdafx.h"
void HelloWorld() {
printf("Hello World");
getchar();
}
void Fun() {
int arr[5] = {1,2,3,4,5};
arr[6] = (int)HelloWorld;
}
int main(int argc, char* argv[]) {
Fun();
return 0;
}
情况说明
代码并没有调用HelloWorld
,但成功执行了HelloWorld
分析
初步分析
很容易看出arr[6] = (int)HelloWorld;
这行代码有问题,将一个函数名强转为int
型,并赋值给arr[6]
,而arr[6]
已经超出数组大小
反汇编分析
main()
反汇编
main:
00410790 push ebp
00410791 mov ebp,esp
00410793 sub esp,40h
00410796 push ebx
00410797 push esi
00410798 push edi
00410799 lea edi,[ebp-40h]
0041079C mov ecx,10h
004107A1 mov eax,0CCCCCCCCh
004107A6 rep stos dword ptr [edi]
004107A8 call @ILT+15(Fun) (00401014)
004107AD xor eax,eax
004107AF pop edi
004107B0 pop esi
004107B1 pop ebx
004107B2 add esp,40h
004107B5 cmp ebp,esp
004107B7 call __chkesp (00401140)
004107BC mov esp,ebp
004107BE pop ebp
004107BF ret
call
跟进
00401014 jmp Fun (00410740)
00401019 jmp HelloWorld (004106c0)
Fun()
反汇编
Fun:
00410740 push ebp
00410741 mov ebp,esp
00410743 sub esp,54h
00410746 push ebx
00410747 push esi
00410748 push edi
00410749 lea edi,[ebp-54h]
0041074C mov ecx,15h
00410751 mov eax,0CCCCCCCCh
00410756 rep stos dword ptr [edi]
00410758 mov dword ptr [ebp-14h],1
0041075F mov dword ptr [ebp-10h],2
00410766 mov dword ptr [ebp-0Ch],3
0041076D mov dword ptr [ebp-8],4
00410774 mov dword ptr [ebp-4],5
0041077B mov dword ptr [ebp+4],offset @ILT+20(HelloWorld) (00401019)
00410782 pop edi
00410783 pop esi
00410784 pop ebx
00410785 mov esp,ebp
00410787 pop ebp
00410788 ret
堆栈图分析
-
初始状态
堆栈图:
-
call
指令执行后将
call
后的下一指令004107AD
地址压入栈堆栈图:
-
jmp
跳转后,到设置缓冲区后的状态这里要注意
[ebp+4]
,此时为004107AD
为函数的返回地址堆栈图:
-
局部变量设置
int arr[5] = {1,2,3,4,5};
这行代码,编译器会划分出5
个int
宽度的内存空间存放,根据下标由小到大,内存地址由低到高。要分配
5
个int
大小的空间,所以从ebp-0x4*0x5
即ebp-0x14
开始分配局部变量设置完成后的堆栈图:
-
执行
arr[6] = (int)HelloWorld;
发生了生么?(int)HelloWorld
这里的HelloWorld
不是字符串,而是一个函数名,使用(int)
强制转换为了内存地址,所以(int)HelloWorld
的返回值为该指令的内存地址- 数组
arr
的大小为5
,即最大下标为4
,arr[6]
发生数组越界,造成了缓冲区溢出,当给arr[6]
赋值时,编译器直接以arr
的内存地址为基础+0x4*0x6
即0x18
结果为0012FF30
,也就相当把返回地址的值修改为函数HelloWorld
的内存地址 - 执行
ret
时,eip
变为了函数HelloWorld
的内存地址,导致执行了函数HelloWorld
HelloWorld
内存地址:00401019004110B8 call @ILT+20(HelloWorld) (00401019)