logo资料库

深入理解计算机系统 六个重要实验之lab2 实验报告.doc

第1页 / 共11页
第2页 / 共11页
第3页 / 共11页
第4页 / 共11页
第5页 / 共11页
第6页 / 共11页
第7页 / 共11页
第8页 / 共11页
资料共11页,剩余部分请下载后查看
一、实验目的 本实验通过要求你使用课程所学知识拆除一个“binary bombs”来增强对程序的机 器级表示、汇编语言、调试器和逆向工程等方面原理与技能的掌握。一个“binary bombs” (二进制炸弹,下文将简称为炸弹)是一个 Linux 可执行程序,包含了 6 个阶段(或层 次、关卡)。炸弹运行的每个阶段要求你输入一个特定字符串,你的输入符合程序预期 的输入,该阶段的炸弹就被拆除引信即解除了,否则炸弹“爆炸”打印输出 "BOOM!!!"。 实验的目标是拆除尽可能多的炸弹层次。 每个炸弹阶段考察了机器级程序语言的一个不同方面,难度逐级递增: 阶段 1:字符串比较 阶段 2:循环 阶段 3:条件/分支 阶段 4:递归调用和栈 阶段 5:指针 阶段 6:链表/指针/结构 另外还有一个隐藏阶段,只有当你在第 4 阶段的解后附加一特定字符串后才会出现。 为完成二进制炸弹拆除任务,你需要使用 gdb 调试器和 objdump 来反汇编炸弹的可执 行文件并单步跟踪调试每一阶段的机器代码,从中理解每一汇编语言代码的行为或作用, 进而设法推断拆除炸弹所需的目标字符串。比如在每一阶段的开始代码前和引爆炸弹的 函数前设置断点。 二、报告要求 本次报告需要同学们对破解炸弹过程中的 6 个阶段进行推理说明,尽可能结合实验 截图和代码分析。本次实验略有难度,希望同学们耐心研究,细心解答。 三、实验分析 1. 阶段一 调用前通过读取一个字符串,入栈 在中,调用来比较读取的结果和正确结果 (存放在$0x80497c0) 所以只需要查看在$0x80497c0 处存放的字符串就能得到第一个答案. 2. 阶段二
根据以上分析得出:数字的递推公式——n=1 num1=1;num(n+1)=(n+1)*num(n); 所以六个数字为:1 2 6 24 120 720 3. 阶段三 分析调用 sscanf 函数之前的堆栈信息
通 过 查 看 $0x80497de 处 的 内 存 能 够 得 到 sscanf 读 取 的 数 据 类 型 : %eax 中存放的是什么?sscanf 的返回值?如果读取的参数个数大于 2 就爆炸。 可知读取了三个变量,和之前堆栈中分配的内存照应 判断:-0xc(%ebp)处储存的是第一个整数 num1. if(num1>7) %bl=0x78,explode_bomb; 看来 if 应该小于等于 7 跳转表的地址在:0x80497e8,用 x/8xw 指令检查一下跳转表的内容: 得到 8 种情况的地址,根据地址找到对应代码,以 case0 为例: 找到对应的 case 代码,可知 case 中的内容:先把%ebx 寄存器的低 8 位置为 0x71, 接着比较 0x309 和第三个整数(储存在-0x4(%ebp)中)如果相同,接着比较%bl 和 第二个 char 类型的数据(储存在-0x5(%ebp)中),如果都相同则结束,因此,可以 推断满足 case0 的 char 为 q,整数值为 777。其他 case 同理。default 为 explode。 八种能够通过的情况对应的内容: num1 0 1 2 3 4 5 6 7 char q b b k o t v b num2 777 214 755 251 160 458 780 524
4. 阶段四 对 phase_4 的分析:如果调用 fun4 的结果是 55,成功返回。 对 fun4 的分析:fun4 需要一个参数 a,如果 a<=1 返回 1,否则返回 fun4(a-1)+fun4(a-2) 的值。即 fun4(a)=fun4(a-1)+fun(a-2),其中 a=1 时 fun4(1)=1; 由以上递推关系可得数列为(1)1 2 3 5 8 13 21 34 55……第 9 项是 55 因此输入 9 可以得到正确答案. 5. 阶段五
上面%eax 保存 string_length 函数的返回值,说明 phase_5 的输入要求有 6 个字符。 以上的代码的分析:程序从输入字符串 s[0]开始到 s[5]结束。对于第 i 次循环:把 s[i] 的后四位作为偏移量,以 0x804b220 为起始地址。得到对应内容后把这个内容写回 s[i]。 0x804b220 处的内容: 程序修改完毕之后进行比较。被比较的地址在 0x804980b。 可知经过变换后的正确结果应该为“giants”。 根据 0x804b220 处的内容,我们可以得到每个字符的偏移量:15 0 5 11 13 1。 即输入字符的后四位对应的以上六个偏移量。 可能的结果 (理论上每个位置的输入都有七种可能(高四位从 0000 到 0111),但是由于某 些 ascii 码对应的符号无法被显示或为转义字符,下面列举的符合条件的字符都不足 七个,并且有些字符被当做‘’显示):
/?O_o 0@P` %5EUe +;K[k -=M]m !1AQa 从每组中任选一个输入: 6. 阶段六 阶段六可以分成 4 个部分: part1:输入检查。输入六个数字,检查 检查内容为:1.每个数字 a 是否满足:1<=a&&a<=6 2.六个数字之间必须两两不相等 为方便后期整合以上内容的 C 语言代码为: int a[6]; for(int i=0;i<6;i++){ scanf("%d",a[i]); } for(int i=0;i<6;i++){ if(a[i]>6)printf("BOOM!"); for(int j=i+1;j<6;j++){ if(a[i]=a[j])printf("BOOM!"); } } part2:地址修改
part2: 根据上面输入的 6 个数字中的每一个,计算出一个对应的偏移量,这个偏 移量加基地址,得到一个 node 的地址。 首先载入一个基地址:0x804b26c 执行过 0x8048e30 语句后 在循环中依次查看寄存器中的内容就可以得到下面的地址表: 1 2 3 4 5 6 0x804b26c 0x804b260 0x804b254 0x804b248 0x804b23c 0x804b230
part3 链表构建: 假设:存放“被修改过的地址”的容器为数组 b,b[i]存放,根据 a[i]内容进行基地 址偏移的结果。 根据数组 b 的元素内容构建链表:b[i]->next=b[i+1] part4 链表检查: 遍历链表。需要确保链表的前一个结点的数据值 val 大于后一个节点的数据值。 因此我们需要查看每个节点的数据值是什么,再根据这些数据值对节点进行排序, 找到正确的顺序之后就可以得到每个节点相对基地址的偏移量,就能够得出数组 a 中的内容,即可得到正确答案。 node 内容: node 内容 0xfd 1 2 0x2d5 0x12d 3 0x3e5 4 5 0xd4 6 0x1b0 正确结果: 4 2 6 3 1 5 7 secret phase part1 发现:secret phase 程序每次执行完一个 phase 判断程序后都会执行 phase_defused 程序,会不会在这里 呢? phase_defused:
分享到:
收藏