学习笔记栈溢出的使用

学习目标:

  • 1.函数的本质
  • 2.学会栈溢出的使用

学习内容:

一.认识两个寄存器esp,ebp
1.esp指向栈顶地址
2.ebp指向栈底地址
3.eip存储下一条执行指令的地址


二.认识相关指令
1.push 寄存器或数字  先esp-=4再让寄存器或数字赋值给esp指向地址的值,就是压入的意思
2.pop 寄存器 将esp指向地址的值赋给寄存器,再esp+=4 就是弹出的意思
3.call 可以看作是先esp-=4 再给栈顶地址赋值为函数的下一条指令最后在跳转到另一个指令去执行函数
4.ret 函数的结束 看作是pop eip即将之前call存的指令值给eip 

三。认识函数的调用过程

//要把优化关掉,不然就找不到add函数
#include <iostream>
using namespace std;
int add(int a, int b)
{
    return a + b;
}
int main()
{
    int c=add(1, 2);
    cout << c;
    return 0;
}

这个函数比较简单,也就给我老师拿来入门

先看看调用前是咋样的吧

int c=add(1, 2);
00281014 6A 02                push        2  
00281016 6A 01                push        1  
00281018 E8 E3 FF FF FF       call        00281000  
可以看到他将我们的参数从右向左依次压入了栈中

此时栈中

0028101D下一条命令地址
1
2

int add(int a, int b)
{
00281000 55                   push        ebp  
00281001 8B EC                mov         ebp,esp  
    return a + b;
00281003 8B 45 08             mov         eax,dword ptr [ebp+8]  
00281006 03 45 0C             add         eax,dword ptr [ebp+0Ch]  
}

压入ebp(方便后面复原栈),让ebp=esp,再给eax赋值成第一个参数,再加上第二个参数

因为栈是越往下地址越大所以很容易想到

原先ebp的值(现ebp,esp指向)
0028101D下一条命令地址
1
2

00281009 5D                   pop         ebp  
0028100A C3                   ret  

此时ebp复原了没变过

0028101D下一条命令地址
1
2

0028101D 83 C4 08             add         esp,8  
00281020 89 45 FC             mov         dword ptr [ebp-4],eax  

函数出来后可以看到esp下降了2格,因为ret原因又降了一格,最后esp也复原了

总结:

调用函数前后esp,ebp都会保持平衡,这样子省了空间,达到要用就拿过了,不用就给别人用的效果(个人感觉)。

学习项目:

目标:用栈溢出去攻击驴百万的项目,要把那个安全检查关了

直接上带代码

#include <iostream>
#include<windows.h>
using namespace std;
void Hack()
{
	while (1)
	{
		cout << "hello"<<"你的电脑已被我入侵了"<<endl;
		Sleep(1000);
	}
	return;
}
int GetAge()
{
	int rt;
	std::cout << "请输入学员信息" << endl;
	std::cin >> rt;
	return rt;
}
int count()
{
	int total= 0;
	int i = 0;
	int age[10];
	
	//age[10]不明 age[11]是sum,age[12]是i,age[13]是ebp,age[14]是指令
	//0到10正常输入 然后分别输入sum,i,sum随便,i不要动
	//然后是ebp随便,最后把api输入,再输入0
	
	do {
		age[i] = GetAge();
		total+= age[i];
	} while (age[i++] != 0);
	return total;
}
int main()
{
	cout << "=======驴百万学院 学员年龄统计系统 ======\n";
	cout << "\n      API:" << (int)Hack << endl;
	cout << "\n{说明:最多输入10个学员信息,当输入0时代表输入结束" << endl;
	cout << "\n驴百万学院的总年龄为:" << count();
	return 0;
}

可以看到只是输入函数地址就能执行,老师有个视频更高级,没输入都能调

原理:每个函数会在栈底存储下一条执行指令的值,我们只需串改这个值成我们想要执行的函数地址,例如下载病毒之类的。里面的数组在栈里是从上到下分布,理论上索引足够大就能访问到这个值

主要分析count函数

00711090 55                   push        ebp  
先看下这个esp,ebp位置,ebp是栈底,ebp下面是call的指令

00711091 8B EC                mov         ebp,esp  
让esp指向ebp就是栈顶与栈底一致
00711093 83 EC 34             sub         esp,34h  
栈顶变高了 3*16+4=52个字节就是13个int  
	int total= 0;
00711096 C7 45 F8 00 00 00 00 mov         dword ptr [ebp-8],0  
	int i = 0;
0071109D C7 45 FC 00 00 00 00 mov         dword ptr [ebp-4],0  
然后声明两个局部变量 地址分别是 total:ebp-8 i:ebp-4
栈空间的最下面八个字节给了这两个
do {
		age[i] = GetAge();
007110A4 E8 A7 FF FF FF       call        00711050  //GetAge函数
007110A9 8B 4D FC             mov         ecx,dword ptr [ebp-4]  
007110AC 89 44 8D CC          mov         dword ptr [ebp+ecx*4-34h],eax  
		total+= age[i];
007110B0 8B 55 FC             mov         edx,dword ptr [ebp-4]  
007110B3 8B 45 F8             mov         eax,dword ptr [ebp-8]  
007110B6 03 44 95 CC          add         eax,dword ptr [ebp+edx*4-34h]  
007110BA 89 45 F8             mov         dword ptr [ebp-8],eax  
	} while (age[i++] != 0);
GetAge函数
std::cin >> rt;
00711074 8D 4D FC             lea         ecx,[ebp-4]  
00711077 51                   push        ecx  
00711078 8B 0D 70 30 71 00    mov         ecx,dword ptr ds:[00713070h]  
0071107E FF 15 40 30 71 00    call        dword ptr ds:[00713040h]  
	return rt;
00711084 8B 45 FC             mov         eax,dword ptr [ebp-4]  
}
看到返回值是eax返回的ebp-4就是rt
再看这里是个循环赋值 给ecx i的值 i最初=0
007110A9 8B 4D FC             mov         ecx,dword ptr [ebp-4]  
007110AC 89 44 8D CC          mov         dword ptr [ebp+ecx*4-34h],eax
所以判断数组 age[0]是ecx=0时即ebp-34h
age[9]是ebp+36-34h=ebp-10h
所以age分布在ebp-34h到ebp-10h中
age[10]=ebp-0ch//从头到尾都没这个 所以数组跟total就隔了一个int
所以age[11]是total age[12]是i age[13]是ebp age[14]是指令地址,改成我们要的函数地址就行

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值