设为首页 加入收藏

TOP

二进制炸弹(第二次实验)(一)
2016-04-27 17:25:30 】 浏览:2121
Tags:二进制 炸弹 第二 实验

实验目的

本实验通过要求你使用课程所学知识拆除一个“binary bombs”来增强对程序的机器级表示、汇编语言、调试器和逆向工程等方面原理与技能的掌握。 一个“binary bombs”(二进制炸弹,下文将简称为炸弹)是一个Linux可执行程序,包含了6个阶段(或层次、关卡)。炸弹运行的每个阶段要求你输入一个特定字符串,你的输入符合程序预期的输入,该阶段的炸弹就被拆除引信即解除了,否则炸弹“爆炸”打印输出 “BOOM!!!”。
实验的目标是拆除尽可能多的炸弹层次。
每个炸弹阶段考察了机器级程序语言的一个不同方面,难度逐级递增:
阶段1:字符串比较
阶段2:循环
阶段3:条件/分支
阶段4:递归调用和栈
阶段5:指针
阶段6:链表/指针/结构
另外还有一个隐藏阶段,只有当你在第4阶段的解后附加一特定字符串后才会出现。
为完成二进制炸弹拆除任务,你需要使用gdb调试器和objdump来反汇编炸弹的可执行文件并单步跟踪调试每一阶段的机器代码,从中理解每一汇编语言代码的行为或作用,进而设法推断拆除炸弹所需的目标字符串。比如在每一阶段的开始代码前和引爆炸弹的函数前设置断点。

实验分析

为了使分析清晰明了,每个阶段都有等价的c语言代码,隐藏关留到最后分析。
在开始之前,首先介绍两个库函数:
1.int sscanf(char *input,char *format,arg3,arg4….);这个函数和scanf功能相似,只是从input里读数据,而不是从stdin里读数据,返回成功读取数据的个数
2.long int strtol(const char *nptr,char **endptr,int base,int group);这个函数以base为进制将nptr字符串转化为对应的数值并返回

阶段一

08048b20 
   
    : ... 8048b2c: push $0x80497c0 /pattern/ 8048b31: push %eax /input/ 8048b32: call 8049030 
    
      ...
    
   

由上面的代码可以发现,调用了strings_not_equal比较input和pattern,用gdb查看0x80497c处的值:

(gdb) x/20x 0x80497c0
0x80497c0:  0x6c627550  0x73206369  0x6b616570  0x20676e69
0x80497d0:0x76207369    0x20797265  0x79736165  0x6425002e
...(省略)

根据字节顺序对照ASCII码表可知pattern为”Public speaking is easy.”,故阶段一的正确输入就是pattern。

阶段二

08048b48 
   
    : 8048b4b: sub $0x20,%esp 8048b4e: push %esi 8048b4f: push %ebx 8048b50: mov 0x8(%ebp),%edx /edx=input/ 8048b53: add $0xfffffff8,%esp 8048b56: lea -0x18(%ebp),%eax /&a[0]/ 8048b59: push %eax 8048b5a: push %edx /input/ 8048b5b: call 8048fd8 
    
   

这里我们可以看到,代码分配了int a[6]的存储空间,并调用了

read_six_numbers(input,a):
08048fd8 
   
    : 8048fdb: sub $0x8,%esp 8048fde: 08048b48 
    
     : mov 0x8(%ebp),%ecx /input/ 8048fe1: mov 0xc(%ebp),%edx /a/ 8048fe4: lea 0x14(%edx),%eax /a+5/ 8048fe7: push %eax 8048fe8: lea 0x10(%edx),%eax /a+4/ 8048feb: push %eax 8048fec: lea 0xc(%edx),%eax /a+3/ 8048fef: push %eax 8048ff0: lea 0x8(%edx),%eax /a+2/ 8048ff3: push %eax 8048ff4: lea 0x4(%edx),%eax /a+1/ 8048ff7: push %eax 8048ff8: push %edx /a/ 8048ff9: push $0x8049b1b /format/ 8048ffe: push %ecx /input/ 8048fff: call 8048860 
     
    
   

这里可以清楚地看到read_six_numbers将input,format,&a[0],&a[1]…&a[5]保存在esp指向的栈里面,接着调用sscanf,从input里读入数据存入数组a里。使用gdb查看format值:

(gdb) x/20x 0x8049b1b
0x8049b1b:  0x25206425  0x64252064  0x20642520  0x25206425
0x8049b2b:  0x61420064  0x6f682064  0x28207473
...(省略)

通过ASCII码表得知,format确实是”%d %d %d %d %d %d”,接着:

08048fd8 
   
    : 8049004: add $0x20,%esp 8049007: cmp $0x5,%eax /sscanf从input中读取数字个数/ 804900a: jg 8049011 
    
      804900c: call 80494fc 
     
       /if eax<=5,explode/ 8049011: mov %ebp,%esp 8049013: pop %ebp 8049014: ret
     
    
   

当sscanf返回值<=5时,引爆,否则返回phase_2。继续分析phase_2:

08048b48 
   
    : 8048b63: cmpl $0x1,-0x18(%ebp) /a[0]/ 8048b67: je 8048b6e 
    
      8048b69: call 80494fc 
     
       /if (a[0]!=1/ 8048b6e: mov $0x1,%ebx /if (a[0]==1)/ 8048b73: lea -0x18(%ebp),%esi /esi=&a[0]/ .loop 8048b76: lea 0x1(%ebx),%eax /eax=ebx-1/ 8048b79: imul -0x4(%esi,%ebx,4),%eax /eax*=a[ebx]/ 8048b7e: cmp %eax,(%esi,%ebx,4) 8048b81: je 8048b88
      
        8048b83: call 80494fc 
       
         /eax!=a[ebx]/ 8048b88: inc %ebx 8048b89: cmp $0x5,%ebx 8048b8c: jle 8048b76 
        
          goto .loop
        
       
      
     
    
   

这段代码首先比较a[0]和1,如果不相等,爆炸,否则进入for循环,比较每个数组元素的值,整个阶段二的等价C语言代码为:

void read_six_numbers(char *input,int a[])
{
    Int eax=sscanf(input,"%d %d %d %d %d %d",
a,a+1,a+2,a+3,a+4,a+5);
    if (eax<=5)
        explode_bomb();
}
void phase_2(char *input)
{
    int a[6];
    read_six_numbers(input,a);
    if (a[0]!=1)
        explode_bomb();
    for (int ebx=1;ebx<=5;ebx++)
        if (a[ebx]!=(ebx+1)*a[ebx-1])
            explode_bomb();
}

由此可以知道阶段二的字符串必须以”1 2 6 24 120 720 ”为开头,由于read_six_numbers仅限定了读入数据个数不小于6,因此正确答案不唯一

阶段三

08048b98 
   
    : 8048ba5: lea -0x4(%ebp),%eax 8048ba8: push %eax /&c/ 8048ba9: lea -0x5(%ebp),%eax 8048bac: push %ea
首页 上一页 1 2 3 4 下一页 尾页 1/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇OpenCV实践之路――行人检测 下一篇C++学习笔记之四 复合类型1

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目