实验题目:

程序运行在linux环境中。程序运行中有6个关卡(6个phase),每个phase需要用户在终端上输入特定的字符或者数字才能通关,否则会引爆炸弹!需要使用gdb工具反汇编出汇编代码,结合c语言文件找到每个关卡的入口函数。然后分析汇编代码,找到在每个phase程序段中,引导程序跳转到“explode_bomb”程序段的地方,并分析其成功跳转的条件,以此为突破口寻找应该在命令行输入何种字符通关。

实验目的:熟悉汇编代码及其调试方法。

实验环境:个人电脑、32 位ubuntu 18.04环境、GDB调试工具、objdump、32位IDA反汇编工具

实验内容及操作步骤:

第一步首先对bomb可执行文件文件进行反汇编,并将结果输出到bomb.txt,方便查看汇编代码。

使用 objdump -d bomb_64 > bomb.txt指令对可执行文件反汇编并进行输出,为方便查阅汇编代码,在图形化界面中将txt结果用文本编辑器打开。

第二步已知本实验共有6个关卡,通过对bomb.c的C程序代码的浏览,开始对汇编代码中所有phase程序段进行汇编代码的解读过关。

  1. 第一关

【汇编代码】打开反汇编形成的txt文件,定位到phase_1函数处(后续关卡省略截图)

【代码分析】

sub    $0x1c,%esp                     为函数开辟一个新栈,分配0x1c即28个字节的空间

movl   $0x804a1e4,0x4(%esp)           将$0x804a1e4处值存入esp+4地址处

mov    0x20(%esp),%eax                将esp+20处的值存到eax中

mov    %eax,(%esp)                    将eax中的值传递给esp所存值的地址处

call   8049004 <strings_not_equal>    调用8049004处函数,判断字符串是否相等

test   %eax,%eax                      判断eax值是否为0

je     8048b70 <phase_1+0x20>         若eax为0则跳转到8048b70处,进入下一关

call   8049116 <explode_bomb>         否则跳转到8049116处,调用引爆炸弹函数

add    $0x1c,%esp                     开辟一个新栈

ret                                   函数返回

【解题思路】

分析代码,该函数先将存有目标字符串的地址$0x804a1e4中内容先存入了当前帧,再将外部输入的字符串存入到eax寄存器中,再通过eax将外部输入传递到esp中,通过函数调用比较esp(外部输入)与esp+4中的目标字符串是否相等,如果相等,返回值为0,进入下一关,反之则调用爆炸程序,所以我们只需要查看地址$0x804a1e4处的值就能找到通关条件。

使用GDB指令查看指定地址存储的数据:

【其他解法】

打开32位IDA反汇编工具,拖入bomb ELF可执行文件,按F5进行反汇编出伪代码,定位到phase_1函数处,对伪代码进行查看分析,观察发现直接得到第一关的成功跳转的字符串结果:

【通关字符串】

I can see Russia from my house!

  1. 第二关

【汇编代码及分析】

push   %esi                       压栈保存

push   %ebx                       压栈保存

sub    $0x34,%esp                 为函数开辟一个新栈,分配0x34即52个字节的空间

lea    0x18(%esp),%eax            将esp+24得到的地址传送到eax寄存器中

mov    %eax,0x4(%esp)             将eax寄存器内值存入esp+4地址处

mov    0x40(%esp),%eax            将esp+64地址内值存入eax寄存器中

mov    %eax,(%esp)                将eax中的值传递给esp所存值的地址处

call   804924b <read_six_numbers> 调用读取6个输入数字的函数,即字符串为6个数字组合

cmpl   $0x1,0x18(%esp)            判断立即数1和esp+24内所存值是否相等

je     8048b99 <phase_2+0x25>     若相等则跳转到8048b99处

call   8049116 <explode_bomb>     否则跳转到8049116处,调用引爆炸弹函数

lea    0x1c(%esp),%ebx            将esp+28得到的地址传送到ebx寄存器中

lea    0x30(%esp),%esi            将esp+48得到的地址传送到esi寄存器中

mov    -0x4(%ebx),%eax            将ebx-4地址处值存入eax寄存器中

add    %eax,%eax                  将eax寄存器内值变为2倍后放回

cmp    %eax,(%ebx)                判断eax寄存器内值与ebx寄存器记录地址内值是否相等

je     8048baf <phase_2+0x3b>     若相等则跳转到8048baf处

call   8049116 <explode_bomb>     否则跳转到8049116处,调用引爆炸弹函数

add    $0x4,%ebx                  将ebx寄存器内值加4后放回

cmp    %esi,%ebx                  比较esi寄存器内值与ebx寄存器内值是否相等

jne    8048ba1 <phase_2+0x2d>     若不相等则跳转到8048ba1处

add    $0x34,%esp                 更新栈

pop    %ebx                       释放栈帧

pop    %esi                       释放栈帧

ret                               函数返回

【解题思路】

通过对汇编代码的解读,我们可以发现这段字符串要我们输入6个数字,读入的6个数字被存放在从%esp指向的地址开始向上的位置。这段汇编代码是比较了三次,分别是0x1与0x18(%esp)存的值、%eax存的值与(%ebx) 存的值、%esi存的值与%ebx存的值,三者必须相等,否则调用炸弹函数。

首先,将esp+18处的值传输到eax中,再将eax中的值存入esp+4即edp-32处;将ebp+40中的值传输到eax中,再将eax中的值存入esp处;cmpl指令比较1和esp+24内所存值,相等才不触发炸弹,所以数字串的第一个数字为1;之后,lea将esp+28的值存入ebx中,第二个lea将esp+48的值存入esi中,后面会用到这里的赋值控制循环,再将ebx-4即ebp-24-4的值存入eax中,将eax寄存器内值变为2倍后放回,最后比较eax和ebx中的值,相等才不触发炸弹, add指令将ebx中的值加上4,最后比较esi与ebx中的值,如果不相等则进入下一循环,否则循环五次,整个程序结束,因此可以得到这是一个以1为首项,2为公比的等比数列,解除第二关的炸弹,进入第三关。

【其他解法】

打开32位IDA反汇编工具,拖入bomb ELF可执行文件,按F5进行反汇编出伪代码,定位到phase_2函数处,对伪代码进行查看分析,可以得知第一个数字一定要为1才会进入循环,循环五次,每次将之前一个数字乘以2得到:

【通关字符串】

1 2 4 8 16 32

  1. 第三关

【汇编代码及分析】

sub    $0x2c,%esp                       为函数开辟一个新栈,分配0x2c即44个字节的空间

lea    0x1c(%esp),%eax                  将esp+28得到的地址传送到eax寄存器中

mov    %eax,0xc(%esp)                   将eax寄存器内值存入esp+12地址处

lea    0x18(%esp),%eax                  将esp+24得到的地址传送到eax寄存器中

mov    %eax,0x8(%esp)                   将eax寄存器内值存入esp+8地址处

movl   $0x804a403,0x4(%esp)             将$0x804a403处值存入esp+4地址处

     由此可知输入两个数字组合的字符串

mov    0x30(%esp),%eax                  将esp+30处值传送到eax寄存器中

mov    %eax,(%esp)                      将eax寄存器中的值传输到esp记录地址处

call   8048870 <__isoc99_sscanf@plt>    过程调用,8048870为被调用过程起始点指令地址

cmp    $0x1,%eax                        判断eax寄存器中的值是否大于立即数1

jg     8048bed <phase_3+0x31>           若大于则跳转到8048bed处

call   8049116 <explode_bomb>           否则跳转到8049116处调用炸弹函数

cmpl   $0x7,0x18(%esp)                  判断esp+24地址处值减去立即数7是否大于0

ja     8048c5a <phase_3+0x9e>           大于0则跳转到8048c5a处

mov    0x18(%esp),%eax                  将esp+18处值传送到eax寄存器中

jmp    *0x804a240(,%eax,4)              无条件跳转到(4×%eax+0x804a240)地址处

mov    $0x0,%eax                        将立即数0传送到eax寄存器中

jmp    8048c0b <phase_3+0x4f>           无条件跳转到8048c0b地址处

mov    $0x231,%eax                      将立即数561传到eax寄存器中

sub    $0x25d,%eax                      eax寄存器中值减去605再放回eax寄存器中

jmp    8048c17 <phase_3+0x5b>           无条件跳转到8048c17地址处

mov    $0x0,%eax                        将立即数0传送到eax寄存器中

add    $0x37a,%eax                      eax寄存器中值加上890再放回eax寄存器中

jmp    8048c23 <phase_3+0x67>           无条件跳转到8048c23地址处

mov    $0x0,%eax                        将立即数0传送到eax寄存器中

sub    $0x3ae,%eax                      eax寄存器中值减去942再放回eax寄存器中

jmp    8048c2f <phase_3+0x73>           无条件跳转到8048c2f地址处

mov    $0x0,%eax                        将立即数0传送到eax寄存器中

add    $0x3ae,%eax                      eax寄存器中值加上942再放回eax寄存器中

jmp    8048c3b <phase_3+0x7f>           无条件跳转到8048c3b地址处

mov    $0x0,%eax                        将立即数0传送到eax寄存器中

sub    $0x3ae,%eax                      eax寄存器中值减去942再放回eax寄存器中

jmp    8048c47 <phase_3+0x8b>           无条件跳转到8048c47地址处

mov    $0x0,%eax                        将立即数0传送到eax寄存器中

add    $0x3ae,%eax                      eax寄存器中值加上942再放回eax寄存器中

jmp    8048c53 <phase_3+0x97>           无条件跳转到8048c17地址处

mov    $0x0,%eax                        将立即数0传送到eax寄存器中

sub    $0x3ae,%eax                      eax寄存器中值减去942再放回eax寄存器中

jmp    8048c64 <phase_3+0xa8>           无条件跳转到8048c64地址处

call   8049116 <explode_bomb>           跳转到8049116处调用炸弹函数

mov    $0x0,%eax                        将立即数0传送到eax寄存器中

cmpl   $0x5,0x18(%esp)                  判断立即数5减去eax+18处值是否大于0

jg     8048c71 <phase_3+0xb5>           大于0则跳转至8048c71处

cmp    0x1c(%esp),%eax                  判断esp+28处值和eax寄存器内值是否相等

je     8048c76 <phase_3+0xba>           相等则跳转至8048c76处

call   8049116 <explode_bomb>           否则跳转到8049116处调用炸弹函数

add    $0x2c,%esp                       更新栈

ret                                     函数返回

【解题思路】

首先,将ebp+28处的值传输到eax中,再将eax中的值存入esp+12处;将esp+24中的值传输到eax中,再将eax中的值存入esp+8处;将0x804a403处的值存入到esp+4中;将ebp+30处的值传输到eax中,再将eax中的值(参数1)存入esp处;cmp将eax与数值1做减法,当结果大于0即eax>1时,程序跳过炸弹。cmpl将esp+24的值(参数A)与数值7做减法,当结果大于0即参数A >7则跳转到炸弹处,所以esp+24的值(参数A)<7;将esp+24中的值(参数A)传输到eax中,跳转到0x804a240(,%eax,4)  中数据指向的地址,esp+24中的值(参数A)的不同将会引起程序跳转到不同地方。将eax清零,跳转到8048c0b处,执行eax先置561再$0x25d的指令;后面几行都是将eax清零,并对eax进行相关操作。cmpl将esp+24中的值(参数A)与0x5相减,当结果大于0即参数A>5则跳转到炸弹处,所以esp+24中的值(参数A)小于等于5;又判断eax中值与esp+28中的值(参数B),相等则得到对应结果。所以参数A的范围为0到5,且参数A的值会决定eax中的初始值,而我们输入的参数B又必须和eax中的值相等,所以参数A为0到5分别会有对应的eax的值,即为我们要求的参数B。

esp+24(参数A)

0x804a240(,%eax,4)的地址

对应的地址

eax算得值(参数B)

0

0x804a240

-96

1

0x804a244

-657

2

0x804a248

-52

3

0x804a24c

-942

4

0x804a250

0

5

0x804a254

-942

【其他解法】

打开32位IDA反汇编工具,拖入bomb ELF可执行文件,按F5进行反汇编出伪代码,定位到phase_3函数处,对伪代码进行查看分析,可以得知我们要输入两个整形的数字,且该函数的返回值要求大于1才不会爆炸,对switch语句进行分析,发现输入的第一个数字v9不能超过5,同时,根据输入的第一个数字可以得到第二个数字对应的值,则找出一共6组解:0 -96、1 -657、2 -52、3 -942、4 0、5 -942

【通关字符串】

共6组答案:0 -96或1 -657或2 -52或3 -942或4 0或5 -942(测试均通过)

  1. 第四关

【汇编代码及分析】

sub    $0x2c,%esp                       为函数开辟一个新栈,分配0x2c即44个字节的空间

lea    0x1c(%esp),%eax                  将esp+28得到的地址传送到eax寄存器中

mov    %eax,0xc(%esp)                   将eax寄存器内值存入esp+12地址

lea    0x18(%esp),%eax                  将esp+24得到的地址传送到eax寄存器中

mov    %eax,0x8(%esp)                   将eax寄存器内值存入esp+8地址处

movl   $0x804a403,0x4(%esp)             将$0x804a403处值存入esp+4地址处

     由此可知输入两个数字组合的字符串

mov    0x30(%esp),%eax                  将esp+30处值传送到eax寄存器中

mov    %eax,(%esp)                      将eax寄存器中的值传输到esp记录地址处

call   8048870 <__isoc99_sscanf@plt>    过程调用,8048870为被调用过程起始点指令地址

cmp    $0x2,%eax                        判断立即数2和eax寄存器中的值是否相等

jne    8048d20 <phase_4+0x39>           若不相等则跳转到8048d20处调用炸弹函数

mov    0x18(%esp),%eax                  将esp+18处值传送到eax寄存器中

test   %eax,%eax                        判断eax值是否为0

js     8048d20 <phase_4+0x39>           根据符号标志位SF跳转到8048d20处

cmp    $0xe,%eax                        判断eax寄存器中的值是否小于等于立即数16

jle    8048d25 <phase_4+0x3e>           小于等于则跳转至8048d25处

call   8049116 <explode_bomb>           否则跳转到8049116处调用炸弹函数

movl   $0xe,0x8(%esp)                   将立即数16传送到esp+8处中

movl   $0x0,0x4(%esp)                   将立即数0传送到esp+4处中

mov    0x18(%esp),%eax                  将esp+24处值传送到eax寄存器中

mov    %eax,(%esp)                      将eax寄存器中的值传输到esp记录地址处

call   8048c7a <func4>                  调用8048c7a处的func4函数

cmp    $0x5,%eax                        比较eax寄存器与5的值

jne    8048d4d <phase_4+0x66>           若不相等则跳转至8048d4d处

cmpl   $0x5,0x1c(%esp)                  比较esp+5处值与立即数5的值

je     8048d52 <phase_4+0x6b>           若相等则跳转到8048d52处,进入下一关

call   8049116 <explode_bomb>           否则调用8049116处炸弹函数

add    $0x2c,%esp                       释放栈帧

ret                                     函数返回

【调用的func4函数汇编代码及分析】

sub    $0x1c,%esp                       为函数开辟一个新栈,分配0x2c即28个字节的空间

mov    %ebx,0x14(%esp)                  将ebx寄存器内值(传入的参数A)存入esp+20地址处

mov    %esi,0x18(%esp)                  将esi寄存器内值(传入的参数B)存入esp+24地址处

mov    0x20(%esp),%edx                  将esp+32处值传送到edx寄存器中

mov    0x24(%esp),%eax                  将esp+36处值传送到eax寄存器中

mov    0x28(%esp),%ebx                  将esp+30处值传送到ebx寄存器中

mov    %ebx,%ecx                        将ebx寄存器中的值传输到ecx寄存器中

sub    %eax,%ecx                        用ecx寄存器中的值减去eax寄存器中值后存入ecx中

mov    %ecx,%esi                        将ecx寄存器中的值传输到esi寄存器中

shr    $0x1f,%esi                       对esi寄存器中的值逻辑右移31位

add    %esi,%ecx                        将ecx寄存器中的值加上esi寄存器中值后存入ecx中

sar    %ecx                             将ecx寄存器中的值算术右移1位,即除2

add    %eax,%ecx                        将ecx寄存器中的值加上eax寄存器中值后存入ecx中

cmp    %edx,%ecx                        判断ecx寄存器中的值是否小于等于edx寄存器中的值

jle    8048cbb <func4+0x41>             小于等于则跳转至8048cbb处

sub    $0x1,%ecx                        用ecx寄存器中的值减去立即数1后存入ecx中

mov    %ecx,0x8(%esp)                   将ecx寄存器中的值传输到esp+8处地址中

mov    %eax,0x4(%esp)                   将eax寄存器中的值传输到esp+4处地址中

mov    %edx,(%esp)                      将edx寄存器内值存入esp地址处

call   8048c7a <func4>                  递归调用func4函数

add    %eax,%eax                        将eax寄存器的值加后变为2倍后放回

jmp    8048cdb <func4+0x61>             无条件跳转至8048cdb处

mov    $0x0,%eax                        将立即数0传输到eax寄存器中

cmp    %edx,%ecx                        比较ecx寄存器中的值是否大于等于edx寄存器中值

jge    8048cdb <func4+0x61>             大于等于则跳转至8048cdb处进入下一关

mov    %ebx,0x8(%esp)                   将ebx寄存器中的值传输到esp+8处地址中

add    $0x1,%ecx                        将ecx寄存器中的值加上立即数1后存入ecx中

mov    %ecx,0x4(%esp)                   将ecx寄存器中的值传输到esp+4处地址中

mov    %edx,(%esp)                      将edx寄存器内值存入esp地址处

call   8048c7a <func4>                  递归调用func4函数

lea    0x1(%eax,%eax,1),%eax            将eax×1+eax+1处值传入eax寄存器中

mov    0x14(%esp),%ebx                  将esp+20地址处值存入ebx寄存器内值(参数A)

mov    0x18(%esp),%esi                  将esp+24地址处值存入ebx寄存器内值(参数B)

add    $0x1c,%esp                       释放栈帧

ret                                     函数返回

【解题思路】

首先,整个函数的输入是两个数字组成的字符串,调用的func4的函数就是一个递归函数,其中cmp    $0x5,%eax可知该递归函数的返回值要为5,且cmpl   $0x5,0x1c(%esp)可知我们将输入的第二个参数要与返回值5相等,且在func4函数中mov    0x20(%esp),%edx  mov    0x24(%esp),%eax               mov    0x28(%esp),%ebx 可知传入func4函数中的有三个参数,且第一个参数为输入,第二个参数为0,第三个参数为14,根据递归关系,可以得知当第一个参数为10时,返回值为5,得到答案的两个数字10和5.

【其他解法】

打开32位IDA反汇编工具,拖入bomb ELF可执行文件,按F5进行反汇编出伪代码,定位到phase_4函数处,对伪代码进行查看分析,发现其调用了func4函数(该函数为递归函数),调出其伪代码,可以看出是对两个数字进行输入,改写得到一个main函数由phase_4构成、引用函数由func4函数构成的C++文件,进行编译,得到输入的两个数字结果:

phase_4()伪代码:

调用的func4函数伪代码:

改写好的C++文件:

输出结果:

【通关字符串】

10 5

  1. 第五关

【汇编代码及分析】

sub    $0x2c,%esp                       为函数开辟一个新栈,分配0x2c即44个字节的空间

lea    0x1c(%esp),%eax                  将esp+28得到的地址(参数A)传送到eax寄存器中

mov    %eax,0xc(%esp)                   将eax寄存器内值存入esp+12地址处

lea    0x18(%esp),%eax                  将esp+24得到的地址(参数B)传送到eax寄存器中

mov    %eax,0x8(%esp)                   将eax寄存器内值存入esp+8地址处

movl   $0x804a403,0x4(%esp)             将$0x804a403处值存入esp+4地址处

     由此可知输入两个数字组合的字符串

mov    0x30(%esp),%eax                  将esp+30处值传送到eax寄存器中

mov    %eax,(%esp)                      将eax寄存器中的值传输到esp记录地址处

call   8048870 <__isoc99_sscanf@plt>    过程调用,8048870为被调用过程起始点指令地址

cmp    $0x1,%eax                        判断eax寄存器中的值是否大于立即数1

jg     8048d87 <phase_5+0x31>           若大于则跳转到8048d87处

call   8049116 <explode_bomb>           否则跳转到8049116处调用炸弹函数

mov    0x18(%esp),%eax                  将esp+18处值传送到eax寄存器中

and    $0xf,%eax                        将ecx寄存器中的值加上立即数16后存入ecx中

mov    %eax,0x18(%esp)                  将eax寄存器中值传送回esp+18处

cmp    $0xf,%eax                        比较eax寄存器中值是否与立即数15相等,循环15次

je     8048dc1 <phase_5+0x6b>           若相等则跳转到8048dc1处,调用炸弹函数

mov    $0x0,%ecx                        将立即数0传入ecx寄存器中,设置初始值

mov    $0x0,%edx                        将立即数0传入edx寄存器中,设置初始值

add    $0x1,%edx                        将edx寄存器中的值加上立即数1后存入edx中

mov    0x804a260(,%eax,4),%eax          将eax×4+0x804a260处值放入eax寄存器, 取数组元素

add    %eax,%ecx                        将ecx寄存器中的值加上eax寄存器中值后存入ecx中

cmp    $0xf,%eax                        比较eax寄存器中值是否与立即数15相等,跳出循环

jne    8048da1 <phase_5+0x4b>           若不相等则跳转至8048da1处,跳出循环

mov    %eax,0x18(%esp)                  将eax寄存器中值传送回esp+24处

cmp    $0xf,%edx                        比较edx寄存器中值是否与立即数15相等

jne    8048dc1 <phase_5+0x6b>           若不相等则跳转至8048dc1处,调用炸弹

cmp    0x1c(%esp),%ecx                  比较esp+28处值是否与ecx寄存器中相等

je     8048dc6 <phase_5+0x70>           若相等则跳转到8048dc6处,进入下一关

call   8049116 <explode_bomb>           否则调用8049116处炸弹函数

add    $0x2c,%esp                       释放栈帧

ret                                     函数返回

【解题思路】

首先,将ebp+28处的值传输到eax中,再将eax中的值存入esp+12处;将esp+24中的值传输到eax中,再将eax中的值存入esp+8处;将0x804a403处的值存入到esp+4中;将ebp+30处的值传输到eax中,再将eax中的值(参数A)存入esp处;cmp将eax与数值1做减法,当结果大于0即eax>1时,程序跳过炸弹,看到有edx和esp考虑下面的情况中有循环或者数组.这题要求输入两个数字, 然后第一个数字只保留后四位,其他位置为0。edx用于循环次数的计数,则循环15次,当eax为16时跳出循环,但是这里有一个需要注意的地方,我们输入的第一个数用来被计算偏移下标了。也就是说下标不是连续的。每次取出来的元素的值用到下一次去数组元素时计算下标。可以看到ecx寄存器是一个累加器,先赋值为零,然后用来保存数组元素的和,然后eax用来循环计数,在这里,只要取到的数组中元素不为15就继续循环累加求和,可以看出数组中有一个元素是15,且数组首地址为0x804a260,则先将数组中的首地址里面存的数值取出来。另外输入的数参数B要等于ecx,也就是要等于累加之后的结果。且最后取出的值为15,则取出元素的值(取15次)依次为:15 6 14 2 1 10 0 8 4 9 13 11 7 3 12,最先取出数为12,偏移量为20,即4*5,则第一个数为5,此时累加和为115

【通关字符串】

5 115

  1. 第六关

【汇编代码及分析】

push   %esi                          压栈保存

push   %ebx                          压栈保存

sub    $0x44,%esp                    为函数开辟一个新栈,分配0x44即68个字节的空间

lea    0x10(%esp),%eax               将esp+16得到的地址传送到eax寄存器中

mov    %eax,0x4(%esp)                将eax寄存器内值存入esp+4地址处

mov    0x50(%esp),%eax               将esp+80地址内值存入eax寄存器中

mov    %eax,(%esp)                   将eax中的值传递给esp所存值的地址处

call   804924b <read_six_numbers>    用读取6个输入数字的函数,即字符串为6个数字组合

mov    $0x0,%esi                     将立即数0传入esi寄存器中

mov    0x10(%esp,%esi,4),%eax        将esi×4+esp+16处值放入eax寄存器中

sub    $0x1,%eax                     将eax寄存器中的值减去立即数1后存入eax中

cmp    $0x5,%eax                     比较eax中值是否小于等于立即数5

jbe    8048df9 <phase_6+0x2f>        小于等于则跳转至8048df9处,即下下行汇编代码

call   8049116 <explode_bomb>        否则跳转至8049116调用炸弹函数

add    $0x1,%esi                     将esi寄存器中的值加上立即数1后存入esi中

cmp    $0x6,%esi                     比较esi寄存器中的值与立即数6是否相等

je     8048e34 <phase_6+0x6a>        若相等则跳转到8048e34处

mov    %esi,%ebx                     将esi寄存器中的值传入ebx寄存器中

mov    0x10(%esp,%ebx,4),%eax        将esi×4+esp+16处值放入eax寄存器中

cmp    %eax,0xc(%esp,%esi,4)         比较esi×4+esp+12处值与eax寄存器中值是否相等

jne    8048e12 <phase_6+0x48>        若不相等则跳转至8048e12处,即下下行汇编代码

call   8049116 <explode_bomb>        否则调用炸弹函数

add    $0x1,%ebx                     将ebx寄存器中值加1再放回

cmp    $0x5,%ebx                     判断ebx寄存器中值是否小于等于立即数5

jle    8048e03 <phase_6+0x39>        小于等于则跳转至8048e03处, phase_6+57

jmp    8048de8 <phase_6+0x1e>        无条件跳转至8048de8处, phase_6+30

mov    0x8(%edx),%edx                将edx+8处值传入edx寄存器中

add    $0x1,%eax                     将eax寄存器中值加1再放回

cmp    %ecx,%eax                     判断eax寄存器中值是否等于ecx寄存器中值

jne    8048e1c <phase_6+0x52>        若不相等则跳转至8048e1c处

mov    %edx,0x28(%esp,%esi,4)        将eax寄存器中值放入esi×4+esp+30处

add    $0x1,%ebx                     将ebx寄存器中值加1再放回

cmp    $0x6,%ebx                     判断ebx寄存器中值是否等于立即数6

jne    8048e39 <phase_6+0x6f>        若不相等则跳转至8048e39处,phase_6+111

jmp    8048e50 <phase_6+0x86>        无条件跳转至8048e50处,phase_6+134

mov    $0x0,%ebx                     将立即数0放入ebx寄存器中

mov    %ebx,%esi                     将ebx寄存器中值传入esi寄存器中

mov    0x10(%esp,%ebx,4),%ecx        将esi×4+esp+16处值放入ecx寄存器中

mov    $0x1,%eax                     将立即数1放入eax寄存器中

mov    $0x804c13c,%edx               将$0x804c13c地址中值放入edx中

说明此处为连续存放的链表,则查看该链表中的六个数(16进制转10进制):252 978 122 956 603 53

cmp    $0x1,%ecx                     判断ecx寄存器中值是否大于1

jg     8048e1c <phase_6+0x52>        大于则跳转至8048e1c处,phase_6+82

jmp    8048e26 <phase_6+0x5c>        无条件跳转至8048e26处,phase_6+92

mov    0x28(%esp),%ebx               将esp+30处值放入ebx寄存器中

mov    0x2c(%esp),%eax               将esp+44处值放入eax寄存器中

mov    %eax,0x8(%ebx)                将eax寄存器中值放入ebx+8处

mov    0x30(%esp),%edx               将esp+48处值放入edx寄存器中

mov    %edx,0x8(%eax)                将edx寄存器中值放入eax+8处

mov    0x34(%esp),%eax               将esp+52处值放入eax寄存器中

mov    %eax,0x8(%edx)                将eax寄存器中值放入edx+8处

mov    0x38(%esp),%edx               将esp+56处值放入edx寄存器中

mov    %edx,0x8(%eax)                将edx寄存器中值放入eax+8处

mov    0x3c(%esp),%eax               将esp+60处值放入eax寄存器中

mov    %eax,0x8(%edx)                将eax寄存器中值放入edx+8处

movl   $0x0,0x8(%eax)                将立即数0放入eax+8处

mov    $0x5,%esi                     将立即数5放入esi寄存器中

mov    0x8(%ebx),%eax                将ebx+8处值放入eax寄存器中

mov    (%eax),%edx                   将eax记录地址处值放入edx寄存器中

cmp    %edx,(%ebx)                   判断ebx记录的地址中值是否小于等于edx寄存器中的值

jle    8048e91 <phase_6+0xc7>        小于等于则跳转至8048e91处,即phase_6+199

call   8049116 <explode_bomb>        否则调用炸弹函数

mov    0x8(%ebx),%ebx                将ebx+8处值放入ebx寄存器中

sub    $0x1,%esi                     用esi寄存器中值减去立即数1再放回

jne    8048e83 <phase_6+0xb9>        若不相等则跳转至8048e83处,即phase_6+185

add    $0x44,%esp                    释放栈帧

pop    %ebx                          出栈操作

pop    %esi                          出栈操作

ret                                  函数返回

【解题思路】

首先通过调用的函数可以知道字符串为6个数字,可以看出程序内部存储了一个长度为6的链表,之后根据下面四句可以看出有一个双层的嵌套循环分别执行5次,要求6个数全部小于等于6并且各不相等。其中有一行地址引用,查看内容可以看到是node结构体,猜测包含了一个链表,那就继续往下打印这个链表可以6个数:252 978 122 956 603 53,之后又产生了一个双层的循环嵌套,并且可以看出循环一开始便将链表第一个节点的值存入了堆栈,之后内层每循环一次就将节点往后取,直至跳出内层循环,便将节点地址存入一个新的堆栈地址中。接下来根据下面语句可以看出又是一个循环,此循环将链表按照刚刚存入堆栈中的顺序重新连接成新的链表。接下来又是一个循环,此循环中判断新的链表中的第一个数据域中的值,前面的数小于后面的数则不会爆炸,则这6个数从小到大的排序为6 3 1 5 4 2。

【通关字符串】

6 3 1 5 4 2

  1. 隐藏关卡

【如何进入隐藏关卡】

  1. 观察主函数的汇编代码,发现每一关结束后都会调用<phase_defused>函数。所以猜测这个函数就是进入隐藏关的关键。
  2. <phase_defused>函数:

  1. 通过观察,可以发现有个cmpl   $0x6,0x804c3cc比较指令,则0x804c3cc是个计数器,判断是否通过6关,其中,movl   $0x804a409,0x4(%esp)操作中0x804a409是

即符合条件进入隐藏关卡的条件是输入两个数字和一个字符串的组合

  1. 设置断点,程序运行到第六关后,查看传入的两个数字和一个字符串

由此可知在第四关的答案后面加DrEvil即可。

【汇编代码】

push   %ebx                          压栈保存

sub    $0x18,%esp                    为函数开辟一个新栈,分配0x18即24个字节的空间

call   804913d <read_line>           调转到804913d处开始函数调用,说明此处要输入一行

movl   $0xa,0x8(%esp)                将立即数10传入esp+8处

movl   $0x0,0x4(%esp)                将立即数0传入esp+4处

mov    %eax,(%esp)                   将eax中的值传递给esp所存值的地址处

call   80488e0 <strtol@plt>          调转到80488e0处开始函数调用

mov    %eax,%ebx                     将eax中的值传递给esp所存值的地址处

lea    -0x1(%eax),%eax               将eax-1地址传入eax寄存器中

cmp    $0x3e8,%eax                   判断eax寄存器内值是否小于等于1000

jbe    8048f22 <secret_phase+0x32>   小于等于则跳转至8048f22处

call   8049116 <explode_bomb>        否则调用炸弹函数,彩蛋破解失败

mov    %ebx,0x4(%esp)                将ebx寄存器中值放入esp+4处

movl   $0x804c088,(%esp)             将0x804c088处内容放入esp所存值的地址处

call   8048e9f <fun7>                函数调用,引用fun7函数

cmp    $0x4,%eax                     比较eax寄存器中值与立即数4是否相等

je     8048f3c <secret_phase+0x4c>   相等则跳转至8048f3c处

call   8049116 <explode_bomb>        否则调用炸弹函数,彩蛋破解失败

movl   $0x804a204,(%esp)             将0x804a204处内容放入esp所存值的地址处

call   8048800 <puts@plt>            调用函数,打印操作

call   804929b <phase_defused>       调用函数,彩蛋破解成功

add    $0x18,%esp                    释放栈帧

pop    %ebx                          出栈操作

ret                                  函数返回

【调用的fun7函数汇编代码及分析】

push   %ebx                          压栈保存

sub    $0x18,%esp                    为函数开辟一个新栈,分配0x18即24个字节的空间

mov    0x20(%esp),%edx               将esp+32地址内值存入edx寄存器中

mov    0x24(%esp),%ecx               将esp+36地址内值存入ecx寄存器中

test   %edx,%edx                     判断edx内值是否为0

je     8048ee6 <fun7+0x47>           为0则跳转至8048ee6处

mov    (%edx),%ebx                   将edx记录地址所存的值放入ebx寄存器中

cmp    %ecx,%ebx                     判断ebx寄存器中值是否小于等于ecx寄存器中值

jle    8048ec8 <fun7+0x29>           小于等于则跳转至8048ec8处

mov    %ecx,0x4(%esp)                将ecx寄存器内值存入esp+4地址处

mov    0x4(%edx),%eax                将edx+4处值传入eax寄存器中,左结点

mov    %eax,(%esp)                   将eax寄存器中值传入esp存的地址处

call   8048e9f <fun7>                递归调用fun7函数

add    %eax,%eax                     将eax寄存器中的值变为两倍后放回

jmp    8048eeb <fun7+0x4c>           无条件跳转到8048eeb处

mov    $0x0,%eax                     将立即数0传入eax寄存器中

cmp    %ecx,%ebx                     比较ebx寄存器中值和ecx寄存器中值是否相等

je     8048eeb <fun7+0x4c>           相等则跳转至8048eeb处

mov    %ecx,0x4(%esp)                将ecx寄存器中值放入esp+4中

mov    0x8(%edx),%eax                将edx+8处值存入eax寄存器中,右结点

mov    %eax,(%esp)                   将eax寄存器值存入esp所存地址中

call   8048e9f <fun7>                递归调用fun7函数

lea    0x1(%eax,%eax,1),%eax         将eax×1+eax+1处的值传入eax寄存器中

jmp    8048eeb <fun7+0x4c>           无条件跳转至8048eeb处

mov    $0xffffffff,%eax              将最大的int型数放入eax寄存器中

add    $0x18,%esp                    释放栈帧

pop    %ebx                          出栈操作

ret                                  函数返回

【解题思路】

引用fun7的secret_phase函数就是一个数字转为整数后减1作为一个参数传入fun7中,在观察fun7函数的汇编代码,可以看出这是一个递归函数,且类似于二叉树的结构。其中,0x804c088为二叉树的根节点地址,从cmp    $0x4,%eax 看出fun7函数的返回值要为4,且对于左子结点,返回值是上一步返回值*2,对于右子结点是上一步返回值*2+1,返回值是要得到4,只能通过,2*0+1,1*2,2*2得到,则该结果为根节点的左子结点的左子结点的右子结点,只要查看内存得到该结点数值即为答案:

则7为答案

【通关字符串】

7

第三步验证通关字符串的正确性

收获与体会:

1.每一关的知识点:
第一关(知识点:string,函数调用,栈)

第二关(知识点:循环语句)

第三关(知识点:switch语句)

第四关(知识点:递归)

第五关(知识点:数组寻址)

第六关(知识点:链表寻址)

隐藏关(知识点:二叉数,递归)

2.gdb中,disassemble指令可以更好查看对应函数的汇编代码

3.本次实验中,在iata情况下,几种常用的跳转指令:

Cmp a b

je    a=b

jne   a!=b

jle   b<=a

jbe   (无符号) b<=a

jge   b>=a

jg   (有符号) ja(无符号)b> a

jmp  无条件

ja   b > a

通过这次实验,对于Linux系统的一些操作命令有了一些了解和掌握,以及学习了如何使用gdb这个强大的工具进行调试,对于汇编语言有了更加深刻更加熟练的运用。

 

课程实验三-bomb实验相关推荐

  1. 20135302魏静静——linux课程第三周实验及总结

    linux课程第三周实验及总结 一.实验:跟踪分析Linux内核的启动过程 使用gdb跟踪调试内核从start_kernel到init进程启动 使用实验楼的虚拟机打开shell cd LinuxKer ...

  2. 20162329 张旭升 实验三:实验报告

    实验三:实验报告 课程:程序设计与数据结构 班级: 1623 姓名: 张旭升 学号:20162329 指导教师:娄嘉鹏 王志强 实验日期:5月12日 实验密级: 非密级 预习程度: 已预习 必修/选修 ...

  3. 计算机网络实验类型有哪些,北航研究生计算机网络实验_实验三 网络层实验

    实验三  网络层实验 将执行命令的结果填入下表: 2.6.1中步骤2中的执行结果 2.6.1中步骤4中的执行结果 2.6.2中步骤11中的执行结果 2.分析2.6.1步骤3中截获的报文,统计" ...

  4. 计算机网络icmp实验,北航研究生计算机网络实验_实验三 网络层实验

    实验三  网络层实验 将执行命令的结果填入下表:

  5. 定时器实验循环彩灯C语言,单片机实验三-定时器实验

    实验三 定时器实验 --循环彩灯实验 一. 实验目的 1. 学习8051内部计数器的使用和编程方法. 2. 进一步掌握中断处理程序的编写方法. 二. 实验原理 1. 定时常数的确定 定时器/计数器的输 ...

  6. c语言数据结构二叉树实验报告,数据结构实验三二叉树实验报告.doc

    数据结构实验三二叉树实验报告 数据结构实验报告 实验名称: 实验三--二叉树 学生姓名: XX 班 级: 班内序号: 学 号: 日 期: 1.实验要求 1.1实验目的 通过选择下面两个题目之一进行实现 ...

  7. 2017-2018-11 20155307刘浩 20155338常胜杰 20155335俞昆 实验三 实时系统实验报告

    2017-2018-11 20155307刘浩 20155338常胜杰 20155335俞昆 实验三 实时系统 实验目的 实验一: 学习使用Linux命令wc(1) 基于Linux Socket程序设 ...

  8. python语言程序设计实验教程答案实验三_20182204 实验三《Python程序设计》实验报告...

    20182204 <Python程序设计>实验三报告 课程:<Python程序设计> 班级:1822 姓名:20182204zwp 学号:20182204 实验教师:王志强老师 ...

  9. java实验三_java实验三实验报告.docx

    java实验三实验报告.docx 实验报告课程名称面向对象课程设计实验项目名称类的继承班级与班级代码13计算机科学与技术1班实验室名称(或课室)SS1205专业计算机科学与技术任课教师尹华学号1225 ...

  10. 计算机网络实验三 CPT实验

    Cisco Packet Tracer 实验 本部分实验共有 15 个,需使用 Cisco Packet Tracer 软件完成. 请大家先了解 VLSM.CIDR.RIP.OSPF.VLAN.STP ...

最新文章

  1. centOS外部浏览器无法访问tomcat8000端口解决办法
  2. 神策 FM:从 IT 到 DT,To B 市场走到了哪一步?
  3. 大数据_Hbase-Filter 索引(优化)_根据column查询---Hbase工作笔记0020
  4. 如何将c语言转成汇编语言,如何把汇编语言转换成C语言
  5. Web SQL Database
  6. 你知道嵌入式开发主要做什么吗?
  7. c语言考研必刷题小程序,小程序推荐:大学生必备刷题小程序,内容涵盖各种证书考试题型...
  8. OA系统(海信集团)双因素身份认证解决方案
  9. 计算机组成原理实验报告一静态随机存储器
  10. html页面通过flv.js实现视频监控直播和点播功能。
  11. CTFHub 技能树web
  12. Ubuntu2Go制作使用和资料说明(LinuxtoGo)
  13. 02 数字图像技术——颜色空间转换与颜色空间分割实验结果与分析——python
  14. 如何用java POI在excel中画线_java poi对excel的操作详解
  15. TreeView的使用方法
  16. latex自己记录需要的
  17. 五行中的土在哪个方位_五行代表的方位
  18. JavaScript 动画效果
  19. 基于FFmpeg+SDL的视频播放器的制作-基础知识
  20. 机器人程序设计c语言,机器人辅助C程序设计

热门文章

  1. 教你用arduino控制LCD1602液晶屏的底层程序实现(全网最笨的方法)
  2. linux格式化只读u盘,linux下FAT32格式u盘只读的问题及解决方法
  3. Android中BottomSheetDialog如何设置透明背景
  4. Crucible安装使用
  5. Bumped! 2017 ICPC North American Qualifier Contest (分层建图+dijstra)
  6. 淘宝关键词API接口
  7. 下厨房app竞品分析(产品和用户)
  8. 元数据管理 开源项目技术选型
  9. 长假将至,携程滴滴都太老土了!俺们区块链的出行方式是酱紫的……
  10. 红米Note3全网通开发版(MIUI10 8.11.22 安卓6)获取完整root权限