利用栈溢出控制程序跳转运行的小实验
之前写代码的时候总是会提示memcpy 是不安全的,建议的函数进行替代.不知道为什么不安全的,今天做了个小实验.
实验目标:通过栈溢出的方式让程序不按照原来的逻辑运行.
步骤1:用C语言写一个栈溢出的代码
#include<windows.h>
CHAR szText[] = { "HelloWorldPe" };
CHAR szText2[] = { "Touch Me!" };
DWORD szShellCode[] = { 0xffffffff,0xdddddddd,0x01211888 ,0 };
INT _memCopy(LPSTR _lpSrc)
{
CHAR buf[4] = { 0 };
INT i = 0;
while (0!=_lpSrc[i])//只是检测值为0 szShellCode 数组的大小是 sizeof(DWORD) * 4 .目标数组的大小是4个字节肯定能够溢出。
{
buf[i] = _lpSrc[i];
i++;
}
return 0;
}
INT main()
{
_memCopy((LPSTR)szShellCode);
MessageBoxA(NULL, szText, NULL, MB_OK);//正常执行完_memCopy() 之后要先弹出一个 "HelloWorldPe"的会话框然后再弹出一个 "Touch Me!"的对话框
MessageBoxA(NULL, szText2, NULL, MB_OK);
return 0;
}
- 使用vs 编译程序的时候需要把这个选项改成默认值
- 如果不改的话,以为vs 有个运行时检查,即便是栈溢出了程序好像还是可以正常执行.
- 关掉之后程序终于如我所愿崩了
步骤2 使用x64dbg调试程序.
- 在程序的main 函数处下个断点.F9 执行到断点
- F7 步进,到_memCopy 代码处,在步进的过程中,可以看到栈中的值不断的被修改成了数组 szShellCode 中的值,大概是因为 _memCopy 中的 目标数据 buf 是局部变量,局部变量是在栈上开辟的.
- 图中栈区00CFFD88 记录的数据,是本来子函数执行完成之后要程序要执行的下一个指令的地址.因为栈溢出的缘故,这个地址将会被我修改.
- 子函数执行完成之后,成功跳转到我修改之后的执行地址.实现的效果就是,跳过 原来 “HelloWorldPe” 的massgeBox 不弹出. 直接弹出后面的 “Touch Me!”.
其他问题补充
- “图中栈区00CFFD88 记录的数据,是本来子函数执行完成之后要程序要执行的下一个指令的地址.因为栈溢出的缘故,这个地址将会被我修改.” 不难看出,栈上的数据都是从szShellCode 处复制过来的.第三个 dword 值就是.函数执行完成之后EIP 的值.就是下一个会执行的指令的地址.
- 为什么这个第三个dword ?函数调用的时候是要压栈的,调用完成之后是要弹栈的,至于为什么弹到这个值到 EIP .我不是很懂就不班门弄斧了.
- szShellcode 的第三个 dword. 的值就是 下一个执行的指令的值.我事先是不知道的,我随便乱写一个值,程序执行是会崩溃的,但是没有关系,我就随便乱写了.我使用x64 dbg 调试的时候.我就能够看到,我先要跳的指令的地址:01241851. 我在内存中找到 HelloWorldPe 这个字符串,就能发现szShellCode 数据的值就在它附近.
因为全局变量都是放在静态储存区(面试八股文,背是背熟了).汇编里面就是.data 段.pe结构里面的.data 节.
然后把第三个dword 改成:01241851目的就达成.
- 如果使用flexHex 这类的二进制编辑工具,找到szShellcode ,将第三个 dword 的值修改成01241851.会发现程序没有办法正常执行,程序被加载到内存中的地址,貌似会改变.可能跟重定位有关.所以szShellcode 的构造,是一门我还不懂的学问.