基于缓冲区溢出的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

基于缓冲区溢出的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

堆栈图分析

  1. 初始状态

    基于缓冲区溢出的HelloWorld

    堆栈图:

    基于缓冲区溢出的HelloWorld

  2. call指令执行后

    call后的下一指令004107AD地址压入栈

    基于缓冲区溢出的HelloWorld

    堆栈图:

    基于缓冲区溢出的HelloWorld

  3. jmp跳转后,到设置缓冲区后的状态

    基于缓冲区溢出的HelloWorld

    这里要注意[ebp+4],此时为004107AD为函数的返回地址

    基于缓冲区溢出的HelloWorld

    堆栈图:

    基于缓冲区溢出的HelloWorld

  4. 局部变量设置

    int arr[5] = {1,2,3,4,5};这行代码,编译器会划分出5int宽度的内存空间存放,根据下标由小到大,内存地址由低到高。

    要分配5int大小的空间,所以从ebp-0x4*0x5ebp-0x14开始分配

    基于缓冲区溢出的HelloWorld

    局部变量设置完成后的堆栈图:

    基于缓冲区溢出的HelloWorld

  5. 执行arr[6] = (int)HelloWorld;发生了生么?

    • (int)HelloWorld这里的HelloWorld不是字符串,而是一个函数名,使用(int)强制转换为了内存地址,所以(int)HelloWorld的返回值为该指令的内存地址
    • 数组arr的大小为5,即最大下标为4arr[6]发生数组越界,造成了缓冲区溢出,当给arr[6]赋值时,编译器直接以arr的内存地址为基础+0x4*0x60x18结果为0012FF30,也就相当把返回地址的值修改为函数HelloWorld的内存地址
    • 执行ret时,eip变为了函数HelloWorld的内存地址,导致执行了函数HelloWorld

    HelloWorld内存地址:00401019

    004110B8   call        @ILT+20(HelloWorld) (00401019)
    

    基于缓冲区溢出的HelloWorld

    基于缓冲区溢出的HelloWorld

上一篇:如何快速掌握Sportisimo EDI项目中的ORDERS报文?


下一篇:逆向学习第五天