二进制炸弹(arm)
2016-04-14 17:01
246 查看
x86上的二进制炸弹对于反汇编的练习来说还是比较经典的,由于网上有很多该程序的讲解,所以在此我打算写一下arm平台上的二进制拆炸弹这个游戏。
sudo apt-get install qemu-user
运行ARM指令集模拟器并运行开启gdbserver和运行bomb_1程序
qemu-arm -g 8009 bomb_1
其中,-g参数是为了添加调试信息,为了使远程gdb调试能够起作用,8009为自定义的端口号。
另外启动一个终端,通过命令远程开启gdb调试器并加载待调试程序。
arm-linux-gdb bomb_1
输命令来连接模拟器中的gdbserver
target remote localhost:8009
辅助工具IDA pro。IDA pro是一款静态分析的反汇编工具,利用它可以查看数据段的具体数据,用起来十分方便。
反汇编分析
从标重点的三行汇编可以看出,该代码从把输入的字符串为参数1,把8484里存的字符串作为参数2,然后再调用函数strings_not_equal,判断两个函数是否相等。所以关键是找8484处的地址存的字符串。有IDA pro可以看出8484处存的是数据段6483c处存的字符串,所以用ida可以找出该处的字符串。
密码
密码为Let’s begin now!
利用gdb及arm服务器验证该答案正确。
反汇编分析
该炸弹的逻辑是for循环。
○1处那两行由函数名可以看出为从终端读取六个数,并将其存入一个数组中,且地址从fp-32开始。○2处那四行是读取数组第一个数判断是否为1,如果是1继续判断,如果不是就会explode_bomb。如果是1 的话就会使i = 1到5,然后判断每一个数值。○3那四行及以上几行的逻辑是取出a[i-1]的值,并将a[i-1]*(i-1),然后存入r2中。○4那两行及以上几行的逻辑是取出a[i]的数据,并将其存入r3中。○5处的逻辑是判断r2和r3的值,如果相等则i+1,继续判断,如果不行等则explode_bomb。
其大致的c语言逻辑如下:
所以a[0] = 1;a[1] = a[2] = a[3] = a[4] = a[5] = 0;
密码
1 0 0 0 0 0
反汇编分析
○1处将pc+412的数据传入r1,借助IDA pro可以查看pc+412引用的是
00064850处的数据,如图:
所以该处的数据为”%d %c %d”,由此可知输入的数据的形式为int,char,int。
○2处判断第一个参数int是否大于2,如果大于2则进行switch操作,如果不是则explode_bomb。○3处是对输入的第一个int进行switch判断,其伪代码如下:
○4-○11是对case 0 –case 7这八种情况的具体判断,其逻辑都是一样的,所以在此只分析一种情况(由于必须要求第一个int大于2,所以分析为3,4,5,6,7这五种情况)。现分析○7,首先将0x6b放入fp-5,然后将fp-12的值(即第三个传入的int的值)与0xfb(十进制为251)进行比较,如果相等则跳转86b4,如果不是的话就会explode_bomb;然后相等的话跳转86b4,我们发现从869c到86cc的逻辑都是先nop,什么都不做,然后再b 86d0
反汇编分析
○1处是输入的参数的形式,位于87d0处,利用IDA pro找到了87d0引用了0006485C数据段的数据,为
即要求输入一个数字。○2处判断是否是输入的参数是否大于0,如果大于0则继续判断,如果不是则explode_bomb。○3处将输入的数传入r0中作为参数然后调用func4()。○4首先将传入的参数存入fp-16中,然后判断参数是否小于等于1,如果小于等于1的话就跳到○7处,○7处将返回值赋值为1,然后pop返回值和参数;如果大于1的话就到○5,○5和○6的逻辑就是分别让参数-1和-2,然后再分别调用func4,由此可以看出该bomb的逻辑是一个递归的调用。其c语言的伪代码如下:
然后看代码块○8,其将func4函数的返回值与8进行比较,如果等于8就通过,否则explode_bomb。所以通过计算可以得出输入的值为5。
密码
5
反汇编分析
○1中代码首先判断读入的字符串的长度,如果长度等于6则跳到代码块○2中去,如果不等于6则explode_bomb。在代码块○2中,首先将计数变量i置为0,然后跳到代码块○3中去,在代码块○3中先判断i是否小于等于5,如果小于等于5的话就跳入○4中,其中○4○5○6○7为for循环的主体,我将其化成了这4部分。其中在○4的逻辑如下:取出字符串的第i个字符s[i],
然后将s[i]与0xF相与,其中一个char为一个字节,由两个16进制数组成,做相与运算后就只取出char的后4个b,将数值存入r3中。然后到代码块○5中,找到数据pc+96(8888)处的数据,根据IDA pro得出其引用的是0008216C处的数据,数据如图:
,然后根据r3中的数值作为索引取得相应的字符,将得到的字符存入r2中,然后到代码块○6中,其将r2的数据存入(fp-4-11)+i的地址处。代码○7是将i++。所以该段代码的伪代码如下:
其中s为输入的字符串,s1为找到的字符串。
for循环结束了之后,得到长度为6的s1字符串,到了代码块○8中,该逻辑是将s1与(pc-32)即888c处的字符串进行比较,根据IDA pro得到引用了数据段00064860处的数据为:
所以只有当s1为”giants”时,才能通过,即索引顺序为0xF,0x0,0x5,0xB,0xD,0x1,查ascii表得到后4个b分别为这些的十六进制的数的字符分别为opeka(可能有多重情况,只要后4个b分别对应那五个十六进制数的字符即可)。
密码
opeka
由于该炸弹的指令及逻辑较长,所以指令分开了几份分别进行分析。
00008890 :
1:读入六个数
以上的指令的逻辑比较简单,是首先读入六个数字,并将其放入数组中,假设数组为a。
2:对这六个数的值进行判定
以上的指令为两个for循环的嵌套。
其中○1为(fp-12)处存的变量假设为i,把变量i的值存入r2,然后代码段○2处为取出a[i]的值并将其存入r3中,紧接着代码段○3处判断r3的值是否大于6,如果大于6就explode_bomb。然后进入代码块○4中,在此就进入了第二个for循环,首先初始化(fp-8)处的变量,设为j,j = i+1;然后进入代码段○5处对j的值进行判断,如果大于5就进入代码段○9,其中代码○9是将i增1并进行判断,如果i大于5就跳出for循环,如果小于5则跳至○1再进行一次for循环,对于代码○5处的判断如果j小于等于5的话,则跳入代码○6处,其中逻辑为取出a[i]的值将其放入r2中,然后进入○7中,取出a[j]的值将其放入r3中,然后进入○8,将r2和r3进行比较,如果相等的话就explode_bomb,不行等就进入○5,又进行了一次循环。其伪代码如下:
3:根据输入的6个数把链表的6个node进行索引排序
该段代码也有一个for循环的嵌套。
首先初始化,将(PC+348)的索引的数存入r3中,由ida pro得出具体数据为
所以将node1的索引传入r3,然后跳入到代码块○2,其逻辑是先取出a[i]的数据至r2,然后取出j至r3,比较这两个数据的大小,如果r2 >r3,就跳到代码段○3,该逻辑是将r3+0x8的数据存入fp-16中,有以上的数据可知该数据为0x20A0,用IDA pro查找到为:
以此类推,根据每个节点的第8个字节处的数据作为下一个节点的地址,直到找到链表的a[i]个元素,就会跳出该内层的for循环,然后进入代码块○4,该逻辑是将该node的地址存入-0x3c+[R11] + 4 * i中,然后进入代码块○5,其逻辑是使变量i增1,然后判断是否大于5,如果小于5再跳入○1中继续循环。
其for循环的伪代码如下:
所以经过上一个for循环的嵌套,从-0x3c+[R11]开始就有了这些节点的地址的索引,然后进入代码段○9,其逻辑是先将fp-12处的变量i初始化为1,目的是进入for循环。进入代码段○6,其目的是将*((-0x3c+[R11]+i-1)+0x8) = (-0x3c+[R11]+i);然后进入代码段○7,其目的是将当前节点设为-0x3c+[R11]+i处的地址所指向的节点,进入代码块○8,使i增1并判断和5的大小关系。
4:判断链表的节点的数值是否是按从大到小的顺序排列的
首先进入○1进行初始化,将(fp-16)处的地址换为链表的第一个node,并对(fp-12)的变量i初始化为0。然后进入代码块○2,首先获得当前node的地址,并将该node的数据存入r2中,地址存入r3中,然后通过[r3+8]获得下一个node的地址,并将下一个node的地址存入r3中,然后比较r2和r3的值,如果r2小于r3,就explode_bomb,
如果不小于就进入代码块○3,该逻辑是将当前节点(fp-16)的地址改为[r3+8]处的数值,即为下一个节点的地址,然后进入代码○4,对变量i进行增1操作,并判断和4的大小。其伪代码如下:
其中node的数据结构如下:
所以根据逻辑,先找出每个节点的数据,然后再根据输入的数进行排序,保证其是从大到小的顺序排列的。根据IDA pro找到每个node所在的地址为:
地址 数据 下个节点地址
0x820AC 0xFD 0x820A0
0x820A0 0x2D5 0x82094
0x82094 0x12D 0x82088
0x82088 0x3E5 0x8207C
0x8207C 0xD4 0x82070
0x82070 0x1B0
所以由大到小排列的话就为4 2 6 3 1 5
密码
4 2 6 3 1 5
环境的搭建
由于是arm平台的环境,所以需要在linux环境下安装一个模拟器,在此我选择了qemu该模拟器,具体操作如下(该操作对Ubuntu环境有效,其他linux版本可自行查找方法)sudo apt-get install qemu-user
运行ARM指令集模拟器并运行开启gdbserver和运行bomb_1程序
qemu-arm -g 8009 bomb_1
其中,-g参数是为了添加调试信息,为了使远程gdb调试能够起作用,8009为自定义的端口号。
另外启动一个终端,通过命令远程开启gdb调试器并加载待调试程序。
arm-linux-gdb bomb_1
输命令来连接模拟器中的gdbserver
target remote localhost:8009
辅助工具IDA pro。IDA pro是一款静态分析的反汇编工具,利用它可以查看数据段的具体数据,用起来十分方便。
具体分析
Phase 1
Arm指令0000844c <phase_1>: 844c: e92d4800 push {fp, lr} 8450: e28db004 add fp, sp, #4 8454: e24dd008 sub sp, sp, #8 8458: e50b0008 str r0, [fp, #-8] 845c: e51b0008 ldr r0, [fp, #-8] 8460: e59f101c ldr r1, [pc, #28] ; 8484 <phase_1+0x38> 8464: eb000241 bl 8d70 <strings_not_equal> 8468: e1a03000 mov r3, r0 846c: e3530000 cmp r3, #0 8470: 0a000000 beq 8478 <phase_1+0x2c> 8474: eb000321 bl 9100 <explode_bomb> 8478: e24bd004 sub sp, fp, #4 847c: e8bd4800 pop {fp, lr} 8480: e12fff1e bx lr 8484: 0006483c .word 0x0006483c
反汇编分析
从标重点的三行汇编可以看出,该代码从把输入的字符串为参数1,把8484里存的字符串作为参数2,然后再调用函数strings_not_equal,判断两个函数是否相等。所以关键是找8484处的地址存的字符串。有IDA pro可以看出8484处存的是数据段6483c处存的字符串,所以用ida可以找出该处的字符串。
密码
密码为Let’s begin now!
利用gdb及arm服务器验证该答案正确。
Phase 2
Arm指令00008488 <phase_2>: 8488: e92d4800 push {fp, lr} 848c: e28db004 add fp, sp, #4 8490: e24dd028 sub sp, sp, #40 ; 0x28 8494: e50b0028 str r0, [fp, #-40] ; 0xffffffd8 8498: e24b3020 sub r3, fp, #32 849c: e51b0028 ldr r0, [fp, #-40] ; 0xffffffd8 84a0: e1a01003 mov r1, r3 84a4: eb0001f4 bl 8c7c <read_six_numbers> ○1 //////////////////////////////////////////////// 84a8: e51b3020 ldr r3, [fp, #-32] ; 0xffffffe0 84ac: e3530001 cmp r3, #1 84b0: 0a000000 beq 84b8 <phase_2+0x30> ○2 84b4: eb000311 bl 9100 <explode_bomb> 84b8: e3a03001 mov r3, #1 84bc: e50b3008 str r3, [fp, #-8] 84c0: e51b3008 ldr r3, [fp, #-8] 84c4: e2432001 sub r2, r3, #1 84c8: e3e0301b mvn r3, #27 84cc: e1a02102 lsl r2, r2, #2 84d0: e24b0004 sub r0, fp, #4 84d4: e0802002 add r2, r0, r2 84d8: e0823003 add r3, r2, r3 84dc: e5933000 ldr r3, [r3] 84e0: e51b2008 ldr r2, [fp, #-8] 84e4: e2421001 sub r1, r2, #1 ○3 84e8: e0020391 mul r2, r1, r3 84ec: e51b1008 ldr r1, [fp, #-8] 84f0: e3e0301b mvn r3, #27 84f4: e1a01101 lsl r1, r1, #2 84f8: e24b0004 sub r0, fp, #4 84fc: e0801001 add r1, r0, r1 8500: e0813003 add r3, r1, r3 ○4 8504: e5933000 ldr r3, [r3] ////////////////////////////////////////////// 8508: e1520003 cmp r2, r3 850c: 0a000000 beq 8514 <phase_2+0x8c> ○5 8510: eb0002fa bl 9100 <explode_bomb> ////////////////////////////////////////////// 8514: e51b3008 ldr r3, [fp, #-8] 8518: e2833001 add r3, r3, #1 851c: e50b3008 str r3, [fp, #-8] 8520: e51b3008 ldr r3, [fp, #-8] 8524: e3530005 cmp r3, #5 8528: daffffe4 ble 84c0 <phase_2+0x38> 852c: e24bd004 sub sp, fp, #4 8530: e8bd4800 pop {fp, lr} 8534: e12fff1e bx lr
反汇编分析
该炸弹的逻辑是for循环。
○1处那两行由函数名可以看出为从终端读取六个数,并将其存入一个数组中,且地址从fp-32开始。○2处那四行是读取数组第一个数判断是否为1,如果是1继续判断,如果不是就会explode_bomb。如果是1 的话就会使i = 1到5,然后判断每一个数值。○3那四行及以上几行的逻辑是取出a[i-1]的值,并将a[i-1]*(i-1),然后存入r2中。○4那两行及以上几行的逻辑是取出a[i]的数据,并将其存入r3中。○5处的逻辑是判断r2和r3的值,如果相等则i+1,继续判断,如果不行等则explode_bomb。
其大致的c语言逻辑如下:
if(a[0] != 1) explode_bomb(); for(i = 1;i <= 5;i++) { if(a[i] != a[i-1]*(i-1)) explode_bomb(); }
所以a[0] = 1;a[1] = a[2] = a[3] = a[4] = a[5] = 0;
密码
1 0 0 0 0 0
Phase 3
arm指令00008538 <phase_3>: 8538: e92d4800 push {fp, lr} 853c: e28db004 add fp, sp, #4 8540: e24dd020 sub sp, sp, #32 8544: e50b0018 str r0, [fp, #-24] ; 0xffffffe8 8548: e51b0018 ldr r0, [fp, #-24] ; 0xffffffe8 854c: e59f119c ldr r1, [pc, #412] ; 86f0 <phase_3+0x1b8>○1 8550: e24b2014 sub r2, fp, #20 8554: e24b300d sub r3, fp, #13 8558: e24bc00c sub ip, fp, #12 855c: e58dc000 str ip, [sp] 8560: eb000976 bl ab40 <_IO_sscanf> 8564: e1a03000 mov r3, r0 8568: e3530002 cmp r3, #2 856c: ca000000 bgt 8574 <phase_3+0x3c> ○2 8570: eb0002e2 bl 9100 <explode_bomb> /////////////////////////////////////////////////// 8574: e51b3014 ldr r3, [fp, #-20] ; 0xffffffec 8578: e3530007 cmp r3, #7 857c: 979ff103 ldrls pc, [pc, r3, lsl #2] 8580: ea000041 b 868c <phase_3+0x154> 8584: 000085a4 .word 0x000085a4 8588: 000085c4 .word 0x000085c4 858c: 000085e0 .word 0x000085e0 ○3 8590: 00008600 .word 0x00008600 8594: 0000861c .word 0x0000861c 8598: 00008638 .word 0x00008638 859c: 00008658 .word 0x00008658 85a0: 00008670 .word 0x00008670 ///////////////////////////////////////////////// 85a4: e3a03071 mov r3, #113 ; 0x71 ○4 85a8: e54b3005 strb r3, [fp, #-5] 85ac: e51b200c ldr r2, [fp, #-12] 85b0: e59f313c ldr r3, [pc, #316] ; 86f4 <phase_3+0x1bc> 85b4: e1520003 cmp r2, r3 85b8: 0a000037 beq 869c <phase_3+0x164> 85bc: eb0002cf bl 9100 <explode_bomb> 85c0: ea000042 b 86d0 <phase_3+0x198> 85c4: e3a03062 mov r3, #98 ; 0x62○5 85c8: e54b3005 strb r3, [fp, #-5] 85cc: e51b300c ldr r3, [fp, #-12] 85d0: e35300d6 cmp r3, #214 ; 0xd6 85d4: 0a000032 beq 86a4 <phase_3+0x16c> 85d8: eb0002c8 bl 9100 <explode_bomb> 85dc: ea00003b b 86d0 <phase_3+0x198> 85e0: e3a03062 mov r3, #98 ; 0x62○6 85e4: e54b3005 strb r3, [fp, #-5] 85e8: e51b200c ldr r2, [fp, #-12] 85ec: e59f3104 ldr r3, [pc, #260] ; 86f8 <phase_3+0x1c0> 85f0: e1520003 cmp r2, r3 85f4: 0a00002c beq 86ac <phase_3+0x174> 85f8: eb0002c0 bl 9100 <explode_bomb> 85fc: ea000033 b 86d0 <phase_3+0x198> 8600: e3a0306b mov r3, #107 ; 0x6b ○7 8604: e54b3005 strb r3, [fp, #-5] 8608: e51b300c ldr r3, [fp, #-12] 860c: e35300fb cmp r3, #251 ; 0xfb 8610: 0a000027 beq 86b4 <phase_3+0x17c> 8614: eb0002b9 bl 9100 <explode_bomb> 8618: ea00002c b 86d0 <phase_3+0x198> 861c: e3a0306f mov r3, #111 ; 0x6f○8 8620: e54b3005 strb r3, [fp, #-5] 8624: e51b300c ldr r3, [fp, #-12] 8628: e35300a0 cmp r3, #160 ; 0xa0 862c: 0a000022 beq 86bc <phase_3+0x184> 8630: eb0002b2 bl 9100 <explode_bomb> 8634: ea000025 b 86d0 <phase_3+0x198> 8638: e3a03074 mov r3, #116 ; 0x74○9 863c: e54b3005 strb r3, [fp, #-5] 8640: e51b200c ldr r2, [fp, #-12] 8644: e59f30b0 ldr r3, [pc, #176] ; 86fc <phase_3+0x1c4> 8648: e1520003 cmp r2, r3 864c: 0a00001c beq 86c4 <phase_3+0x18c> 8650: eb0002aa bl 9100 <explode_bomb> 8654: ea00001d b 86d0 <phase_3+0x198> 8658: e3a03076 mov r3, #118 ; 0x76○10 865c: e54b3005 strb r3, [fp, #-5] 8660: e51b300c ldr r3, [fp, #-12] 8664: e3530fc3 cmp r3, #780 ; 0x30c 8668: 0a000000 beq 8670 <phase_3+0x138> 866c: eb0002a3 bl 9100 <explode_bomb> 8670: e3a03062 mov r3, #98 ; 0x62○11 8674: e54b3005 strb r3, [fp, #-5] 8678: e51b300c ldr r3, [fp, #-12] 867c: e3530f83 cmp r3, #524 ; 0x20c 8680: 0a000011 beq 86cc <phase_3+0x194> 8684: eb00029d bl 9100 <explode_bomb> 8688: ea000010 b 86d0 <phase_3+0x198> 868c: e3a03078 mov r3, #120 ;0x78 ○12 8690: e54b3005 strb r3, [fp, #-5] 8694: eb000299 bl 9100 <explode_bomb> 8698: ea00000c b 86d0 <phase_3+0x198> 869c: e1a00000 nop ; (mov r0, r0) 86a0: ea00000a b 86d0 <phase_3+0x198> 86a4: e1a00000 nop ; (mov r0, r0) 86a8: ea000008 b 86d0 <phase_3+0x198> 86ac: e1a00000 nop ; (mov r0, r0) 86b0: ea000006 b 86d0 <phase_3+0x198> 86b4: e1a00000 nop ; (mov r0, r0) 86b8: ea000004 b 86d0 <phase_3+0x198> 86bc: e1a00000 nop ; (mov r0, r0) 86c0: ea000002 b 86d0 <phase_3+0x198> 86c4: e1a00000 nop ; (mov r0, r0) 86c8: ea000000 b 86d0 <phase_3+0x198> 86cc: e1a00000 nop ; (mov r0, r0) 86d0: e55b300d ldrb r3, [fp, #-13] 86d4: e55b2005 ldrb r2, [fp, #-5] 86d8: e1520003 cmp r2,r3○13 86dc: 0a000000 beq 86e4 <phase_3+0x1ac> 86e0: eb000286 bl 9100 <explode_bomb> 86e4: e24bd004 sub sp, fp, #4 86e8: e8bd4800 pop {fp, lr} 86ec: e12fff1e bx lr 86f0: 00064850 .word 0x00064850 86f4: 00000309 .word 0x00000309 86f8: 000002f3 .word 0x000002f3 86fc: 000001ca .word 0x000001ca
反汇编分析
○1处将pc+412的数据传入r1,借助IDA pro可以查看pc+412引用的是
00064850处的数据,如图:
所以该处的数据为”%d %c %d”,由此可知输入的数据的形式为int,char,int。
○2处判断第一个参数int是否大于2,如果大于2则进行switch操作,如果不是则explode_bomb。○3处是对输入的第一个int进行switch判断,其伪代码如下:
switch(int c) { case 0: jmp 85a4; break; case 1: jmp 85c4; break; case 2: jmp 85e0; break; case 3: jmp 8600; break; case 4: jmp 861c; break; case 5: jmp 8638; break; case 6: jmp 8658; break; case 7: jmp 8670; break; default: jmp 868c; break; }
○4-○11是对case 0 –case 7这八种情况的具体判断,其逻辑都是一样的,所以在此只分析一种情况(由于必须要求第一个int大于2,所以分析为3,4,5,6,7这五种情况)。现分析○7,首先将0x6b放入fp-5,然后将fp-12的值(即第三个传入的int的值)与0xfb(十进制为251)进行比较,如果相等则跳转86b4,如果不是的话就会explode_bomb;然后相等的话跳转86b4,我们发现从869c到86cc的逻辑都是先nop,什么都不做,然后再b 86d0
00008760 <phase_4>: 8760: e92d4800 push {fp, lr} 8764: e28db004 add fp, sp, #4 8768: e24dd010 sub sp, sp, #16 876c: e50b0010 str r0, [fp, #-16] 8770: e51b1010 ldr r1, [fp, #-16] 8774: e59f2054 ldr r2, [pc, #84] ; 87d0 <phase_4+0x70> ○1 8778: e24b3008 sub r3, fp, #8 877c: e1a00001 mov r0, r1 8780: e1a01002 mov r1, r2 8784: e1a02003 mov r2, r3 8788: eb0008ec bl ab40 <_IO_sscanf> 878c: e1a03000 mov r3, r0 8790: e3530001 cmp r3, #1 8794: 1a000002 bne 87a4 <phase_4+0x44> 8798: e51b3008 ldr r3, [fp, #-8] 879c: e3530000 cmp r3, #0 87a0: ca000000 bgt 87a8 <phase_4+0x48> ○2 87a4: eb000255 bl 9100 <explode_bomb> //////////////////////////////////// 87a8: e51b3008 ldr r3, [fp, #-8] 87ac: e1a00003 mov r0, r3 ○3 87b0: ebffffd2 bl 8700 <func4> /////////////////////////////////// 87b4: e1a03000 mov r3, r0 87b8: e3530008 cmp r3, #8 87bc: 0a000000 beq 87c4 <phase_4+0x64> ○8 87c0: eb00024e bl 9100 <explode_bomb> 87c4: e24bd004 sub sp, fp, #4 87c8: e8bd4800 pop {fp, lr} 87cc: e12fff1e bx lr 87d0: 0006485c .word 0x0006485c 00008700 <func4>: 8700: e92d4810 push {r4, fp, lr} 8704: e28db008 add fp, sp, #8 8708: e24dd00c sub sp, sp, #12 870c: e50b0010 str r0, [fp, #-16] 8710: e51b3010 ldr r3, [fp, #-16] 8714: e3530001 cmp r3, #1 ○4 8718: da00000b ble 874c <func4+0x4c> //////////////////////////////////////////// 871c: e51b3010 ldr r3, [fp, #-16] 8720: e2433001 sub r3, r3, #1 8724: e1a00003 mov r0, r3 ○5 8728: ebfffff4 bl 8700 <func4> ///////////////////////////////////////////// 872c: e1a04000 mov r4, r0 8730: e51b3010 ldr r3, [fp, #-16] 8734: e2433002 sub r3, r3, #2 ○6 8738: e1a00003 mov r0, r3 873c: ebffffef bl 8700 <func4> 8740: e1a03000 mov r3, r0 8744: e0843003 add r3, r4, r3 8748: ea000000 b 8750 <func4+0x50> 874c: e3a03001 mov r3, #1 8750: e1a00003 mov r0, r3 8754: e24bd008 sub sp, fp, #8 ○7 8758: e8bd4810 pop {r4, fp, lr} 875c: e12fff1e bx lr
反汇编分析
○1处是输入的参数的形式,位于87d0处,利用IDA pro找到了87d0引用了0006485C数据段的数据,为
即要求输入一个数字。○2处判断是否是输入的参数是否大于0,如果大于0则继续判断,如果不是则explode_bomb。○3处将输入的数传入r0中作为参数然后调用func4()。○4首先将传入的参数存入fp-16中,然后判断参数是否小于等于1,如果小于等于1的话就跳到○7处,○7处将返回值赋值为1,然后pop返回值和参数;如果大于1的话就到○5,○5和○6的逻辑就是分别让参数-1和-2,然后再分别调用func4,由此可以看出该bomb的逻辑是一个递归的调用。其c语言的伪代码如下:
func4(int i) { if(i < = 1) return 1; else return func4(i-1) + func4(i-2); }
然后看代码块○8,其将func4函数的返回值与8进行比较,如果等于8就通过,否则explode_bomb。所以通过计算可以得出输入的值为5。
密码
5
Phase 5
Arm指令000087d4 <phase_5>: 87d4: e92d4800 push {fp, lr} 87d8: e28db004 add fp, sp, #4 87dc: e24dd018 sub sp, sp, #24 87e0: e50b0018 str r0, [fp, #-24] ; 0xffffffe8 87e4: e51b0018 ldr r0, [fp, #-24] ; 0xffffffe8 87e8: eb000144 bl 8d00 <string_length> 87ec: e1a03000 mov r3, r0 87f0: e3530006 cmp r3, #6 ○1 87f4: 0a000000 beq 87fc <phase_5+0x28> 87f8: eb000240 bl 9100 <explode_bomb> //////////////////////////////////////// 87fc: e3a03000 mov r3, #0 8800: e50b3008 str r3, [fp, #-8]○2 8804: ea00000f b 8848 <phase_5+0x74> //////////////////////////////////////// 8808: e51b1008 ldr r1, [fp, #-8] 880c: e51b3008 ldr r3, [fp, #-8] 8810: e51b2018 ldr r2, [fp, #-24] ; 0xffffffe8 8814: e0823003 add r3, r2, r3○4 8818: e5d33000 ldrb r3, [r3] 881c: e203300f and r3, r3, #15 /////////////////////////////////////// 8820: e59f2060 ldr r2, [pc, #96] ; 8888 <phase_5+0xb4> 8824: e7d22003 ldrb r2, [r2, r3] ○5 /////////////////////////////////////// 8828: e3e0300b mvn r3, #11 882c: e24b0004 sub r0, fp, #4 8830: e0801001 add r1, r0, r1 ○6 8834: e0813003 add r3, r1, r3 8838: e5c32000 strb r2, [r3] //////////////////////////////////// 883c: e51b3008 ldr r3, [fp, #-8] 8840: e2833001 add r3, r3, #1 ○7 8844: e50b3008 str r3, [fp, #-8] //////////////////////////////////// 8848: e51b3008 ldr r3, [fp, #-8] 884c: e3530005 cmp r3, #5 ○3 8850: daffffec ble 8808 <phase_5+0x34> /////////////////////////////////// 8854: e3a03000 mov r3, #0 8858: e54b300a strb r3, [fp, #-10] 885c: e24b3010 sub r3, fp, #16 8860: e1a00003 mov r0, r3 ○8 8864: e59f1020 ldr r1, [pc, #32] ; 888c <phase_5+0xb8> 8868: eb000140 bl 8d70 <strings_not_equal> 886c: e1a03000 mov r3, r0 8870: e3530000 cmp r3, #0 8874: 0a000000 beq 887c <phase_5+0xa8> 8878: eb000220 bl 9100 <explode_bomb> 887c: e24bd004 sub sp, fp, #4 8880: e8bd4800 pop {fp, lr} 8884: e12fff1e bx lr 8888: 0008216c .word 0x0008216c 888c: 00064860 .word 0x00064860
反汇编分析
○1中代码首先判断读入的字符串的长度,如果长度等于6则跳到代码块○2中去,如果不等于6则explode_bomb。在代码块○2中,首先将计数变量i置为0,然后跳到代码块○3中去,在代码块○3中先判断i是否小于等于5,如果小于等于5的话就跳入○4中,其中○4○5○6○7为for循环的主体,我将其化成了这4部分。其中在○4的逻辑如下:取出字符串的第i个字符s[i],
然后将s[i]与0xF相与,其中一个char为一个字节,由两个16进制数组成,做相与运算后就只取出char的后4个b,将数值存入r3中。然后到代码块○5中,找到数据pc+96(8888)处的数据,根据IDA pro得出其引用的是0008216C处的数据,数据如图:
,然后根据r3中的数值作为索引取得相应的字符,将得到的字符存入r2中,然后到代码块○6中,其将r2的数据存入(fp-4-11)+i的地址处。代码○7是将i++。所以该段代码的伪代码如下:
for(i = 0;i <= 5;i++) { int a = (int)(s[i]&0xF); s1[i] = 0x0008216c+a; }
其中s为输入的字符串,s1为找到的字符串。
for循环结束了之后,得到长度为6的s1字符串,到了代码块○8中,该逻辑是将s1与(pc-32)即888c处的字符串进行比较,根据IDA pro得到引用了数据段00064860处的数据为:
所以只有当s1为”giants”时,才能通过,即索引顺序为0xF,0x0,0x5,0xB,0xD,0x1,查ascii表得到后4个b分别为这些的十六进制的数的字符分别为opeka(可能有多重情况,只要后4个b分别对应那五个十六进制数的字符即可)。
密码
opeka
Phase 6
指令及逻辑分析:由于该炸弹的指令及逻辑较长,所以指令分开了几份分别进行分析。
00008890 :
1:读入六个数
8890: e92d4800 push {fp, lr} 8894: e28db004 add fp, sp, #4 8898: e24dd048 sub sp, sp, #72 ; 0x48 889c: e50b0048 str r0, [fp, #-72] ; 0xffffffb8 88a0: e59f3234 ldr r3, [pc, #564] ; 8adc <phase_6+0x24c> 88a4: e50b3010 str r3, [fp, #-16] 88a8: e24b3028 sub r3, fp, #40 ; 0x28 88ac: e51b0048 ldr r0, [fp, #-72] ; 0xffffffb8 88b0: e1a01003 mov r1, r3 88b4: eb0000f0 bl 8c7c <read_six_numbers>
以上的指令的逻辑比较简单,是首先读入六个数字,并将其放入数组中,假设数组为a。
2:对这六个数的值进行判定
88b8: e3a03000 mov r3, #0 88bc: e50b300c str r3, [fp, #-12] 88c0: e51b200c ldr r2, [fp, #-12] ○1 //////////////////////////////////// 88c4: e3e03023 mvn r3, #35 ; 0x23 88c8: e1a02102 lsl r2, r2, #2 88cc: e24b0004 sub r0, fp, #4 88d0: e0802002 add r2, r0, r2 ○2 88d4: e0823003 add r3, r2, r3 88d8: e5933000 ldr r3, [r3] /////////////////////////////////// 88dc: e2433001 sub r3, r3, #1 88e0: e3530005 cmp r3, #5 ○3 88e4: 9a000000 bls 88ec <phase_6+0x5c> 88e8: eb000204 bl 9100 <explode_bomb> ////////////////////////////////// 88ec: e51b300c ldr r3, [fp, #-12] 88f0: e2833001 add r3, r3, #1 ○4 88f4: e50b3008 str r3, [fp, #-8] 88f8: ea000013 b 894c <phase_6+0xbc> ////////////////////////////////// 88fc: e51b200c ldr r2, [fp, #-12] 8900: e3e03023 mvn r3, #35 ; 0x23 8904: e1a02102 lsl r2, r2, #2 8908: e24b1004 sub r1, fp, #4 ○6 890c: e0812002 add r2, r1, r2 8910: e0823003 add r3, r2, r3 8914: e5932000 ldr r2, [r3] ////////////////////////////////// 8918: e51b1008 ldr r1, [fp, #-8] 891c: e3e03023 mvn r3, #35 ; 0x23 8920: e1a01101 lsl r1, r1, #2 8924: e24b0004 sub r0, fp, #4 ○7 8928: e0801001 add r1, r0, r1 892c: e0813003 add r3, r1, r3 8930: e5933000 ldr r3, [r3] ///////////////////////////////// 8934: e1520003 cmp r2, r3 8938: 1a000000 bne 8940 <phase_6+0xb0> 893c: eb0001ef bl 9100 <explode_bomb> 8940: e51b3008 ldr r3, [fp, #-8]○8 8944: e2833001 add r3, r3, #1 8948: e50b3008 str r3, [fp, #-8] /////////////////////////////////// 894c: e51b3008 ldr r3, [fp, #-8] 8950: e3530005 cmp r3, #5 ○5 8954: daffffe8 ble 88fc <phase_6+0x6c> ////////////////////////////////// 8958: e51b300c ldr r3, [fp, #-12] 895c: e2833001 add r3, r3, #1 8960: e50b300c str r3, [fp, #-12] ○9 8964: e51b300c ldr r3, [fp, #-12] 8968: e3530005 cmp r3, #5 896c: daffffd3 ble 88c0 <phase_6+0x30> 8970: e3a03000 mov r3, #0 8974: e50b300c str r3, [fp, #-12]
以上的指令为两个for循环的嵌套。
其中○1为(fp-12)处存的变量假设为i,把变量i的值存入r2,然后代码段○2处为取出a[i]的值并将其存入r3中,紧接着代码段○3处判断r3的值是否大于6,如果大于6就explode_bomb。然后进入代码块○4中,在此就进入了第二个for循环,首先初始化(fp-8)处的变量,设为j,j = i+1;然后进入代码段○5处对j的值进行判断,如果大于5就进入代码段○9,其中代码○9是将i增1并进行判断,如果i大于5就跳出for循环,如果小于5则跳至○1再进行一次for循环,对于代码○5处的判断如果j小于等于5的话,则跳入代码○6处,其中逻辑为取出a[i]的值将其放入r2中,然后进入○7中,取出a[j]的值将其放入r3中,然后进入○8,将r2和r3进行比较,如果相等的话就explode_bomb,不行等就进入○5,又进行了一次循环。其伪代码如下:
for(int i = 0;i <= 5;i++) {if(a[i]>6) explode_bomb(); for(int j = i+1;j<=5;j++) {if(a[j] == a[i]) explode_bomb(); } }
3:根据输入的6个数把链表的6个node进行索引排序
8978: e59f315c ldr r3, [pc, #348] ; 8adc <phase_6+0x24c> 897c: e50b3010 str r3, [fp, #-16] 8980: e3a03001 mov r3, #1 ○1 8984: e50b3008 str r3, [fp, #-8] 8988: ea000005 b 89a4 <phase_6+0x114> ///////////////////////////////////////////// 898c: e51b3010 ldr r3, [fp, #-16] 8990: e5933008 ldr r3, [r3, #8] 8994: e50b3010 str r3, [fp, #-16] ○3 8998: e51b3008 ldr r3, [fp, #-8] 899c: e2833001 add r3, r3, #1 89a0: e50b3008 str r3, [fp, #-8] //////////////////////////////////////// 89a4: e51b200c ldr r2, [fp, #-12] 89a8: e3e03023 mvn r3, #35 ; 0x23 89ac: e1a02102 lsl r2, r2, #2 89b0: e24b1004 sub r1, fp, #4 89b4: e0812002 add r2, r1, r2 ○2 89b8: e0823003 add r3, r2, r3 89bc: e5932000 ldr r2, [r3] 89c0: e51b3008 ldr r3, [fp, #-8] 89c4: e1520003 cmp r2, r3 89c8: caffffef bgt 898c <phase_6+0xfc> //////////////////////////////////////////// 89cc: e51b200c ldr r2, [fp, #-12] 89d0: e3e0303b mvn r3, #59 ; 0x3b 89d4: e1a02102 lsl r2, r2, #2 89d8: e24b0004 sub r0, fp, #4 ○4 89dc: e0802002 add r2, r0, r2 89e0: e0823003 add r3, r2, r3 89e4: e51b2010 ldr r2, [fp, #-16] 89e8: e5832000 str r2, [r3] /////////////////////////////////////////// 89ec: e51b300c ldr r3, [fp, #-12] 89f0: e2833001 add r3, r3, #1 89f4: e50b300c str r3, [fp, #-12] ○5 89f8: e51b300c ldr r3, [fp, #-12] 89fc: e3530005 cmp r3, #5 8a00: daffffdc ble 8978 <phase_6+0xe8> /////////////////////////////////////////// 8a04: e51b3040 ldr r3, [fp, #-64] ; 0xffffffc0 8a08: e50b3010 str r3, [fp, #-16]○9 8a0c: e3a03001 mov r3, #1 8a10: e50b300c str r3, [fp, #-12] ///////////////////////////////////////// 8a14: e51b200c ldr r2, [fp, #-12] 8a18: e3e0303b mvn r3, #59 ; 0x3b 8a1c: e1a02102 lsl r2, r2, #2 8a20: e24b1004 sub r1, fp, #4 8a24: e0812002 add r2, r1, r2○6 8a28: e0823003 add r3, r2, r3 8a2c: e5932000 ldr r2, [r3] 8a30: e51b3010 ldr r3, [fp, #-16] 8a34: e5832008 str r2, [r3, #8] /////////////////////////////////////// 8a38: e51b200c ldr r2, [fp, #-12] 8a3c: e3e0303b mvn r3, #59 ; 0x3b 8a40: e1a02102 lsl r2, r2, #2○7 8a44: e24b0004 sub r0, fp, #4 8a48: e0802002 add r2, r0, r2 8a4c: e0823003 add r3, r2, r3 8a50: e5933000 ldr r3, [r3] 8a54: e50b3010 str r3, [fp, #-16] //////////////////////////////////// 8a58: e51b300c ldr r3, [fp, #-12] 8a5c: e2833001 add r3, r3, #1 8a60: e50b300c str r3, [fp, #-12] ○8 8a64: e51b300c ldr r3, [fp, #-12] 8a68: e3530005 cmp r3, #5 8a6c: daffffe8 ble 8a14 <phase_6+0x184>
该段代码也有一个for循环的嵌套。
首先初始化,将(PC+348)的索引的数存入r3中,由ida pro得出具体数据为
所以将node1的索引传入r3,然后跳入到代码块○2,其逻辑是先取出a[i]的数据至r2,然后取出j至r3,比较这两个数据的大小,如果r2 >r3,就跳到代码段○3,该逻辑是将r3+0x8的数据存入fp-16中,有以上的数据可知该数据为0x20A0,用IDA pro查找到为:
以此类推,根据每个节点的第8个字节处的数据作为下一个节点的地址,直到找到链表的a[i]个元素,就会跳出该内层的for循环,然后进入代码块○4,该逻辑是将该node的地址存入-0x3c+[R11] + 4 * i中,然后进入代码块○5,其逻辑是使变量i增1,然后判断是否大于5,如果小于5再跳入○1中继续循环。
其for循环的伪代码如下:
for(int i = 0;i <=5;i++) { node = 0x000820AC; for(int j = 1;j<a[i];j++) node = *(node+0x8); -0x3c+[R11] + 4 * i = node; }
所以经过上一个for循环的嵌套,从-0x3c+[R11]开始就有了这些节点的地址的索引,然后进入代码段○9,其逻辑是先将fp-12处的变量i初始化为1,目的是进入for循环。进入代码段○6,其目的是将*((-0x3c+[R11]+i-1)+0x8) = (-0x3c+[R11]+i);然后进入代码段○7,其目的是将当前节点设为-0x3c+[R11]+i处的地址所指向的节点,进入代码块○8,使i增1并判断和5的大小关系。
4:判断链表的节点的数值是否是按从大到小的顺序排列的
8a70: e51b3010 ldr r3, [fp, #-16] 8a74: e3a02000 mov r2, #0 8a78: e5832008 str r2, [r3, #8] 8a7c: e3a03000 mov r3, #0 ○1 8a80: e50b300c str r3, [fp, #-12] 8a84: e51b3040 ldr r3, [fp, #-64] ; 0xffffffc0 8a88: e50b3010 str r3, [fp, #-16] ////////////////////////////////////// 8a8c: e51b3010 ldr r3, [fp, #-16] 8a90: e5932000 ldr r2, [r3] 8a94: e51b3010 ldr r3, [fp, #-16] 8a98: e5933008 ldr r3, [r3, #8] ○2 8a9c: e5933000 ldr r3, [r3] 8aa0: e1520003 cmp r2, r3 8aa4: aa000000 bge 8aac <phase_6+0x21c> 8aa8: eb000194 bl 9100 <explode_bomb> ////////////////////////////////////////// 8aac: e51b3010 ldr r3, [fp, #-16] 8ab0: e5933008 ldr r3, [r3, #8] ○3 8ab4: e50b3010 str r3, [fp, #-16] /////////////////////////////////////// 8ab8: e51b300c ldr r3, [fp, #-12] 8abc: e2833001 add r3, r3, #1 8ac0: e50b300c str r3, [fp, #-12] ○4 8ac4: e51b300c ldr r3, [fp, #-12] 8ac8: e3530004 cmp r3, #4 8acc: daffffee ble 8a8c <phase_6+0x1fc>
首先进入○1进行初始化,将(fp-16)处的地址换为链表的第一个node,并对(fp-12)的变量i初始化为0。然后进入代码块○2,首先获得当前node的地址,并将该node的数据存入r2中,地址存入r3中,然后通过[r3+8]获得下一个node的地址,并将下一个node的地址存入r3中,然后比较r2和r3的值,如果r2小于r3,就explode_bomb,
如果不小于就进入代码块○3,该逻辑是将当前节点(fp-16)的地址改为[r3+8]处的数值,即为下一个节点的地址,然后进入代码○4,对变量i进行增1操作,并判断和4的大小。其伪代码如下:
其中node的数据结构如下:
struct node { int x, y; node *next; }; //进行判断: node a = firstNode; for(int i = 0; i < 5; i++) { node b = a->next; if (a->x >= b->x) a = b; else explode_bomb(); }
所以根据逻辑,先找出每个节点的数据,然后再根据输入的数进行排序,保证其是从大到小的顺序排列的。根据IDA pro找到每个node所在的地址为:
地址 数据 下个节点地址
0x820AC 0xFD 0x820A0
0x820A0 0x2D5 0x82094
0x82094 0x12D 0x82088
0x82088 0x3E5 0x8207C
0x8207C 0xD4 0x82070
0x82070 0x1B0
所以由大到小排列的话就为4 2 6 3 1 5
密码
4 2 6 3 1 5
相关文章推荐
- 不气馁,不牵强
- Android studio 报一下错时解决方案For example, the following line, in the gradle.properties file, sets the max
- [置顶] 机器学习总结二:逻辑回归Logistic Regression
- MySQL通信协议栈Java实现-(1)数据类型
- centos7 LV XFS添加磁盘
- 生产者/消费者模型
- 与VMware成立合资公司 中科曙光构建云计算平台
- jstl c:forEach 一行排三个图片然后自动换行
- HDU 1013 Digital Roots(模拟计算)
- LeakCanary的使用
- Perl 数据类型
- 15电气李书鹏4月14日作业(1)
- TCP/IP详解学习笔记(2)-数据链路层
- 使用XStream将XML转化成对象,忽略没有关联的属性
- Android学习之使用HttpURLConnection上传单个文件
- 【JS】:JS如何实现加载别的框架
- 在线条形码生成
- Android动画之Property属性动画
- Raytracing
- Spring 学习笔记(1)注入Injection_type