Category: Reverse Engineering
Reference: https://github.com/ctfs/write-ups-2017/tree/master/alexctf-2017/reverse-engineering/re2-cpp-is-awesome-100
Download: re2
這題需要解讀一下組合語言,當然用qira或IDA Pro看一下會比較有助於理解,但是最終還是回歸到objdump與gdb。
首先,經由qira或IDA Pro我大概知道程式不是一整段密碼一次比對,而是一個字母一個字母按照順序比對,有錯便會exit。
現在我們來看看關鍵的程式碼所在:
400c66: 8b 04 85 c0 20 60 00 mov 0x6020c0(,%rax,4),%eax
400c6d: 48 98 cltq
400c6f: 48 01 c8 add %rcx,%rax
400c72: 0f b6 00 movzbl (%rax),%eax
400c75: 38 c2 cmp %al,%dl
400c77: 0f 95 c0 setne %al
400c7a: 84 c0 test %al,%al
以上是透過IDA Pro看出來的,現在來gdb調試一下:
$ gdb ./re2
(gdb) break *0x400c75
(gdb) run AAAA
(gdb) info registers
rax 0x41 65 ==========> "A"
rbx 0x0 0
rcx 0x400e58 4197976
rdx 0x41 65 ==========> "A"
......(skip)
(gdb) continue
(gdb) info registers
rax 0x4c 76 ==========> "L"
rbx 0x0 0
rcx 0x400e58 4197976
rdx 0x41 65 ==========> "A"
......(skip)
由此,我們發現
0x400c75: cmp %al,%dl
此程式碼中的al為我們輸入的"AAAA",而dl為程式計算出的正確通關密碼。(al與dl分別為rax與rdx中最低位8位元之部分,註一)
雖然只要一直重複如此操作gdb便可以得到完整flag,但何不直接計算呢?
再者,
0x400c66: mov 0x6020c0(,%rax,4),%eax
0x400c6f: add %rcx,%rax
這兩行顯而易見的就是在做flag的計算
我們現在先來看看0x6020c0與rcx的內容吧:
$ gdb ./re2
(gdb) break *0x400c75
(gdb) run AAAA
(gdb) info registers
rax 0x41 65 ==========> "A"
rbx 0x0 0
rcx 0x400e58 4197976
rdx 0x41 65 ==========> "A"
......(skip)
(gdb) continue
(gdb) info registers
rax 0x4c 76 ==========> "L"
rbx 0x0 0
rcx 0x400e58 4197976
rdx 0x41 65 ==========> "A"
......(skip)
原來rcx裡面放的是一個字串陣列,可惜不是flag,但flag應該是從這裡計算出來的!
現在來看看0x6020c0(data區段):
$ objdump -s -j .data ./re2
......(skip)
6020c0 24000000 00000000 05000000 36000000 $...........6...
6020d0 65000000 07000000 27000000 26000000 e.......'...&...
6020e0 2d000000 01000000 03000000 00000000 -...............
6020f0 0d000000 56000000 01000000 03000000 ....V...........
602100 65000000 03000000 2d000000 16000000 e.......-.......
602110 02000000 15000000 03000000 65000000 ............e...
602120 00000000 29000000 44000000 44000000 ....)...D...D...
602130 01000000 44000000 2b000000 ....D...+...
好,來解釋程序:
0x400c66: mov 0x6020c0(,%rax,4),%eax
首先將0x24放進eax裡。
加法運算:
0x400c6f: add %rcx,%rax
此時:
rcx→
"L3t_ME_T3ll_Y0u_S0m3th1ng_1mp0rtant_A_{FL4G}_W0nt_b3_3X4ctly_th4t_345y_t0_c4ptur3_H0wev3r_1T_w1ll_b3_C00l_1F_Y0u_g0t_1t"
rax→
"A_{FL4G}_W0nt_b3_3X4ctly_th4t_345y_t0_c4ptur3_H0wev3r_1T_w1ll_b3_C00l_1F_Y0u_g0t_1t"
接下來,
0x400c72: movzbl (%rax),%eax
使rax取得值0x41,也就是"A"。
最後,
0x400be7: add $0x8,%rax
迴圈將會往上來會到這裡,rax遞增,依序取得0x00, 0x05, 0x36, 0x65, 0x07, ......
由此可判斷出,我們有個原始陣列
"L3t_ME_T3ll_Y0u_S0m3th1ng_1mp0rtant_A_{FL4G}_W0nt_b3_3X4ctly_th4t_345y_t0_c4ptur3_H0wev3r_1T_w1ll_b3_C00l_1F_Y0u_g0t_1t"
而索引(16進位)就是0x6020c0指向的數字陣列(還各隔8 bits)。
直接算:
01234567890123456789
L3t_ME_T3ll_Y0u_S0m3
th1ng_1mp0rtant_A_{F
L4G}_W0nt_b3_3X4ctly
_th4t_345y_t0_c4ptur
3_H0wev3r_1T_w1ll_b3
_C00l_1F_Y0u_g0t_1t
以下都是16進位,要記得轉成10進位
24 00 05 36 65 07 27 26 2d 01 03 00 0d 56 01 03 65 03 2d 16 02 15 03 65 00 29 44 44 01 44 2b
A L E X C T F { W 3 _ L 0 v 3 _ C _ W 1 t h _ C L 4 5 5 3 s }
Finally, flag gotten!
ALEXCTF{W3_L0v3_C_W1th_CL45535}
註一:
================ rax (64 bits)
======== eax (32 bits)
==== ax (16 bits)
== ah (8 bits)
== al (8 bits)
留言
張貼留言