CSAPP 3e: Bomb lab (phase_6)

  这一关很复杂,需要非常耐心。如果感觉容易在循环中绕晕,可以参考一下我最后附上的画图分析法2333,小把戏,不过挺有用的。

  先看函数phase_6:

00000000004010f4 <phase_6>:
  4010f4:    41 56                    push   %r14
  4010f6:    41 55                    push   %r13
  4010f8:    41 54                    push   %r12
  4010fa:    55                       push   %rbp
  4010fb:    53                       push   %rbx
  4010fc:    48 83 ec 50              sub    $0x50,%rsp
  401100:    49 89 e5                 mov    %rsp,%r13
  401103:    48 89 e6                 mov    %rsp,%rsi
  401106:    e8 51 03 00 00           callq  40145c <read_six_numbers>    ;读取六个数字
  40110b:    49 89 e6                 mov    %rsp,%r14
  40110e:    41 bc 00 00 00 00        mov    $0x0,%r12d
  401114:    4c 89 ed                 mov    %r13,%rbp
  401117:    41 8b 45 00              mov    0x0(%r13),%eax        ;%r13的值在循环过程中有变化,%r13+=4.
  40111b:    83 e8 01                 sub    $0x1,%eax            
  40111e:    83 f8 05                 cmp    $0x5,%eax            ;每一个数字必须小于等于6,(x-1)<=5就是x<=6.
  401121:    76 05                    jbe    401128 <phase_6+0x34>
  401123:    e8 12 03 00 00           callq  40143a <explode_bomb>
  401128:    41 83 c4 01              add    $0x1,%r12d
  40112c:    41 83 fc 06              cmp    $0x6,%r12d
  401130:    74 21                    je     401153 <phase_6+0x5f>;检查完所有6个数字各不相同后跳出此循环。
  401132:    44 89 e3                 mov    %r12d,%ebx
  401135:    48 63 c3                 movslq %ebx,%rax                ;......
  401138:    8b 04 84                 mov    (%rsp,%rax,4),%eax        ;这一段循环操作要求所输入的6个数字中
  40113b:    39 45 00                 cmp    %eax,0x0(%rbp)            ;其中任何两个数字都不能等同,也就是需要输入
  40113e:    75 05                    jne    401145 <phase_6+0x51>    ;各不相同的六个数字。
  401140:    e8 f5 02 00 00           callq  40143a <explode_bomb>    ;
  401145:    83 c3 01                 add    $0x1,%ebx                ;
  401148:    83 fb 05                 cmp    $0x5,%ebx                ;
  40114b:    7e e8                    jle    401135 <phase_6+0x41>    ;......
  40114d:    49 83 c5 04              add    $0x4,%r13
  401151:    eb c1                    jmp    401114 <phase_6+0x20>
  401153:    48 8d 74 24 18           lea    0x18(%rsp),%rsi
  401158:    4c 89 f0                 mov    %r14,%rax                ;%rax=%r14=%rsp,在下面的循环中,%rax+=4.
  40115b:    b9 07 00 00 00           mov    $0x7,%ecx    ;注意这里的7.
  401160:    89 ca                    mov    %ecx,%edx                ;******
  401162:    2b 10                    sub    (%rax),%edx                ;这一段循环用7减去每个值,比如y=7-x,x为输入的
  401164:    89 10                    mov    %edx,(%rax)                ;原来的值,y为新值,新值y覆盖旧值x,存储地址从
  401166:    48 83 c0 04              add    $0x4,%rax                ;第一个数的(%rsp)到最后一个数(%rsp+0x18).
  40116a:    48 39 f0                 cmp    %rsi,%rax                ;
  40116d:    75 f1                    jne    401160 <phase_6+0x6c>    ;******
  40116f:    be 00 00 00 00           mov    $0x0,%esi
  401174:    eb 21                    jmp    401197 <phase_6+0xa3>    ;+++++++++
  401176:    48 8b 52 08              mov    0x8(%rdx),%rdx            ;这一段循环是依据上一段循环之后的新值y,将地址
  40117a:    83 c0 01                 add    $0x1,%eax                ;0x6032d0上的六个地址值依次写入地址(%rsp+0x20+2*%rsi)
  40117d:    39 c8                    cmp    %ecx,%eax                ;%rsi+=4; 例如,如果如果第一个数是1,第二个数是2,则
  40117f:    75 f5                    jne    401176 <phase_6+0x82>    ;(%rsp+0x20)处存储0x6032d0处的地址本身0x6032d0
  401181:    eb 05                    jmp    401188 <phase_6+0x94>    ;(%rsp+0x28)处存储0x6032d0上的第1个地址值0x6032e0
  401183:    ba d0 32 60 00           mov    $0x6032d0,%edx            ;其他值请参考地址0x6032d0处的6个16字节的十六进制数。
  401188:    48 89 54 74 20           mov    %rdx,0x20(%rsp,%rsi,2)    ;eg:第一个16字节的数为(小端法显示)
  40118d:    48 83 c6 04              add    $0x4,%rsi                ;0x6032d0:    4c 01 00 00 01 00 00 00    前8字节
  401191:    48 83 fe 18              cmp    $0x18,%rsi                ;0x6032d8:    e0 32 60 00 00 00 00 00    后8字节
  401195:    74 14                    je     4011ab <phase_6+0xb7>    ;描述为long类型则为
  401197:    8b 0c 34                 mov    (%rsp,%rsi,1),%ecx        ;0x6032d0:    0x000000010000014c        前8字节
  40119a:    83 f9 01                 cmp    $0x1,%ecx                ;0x6032d8:    0x00000000006032e0        后8字节
  40119d:    7e e4                    jle    401183 <phase_6+0x8f>    ;
  40119f:    b8 01 00 00 00           mov    $0x1,%eax                ;
  4011a4:    ba d0 32 60 00           mov    $0x6032d0,%edx            ;
  4011a9:    eb cb                    jmp    401176 <phase_6+0x82>    ;++++++++++
  4011ab:    48 8b 5c 24 20           mov    0x20(%rsp),%rbx
  4011b0:    48 8d 44 24 28           lea    0x28(%rsp),%rax
  4011b5:    48 8d 74 24 50           lea    0x50(%rsp),%rsi
  4011ba:    48 89 d9                 mov    %rbx,%rcx
  4011bd:    48 8b 10                 mov    (%rax),%rdx
  4011c0:    48 89 51 08              mov    %rdx,0x8(%rcx)
  4011c4:    48 83 c0 08              add    $0x8,%rax
  4011c8:    48 39 f0                 cmp    %rsi,%rax
  4011cb:    74 05                    je     4011d2 <phase_6+0xde>
  4011cd:    48 89 d1                 mov    %rdx,%rcx
  4011d0:    eb eb                    jmp    4011bd <phase_6+0xc9>
  4011d2:    48 c7 42 08 00 00 00     movq   $0x0,0x8(%rdx)
  4011d9:    00 
  4011da:    bd 05 00 00 00           mov    $0x5,%ebp
  4011df:    48 8b 43 08              mov    0x8(%rbx),%rax        ;//////
  4011e3:    8b 00                    mov    (%rax),%eax            ;这一段循环比较五次大小,
  4011e5:    39 03                    cmp    %eax,(%rbx)            ;假设地址(%rsp+0x20)存储的值为0x6032d0
  4011e7:    7d 05                    jge    4011ee <phase_6+0xfa>;假设地址(%rsp+0x28)存储的值为0x6032e0
  4011e9:    e8 4c 02 00 00           callq  40143a <explode_bomb>;则需要地址(0x6032d0)处的值x大于等于
  4011ee:    48 8b 5b 08              mov    0x8(%rbx),%rbx        ;地址(0x6032e0)处的值y。否则bomb.
  4011f2:    83 ed 01                 sub    $0x1,%ebp            ;
  4011f5:    75 e8                    jne    4011df <phase_6+0xeb>;//////
  4011f7:    48 83 c4 50              add    $0x50,%rsp
  4011fb:    5b                       pop    %rbx
  4011fc:    5d                       pop    %rbp
  4011fd:    41 5c                    pop    %r12
  4011ff:    41 5d                    pop    %r13
  401201:    41 5e                    pop    %r14
  401203:    c3                       retq   

  在注释中说了输入要求,输入6个各不相同的数,每个数都要小于6,然后每个数都被7减,新值 y 覆盖旧值 x ,用新值进行了后续的操作。

其中操作重点是对地址0x6032d0处的6个16字节的数的操作。

 用x/12x 0x603200查看0x6032d0处的数据

0x6032d0:    0x000000010000014c    0x00000000006032e0
0x6032e0:    0x00000002000000a8    0x00000000006032f0
0x6032f0:    0x000000030000039c    0x0000000000603300
0x603300:    0x00000004000002b3    0x0000000000603310
0x603310:    0x00000005000001dd    0x0000000000603320
0x603320:    0x00000006000001bb    0x0000000000000000

  注意这是小端法显示,也就是说,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按顺序为  "3  4  5  6  1  2"

  而被7减之前的旧值x按顺序应为    "4  3  2  1  6  5"

这就是我们需要按顺序输入的六个各不相同的数字,输入"4 3 2 1 6 5"即可通过本关(中间空格隔开)。

最后附上我当时这一关的解题手稿,画出逻辑图之后就感觉更加清爽了,更加容易理解思路,省的总在循环上绕死。

  逻辑图笨拙式手稿

  之后是分析手稿

原文地址:https://www.cnblogs.com/xihuyouyu/p/7544514.html