1 本文搬运于我的CSDN blog。
2 第一次发帖,有不合理的地方,希望斑竹直接delete。
3 由于长期拿着各位大大的总结的知识,这里我总结了一个关于软件调试的原理吧,回馈给大家。
<font color = red size = 7>#PS:要转载请注明出处,本人版权所有</font>
<font color = red size = 7 >#PS:这个只是 《 我自己 》理解,如果和你的
</font>
<font color = red size = 7 >#原则相冲突,请谅解,勿喷</font>
本文仅用于学习计算机程序运行原理,请不要用作其他违法用途。
内存溢出可以说是我们程序员经常遇到的问题了,但是一般过程中,我们只会处理让程序崩溃的内存溢出,只要程序不崩溃,我们基本不会管的了。这里,我将会演示一下程序内存溢出的严重后果。同时也警示我们自身,写程序一定要逻辑严密一点,不要犯低级错误。(然而我们不可能避免错误,只要没有比较明显的错误即可。)
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 地址空间随机化等等
这些东西都可以提高内存溢出的难度,我是一个小白,为了理解内存攻击,我得把他们关闭了。
对应的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版本
汇编版本(64位,注意)
64位系统,execve的系统调用号为59,也就是0x3b

异常代码
exp 辅助生产工具,生成exp文件,python exp.py>msg
exp.py 文件内容
编译方法,去掉堆栈保护,设置堆栈可执行
关闭地址随机化(必须root用户情况下):
echo 0 > /proc/sys/kernel/randomize_va_space
效果:

至此我们成功拿到了shell,可以做一些简单的shell操作等等。
根据上文overflow源码分析得出,我们溢出了90个字节,由于程序员的不小心。这100个字节是来至于文件的,我们可以构建一个特殊的文件来达到我们的目的。
根据exp助手,我们可以生成一个创建shell的exp文件。
根据exp助手源码可知:
1-10字节为M ------ 这对应我们申请的buf内容
11-18字节为M ------ 这对应在子过程调用中,push rbp时,保存的原有的rbp
19-26字节为eip在栈中的位置 ------ 这就是我们要修改当overflow返回时,我要计算机执行的我的代码的地方,也就是shellcode中的xor eax,eax
27-54字节即为创建shell的shellcode
如果我们在overflow中申请的buf地址为N,那么:
N~N+0xa 为buf的内存空间
N+0xb~N+0x12 为原rbp保存的位置
N+0x13~N+0x1a 为我们需要控制的eip的值,需要让他指定到我们想要的地址去,明显我们想要的地址就是N+0x1b,也就是我们创建shell的汇编存放的地方
N+0x1b~N+0x36 为我们存放创建shell汇编代码的存放的地方。
从上述分析可知:
我们需要改的就是N+0x13~N+0x1a内存中存放的值,改为N+0x1b.
在操作系统中:当我们关闭的地址虚拟化后,我们的程序在开机的过程中,每次运行的时候,基地址的一致的,这样我们每次运行的时候,我们的buf地址是一致,当我们获取了buf地址后,即可生成exp文件。
我们通过core文件和gdb来找到buf的地址如下图:
先运行./a.out msg
这个时候msg的地址可以乱填,反正会段错误。得到core文件
在运行 gdb --core=core
这个时候查看几个寄存器的值,唯一的有效值是rsp的值如下图:

[培训]科锐逆向工程师培训第53期2025年7月8日开班!
最后于 2018-12-17 12:02
被Iflyinsky编辑
,原因: 纠错