@@ -654,5 +654,157 @@ finish # 執行完當前函數返回上一層
654654- 如何通過返回值編碼不同的路徑
655655- 為什麼某些看似合理的輸入會失敗(不在二分搜尋的「自然路徑」上)
656656
657+ ## :whale: Phase 5
658+
659+ ```bash
660+ (gdb) break phase_5
661+ Breakpoint 1 at 0x401062
662+ (gdb) run solution.txt
663+ Starting program: /home/nvidia/Desktop/bomb/bomb solution.txt
664+ Welcome to my fiendish little bomb. You have 6 phases with
665+ which to blow yourself up. Have a nice day!
666+ Phase 1 defused. How about the next one?
667+ That' s number 2. Keep going!
668+ Halfway there!
669+ So you got that one. Try this one.
670+
671+ Breakpoint 1, 0x0000000000401062 in phase_5 ()
672+ (gdb) disassemble
673+ Dump of assembler code for function phase_5:
674+ => 0x0000000000401062 < +0> : push %rbx
675+ 0x0000000000401063 < +1> : sub $0 x20,%rsp
676+ 0x0000000000401067 < +5> : mov %rdi,%rbx
677+ 0x000000000040106a < +8> : mov %fs:0x28,%rax
678+ 0x0000000000401073 < +17> : mov %rax,0x18(%rsp)
679+ 0x0000000000401078 < +22> : xor %eax,%eax
680+ 0x000000000040107a < +24> : callq 0x40131b < string_length>
681+ 0x000000000040107f < +29> : cmp $0 x6,%eax
682+ 0x0000000000401082 < +32> : je 0x4010d2 < phase_5+112>
683+ 0x0000000000401084 < +34> : callq 0x40143a < explode_bomb>
684+ 0x0000000000401089 < +39> : jmp 0x4010d2 < phase_5+112>
685+ 0x000000000040108b < +41> : movzbl (%rbx,%rax,1),%ecx
686+ 0x000000000040108f < +45> : mov %cl,(%rsp)
687+ 0x0000000000401092 < +48> : mov (%rsp),%rdx
688+ 0x0000000000401096 < +52> : and $0 xf,%edx
689+ 0x0000000000401099 < +55> : movzbl 0x4024b0(%rdx),%edx
690+ 0x00000000004010a0 < +62> : mov %dl,0x10(%rsp,%rax,1)
691+ 0x00000000004010a4 < +66> : add $0 x1,%rax
692+ 0x00000000004010a8 < +70> : cmp $0 x6,%rax
693+ 0x00000000004010ac < +74> : jne 0x40108b < phase_5+41>
694+ 0x00000000004010ae < +76> : movb $0 x0,0x16(%rsp)
695+ 0x00000000004010b3 < +81> : mov $0 x40245e,%esi
696+ 0x00000000004010b8 < +86> : lea 0x10(%rsp),%rdi
697+ 0x00000000004010bd < +91> : callq 0x401338 < strings_not_equal>
698+ 0x00000000004010c2 < +96> : test %eax,%eax
699+ 0x00000000004010c4 < +98> : je 0x4010d9 < phase_5+119>
700+ 0x00000000004010c6 < +100> : callq 0x40143a < explode_bomb>
701+ 0x00000000004010cb < +105> : nopl 0x0(%rax,%rax,1)
702+ 0x00000000004010d0 < +110> : jmp 0x4010d9 < phase_5+119>
703+ 0x00000000004010d2 < +112> : mov $0 x0,%eax
704+ 0x00000000004010d7 < +117> : jmp 0x40108b < phase_5+41>
705+ 0x00000000004010d9 < +119> : mov 0x18(%rsp),%rax
706+ 0x00000000004010de < +124> : xor %fs:0x28,%rax
707+ 0x00000000004010e7 < +133> : je 0x4010ee < phase_5+140>
708+ 0x00000000004010e9 < +135> : callq 0x400b30 < __stack_chk_fail@plt>
709+ 0x00000000004010ee < +140> : add $0 x20,%rsp
710+ 0x00000000004010f2 < +144> : pop %rbx
711+ 0x00000000004010f3 < +145> : retq
712+ End of assembler dump.
713+ ```
714+
715+ ### :crab : 解題邏輯
716+ 輸入 6 個字元 → 每個字元取低 4 bits 當索引 → 查表轉換 → 必須變成 "flyers"
717+
718+ ### :crab : 關鍵指令解析
719+
720+ ** 1. 長度檢查 (+24 ~ +34)**
721+ ``` asm
722+ callq 0x40131b <string_length>
723+ cmp $0x6,%eax
724+ je 0x4010d2 <phase_5+112>
725+ callq 0x40143a <explode_bomb>
726+ ```
727+ - 輸入必須是 6 個字元
728+
729+ ** 2. 初始化 loop counter (+112)**
730+ ``` asm
731+ mov $0x0,%eax
732+ jmp 0x40108b <phase_5+41>
733+ ```
734+ - ` %eax ` = 0(迴圈計數器)
735+
736+ ** 3. 核心轉換迴圈 (+41 ~ +74)**
737+ ``` asm
738+ movzbl (%rbx,%rax,1),%ecx # 讀取輸入字串第 i 個字元
739+ mov %cl,(%rsp) # 暫存到 stack
740+ mov (%rsp),%rdx # 讀回到 %rdx
741+ and $0xf,%edx # 取低 4 bits (0-15)
742+ movzbl 0x4024b0(%rdx),%edx # 查表!key instruction
743+ mov %dl,0x10(%rsp,%rax,1) # 存結果到 stack offset 0x10
744+ add $0x1,%rax # i++
745+ cmp $0x6,%rax # 迴圈 6 次
746+ jne 0x40108b <phase_5+41>
747+ ```
748+
749+ ** 關鍵概念:**
750+ - ` and $0xf, %edx ` :只保留字元的低 4 bits
751+ - ` 0x4024b0(%rdx) ` :base + index 定址,從查表陣列取字元
752+ - 轉換後的字串存在 ` %rsp + 0x10 `
753+
754+ ** 4. 字串比較 (+76 ~ +100)**
755+ ``` asm
756+ movb $0x0,0x16(%rsp) # 加 null terminator
757+ mov $0x40245e,%esi # "flyers" 字串位址
758+ lea 0x10(%rsp),%rdi # 轉換後的字串
759+ callq 0x401338 <strings_not_equal>
760+ test %eax,%eax
761+ je 0x4010d9 <phase_5+119> # 相等就通過
762+ callq 0x40143a <explode_bomb>
763+ ```
764+
765+ ### :crab : 解題步驟
766+
767+ ** 1. 查看查表陣列**
768+ ``` gdb
769+ (gdb) x/s 0x4024b0
770+ ```
771+ 找出索引 0-15 對應的字元
772+
773+ ** 2. 反推輸入**
774+ - 目標:'f', 'l', 'y', 'e', 'r', 's'
775+ - 找出查表陣列中這些字母的索引位置
776+ - 找任意 ASCII 字元,其低 4 bits 等於這些索引
777+
778+ ** 3. 驗證**
779+ ``` gdb
780+ (gdb) break *0x4010bd
781+ (gdb) x/s $rdi # 檢查轉換結果
782+ (gdb) x/s 0x40245e # 確認目標是 "flyers"
783+ ```
784+
785+ ### :crab : 新學到的指令
786+
787+ - ** ` movzbl src, dst ` ** :move zero-extend byte to long
788+ - 讀 1 byte,放進 32-bit 暫存器,高位補 0
789+
790+ - ** ` and $0xf, %reg ` ** :bit masking
791+ - 取最低 4 bits(範圍 0-15)
792+
793+ - ** ` addr(%base, %index, scale) ` ** :陣列定址
794+ - 計算:base + index × scale
795+ - 例:` 0x4024b0(%rdx) ` = 0x4024b0 + %rdx
796+
797+ ### :crab : Stack Canary (+8, +119 ~ +135)
798+ ``` asm
799+ mov %fs:0x28,%rax # 讀 canary
800+ mov %rax,0x18(%rsp) # 存到 stack
801+ ...
802+ xor %fs:0x28,%rax # 檢查是否被改
803+ je 0x4010ee # 沒變就 OK
804+ callq 0x400b30 <__stack_chk_fail@plt>
805+ ```
806+ - 防止 buffer overflow 的保護機制
807+ - 解題時可忽略
808+
657809## :whale : x86-64 assembly cheat sheet
658810- https://web.stanford.edu/class/cs107/resources/x86-64-reference.pdf
0 commit comments