-
-
KCTF2021[秋季赛][第八题][群狼环伺]wp
-
2021-12-4 20:22 17172
-
这是一道android题目
dex里没什么看点,直接到libcrackme.so里找到Java_www_vprotect_cn_crackme_GoodLuck
传了3个参数:(name, sn, time)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | .text: 00001860 EXPORT Java_www_vprotect_cn_crackme_GoodLuck .text: 00001860 Java_www_vprotect_cn_crackme_GoodLuck ; DATA XREF: LOAD: 00000188 ↑o .text: 00001860 PUSH {LR} .text: 00001862 BL sub_87BE .text: 00001866 ASRS R5, R1, #0x1C .text: 00001868 LDR R3, [R4,R4] .text: 0000186A STRB R1, [R1, #0xC] .text: 0000186C ORNS.W R8, R0, #0x8800 .text: 00001870 DCB 0x50 ; P .text: 00001871 DCB 0xB7 .text: 00001872 DCB 6 .text: 00001873 DCB 0x9A .text: 00001874 BCC loc_17B0 .text: 00001876 STRB R5, [R1, #0x14] .text: 00001878 LDRH R2, [R5,R1] |
看起来不太正常,似乎是有混淆,静态不太好分析,想动态也没有手机
先静态看着玩玩,发现JNI_OnLoad前面有几个函数没有混淆
先看到这个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | int __fastcall sub_12A0() { ... .text: 000012D0 LDR.W R5, = (unk_5004 - 0x12DE ) .text: 000012D4 ADD R6, SP, #0x558+var_528 .text: 000012D6 MOVS R1, #0 ; int .text: 000012D8 MOVS R2, #0x64 ; 'd' ; size_t .text: 000012DA ADD R5, PC ; unk_5004 .text: 000012DC MOV R0, R6 ; void * .text: 000012DE ADD.W R8, R5, #0x12A0 .text: 000012E2 ADD.W R5, R5, #0x1440 .text: 000012E6 ADD.W R4, SP, #0x558+var_529 .text: 000012EA BLX memset .text: 000012EE ADD.W R8, R8, #0x1C .text: 000012F2 ADDS R5, #0xC .text: 000012F4 B loc_1302 .text: 000012F6 BL sub_E60 .text: 000012FA CMP R8, R5 .text: 000012FC STRB.W R0, [R4, #1]! .text: 00001300 BEQ loc_1310 .text: 00001302 LDR.W R3, [R8, #4]! .text: 00001306 AND.W R1, R3, #0xF .text: 0000130A ASRS R0, R3, #4 .text: 0000130C CMP R3, #0 .text: 0000130E BNE loc_12F6 ... } |
sub_E60有多处调用,可以F5出来自己写程序跑,把unk_5004后面的数据都解密出来得到20个字符串:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | java / lang / String utf - 8 getBytes (Ljava / lang / String;)[B cat / proc / % d / cmdline www.vprotect.cn cat / proc / % d / status TracerPid: cat / proc / % d / maps / system / bin / linker rtld_db_dlactivity % 04x popen pclose fgets sprintf malloc gettimeofday getpid free % 08X % 08X % 08X % 08X % 08X % 08X % 08X % 08X |
猜测是一些anti和时间检查,动态调试应该会用到
再继续看其它函数,又注意到:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | int __fastcall sub_788( int * a1, unsigned int * a2, int * a3) { ... v3 = a1 + 4 ; v4 = a1 + 0x24 ; v5 = _byteswap_ulong( * a2); v6 = _byteswap_ulong(a2[ 1 ]); v7 = (v6 ^ (v5 >> 4 )) & 0xF0F0F0F ; v8 = v7 ^ v6; v9 = v5 ^ ( 16 * v7); v10 = (unsigned __int16)(v8 ^ HIWORD(v9)); v11 = v10 ^ v8; v12 = v9 ^ (v10 << 16 ); v13 = (v12 ^ (v11 >> 2 )) & 0x33333333 ; v14 = v13 ^ v12; v15 = v11 ^ ( 4 * v13); v16 = (v14 ^ (v15 >> 8 )) & 0xFF00FF ; v17 = v14 ^ v16; v18 = __ROR4__(v15 ^ (v16 << 8 ), 31 ); v19 = (v18 ^ v17) & 0xAAAAAAAA ; v20 = v17 ^ v19; v21 = v19 ^ v18; v22 = __ROR4__(v20, 31 ); do { v23 = * (v3 - 4 ); v3 + = 4 ; v24 = * (v3 - 7 ) ^ __ROR4__(v21, 4 ); v22 ^ = dword_31B0[(v24 & 0x3F ) + 0x20 ] ^ dword_31B0[((v21 ^ v23) & 0x3F ) + 0x60 ] ^ dword_31B0[(((v21 ^ v23) >> 8 ) & 0x3F ) + 0xA0 ] ^ dword_31B0[(((v21 ^ v23) >> 16 ) & 0x3F ) + 0xE0 ] ^ dword_31B0[(((v21 ^ v23) >> 24 ) & 0x3F ) + 0x120 ] ^ dword_31B0[((v24 >> 8 ) & 0x3F ) + 0x160 ] ^ dword_31B0[(HIWORD(v24) & 0x3F ) + 0x1A0 ] ^ dword_31B0[(HIBYTE(v24) & 0x3F ) + 0x1E0 ]; v25 = * (v3 - 6 ) ^ v22; v26 = __ROR4__(v22, 4 ); v27 = v26 ^ * (v3 - 5 ); v21 ^ = dword_31B0[(v25 & 0x3F ) + 0x60 ] ^ dword_31B0[((v25 >> 8 ) & 0x3F ) + 0xA0 ] ^ dword_31B0[(HIWORD(v25) & 0x3F ) + 0xE0 ] ^ dword_31B0[(HIBYTE(v25) & 0x3F ) + 0x120 ] ^ dword_31B0[(v27 & 0x3F ) + 0x20 ] ^ dword_31B0[((v27 >> 8 ) & 0x3F ) + 0x160 ] ^ dword_31B0[(HIWORD(v27) & 0x3F ) + 0x1A0 ] ^ dword_31B0[(HIBYTE(v27) & 0x3F ) + 0x1E0 ]; } while ( v3 ! = v4 ); v28 = a1 + 0x44 ; while ( 1 ) { v29 = * (v4 - 4 ); v4 + = 4 ; v30 = v26 ^ * (v4 - 7 ); v21 ^ = dword_31B0[(v30 & 0x3F ) + 32 ] ^ dword_31B0[((v22 ^ v29) & 0x3F ) + 96 ] ^ dword_31B0[(((v22 ^ v29) >> 8 ) & 0x3F ) + 160 ] ^ dword_31B0[(((v22 ^ v29) >> 16 ) & 0x3F ) + 224 ] ^ dword_31B0[(((v22 ^ v29) >> 24 ) & 0x3F ) + 288 ] ^ dword_31B0[((v30 >> 8 ) & 0x3F ) + 352 ] ^ dword_31B0[(HIWORD(v30) & 0x3F ) + 416 ] ^ dword_31B0[(HIBYTE(v30) & 0x3F ) + 480 ]; v31 = v21 ^ * (v4 - 6 ); v32 = __ROR4__(v21, 4 ); v33 = v32 ^ * (v4 - 5 ); v22 ^ = dword_31B0[(HIWORD(v33) & 0x3F ) + 416 ] ^ dword_31B0[(v31 & 0x3F ) + 96 ] ^ dword_31B0[((v31 >> 8 ) & 0x3F ) + 160 ] ^ dword_31B0[(HIWORD(v31) & 0x3F ) + 224 ] ^ dword_31B0[(HIBYTE(v31) & 0x3F ) + 288 ] ^ dword_31B0[(v33 & 0x3F ) + 32 ] ^ dword_31B0[((v33 >> 8 ) & 0x3F ) + 352 ] ^ dword_31B0[(HIBYTE(v33) & 0x3F ) + 480 ]; if ( v4 = = v28 ) break ; v26 = __ROR4__(v22, 4 ); } v34 = a1 + 0x64 ; while ( 1 ) { v35 = * (v28 - 4 ); v28 + = 4 ; v36 = v35 ^ v21; v37 = * (v28 - 7 ) ^ v32; v22 ^ = dword_31B0[(v37 & 0x3F ) + 32 ] ^ dword_31B0[(v36 & 0x3F ) + 96 ] ^ dword_31B0[((v36 >> 8 ) & 0x3F ) + 160 ] ^ dword_31B0[(HIWORD(v36) & 0x3F ) + 224 ] ^ dword_31B0[(HIBYTE(v36) & 0x3F ) + 288 ] ^ dword_31B0[((v37 >> 8 ) & 0x3F ) + 352 ] ^ dword_31B0[(HIWORD(v37) & 0x3F ) + 416 ] ^ dword_31B0[(HIBYTE(v37) & 0x3F ) + 480 ]; v38 = v22 ^ * (v28 - 6 ); v39 = * (v28 - 5 ) ^ __ROR4__(v22, 4 ); v21 ^ = dword_31B0[(v38 & 0x3F ) + 96 ] ^ dword_31B0[((v38 >> 8 ) & 0x3F ) + 160 ] ^ dword_31B0[(HIWORD(v38) & 0x3F ) + 224 ] ^ dword_31B0[(HIBYTE(v38) & 0x3F ) + 288 ] ^ dword_31B0[(v39 & 0x3F ) + 32 ] ^ dword_31B0[((v39 >> 8 ) & 0x3F ) + 352 ] ^ dword_31B0[(HIWORD(v39) & 0x3F ) + 416 ] ^ dword_31B0[(HIBYTE(v39) & 0x3F ) + 480 ]; if ( v28 = = v34 ) break ; v32 = __ROR4__(v21, 4 ); } ... return result; } |
看特征比较像des类的算法,最后确认应该是3des-ecb,我大概只能走这么远了,然后在大帅锅的支持和指导下学习一下unidbg的使用
unidbg里磕磕绊绊地勉强能动态调试,ida经常会卡死,几分钟就要重开一下,好在anti什么的我不需要关心,大帅锅已经hook过掉了
我只需直接研究算法,那么就直奔sub_788看看这个3des,断下来观察传入参数,果然是对输入的sn做加密
1 2 | 公开序列号:DA 21 5D 85 F8 2B 13 FB 41 65 CF 78 2F A6 E6 9A (输入sn经两次 hex 编码) 加密后得到:BD 3A B0 69 39 40 F8 CD 42 0D E3 8A 79 DB 52 BD 输出到r2寄存器: 0x40392030 |
后面就浪费很多时间,单步胡乱走,走走看看,一直找不到更多线索,3des还会多次调用,但也没发现对数据做什么进一步有效处理
就是花了好几个小时也没啥进展,偶然一次在单步中注意到一个次数据读取,从0x40392020处读取到一个字节BD,突然敏感起来,这个地址临近前面的3des加密结果返回地址,而且刚好等于那个字节BD
1 2 | 0x40392020 : BD ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 0x40392030 : BD 3A B0 69 39 40 F8 CD 42 0D E3 8A 79 DB 52 BD |
这就大胆猜想一下了,也许是比较结果?进一步证实确实16个字节都一致,这里全凭运气哈
那么解决方案就来了,这次输入名字KCTF,然后再去下个断点把0x40392020处的16字节抓出来
得到:45 68 97 A3 29 2A 7F D4 F5 90 73 57 46 02 AE D5
然后3des解密一下就应该可以得到答案了
扩展密钥直接抓出来用,大概spbox做了什么手脚,花了很多时间都没凑对结果,F5出来的代码也一直没调对,最后还是大帅锅动作敏捷先搞对了,得到flag:
3633386636373733353933626439316437383865383931653663663432656661
我无奈,只能做点力所能及的工作了:提交答案!
[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界