bomb labs

隐藏关卡暂时没找到,前面6个都找到了,前五个不是很难,最后一个比前面复杂很多。

phase_1:
首先反汇编程序
bomb labs第一句是分配栈空间,第二句是设置函数参数,由此可知(rdi,rsi)一共有两个参数,第一个是输入字符串的地址,第二个是$0x402400,由后面函数名推测,这也是一个地址,函数作用是比较两个字符串是否相等,所以我们要找的字符串应该就在那个地址里,先继续往下看,后面的两句测试eax(返回值)的值如果不等于0,就会调用炸弹爆炸函数,所以必须让前面函数的返回值为0,接着反汇编函数strings_not_equal:
bomb labs前三句是把被调用者保存的寄存器压入栈中,目的是函数返回时重新赋值,保证调用前调用后寄存器值不变。后面两句是把两个参数保存到被调用者保存的寄存器中,保证值不会发生变化,然后调用函数string_length,推测作用为返回字符串的长度,所以两次调用获得字符串的长度,之后进行比较,如果不相等就返回rdx的值(1)(如果返回1就会爆炸),所以必须让两个长度相等可以可以在测试语句前设置断点,来查看第二个字符串的长度,但是我们先看后面语句(假设长度已经相等),后面一句是把输入字符串的第一个字符取出来放到eax中(前面已经把rdi放到rbx中),接着测试al(rax的低8位,也就是我们输入的第一个字符),如果结果为0(字符串的结束符’\0’的ASCII码就是0),就跳转,跳转后就是设置rax为0并返回,也就是说,这就是我们的目标,由于前面测试了字符串的长度必须与内存中的相等,所以一开始测试结果肯定是false,接着往下看,比较(%rbp)和al的值,(也就是这个函数第一个参数和第二个参数的值的间接引用,也就是两个字符串的第一个字符),相等的话就跳到后面,把两个地址的值加1,到这里我们就已经知道了,这个函数就是比较两个字符串直到末尾,看是否相等,相等就返回0,否则返回1,所以我们接下来用print命令获取字符串的值
bomb labs由于有52个字符比较长,所以我就只打印了前几个和结尾。
最后答案:
bomb labs
phase_2:
bomb labs
首先把当前栈顶地址设置为第二个参数,调用函数read_six_numbers
反编译read_six_numbers
bomb labs第二句,把前面一个函数的栈顶地址保存到rdx(第三个参数)中,接着后面几句分别是把栈顶地址+4放到rcx中(第四个参数),把原栈顶地址(rsi)+20放到当前栈顶+8(第8个参数),把栈顶地址(rsi)+16放到当前栈顶(第7个参数),栈顶地址+12放到r9(第6个参数),栈顶地址+8放到r8(第5个参数),把0x4025c3放到esi(第二个参数)
然后调用函数sscanf,该函数的作用是,把一个字符串中的字符,按某种格式写入到参数中(input,格式,参数3,参数4,参数5,参数6,参数7,参数8),查看格式字符串:
bomb labs函数的返回值是成功读取的数字的个数,后面一句把返回值与5比较,只有大于5炸弹才不会爆炸。
所以该函数(read_six_numbers)作用为从输入的字符串中读取6个数字到栈顶.
接着看后面,把栈顶元素(输入的第一个数字)与1进行比较,不等于就会爆炸,所以第一个数就是1,然后跳转,把栈中存放的第二个数的地址放入bx,然后把第一个数放入ax,ax2与(bx)相比相等就继续循环,到这里就可以知道,结果为6个数,首项为1,倍数为2的等比数列,结果就是1 2 4 8 16 32
phase_3:
bomb labs前面与phase_2类似,读取两个数到栈中,第一个数和7比较,必须小于等于7(注意是无符号比较),然后根据输入的数跳转到指定位置(该地址存储在内存中),所以先打印出地址,假设输入的数为0
bomb labs把0xcf放入rax中,跳转之后与输入的第二个数的值(保存在栈中)比较,如果不相等就爆炸,相等就释放内存并返回,也就是说,根据第一个数,第二个数有7种可能的值分别是0 207;1 311;2 707;3 256;4 389;5 206;6 682;7 327;
phase_4:
bomb labs前面还是一样,读入两个数到栈中,后面判断第一个数的大小,必须小于等于0xe,否则就会爆炸,接下来设置三个参数的值,edi设置为第一个输入的数,esi设置为0,edx设置为0xe,然后调用函数func4,先接着往下看,测试返回值,如果不为0就爆炸,然后判断第二个输入的数,不为0就爆炸,所以第二个数一定是0,然后进入函数func4:
bomb labs假设三个参数为(x,y,z)
前面几行的作用是把第三个参数减去第二个参数(z-y)的值放到cx和ax中,然后右移31位,加到ax上,也就是把符号位加上减法的结果,然后右移一位,之后再加上第二个参数的值放到cx中,如果结果为正cx=(y + (z - y) / 2),从这里其实可以推测出该函数与二分法有关,然后比较输入的数与计算结果的大小,如果小于等于就把eax清零然后比较计算计算结果与输入的值的关系,如果大于等于,就释放栈空间并返回,到这里其实我们就已经知道一组答案了7 0;因为第一次计算cx的结果是固定的就是7所以只要与它相等就可以返回0,但是还有其它几种情况,首先如果第二次比较不满足大于等于,就把rcx+1放到第二参数中,继续递归调用函数,也就是我们非常熟悉的二分法查找数字,(x,cx+1,z),cx就是中位数,然后再往上看就可以非常轻松的发现如果第一次比较也不满足就把cx-1放到第三个参数中也就是(x,y,cx - 1),最后返回的就是找到了数的时候,然后看返回值,往左边找是2
ax,往右边找是2*ax + 1,所以为了得到返回值为0,必须一直往左边找,也就是0 0;1 0;3 0;7 0;这几组值

phase_5:
bomb labs这个函数的前几行是用于获取金丝雀值放到栈中,用于判断是否局部缓冲区被破坏(详见深入理解计算机系统P199),后面调用函数获取输入字符串长度,长度必须等于6否则就爆炸,接下来的一系列操作是取出第一个字符并且和0xf做与操作,以此为偏移值获取内存中的某个地址(0x4024b0)的字符(也就是映射,一个字母对应变成另一个字母),并且保存到栈中,然后继续取下一个字符,结束循环后,调用判断函数,判断映射获取的字符串是否与内存中的字符串相等,所以我们先获得内存中的字符串
bomb labs字符串为flyers
bomb labsbomb labsbomb labs
bomb labsa的偏移值为1,所以flyers对应的偏移值分别为9i 15o 14n 5e 6f 7g
所以答案为ionefg

phase_6
bomb labsbomb labs

前面几行与上面类似,读取6个数到栈中,后面通过循环判断,6个数都在1-6之间并且互不相等,然后跳转到+95,后面这段的意思是把栈中存储的每个数用7减然后重新存进去(对7取补),再后面是取出地址为0x6032d0+(n-1)*8 的地址存入栈中,n为取补后的值,最后一步,根据栈中的值对内存中的原来存的值进行修改,把栈中后一个值(地址)放到(前一个值+8)(取值)的位置,也就是替换掉下面表格里的地址(下面表格是一开始的内存空间),就是把栈中地址对应的值逆序排列,越靠近栈顶所对应的内存中的值越大,然后就是比较判断,只要栈中地址取值按逆序排列,就能拆除炸弹

地址
0x6032d0 0x14c
0x6032d8 0x6032e0
0x6032e0 0xa8
0x6032e8 0x6032f0
0x6032f0 0x39c
0x6032f8 0x603300
0x603300 0x2b3
0x603308 0x603310
0x603310 0x1dd
0x603318 0x603320
0x603320 0x1bb
0x603328 0x0

所以栈中存储的地址应该为

值(越上面越靠近栈顶)
0x6032f0
0x603300
0x603310
0x603320
0x6032d0
0x6032e0

所以输入的值应该为4 3 2 1 6 5