-
-
[原创][推荐][原创]CodeGateCTF 2026 - Silicon Dream WP
-
发表于: 18小时前 360
-
CodeGateCTF 2026 - Silicon Dream WP
写在前面
赛后反思,在比赛期间没有解出这道80+多解题目,十分惭愧。是我过度依赖AI,也是我能力的退步。
题目描述
作者实现了一个基于魔改过的 openMSP430 硬件处理器,看似合理的扩展指令实际会触发基于Fistel网络的加密。
解题
0x01 基本逆向
这一步通过AI基本都能逆明白,加载字节码,然后解执行。
执行的字节码反汇编后(部分):
; Segment starting at 0x0000c000:
0xc000: 4255 0120 mov.b &0x0120, R5 ; ca. 3 cycles
0xc004: d035 5a08 bis #0x5a08, R5 ; ca. 2 cycles
0xc008: 4582 02d2 mov R5, &0x02d2 ; ca. 4 cycles
0xc00c: 4031 0400 mov #0x0400, SP ; ca. 2 cycles
0xc010: 403f 0000 mov #0x0000, R15 ; ca. 2 cycles
0xc014: 930f tst R15 ; ca. 1 cycle
0xc016: 2408 jz .L0001 ; ca. 2 cycles +16 --> 0xc028
0xc018: 4292 02d2 0120 .L0002: mov &0x02d2, &0x0120 ; ca. 6 cycles
0xc01e: 832f decd R15 ; ca. 1 cycle
0xc020: 4f9f c740 0200 mov 0xc740(R15), 512(R15) ; ca. 6 cycles
0xc026: 23f8 jnz .L0002 ; ca. 2 cycles -16 --> 0xc018
0xc028: 403f 006a .L0001: mov #0x006a, R15 ; ca. 2 cycles
0xc02c: 930f tst R15 ; ca. 1 cycle
0xc02e: 2407 jz .L0003 ; ca. 2 cycles +14 --> 0xc03e
0xc030: 4292 02d2 0120 .L0004: mov &0x02d2, &0x0120 ; ca. 6 cycles
0xc036: 831f dec R15 ; ca. 1 cycle
0xc038: 43cf 0200 clr.b 512(R15) ; ca. 4 cycles
0xc03c: 23f9 jnz .L0004 ; ca. 2 cycles -14 --> 0xc030
0xc03e: 5031 ffdc .L0003: add #0xffdc, SP ; ca. 2 cycles
0xc042: 40b2 5a80 0120 mov #0x5a80, &0x0120 ; ca. 5 cycles
0xc048: 4381 0020 clr 32(SP) ; ca. 4 cycles
0xc04c: 43c1 0022 clr.b 34(SP) ; ca. 4 cycles
0xc050: 40b1 c64a 0010 mov #0xc64a, 16(SP) ; ca. 5 cycles
0xc056: 40b1 026a 0012 mov #0x026a, 18(SP) ; ca. 5 cycles
0xc05c: 40b1 0200 0014 mov #0x0200, 20(SP) ; ca. 5 cycles
0xc062: 4381 0016 clr 22(SP) ; ca. 4 cycles
0xc066: 4381 0018 clr 24(SP) ; ca. 4 cycles
0xc06a: 40b1 000d 001a mov #0x000d, 26(SP) ; ca. 5 cycles
0xc070: 411f 0020 .L0006: mov 0x0020(SP), R15 ; ca. 3 cycles
0xc074: 4f5e c6b3 mov.b 0xc6b3(R15), R14 ; ca. 3 cycles
0xc078: 531f inc R15 ; ca. 1 cycle
0xc07a: 537e add.b #0xff, R14 ; ca. 1 cycle
0xc07c: 907e 0015 cmp.b #0x15, R14 ; ca. 2 cycles
0xc080: 2802 jnc .L0005 ; ca. 2 cycles +4 --> 0xc086
0xc082: 4030 c446 br #0xc446 ; ca. 3 cycles
0xc086: 4e4e .L0005: mov.b R14, R14 ; ca. 1 cycle
0xc088: 5e0e rla R14 ; ca. 1 cycle
0xc08a: 4e10 c620 br 0xc620(R14) ; ca. 3 cycles
0xc08e: 4f5d c6b3 mov.b 0xc6b3(R15), R13 ; ca. 3 cycles
0xc092: 531f inc R15 ; ca. 1 cycle
0xc094: 4f81 0020 mov R15, 32(SP) ; ca. 4 cycles
0xc098: 4d0e mov R13, R14 ; ca. 1 cycle
0xc09a: f03e 000f and #0x000f, R14 ; ca. 2 cycles
0xc09e: 5e0e rla R14 ; ca. 1 cycle
0xc0a0: 510e add SP, R14 ; ca. 1 cycle
0xc0a2: 4e2e mov @R14, R14 ; ca. 1 cycle
0xc0a4: 4d4f mov.b R13, R15 ; ca. 1 cycle
0xc0a6: c312 clrc ; ca. 1 cycle
0xc0a8: 104f rrc.b R15 ; ca. 1 cycle
0xc0aa: c312 clrc ; ca. 1 cycle
0xc0ac: 104f rrc.b R15 ; ca. 1 cycle
0xc0ae: c312 clrc ; ca. 1 cycle
0xc0b0: 104f rrc.b R15 ; ca. 1 cycle
0xc0b2: c312 clrc ; ca. 1 cycle
0xc0b4: 104f rrc.b R15 ; ca. 1 cycle
0xc0b6: f03f 000f and #0x000f, R15 ; ca. 2 cycles
0xc0ba: 5f0f rla R15 ; ca. 1 cycle
0xc0bc: 510f add SP, R15 ; ca. 1 cycle
0xc0be: 4eaf 0000 mov @R14, 0(R15) ; ca. 4 cycles
0xc0c2: 3fd6 jmp .L0006 ; ca. 2 cycles -84 --> 0xc070
0xc0c4: 4f5e c6b3 mov.b 0xc6b3(R15), R14 ; ca. 3 cycles
0xc0c8: 531f inc R15 ; ca. 1 cycle
0xc0ca: 4f81 0020 mov R15, 32(SP) ; ca. 4 cycles
0xc0ce: 4e4f mov.b R14, R15 ; ca. 1 cycle
0xc0d0: c312 clrc ; ca. 1 cycle
0xc0d2: 104f rrc.b R15 ; ca. 1 cycle
0xc0d4: c312 clrc ; ca. 1 cycle
0xc0d6: 104f rrc.b R15 ; ca. 1 cycle
0xc0d8: c312 clrc ; ca. 1 cycle
0xc0da: 104f rrc.b R15 ; ca. 1 cycle
0xc0dc: c312 clrc ; ca. 1 cycle
0xc0de: 104f rrc.b R15 ; ca. 1 cycle
0xc0e0: f03f 000f and #0x000f, R15 ; ca. 2 cycles
0xc0e4: 5f0f rla R15 ; ca. 1 cycle
0xc0e6: 510f add SP, R15 ; ca. 1 cycle
0xc0e8: f03e 000f and #0x000f, R14 ; ca. 2 cycles
0xc0ec: 5e0e rla R14 ; ca. 1 cycle
0xc0ee: 510e add SP, R14 ; ca. 1 cycle
0xc0f0: 4e2e mov @R14, R14 ; ca. 1 cycle
0xc0f2: 4fae 0000 mov @R15, 0(R14) ; ca. 4 cycles
0xc0f6: 3fbc jmp .L0006 ; ca. 2 cycles -136 --> 0xc070
0xc0f8: 4f0d mov R15, R13 ; ca. 1 cycle
0xc0fa: 503d c6b3 add #0xc6b3, R13 ; ca. 2 cycles
0xc0fe: 4d6e mov.b @R13, R14 ; ca. 1 cycle
0xc100: c312 clrc ; ca. 1 cycle
0xc102: 104e rrc.b R14 ; ca. 1 cycle
0xc104: c312 clrc ; ca. 1 cycle
0xc106: 104e rrc.b R14 ; ca. 1 cycle
0xc108: c312 clrc ; ca. 1 cycle
0xc10a: 104e rrc.b R14 ; ca. 1 cycle
0xc10c: c312 clrc ; ca. 1 cycle
0xc10e: 104e rrc.b R14 ; ca. 1 cycle
0xc110: f03e 000f and #0x000f, R14 ; ca. 2 cycles
0xc114: 5e0e rla R14 ; ca. 1 cycle
0xc116: 510e add SP, R14 ; ca. 1 cycle
0xc118: 4d5c 0002 mov.b 0x0002(R13), R12 ; ca. 3 cycles
0xc11c: 108c swpb R12 ; ca. 1 cycle
0xc11e: 4d5d 0001 mov.b 0x0001(R13), R13 ; ca. 3 cycles
0xc122: dd0c bis R13, R12 ; ca. 1 cycle
0xc124: 4c8e 0000 mov R12, 0(R14) ; ca. 4 cycles
0xc128: 503f 0003 add #0x0003, R15 ; ca. 2 cycles
0xc12c: 4f81 0020 mov R15, 32(SP) ; ca. 4 cycles
0xc130: 3f9f jmp .L0006 ; ca. 2 cycles -194 --> 0xc070
0xc132: 4f5d c6b3 mov.b 0xc6b3(R15), R13 ; ca. 3 cycles
0xc136: 531f inc R15 ; ca. 1 cycle
0xc138: 4f81 0020 mov R15, 32(SP) ; ca. 4 cycles
0xc13c: 4d0e mov R13, R14 ; ca. 1 cycle
0xc13e: f03e 000f and #0x000f, R14 ; ca. 2 cycles
0xc142: 5e0e rla R14 ; ca. 1 cycle
0xc144: 510e add SP, R14 ; ca. 1 cycle
0xc146: 4d4f mov.b R13, R15 ; ca. 1 cycle
0xc148: c312 clrc ; ca. 1 cycle
0xc14a: 104f rrc.b R15 ; ca. 1 cycle
0xc14c: c312 clrc ; ca. 1 cycle
0xc14e: 104f rrc.b R15 ; ca. 1 cycle
0xc150: c312 clrc ; ca. 1 cycle
0xc152: 104f rrc.b R15 ; ca. 1 cycle
0xc154: c312 clrc ; ca. 1 cycle
0xc156: 104f rrc.b R15 ; ca. 1 cycle
0xc158: f03f 000f and #0x000f, R15 ; ca. 2 cycles
0xc15c: 5f0f rla R15 ; ca. 1 cycle
0xc15e: 510f add SP, R15 ; ca. 1 cycle
0xc160: 4eaf 0000 mov @R14, 0(R15) ; ca. 4 cycles
0xc164: 3f85 jmp .L0006 ; ca. 2 cycles -246 --> 0xc070
0xc166: 4f5e c6b3 mov.b 0xc6b3(R15), R14 ; ca. 3 cycles
0xc16a: 531f inc R15 ; ca. 1 cycle
0xc16c: 4f81 0020 mov R15, 32(SP) ; ca. 4 cycles
0xc170: 4e4f mov.b R14, R15 ; ca. 1 cycle
0xc172: c312 clrc ; ca. 1 cycle
0xc174: 104f rrc.b R15 ; ca. 1 cycle
0xc176: c312 clrc ; ca. 1 cycle
0xc178: 104f rrc.b R15 ; ca. 1 cycle
0xc17a: c312 clrc ; ca. 1 cycle
0xc17c: 104f rrc.b R15 ; ca. 1 cycle
0xc17e: c312 clrc ; ca. 1 cycle
0xc180: 104f rrc.b R15 ; ca. 1 cycle
0xc182: f03f 000f and #0x000f, R15 ; ca. 2 cycles
0xc186: 5f0f rla R15 ; ca. 1 cycle
0xc188: 510f add SP, R15 ; ca. 1 cycle
0xc18a: f03e 000f and #0x000f, R14 ; ca. 2 cycles
0xc18e: 5e0e rla R14 ; ca. 1 cycle
0xc190: 510e add SP, R14 ; ca. 1 cycle
0xc192: eeaf 0000 xor @R14, 0(R15) ; ca. 4 cycles
0xc196: 3f6c jmp .L0006 ; ca. 2 cycles -296 --> 0xc070
0xc198: 4f5e c6b3 mov.b 0xc6b3(R15), R14 ; ca. 3 cycles
0xc19c: 531f inc R15 ; ca. 1 cycle
0xc19e: 4f81 0020 mov R15, 32(SP) ; ca. 4 cycles
0xc1a2: 4e4f mov.b R14, R15 ; ca. 1 cycle
0xc1a4: c312 clrc ; ca. 1 cycle
0xc1a6: 104f rrc.b R15 ; ca. 1 cycle
0xc1a8: c312 clrc ; ca. 1 cycle
0xc1aa: 104f rrc.b R15 ; ca. 1 cycle
0xc1ac: c312 clrc ; ca. 1 cycle
0xc1ae: 104f rrc.b R15 ; ca. 1 cycle
0xc1b0: c312 clrc ; ca. 1 cycle
0xc1b2: 104f rrc.b R15 ; ca. 1 cycle
0xc1b4: f03f 000f and #0x000f, R15 ; ca. 2 cycles
0xc1b8: 5f0f rla R15 ; ca. 1 cycle
0xc1ba: 510f add SP, R15 ; ca. 1 cycle
0xc1bc: f03e 000f and #0x000f, R14 ; ca. 2 cycles
0xc1c0: 5e0e rla R14 ; ca. 1 cycle
0xc1c2: 510e add SP, R14 ; ca. 1 cycle
0xc1c4: 5eaf 0000 add @R14, 0(R15) ; ca. 4 cycles
0xc1c8: 3f53 jmp .L0006 ; ca. 2 cycles -346 --> 0xc070
0xc1ca: 4f5e c6b3 mov.b 0xc6b3(R15), R14 ; ca. 3 cycles
0xc1ce: 531f inc R15 ; ca. 1 cycle
0xc1d0: 4f81 0020 mov R15, 32(SP) ; ca. 4 cycles
0xc1d4: 4e4f mov.b R14, R15 ; ca. 1 cycle
0xc1d6: c312 clrc ; ca. 1 cycle
0xc1d8: 104f rrc.b R15 ; ca. 1 cycle
0xc1da: c312 clrc ; ca. 1 cycle
0xc1dc: 104f rrc.b R15 ; ca. 1 cycle
0xc1de: c312 clrc ; ca. 1 cycle
0xc1e0: 104f rrc.b R15 ; ca. 1 cycle
0xc1e2: c312 clrc ; ca. 1 cycle
0xc1e4: 104f rrc.b R15 ; ca. 1 cycle
0xc1e6: f03f 000f and #0x000f, R15 ; ca. 2 cycles
0xc1ea: 5f0f rla R15 ; ca. 1 cycle
0xc1ec: 510f add SP, R15 ; ca. 1 cycle
0xc1ee: f03e 000f and #0x000f, R14 ; ca. 2 cycles
0xc1f2: 5e0e rla R14 ; ca. 1 cycle
0xc1f4: 510e add SP, R14 ; ca. 1 cycle
0xc1f6: 8eaf 0000 sub @R14, 0(R15) ; ca. 4 cycles
0xc1fa: 3f3a jmp .L0006 ; ca. 2 cycles -396 --> 0xc070
0xc1fc: 4f5e c6b3 mov.b 0xc6b3(R15), R14 ; ca. 3 cycles
0xc200: 531f inc R15 ; ca. 1 cycle
0xc202: 4f81 0020 mov R15, 32(SP) ; ca. 4 cycles
0xc206: 4e4f mov.b R14, R15 ; ca. 1 cycle
0xc208: c312 clrc ; ca. 1 cycle
0xc20a: 104f rrc.b R15 ; ca. 1 cycle
0xc20c: c312 clrc ; ca. 1 cycle
0xc20e: 104f rrc.b R15 ; ca. 1 cycle
0xc210: c312 clrc ; ca. 1 cycle
0xc212: 104f rrc.b R15 ; ca. 1 cycle
0xc214: c312 clrc ; ca. 1 cycle
0xc216: 104f rrc.b R15 ; ca. 1 cycle
0xc218: f03f 000f and #0x000f, R15 ; ca. 2 cycles
0xc21c: 5f0f rla R15 ; ca. 1 cycle
0xc21e: 510f add SP, R15 ; ca. 1 cycle
0xc220: f03e 000f and #0x000f, R14 ; ca. 2 cycles
0xc224: 5e0e rla R14 ; ca. 1 cycle
0xc226: 510e add SP, R14 ; ca. 1 cycle
0xc228: 435d mov.b #1, R13 ; ca. 1 cycle
0xc22a: 9eaf 0000 cmp @R14, 0(R15) ; ca. 4 cycles
0xc22e: 2401 jz .L0007 ; ca. 2 cycles +2 --> 0xc232
0xc230: 434d clr.b R13 ; ca. 1 cycle
0xc232: 4dc1 0022 .L0007: mov.b R13, 34(SP) ; ca. 4 cycles
0xc236: 3f1c jmp .L0006 ; ca. 2 cycles -456 --> 0xc070
0xc238: 4f0e mov R15, R14 ; ca. 1 cycle
0xc23a: 531e inc R14 ; ca. 1 cycle
0xc23c: 4f5f c6b3 mov.b 0xc6b3(R15), R15 ; ca. 3 cycles
0xc240: 118f sxt R15 ; ca. 1 cycle
0xc242: 5f0e add R15, R14 ; ca. 1 cycle
0xc244: 4e81 0020 mov R14, 32(SP) ; ca. 4 cycles
0xc248: 3f13 jmp .L0006 ; ca. 2 cycles -474 --> 0xc070
0xc24a: 4f5e c6b3 mov.b 0xc6b3(R15), R14 ; ca. 3 cycles
0xc24e: 531f inc R15 ; ca. 1 cycle
0xc250: 4f81 0020 mov R15, 32(SP) ; ca. 4 cycles
0xc254: 93c1 0022 tst.b 34(SP) ; ca. 4 cycles
0xc258: 270b jz .L0006 ; ca. 2 cycles -490 --> 0xc070
0xc25a: 118e sxt R14 ; ca. 1 cycle
0xc25c: 5f0e add R15, R14 ; ca. 1 cycle
0xc25e: 4e81 0020 mov R14, 32(SP) ; ca. 4 cycles
0xc262: 3f06 jmp .L0006 ; ca. 2 cycles -500 --> 0xc070
0xc264: 4f5e c6b3 mov.b 0xc6b3(R15), R14 ; ca. 3 cycles
0xc268: 531f inc R15 ; ca. 1 cycle
0xc26a: 4f81 0020 mov R15, 32(SP) ; ca. 4 cycles
0xc26e: 93c1 0022 tst.b 34(SP) ; ca. 4 cycles
0xc272: 2402 jz .L0008 ; ca. 2 cycles +4 --> 0xc278
0xc274: 4030 c070 br #0xc070 ; ca. 3 cycles
0xc278: 118e .L0008: sxt R14 ; ca. 1 cycle
0xc27a: 5f0e add R15, R14 ; ca. 1 cycle
0xc27c: 4e81 0020 mov R14, 32(SP) ; ca. 4 cycles
0xc280: 4030 c070 br #0xc070 ; ca. 3 cycles
0xc284: 4f5e c6b3 mov.b 0xc6b3(R15), R14 ; ca. 3 cycles
0xc288: 531f inc R15 ; ca. 1 cycle
0xc28a: 4f81 0020 mov R15, 32(SP) ; ca. 4 cycles
0xc28e: 410f mov SP, R15 ; ca. 1 cycle
0xc290: 12b0 c452 call .L0009 ; ca. 5 cycles --> 0xc452
0xc294: 4030 c070 br #0xc070 ; ca. 3 cycles
0xc298: 4f5e c6b3 mov.b 0xc6b3(R15), R14 ; ca. 3 cycles
0xc29c: 531f inc R15 ; ca. 1 cycle
0xc29e: 4f81 0020 mov R15, 32(SP) ; ca. 4 cycles
0xc2a2: 4e4f mov.b R14, R15 ; ca. 1 cycle
0xc2a4: c312 clrc ; ca. 1 cycle
0xc2a6: 104f rrc.b R15 ; ca. 1 cycle
0xc2a8: c312 clrc ; ca. 1 cycle
0xc2aa: 104f rrc.b R15 ; ca. 1 cycle
0xc2ac: c312 clrc ; ca. 1 cycle
0xc2ae: 104f rrc.b R15 ; ca. 1 cycle
0xc2b0: c312 clrc ; ca. 1 cycle
0xc2b2: 104f rrc.b R15 ; ca. 1 cycle
0xc2b4: f03f 000f and #0x000f, R15 ; ca. 2 cycles
0xc2b8: 5f0f rla R15 ; ca. 1 cycle
0xc2ba: 510f add SP, R15 ; ca. 1 cycle
0xc2bc: f03e 000f and #0x000f, R14 ; ca. 2 cycles
0xc2c0: 5e0e rla R14 ; ca. 1 cycle
0xc2c2: 510e add SP, R14 ; ca. 1 cycle
0xc2c4: 4e2e mov @R14, R14 ; ca. 1 cycle
0xc2c6: 4eef 0000 mov.b @R14, 0(R15) ; ca. 4 cycles
0xc2ca: 43cf 0001 clr.b 1(R15) ; ca. 4 cycles
0xc2ce: 4030 c070 br #0xc070 ; ca. 3 cycles
0xc2d2: 4f5d c6b3 mov.b 0xc6b3(R15), R13 ; ca. 3 cycles
0xc2d6: 531f inc R15 ; ca. 1 cycle
0xc2d8: 4f81 0020 mov R15, 32(SP) ; ca. 4 cycles
0xc2dc: 4d0e mov R13, R14 ; ca. 1 cycle
0xc2de: f03e 000f and #0x000f, R14 ; ca. 2 cycles
0xc2e2: 5e0e rla R14 ; ca. 1 cycle
0xc2e4: 510e add SP, R14 ; ca. 1 cycle
0xc2e6: 4e2e mov @R14, R14 ; ca. 1 cycle
0xc2e8: 4d4f mov.b R13, R15 ; ca. 1 cycle
0xc2ea: c312 clrc ; ca. 1 cycle
0xc2ec: 104f rrc.b R15 ; ca. 1 cycle
0xc2ee: c312 clrc ; ca. 1 cycle
0xc2f0: 104f rrc.b R15 ; ca. 1 cycle
0xc2f2: c312 clrc ; ca. 1 cycle
0xc2f4: 104f rrc.b R15 ; ca. 1 cycle
0xc2f6: c312 clrc ; ca. 1 cycle
0xc2f8: 104f rrc.b R15 ; ca. 1 cycle
0xc2fa: f03f 000f .L0025: and #0x000f, R15 ; ca. 2 cycles
0xc2fe: 5f0f rla R15 ; ca. 1 cycle
0xc300: 510f add SP, R15 ; ca. 1 cycle
0xc302: 4fee 0000 mov.b @R15, 0(R14) ; ca. 4 cycles
0xc306: 4030 c070 .L0030: br #0xc070 ; ca. 3 cycles
0xc30a: 4f5e c6b3 mov.b 0xc6b3(R15), R14 ; ca. 3 cycles
0xc30e: 531f inc R15 ; ca. 1 cycle
0xc310: 4f81 0020 mov R15, 32(SP) ; ca. 4 cycles
0xc314: 4e4f mov.b R14, R15 ; ca. 1 cycle
0xc316: c312 clrc ; ca. 1 cycle
0xc318: 104f rrc.b R15 ; ca. 1 cycle
0xc31a: c312 clrc ; ca. 1 cycle
0xc31c: 104f rrc.b R15 ; ca. 1 cycle
0xc31e: c312 clrc ; ca. 1 cycle
0xc320: 104f rrc.b R15 ; ca. 1 cycle
0xc322: c312 clrc ; ca. 1 cycle
0xc324: 104f rrc.b R15 ; ca. 1 cycle
0xc326: f03f 000f and #0x000f, R15 ; ca. 2 cycles
0xc32a: 5f0f rla R15 ; ca. 1 cycle
0xc32c: 510f add SP, R15 ; ca. 1 cycle
0xc32e: 4f2e mov @R15, R14 ; ca. 1 cycle
0xc330: 531e inc R14 ; ca. 1 cycle
0xc332: 4e8f 0000 mov R14, 0(R15) ; ca. 4 cycles
0xc336: 435f mov.b #1, R15 ; ca. 1 cycle
0xc338: 2401 jz .L0010 ; ca. 2 cycles +2 --> 0xc33c
0xc33a: 434f clr.b R15 ; ca. 1 cycle
0xc33c: 4fc1 0022 .L0010: mov.b R15, 34(SP) ; ca. 4 cycles
0xc340: 4030 c070 br #0xc070 ; ca. 3 cycles
0xc344: 4f5e c6b3 mov.b 0xc6b3(R15), R14 ; ca. 3 cycles
0xc348: 531f inc R15 ; ca. 1 cycle
0xc34a: 4f81 0020 mov R15, 32(SP) ; ca. 4 cycles
0xc34e: 4e4f mov.b R14, R15 ; ca. 1 cycle
0xc350: c312 clrc ; ca. 1 cycle
0xc352: 104f rrc.b R15 ; ca. 1 cycle
0xc354: c312 clrc ; ca. 1 cycle
0xc356: 104f rrc.b R15 ; ca. 1 cycle
0xc358: c312 clrc ; ca. 1 cycle
0xc35a: 104f rrc.b R15 ; ca. 1 cycle
0xc35c: c312 clrc ; ca. 1 cycle
0xc35e: 104f rrc.b R15 ; ca. 1 cycle
0xc360: f03f 000f and #0x000f, R15 ; ca. 2 cycles
0xc364: 5f0f rla R15 ; ca. 1 cycle
0xc366: 510f add SP, R15 ; ca. 1 cycle
0xc368: 4f2e mov @R15, R14 ; ca. 1 cycle
0xc36a: 533e add #0xffff, R14 ; ca. 1 cycle
0xc36c: 4e8f 0000 mov R14, 0(R15) ; ca. 4 cycles
0xc370: 435f mov.b #1, R15 ; ca. 1 cycle
0xc372: 2401 jz .L0011 ; ca. 2 cycles +2 --> 0xc376
0xc374: 434f clr.b R15 ; ca. 1 cycle
0xc376: 4fc1 0022 .L0011: mov.b R15, 34(SP) ; ca. 4 cycles
0xc37a: 4030 c070 br #0xc070 ; ca. 3 cycles
0xc37e: 4f5e c6b3 mov.b 0xc6b3(R15), R14 ; ca. 3 cycles
0xc382: 531f inc R15 ; ca. 1 cycle
0xc384: 4f81 0020 mov R15, 32(SP) ; ca. 4 cycles
0xc388: 4e4f mov.b R14, R15 ; ca. 1 cycle
0xc38a: c312 clrc ; ca. 1 cycle
0xc38c: 104f rrc.b R15 ; ca. 1 cycle
0xc38e: c312 clrc ; ca. 1 cycle
0xc390: 104f rrc.b R15 ; ca. 1 cycle
0xc392: c312 clrc ; ca. 1 cycle
0xc394: 104f rrc.b R15 ; ca. 1 cycle
0xc396: c312 clrc ; ca. 1 cycle
0xc398: 104f rrc.b R15 ; ca. 1 cycle
0xc39a: f03f 000f and #0x000f, R15 ; ca. 2 cycles
0xc39e: 5f0f rla R15 ; ca. 1 cycle
0xc3a0: 510f add SP, R15 ; ca. 1 cycle
0xc3a2: f03e 000f and #0x000f, R14 ; ca. 2 cycles
0xc3a6: 5e0e rla R14 ; ca. 1 cycle
0xc3a8: 510e add SP, R14 ; ca. 1 cycle
0xc3aa: feaf 0000 and @R14, 0(R15) ; ca. 4 cycles
0xc3ae: 4030 c070 br #0xc070 ; ca. 3 cycles
0xc3b2: 4f5e c6b3 mov.b 0xc6b3(R15), R14 ; ca. 3 cycles
0xc3b6: 531f inc R15 ; ca. 1 cycle
0xc3b8: 4f81 0020 mov R15, 32(SP) ; ca. 4 cycles
0xc3bc: 4e4f mov.b R14, R15 ; ca. 1 cycle
0xc3be: c312 clrc ; ca. 1 cycle
0xc3c0: 104f rrc.b R15 ; ca. 1 cycle
0xc3c2: c312 clrc ; ca. 1 cycle
0xc3c4: 104f rrc.b R15 ; ca. 1 cycle
0xc3c6: c312 clrc ; ca. 1 cycle
0xc3c8: 104f rrc.b R15 ; ca. 1 cycle
0xc3ca: c312 clrc ; ca. 1 cycle
0xc3cc: 104f rrc.b R15 ; ca. 1 cycle
0xc3ce: f03f 000f and #0x000f, R15 ; ca. 2 cycles
0xc3d2: 5f0f rla R15 ; ca. 1 cycle
0xc3d4: 510f add SP, R15 ; ca. 1 cycle
0xc3d6: f03e 000f and #0x000f, R14 ; ca. 2 cycles
0xc3da: 5e0e rla R14 ; ca. 1 cycle
0xc3dc: 510e add SP, R14 ; ca. 1 cycle
0xc3de: deaf 0000 bis @R14, 0(R15) ; ca. 4 cycles
0xc3e2: 4030 c070 br #0xc070 ; ca. 3 cycles
0xc3e6: 4f0d mov R15, R13 ; ca. 1 cycle
0xc3e8: 503d c6b3 add #0xc6b3, R13 ; ca. 2 cycles
0xc3ec: 4d7e mov.b @R13+, R14 ; ca. 1 cycle
0xc3ee: c312 clrc ; ca. 1 cycle
0xc3f0: 104e rrc.b R14 ; ca. 1 cycle
0xc3f2: c312 clrc ; ca. 1 cycle
0xc3f4: 104e rrc.b R14 ; ca. 1 cycle
0xc3f6: c312 clrc ; ca. 1 cycle
0xc3f8: 104e rrc.b R14 ; ca. 1 cycle
0xc3fa: c312 clrc ; ca. 1 cycle
0xc3fc: 104e rrc.b R14 ; ca. 1 cycle
0xc3fe: f03e 000f and #0x000f, R14 ; ca. 2 cycles
0xc402: 5e0e rla R14 ; ca. 1 cycle
0xc404: 510e add SP, R14 ; ca. 1 cycle
0xc406: 4d6d mov.b @R13, R13 ; ca. 1 cycle
0xc408: 5d8e 0000 add R13, 0(R14) ; ca. 4 cycles
0xc40c: 532f incd R15 ; ca. 1 cycle
0xc40e: 4f81 0020 mov R15, 32(SP) ; ca. 4 cycles
0xc412: 4030 c070 br #0xc070 ; ca. 3 cycles
0xc416: 4f0d mov R15, R13 ; ca. 1 cycle
0xc418: 503d c6b3 add #0xc6b3, R13 ; ca. 2 cycles
0xc41c: 4d7e mov.b @R13+, R14 ; ca. 1 cycle
0xc41e: c312 clrc ; ca. 1 cycle
0xc420: 104e rrc.b R14 ; ca. 1 cycle
0xc422: c312 clrc ; ca. 1 cycle
0xc424: 104e rrc.b R14 ; ca. 1 cycle
0xc426: c312 clrc ; ca. 1 cycle
0xc428: 104e rrc.b R14 ; ca. 1 cycle
0xc42a: c312 clrc ; ca. 1 cycle
0xc42c: 104e rrc.b R14 ; ca. 1 cycle
0xc42e: f03e 000f and #0x000f, R14 ; ca. 2 cycles
0xc432: 5e0e rla R14 ; ca. 1 cycle
0xc434: 510e add SP, R14 ; ca. 1 cycle
0xc436: 4d6d mov.b @R13, R13 ; ca. 1 cycle
0xc438: 8d8e 0000 sub R13, 0(R14) ; ca. 4 cycles
0xc43c: 532f incd R15 ; ca. 1 cycle
0xc43e: 4f81 0020 mov R15, 32(SP) ; ca. 4 cycles
0xc442: 4030 c070 br #0xc070 ; ca. 3 cycles
0xc446: 3fff .L0012: jmp .L0012 ; ca. 2 cycles -2 --> 0xc446
经过分析,可以发现该汇编实现一个VM,接着提取内层的汇编:
; inner bytecode @ ROM 0xC6B3
; preinitialized virtual registers:
; const_ptr = 0xC64A
; input_ptr = 0x026A
; work_ptr = 0x0200
; loop_bound = 0x000D
loc_0000:
0000 04 E8 mov tmp_ptr, const_ptr
0002 01 0E ldw v0, [tmp_ptr]
0004 14 E0 02 addi tmp_ptr, 2
0007 01 1E ldw v1, [tmp_ptr]
0009 14 E0 02 addi tmp_ptr, 2
000C 01 2E ldw v2, [tmp_ptr]
000E 14 E0 02 addi tmp_ptr, 2
0011 01 3E ldw v3, [tmp_ptr]
0013 04 E9 mov tmp_ptr, input_ptr
0015 01 5E ldw v5, [tmp_ptr]
0017 14 E0 02 addi tmp_ptr, 2
001A 01 4E ldw v4, [tmp_ptr]
001C 14 E0 02 addi tmp_ptr, 2
001F 01 7E ldw v7, [tmp_ptr]
0021 14 E0 02 addi tmp_ptr, 2
0024 01 6E ldw v6, [tmp_ptr]
0026 0C 00 helper helper_rrcm1
0028 0C 01 helper helper_rram1
002A 0C 02 helper helper_rlam1
002C 0C 03 helper helper_rrum1
002E 09 0C jmp loc_003C ; signed rel8 +12
loc_003C:
003C 04 EA mov tmp_ptr, work_ptr
003E 02 0E stw [tmp_ptr], v0
0040 14 E0 02 addi tmp_ptr, 2
0043 02 1E stw [tmp_ptr], v1
0045 14 E0 02 addi tmp_ptr, 2
0048 02 2E stw [tmp_ptr], v2
004A 14 E0 02 addi tmp_ptr, 2
004D 02 3E stw [tmp_ptr], v3
004F 04 E8 mov tmp_ptr, const_ptr
0051 04 FA mov tmp_work, work_ptr
0053 03 00 04 00 movi v0, 0x0004
loc_0057:
0057 01 1E ldw v1, [tmp_ptr]
0059 01 2F ldw v2, [tmp_work]
005B 08 12 cmpeq v1, v2 ; sets the VM flag byte to 1 iff equal
005D 0B 0C jfalse loc_006B ; branch if VM flag byte == 0, rel8 +12
loc_005F:
005F 14 E0 02 addi tmp_ptr, 2
0062 14 F0 02 addi tmp_work, 2
0065 11 00 dec v0 ; updates the VM flag byte with zero(result)
0067 0B EE jfalse loc_0057 ; branch if VM flag byte == 0, rel8 -18
loc_0069:
0069 10 B0 inc vB ; updates the VM flag byte with zero(result)
loc_006B:
006B 14 80 08 addi const_ptr, 8
006E 14 90 08 addi input_ptr, 8
0071 14 A0 08 addi work_ptr, 8
0074 10 C0 inc vC ; updates the VM flag byte with zero(result)
0076 08 CD cmpeq vC, loop_bound ; sets the VM flag byte to 1 iff equal
0078 0B 86 jfalse loc_0000 ; branch if VM flag byte == 0, rel8 -122
loc_007A:
007A 08 BD cmpeq vB, loop_bound ; sets the VM flag byte to 1 iff equal
007C 0B 06 jfalse loc_0084 ; branch if VM flag byte == 0, rel8 +6
loc_007E:
007E 03 00 37 13 movi v0, 0x1337
0082 09 02 jmp loc_0086 ; signed rel8 +2
loc_0084:
0084 04 0B mov v0, vB
loc_0086:
0086 03 E0 68 02 movi tmp_ptr, 0x0268
008A 02 0E stw [tmp_ptr], v0
008C 00 halt ; interpreter would fall into the invalid-op trap
这里可以看到很简单的运算后然后比较,但是稍微发现就会发现运算的古怪之处,如果扩展指令合法的话,压根就没有使用到全部的输入这非常不合理。
并且rrcm这种指令是在msp40X(20位)上支持,本题的msp40(16位)是不支持的。
题目肯定存在处理这些扩展指令的逻辑
eavl函数分析
vatbale[3]就是eavl函数,总体有2000多行,丢给AI,可以分析出其有Fistel、sbox、列混合等操作。
但是我的AI分析的轮数错误了,导致我调试纠错花费了很多时间。
而且也不要直接调试eval函数,这个函数会一直跑,如果下断点会有很多噪声(经验之谈)
gdb脚本探测内存
可以看内存汇编,一开始操作栈帧:sp-0x24,后面mov #imm, imm(sp),这里可以看到这是对内存虚拟寄存器开辟空间,0x24=36正好是18个16位寄存器的大小。
但是在宿主机上调试实际上的地址是 sp - 0x24 * 2 , 并且16位寄存器实际占用4个字节,这个差异化实现还是挺坑的,不过写脚本验证可以纠正。
set pagination off
set confirm off
set debuginfod enabled off
file /mnt/h/CTF/CODEGATE2026/Silicon\ Dream/hand/challenge
set args 6161616162616161636161616461616165616161666161616761616168616161696161616a6161616b6161616c6161616d6161616e6161616f616161706161617161616172616161736161617461616175616161766161617761616178616161796161617a616162
b *0x40A4B8
run
set $vm = $rsp + 0x80
set $ram = *(void**)($vm+0x468)
set $stack = $ram+0x3b8
set $slot = $ram+0x3c4
set $slot_hits = 0
printf "vmctx=%p ram=%p stack=%p slot=%p\n", $vm, $ram, $stack, $slot
watch *(unsigned int*)$slot
commands
silent
set $slot_hits = $slot_hits + 1
printf "[slot-hit #%u] rip=%p\n", $slot_hits, $pc
printf "[before-patch]\n"
x/8wx $stack
set *(unsigned int*)($stack+0x0) = 0x00003939
set *(unsigned int*)($stack+0x4) = 0x00006c20
set *(unsigned int*)($stack+0x8) = 0x00007469
set *(unsigned int*)($stack+0xc) = 0x00006c74
printf "[after-patch]\n"
x/8wx $stack
continue
end
continue
查看 R0-3, R4-7的内容真相大白
加密分析
题目使用的经典fistel网络,只不过F是由sbox + mixColumns实现

这道题目很巧的是最后密文,在加密一开始就参与了加密,实际上就是要计算:
现在的未知量恰恰是 U_L/U_R 本身,所以你面对的是:
- 一个带未知轮注入量的固定点方程
当前 4 轮模型是:
B1 = A0 ^ F(B0 ^ U_L ^ k1)B2 = B0 ^ F(B1 ^ U_R ^ k2)B3 = B1 ^ F(B2 ^ U_L ^ k3)B4 = B2 ^ F(B3 ^ U_R ^ k4)
固定点条件是:
B3 = A0B4 = B0
将条件带入可得
b1 = a0 ^ k2 ^ k4
b2 = b0 ^ k1 ^ k3
题目用的sbox正好是自反置换,也就是说INV_SBOX == SBOX
那么只要实现F_INV(),就能反推出U_L, U_R最终拿到flag
求解
AI直接写出求解脚本
from __future__ import annotations
import argparse
import re
import subprocess
from dataclasses import dataclass
from pathlib import Path
HAND = Path(r"H:\CTF\CODEGATE2026\Silicon Dream\hand")
TMP_GDB = HAND / "_tmp_exp_forward_verify.gdb"
CHALLENGE_WSL = "/mnt/h/CTF/CODEGATE2026/Silicon Dream/hand/challenge"
GDB_WSL = "/mnt/h/CTF/CODEGATE2026/Silicon Dream/hand/_tmp_exp_forward_verify.gdb"
ROUND_KEYS = [
0xE4AFC9DF,
0xAF10C5B5,
0x4361F2A6,
0xDB948BBC,
]
TARGET_HEX = (
"3939206c6974746c65206275677320696e2074686520636f64652c203939206c69"
"74746c6520627567732e2054616b65206f6e6520646f776e2c2070617463682069"
"742061726f756e642c20313237206c6974746c65206275677320696e2074686520"
"636f64652e"
)
TARGET_DATA = bytes.fromhex(TARGET_HEX)
DEFAULT_PAYLOAD_HEX = 'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaab'.encode().hex()
CUSTOM_SBOX = [
0x00, 0x10, 0xB1, 0xD1, 0x91, 0xE1, 0x60, 0x70, 0xC7, 0x57, 0x86, 0x36, 0xF6, 0x26, 0x47, 0xA7,
0x01, 0x11, 0xCC, 0xAA, 0xFF, 0x88, 0x61, 0x71, 0x40, 0xDA, 0x20, 0x9F, 0x30, 0xE8, 0xBC, 0x50,
0x1A, 0xA2, 0x7E, 0xEC, 0x83, 0x68, 0x0D, 0xDE, 0xF9, 0x97, 0x3C, 0x2B, 0x59, 0x4F, 0xCA, 0xB7,
0x1C, 0xC3, 0x9A, 0x79, 0x6F, 0xF2, 0x0B, 0xB9, 0xD7, 0xAC, 0x4E, 0x58, 0x2A, 0x3D, 0xE7, 0x8E,
0x18, 0x84, 0x7C, 0xC5, 0x6B, 0xBF, 0xEB, 0x0E, 0x5F, 0x49, 0x96, 0xF8, 0xAD, 0xD6, 0x3A, 0x2D,
0x1F, 0xF5, 0xA4, 0x7A, 0xD8, 0x6D, 0x9D, 0x09, 0x3B, 0x2C, 0xCB, 0xB6, 0xE6, 0x8F, 0x5E, 0x48,
0x06, 0x16, 0xFE, 0x89, 0xD0, 0xB0, 0x66, 0x76, 0x25, 0xC0, 0x99, 0x44, 0xEE, 0x55, 0xA0, 0x34,
0x07, 0x17, 0x90, 0xE0, 0xAB, 0xCD, 0x67, 0x77, 0xDD, 0x33, 0x53, 0x80, 0x42, 0xF0, 0x22, 0xBB,
0x7B, 0xA5, 0xC1, 0x24, 0x41, 0xDB, 0x0A, 0xB8, 0x15, 0x63, 0xE2, 0xFD, 0x8C, 0x94, 0x3F, 0x5D,
0x72, 0x04, 0xE3, 0xFC, 0x8D, 0x95, 0x4A, 0x29, 0xBE, 0x6A, 0x32, 0xDC, 0xC6, 0x56, 0xA3, 0x1B,
0x6E, 0xF3, 0x21, 0x9E, 0x52, 0x81, 0xEA, 0x0F, 0xA8, 0xB2, 0x13, 0x74, 0x39, 0x4C, 0xC9, 0xD5,
0x65, 0x02, 0xA9, 0xB3, 0xC8, 0xD4, 0x5B, 0x2F, 0x87, 0x37, 0xED, 0x7F, 0x1E, 0xF4, 0x98, 0x45,
0x69, 0x82, 0xE9, 0x31, 0xF1, 0x43, 0x9C, 0x08, 0xB4, 0xAE, 0x2E, 0x5A, 0x12, 0x75, 0xD3, 0xCF,
0x64, 0x03, 0xD2, 0xCE, 0xB5, 0xAF, 0x4D, 0x38, 0x54, 0xEF, 0x19, 0x85, 0x9B, 0x78, 0x27, 0xF7,
0x73, 0x05, 0x8A, 0x92, 0xE4, 0xFB, 0x5C, 0x3E, 0x1D, 0xC2, 0xA6, 0x46, 0x23, 0xBA, 0x6C, 0xD9,
0x7D, 0xC4, 0x35, 0xA1, 0xBD, 0x51, 0x0C, 0xDF, 0x4B, 0x28, 0xFA, 0xE5, 0x93, 0x8B, 0x62, 0x14,
]
assert len(CUSTOM_SBOX) == 256 and len(set(CUSTOM_SBOX)) == 256
INV_SBOX = [0] * 256
for _idx, _value in enumerate(CUSTOM_SBOX):
INV_SBOX[_value] = _idx
assert INV_SBOX == CUSTOM_SBOX
@dataclass(frozen=True)
class RoundTrace:
block_idx: int
round_idx: int
round_key: int
user_half: int
acc_l_in: int
acc_r_in: int
x: int
fx: int
acc_l_out: int
acc_r_out: int
def xtime(value: int) -> int:
value &= 0xFF
if value & 0x80:
return ((value << 1) ^ 0x1B) & 0xFF
return (value << 1) & 0xFF
def gf_mul(a: int, b: int) -> int:
a &= 0xFF
b &= 0xFF
out = 0
cur = a
mask = b
while mask:
if mask & 1:
out ^= cur
cur = xtime(cur)
mask >>= 1
return out & 0xFF
def f_function(word32: int) -> int:
b0 = CUSTOM_SBOX[(word32 >> 0) & 0xFF]
b1 = CUSTOM_SBOX[(word32 >> 8) & 0xFF]
b2 = CUSTOM_SBOX[(word32 >> 16) & 0xFF]
b3 = CUSTOM_SBOX[(word32 >> 24) & 0xFF]
t = b0 ^ b1 ^ b2 ^ b3
o0 = b0 ^ t ^ xtime(b0 ^ b1)
o1 = b1 ^ t ^ xtime(b1 ^ b2)
o2 = b2 ^ t ^ xtime(b2 ^ b3)
o3 = b3 ^ t ^ xtime(b3 ^ b0)
# Dynamic tracing shows the hardware rotates the 4-byte MixColumns output by one byte
# before packing it back into a 32-bit word.
return o1 | (o2 << 8) | (o3 << 16) | (o0 << 24)
def f_inv(word32: int) -> int:
p0 = (word32 >> 0) & 0xFF
p1 = (word32 >> 8) & 0xFF
p2 = (word32 >> 16) & 0xFF
p3 = (word32 >> 24) & 0xFF
# Undo the one-byte rotate used when packing the MixColumns result.
o0, o1, o2, o3 = p3, p0, p1, p2
s0 = gf_mul(o0, 0x0E) ^ gf_mul(o1, 0x0B) ^ gf_mul(o2, 0x0D) ^ gf_mul(o3, 0x09)
s1 = gf_mul(o0, 0x09) ^ gf_mul(o1, 0x0E) ^ gf_mul(o2, 0x0B) ^ gf_mul(o3, 0x0D)
s2 = gf_mul(o0, 0x0D) ^ gf_mul(o1, 0x09) ^ gf_mul(o2, 0x0E) ^ gf_mul(o3, 0x0B)
s3 = gf_mul(o0, 0x0B) ^ gf_mul(o1, 0x0D) ^ gf_mul(o2, 0x09) ^ gf_mul(o3, 0x0E)
x0 = INV_SBOX[s0]
x1 = INV_SBOX[s1]
x2 = INV_SBOX[s2]
x3 = INV_SBOX[s3]
return x0 | (x1 << 8) | (x2 << 16) | (x3 << 24)
def solve_block_via_midstate(target_block: bytes) -> bytes:
if len(target_block) != 8:
raise ValueError("target_block must be exactly 8 bytes")
k1, k2, k3, k4 = ROUND_KEYS
a0 = int.from_bytes(target_block[:4], "little")
b0 = int.from_bytes(target_block[4:], "little")
# Fixed-point equations after 4 rounds:
# B3 = A0
# B4 = B0
# with
# B1 = A0 ^ k2 ^ k4
# B2 = B0 ^ k1 ^ k3
b1 = a0 ^ k2 ^ k4
b2 = b0 ^ k1 ^ k3
# Recover the two user halves directly through F^{-1}.
u_l = f_inv(a0 ^ b1) ^ b0 ^ k1
u_r = f_inv(b0 ^ b2) ^ a0 ^ k4
return u_l.to_bytes(4, "little") + u_r.to_bytes(4, "little")
def solve_payload_via_midstate(target_data: bytes) -> bytes:
if len(target_data) % 8 != 0:
raise ValueError("target_data length must be a multiple of 8 bytes")
out = bytearray()
for off in range(0, len(target_data), 8):
out.extend(solve_block_via_midstate(target_data[off : off + 8]))
return bytes(out)
def encrypt_block_from_exp(
block0: bytes, target_block: bytes, *, block_idx: int = 0
) -> tuple[bytes, list[RoundTrace]]:
if len(block0) != 8:
raise ValueError("block0 must be exactly 8 bytes")
if len(target_block) != 8:
raise ValueError("target_block must be exactly 8 bytes")
user_l, user_r = int.from_bytes(block0[:4], "little"), int.from_bytes(block0[4:], "little")
acc_l = int.from_bytes(target_block[:4], "little")
acc_r = int.from_bytes(target_block[4:], "little")
traces: list[RoundTrace] = []
for round_idx, round_key in enumerate(ROUND_KEYS):
acc_l_in, acc_r_in = acc_l, acc_r
user_half = user_l if (round_idx % 2 == 0) else user_r
x = (acc_r ^ user_half ^ round_key) & 0xFFFFFFFF
fx = f_function(x)
next_acc = (acc_l ^ fx) & 0xFFFFFFFF
acc_l, acc_r = acc_r, next_acc
traces.append(
RoundTrace(
block_idx=block_idx,
round_idx=round_idx + 1,
round_key=round_key,
user_half=user_half,
acc_l_in=acc_l_in,
acc_r_in=acc_r_in,
x=x,
fx=fx,
acc_l_out=acc_l,
acc_r_out=acc_r,
)
)
return acc_l.to_bytes(4, "little") + acc_r.to_bytes(4, "little"), traces
def encrypt_payload_from_exp(payload: bytes, target_data: bytes) -> tuple[bytes, list[RoundTrace]]:
if len(payload) != len(target_data):
raise ValueError("payload and target_data must have the same length")
if len(payload) % 8 != 0:
raise ValueError("payload length must be a multiple of 8 bytes")
out = bytearray()
traces: list[RoundTrace] = []
for block_idx, off in enumerate(range(0, len(payload), 8)):
block = payload[off : off + 8]
target_block = target_data[off : off + 8]
enc_block, block_traces = encrypt_block_from_exp(block, target_block, block_idx=block_idx)
out.extend(enc_block)
traces.extend(block_traces)
return bytes(out), traces
def words_from_block(block8: bytes) -> tuple[int, int, int, int]:
return tuple(int.from_bytes(block8[i : i + 2], "little") for i in range(0, 8, 2))
def fmt_words(words: tuple[int, int, int, int]) -> str:
return "[" + ", ".join(f"0x{word:04X}" for word in words) + "]"
def fmt_block64(block8: bytes) -> str:
words = words_from_block(block8)
return "0x" + "".join(f"{word:04x}" for word in reversed(words))
def fmt_u32(value: int) -> str:
return f"0x{value:08X}"
def normalize_hex(text: str) -> str:
return "".join(ch for ch in text if ch not in " \t\r\n").lower()
def make_gdb_script(payload_hex: str) -> str:
return "\n".join(
[
"set pagination off",
"set confirm off",
"set debuginfod enabled off",
f'file "{CHALLENGE_WSL}"',
f"set args {payload_hex}",
"b *0x40A4B8",
"run",
"set $vm = $rsp + 0x80",
"set $ram = *(void**)($vm+0x468)",
"watch *(unsigned int*)$ram",
"continue",
"x/8wx $ram+0x3b8",
"quit",
"",
]
)
def parse_gdb_words(stdout: str) -> tuple[int, int, int, int]:
for line in stdout.splitlines():
m = re.match(
r"^0x[0-9a-fA-F]+:\s+0x([0-9a-fA-F]+)\s+0x([0-9a-fA-F]+)\s+0x([0-9a-fA-F]+)\s+0x([0-9a-fA-F]+)$",
line.strip(),
)
if not m:
continue
return tuple(int(m.group(i), 16) & 0xFFFF for i in range(1, 5))
raise RuntimeError("failed to parse first-store words from gdb output")
def run_gdb_probe(block0: bytes) -> tuple[int, int, int, int]:
payload = bytearray(104)
payload[:8] = block0
payload_hex = payload.hex()
TMP_GDB.write_text(make_gdb_script(payload_hex), encoding="utf-8", newline="\n")
proc = subprocess.run(
["wsl", "bash", "-lc", f"gdb -nx -q -batch -x '{GDB_WSL}'"],
capture_output=True,
text=True,
encoding="utf-8",
errors="ignore",
check=True,
)
return parse_gdb_words(proc.stdout)
def verify_payload(payload_hex: str, *, do_gdb: bool) -> None:
payload_hex = normalize_hex(payload_hex)
if len(payload_hex) != 208:
raise ValueError("payload must be exactly 104 bytes / 208 hex chars")
payload = bytes.fromhex(payload_hex)
block0 = payload[:8]
target_block = TARGET_DATA[:8]
predicted_data, traces = encrypt_payload_from_exp(payload, TARGET_DATA)
predicted_block = predicted_data[:8]
predicted_words = words_from_block(predicted_block)
print("[payload]")
print(f"input payload : {payload_hex}")
print(f"input block0 : {block0.hex()}")
print(f"target block0 : {target_block.hex()} {fmt_words(words_from_block(target_block))}")
print(f"model block0 : {fmt_block64(predicted_block)} {fmt_words(predicted_words)}")
print(f"model full hex : {predicted_data.hex()}")
print("")
print("[round-trace]")
for trace in traces:
print(
f"b{trace.block_idx:02d}.r{trace.round_idx:02d} "
f"key={fmt_u32(trace.round_key)} "
f"user={fmt_u32(trace.user_half)} "
f"A_in={fmt_u32(trace.acc_l_in)} "
f"B_in={fmt_u32(trace.acc_r_in)} "
f"X={fmt_u32(trace.x)} "
f"F={fmt_u32(trace.fx)} "
f"A_out={fmt_u32(trace.acc_l_out)} "
f"B_out={fmt_u32(trace.acc_r_out)}"
)
if do_gdb:
print("")
gdb_words = run_gdb_probe(block0)
print(f"gdb first-store: {fmt_words(gdb_words)}")
print(f"match-gdb : {predicted_words == gdb_words}")
print("")
def main() -> None:
parser = argparse.ArgumentParser(
description="Forward encryption model derived directly from hand/exp.py, with optional GDB verification."
)
parser.add_argument(
"payload_hex",
nargs="?",
default=DEFAULT_PAYLOAD_HEX,
help="full 104-byte payload as 208 hex chars; default is all 'aa'",
)
parser.add_argument(
"--no-gdb",
action="store_true",
help="skip live GDB verification",
)
args = parser.parse_args()
verify_payload(args.payload_hex, do_gdb=not args.no_gdb)
if __name__ == "__main__":
main()
from z3 import *
import struct
import time
from exp_forward import (
CUSTOM_SBOX,
INV_SBOX,
ROUND_KEYS,
TARGET_DATA,
encrypt_block_from_exp,
solve_block_via_midstate,
)
print("[+] 正在加载硬件密码协处理器的硅片模型...")
# ⚠️ 神级优化:用 O(logN) 的二分树替换低效的 Z3 Array
def sbox_lookup_z3(x):
def build_tree(l, r):
if l == r:
return BitVecVal(CUSTOM_SBOX[l], 8)
mid = (l + r) // 2
# ULT: Unsigned Less Than (无符号小于)
return If(ULT(x, mid + 1), build_tree(l, mid), build_tree(mid + 1, r))
return build_tree(0, 255)
# 4. Z3 下的 MixColumns
def xtime_z3(a):
return If(a & 0x80 != 0, (a << 1) ^ 0x1B, a << 1) & 0xFF
def mix_single_column_z3(s0, s1, s2, s3):
t = s0 ^ s1 ^ s2 ^ s3
u = s0
out0 = s0 ^ t ^ xtime_z3(s0 ^ s1)
out1 = s1 ^ t ^ xtime_z3(s1 ^ s2)
out2 = s2 ^ t ^ xtime_z3(s2 ^ s3)
out3 = s3 ^ t ^ xtime_z3(s3 ^ u)
return out0, out1, out2, out3
def F_function_z3(X_32bit):
# 用优化后的二分树进行查表
b0 = sbox_lookup_z3(Extract(7, 0, X_32bit))
b1 = sbox_lookup_z3(Extract(15, 8, X_32bit))
b2 = sbox_lookup_z3(Extract(23, 16, X_32bit))
b3 = sbox_lookup_z3(Extract(31, 24, X_32bit))
m0, m1, m2, m3 = mix_single_column_z3(b0, b1, b2, b3)
return Concat(m0, m3, m2, m1)
def encrypt_block_z3(U_L, U_R, T_L, T_R):
"""
Mirror hand/exp_forward.py exactly:
- one 8-byte block at a time
- 4 rounds
- user_half alternates U_L/U_R
- A_out = B_in
- B_out = A_in ^ F(B_in ^ user_half ^ round_key)
"""
A = BitVecVal(T_L, 32)
B = BitVecVal(T_R, 32)
for round_idx, r_key in enumerate(ROUND_KEYS):
user_half = U_L if (round_idx % 2 == 0) else U_R
X = B ^ user_half ^ BitVecVal(r_key, 32)
A_next = A ^ F_function_z3(X)
A = B
B = A_next
return A, B
def add_printable_ascii_constraints(solver, word32):
for shift in (0, 8, 16, 24):
byte = Extract(shift + 7, shift, word32)
solver.add(UGE(byte, BitVecVal(0x20, 8)))
solver.add(ULE(byte, BitVecVal(0x7E, 8)))
# ==============================================================
# 分组求解循环
# 先使用 4 轮固定点方程的中间态化简直接恢复 U_L/U_R,
# 再用 forward 模型复核结果。
# ==============================================================
flag_bytes = b""
flag_hex_parts = []
print("[+] 使用中间态化简恢复每组输入,并用 forward 模型复核...\n")
for i in range(0, len(TARGET_DATA), 8):
block = TARGET_DATA[i:i+8]
T_L, T_R = struct.unpack('<II', block)
print(f"[*] 正在撕裂 Block {i//8 + 1}/13 ...")
start_time = time.time()
chunk = solve_block_via_midstate(block)
ul_val, ur_val = struct.unpack("<II", chunk)
out_block, _ = encrypt_block_from_exp(chunk, block, block_idx=i // 8)
if out_block != block:
print(f" [-] forward 复核失败: got={out_block.hex()} expected={block.hex()}")
break
flag_bytes += chunk
flag_hex_parts.append(chunk.hex())
print(
f" [+] 解出: {chunk} "
f"(U_L=0x{ul_val:08X}, U_R=0x{ur_val:08X}; 仅耗时: {time.time() - start_time:.3f} 秒)"
)
print("\n=======================================================")
print("[] 硅之梦核心已被彻底击穿!终极 FLAG: ")
print(flag_bytes.decode('ascii', errors='ignore'))
print("".join(flag_hex_parts))
print("=======================================================")
反思
让ai辅助得时候,自己也要主动思考,不能完全让ai带着走。