实验题目: 程序运行在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程序段进行汇编代码的解读过关。
【汇编代码】打开反汇编形成的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!
【汇编代码及分析】 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
【汇编代码及分析】 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。
【其他解法】 打开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(测试均通过)
【汇编代码及分析】 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
【汇编代码及分析】 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
【汇编代码及分析】 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
【如何进入隐藏关卡】
即符合条件进入隐藏关卡的条件是输入两个数字和一个字符串的组合
由此可知在第四关的答案后面加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.每一关的知识点: 第二关(知识点:循环语句) 第三关(知识点: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这个强大的工具进行调试,对于汇编语言有了更加深刻更加熟练的运用。 |
| |||||||||||||||||||||||||||||