笛里谁知壮士心,沙头空照征人骨。这篇文章主要讲述CSAPP 3e: Bomb lab (phase_6)相关的知识,希望能为你提供帮助。
这一关很复杂,需要非常耐心。如果感觉容易在循环中绕晕,可以参考一下我最后附上的画图分析法2333,小把戏,不过挺有用的。
先看函数phase_6:
00000000004010f4 < phase_6> : 4010f4:41 56push%r14 4010f6:41 55push%r13 4010f8:41 54push%r12 4010fa:55push%rbp 4010fb:53push%rbx 4010fc:48 83 ec 50sub$0x50,%rsp 401100:49 89 e5mov%rsp,%r13 401103:48 89 e6mov%rsp,%rsi 401106:e8 51 03 00 00callq40145c < read_six_numbers> ; 读取六个数字 40110b:49 89 e6mov%rsp,%r14 40110e:41 bc 00 00 00 00mov$0x0,%r12d 401114:4c 89 edmov%r13,%rbp 401117:41 8b 45 00mov0x0(%r13),%eax; %r13的值在循环过程中有变化,%r13+=4. 40111b:83 e8 01sub$0x1,%eax 40111e:83 f8 05cmp$0x5,%eax; 每一个数字必须小于等于6,(x-1)< =5就是x< =6. 401121:76 05jbe401128 < phase_6+0x34> 401123:e8 12 03 00 00callq40143a < explode_bomb> 401128:41 83 c4 01add$0x1,%r12d 40112c:41 83 fc 06cmp$0x6,%r12d 401130:74 21je401153 < phase_6+0x5f> ; 检查完所有6个数字各不相同后跳出此循环。 401132:44 89 e3mov%r12d,%ebx 401135:48 63 c3movslq %ebx,%rax; ...... 401138:8b 04 84mov(%rsp,%rax,4),%eax; 这一段循环操作要求所输入的6个数字中 40113b:39 45 00cmp%eax,0x0(%rbp); 其中任何两个数字都不能等同,也就是需要输入 40113e:75 05jne401145 < phase_6+0x51> ; 各不相同的六个数字。 401140:e8 f5 02 00 00callq40143a < explode_bomb> ; 401145:83 c3 01add$0x1,%ebx; 401148:83 fb 05cmp$0x5,%ebx; 40114b:7e e8jle401135 < phase_6+0x41> ; ...... 40114d:49 83 c5 04add$0x4,%r13 401151:eb c1jmp401114 < phase_6+0x20> 401153:48 8d 74 24 18lea0x18(%rsp),%rsi 401158:4c 89 f0mov%r14,%rax; %rax=%r14=%rsp,在下面的循环中,%rax+=4. 40115b:b9 07 00 00 00mov$0x7,%ecx; 注意这里的7. 401160:89 camov%ecx,%edx; ****** 401162:2b 10sub(%rax),%edx; 这一段循环用7减去每个值,比如y=7-x,x为输入的 401164:89 10mov%edx,(%rax); 原来的值,y为新值,新值y覆盖旧值x,存储地址从 401166:48 83 c0 04add$0x4,%rax; 第一个数的(%rsp)到最后一个数(%rsp+0x18). 40116a:48 39 f0cmp%rsi,%rax; 40116d:75 f1jne401160 < phase_6+0x6c> ; ****** 40116f:be 00 00 00 00mov$0x0,%esi 401174:eb 21jmp401197 < phase_6+0xa3> ; +++++++++ 401176:48 8b 52 08mov0x8(%rdx),%rdx; 这一段循环是依据上一段循环之后的新值y,将地址 40117a:83 c0 01add$0x1,%eax; 0x6032d0上的六个地址值依次写入地址(%rsp+0x20+2*%rsi) 40117d:39 c8cmp%ecx,%eax; %rsi+=4; 例如,如果如果第一个数是1,第二个数是2,则 40117f:75 f5jne401176 < phase_6+0x82> ; (%rsp+0x20)处存储0x6032d0处的地址本身0x6032d0 401181:eb 05jmp401188 < phase_6+0x94> ; (%rsp+0x28)处存储0x6032d0上的第1个地址值0x6032e0 401183:ba d0 32 60 00mov$0x6032d0,%edx; 其他值请参考地址0x6032d0处的6个16字节的十六进制数。 401188:48 89 54 74 20mov%rdx,0x20(%rsp,%rsi,2); eg:第一个16字节的数为(小端法显示) 40118d:48 83 c6 04add$0x4,%rsi; 0x6032d0:4c 01 00 00 01 00 00 00前8字节 401191:48 83 fe 18cmp$0x18,%rsi; 0x6032d8:e0 32 60 00 00 00 00 00后8字节 401195:74 14je4011ab < phase_6+0xb7> ; 描述为long类型则为 401197:8b 0c 34mov(%rsp,%rsi,1),%ecx; 0x6032d0:0x000000010000014c前8字节 40119a:83 f9 01cmp$0x1,%ecx; 0x6032d8:0x00000000006032e0后8字节 40119d:7e e4jle401183 < phase_6+0x8f> ; 40119f:b8 01 00 00 00mov$0x1,%eax; 4011a4:ba d0 32 60 00mov$0x6032d0,%edx; 4011a9:eb cbjmp401176 < phase_6+0x82> ; ++++++++++ 4011ab:48 8b 5c 24 20mov0x20(%rsp),%rbx 4011b0:48 8d 44 24 28lea0x28(%rsp),%rax 4011b5:48 8d 74 24 50lea0x50(%rsp),%rsi 4011ba:48 89 d9mov%rbx,%rcx 4011bd:48 8b 10mov(%rax),%rdx 4011c0:48 89 51 08mov%rdx,0x8(%rcx) 4011c4:48 83 c0 08add$0x8,%rax 4011c8:48 39 f0cmp%rsi,%rax 4011cb:74 05je4011d2 < phase_6+0xde> 4011cd:48 89 d1mov%rdx,%rcx 4011d0:eb ebjmp4011bd < phase_6+0xc9> 4011d2:48 c7 42 08 00 00 00movq$0x0,0x8(%rdx) 4011d9:00 4011da:bd 05 00 00 00mov$0x5,%ebp 4011df:48 8b 43 08mov0x8(%rbx),%rax; ////// 4011e3:8b 00mov(%rax),%eax; 这一段循环比较五次大小, 4011e5:39 03cmp%eax,(%rbx); 假设地址(%rsp+0x20)存储的值为0x6032d0 4011e7:7d 05jge4011ee < phase_6+0xfa> ; 假设地址(%rsp+0x28)存储的值为0x6032e0 4011e9:e8 4c 02 00 00callq40143a < explode_bomb> ; 则需要地址(0x6032d0)处的值x大于等于 4011ee:48 8b 5b 08mov0x8(%rbx),%rbx; 地址(0x6032e0)处的值y。否则bomb. 4011f2:83 ed 01sub$0x1,%ebp; 4011f5:75 e8jne4011df < phase_6+0xeb> ; ////// 4011f7:48 83 c4 50add$0x50,%rsp 4011fb:5bpop%rbx 4011fc:5dpop%rbp 4011fd:41 5cpop%r12 4011ff:41 5dpop%r13 401201:41 5epop%r14 401203:c3retq
在注释中说了输入要求,输入6个各不相同的数,每个数都要小于6,然后每个数都被7减,新值 y 覆盖旧值 x ,用新值进行了后续的操作。
其中操作重点是对地址0x6032d0处的6个16字节的数的操作。
用x/12x 0x603200查看0x6032d0处的数据
0x6032d0:0x000000010000014c0x00000000006032e0 0x6032e0:0x00000002000000a80x00000000006032f0 0x6032f0:0x000000030000039c0x0000000000603300 0x603300:0x00000004000002b30x0000000000603310 0x603310:0x00000005000001dd0x0000000000603320 0x603320:0x00000006000001bb0x0000000000000000
注意这是小端法显示,也就是说,0x6032d0处的字节值为4c,0x6032d1处的字节值为01,组合形成014c。
仔细理解代码之后可以发现,通关要求是:依据被7减之后的新值y,将0x6032d0,0x6032e0等地址值从地址(%rsp+0x20)开始向后写入。然后要求比较大小,比如:
假设地址(%rsp+0x20)存储的值为0x6032d0,假设地址(%rsp+0x28)存储的值为0x6032e0,则需要地址(0x6032d0)处的值x大于等于,地址(0x6032e0)处的值y。否则bomb。
也就是说,我们需要比较十六进制值"(1) 14c(2) a8(3) 39c(4) 2b3(5) 1dd(6) 1bb"这六个数字的大小,从大到小排序。
然后查看排序后的序号变化"(3) 39c(4) 2b3(5) 1dd(6) 1bb(1) 14c(2) a8",十六进制转成十进制进行比较,这里只是便于观察序号变化才没有转换。
由此可知,被7减后的新值y按顺序为"345612"
而被7减之前的旧值x按顺序应为"432165"
这就是我们需要按顺序输入的六个各不相同的数字,输入"4 3 2 1 6 5"即可通过本关(中间空格隔开)。
最后附上我当时这一关的解题手稿,画出逻辑图之后就感觉更加清爽了,更加容易理解思路,省的总在循环上绕死。
逻辑图笨拙式手稿
文章图片
之后是分析手稿
【CSAPP 3e: Bomb lab (phase_6)】
文章图片
推荐阅读
- Mapped Statements collection does not contain value for 问题的解决
- 推荐android布局百分比框架
- 安卓未来发展前景
- [Android FrameWork 6.0源码学习] View的重绘过程之Draw
- 对安卓未来前景的看法
- CSAPP 3e: Bomb lab (phase_5)
- 如何用Java删除文件
- 如何在Java中读取CSV文件
- 如何用Java打开文件