-
-
[原创]KCTF2020秋季赛 第四题 突破重围 writeup
-
2020-11-23 23:42 3498
-
KCTF2020秋季赛 第四题 突破重围 wp
一道Android题
Java层分析
1、com.kanxue.crackme.MainActivity
1 2 3 4 5 | System.loadLibrary( "crack" ); init(); - > DexClassLoader / assets / b.txt check() 反射执行 com.kanxue.crackme.Crack.check() |
2、com.kanxue.crackme.MyCrack
1 2 3 4 5 | public class MyCrack { public static String crypt = "otVvmpP4ZI58pqB26OTaYw==" ; public static native byte[] crackjni(byte[] bArr); } |
3、/assets/b.txt -> /assets/b.dex
com.kanxue.crackme.Crack.check
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 | public static boolean check(String content) { if (content = = null || content.length() ! = 16 ) { return false; } Class MyCrackClass = null; Field cryptfield = null; byte[] result = crypt(content.getBytes()); Method crackjni = null; try { MyCrackClass = Crack. class .getClassLoader().loadClass( "com.kanxue.crackme.MyCrack" ); cryptfield = MyCrackClass.getDeclaredField( "crypt" ); Method[] methods = MyCrackClass.getDeclaredMethods(); for ( int i = 0 ; i < methods.length; i + + ) { if (methods[i].getName().equals( "crackjni" )) { crackjni = methods[i]; } } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchFieldException e2) { e2.printStackTrace(); } if (crackjni ! = null) { try { result = (byte[]) crackjni.invoke(null, new Object []{result}); } catch (IllegalAccessException e3) { e3.printStackTrace(); } catch (InvocationTargetException e4) { e4.printStackTrace(); } } String finalresult = Base64.encodeToString(crypt(result), 0 ); String cryptcontent = "test" ; if (!(cryptfield = = null || MyCrackClass = = null)) { try { cryptcontent = (String) cryptfield.get(null); } catch (IllegalAccessException e5) { e5.printStackTrace(); } } if (finalresult.equals(cryptcontent)) { return true; } return false; } |
com.kanxue.crackme.Crack.crypt
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 | public static byte[] crypt(byte[] b_data) { String mKkey = "kaokaonio" ; if (b_data = = null) { return null; } int x = 0 ; int y = 0 ; byte[] b_key = mKkey.getBytes(); byte[] key = new byte[ 256 ]; for ( int i = 0 ; i < 256 ; i + + ) { key[i] = (byte) i; } int index1 = 0 ; int index2 = 0 ; if (b_key = = null || b_key.length = = 0 ) { return null; } for ( int i2 = 0 ; i2 < 256 ; i2 + + ) { index2 = ((b_key[index1] & 255 ) + (key[i2] & 255 ) + index2) & 255 ; byte tmp = key[i2]; key[i2] = key[index2]; key[index2] = tmp; index1 = (index1 + 1 ) % b_key.length; } byte[] result = new byte[b_data.length]; for ( int i3 = 0 ; i3 < b_data.length; i3 + + ) { x = (x + 1 ) & 255 ; y = ((key[x] & 255 ) + y) & 255 ; byte tmp2 = key[x]; key[x] = key[y]; key[y] = tmp2; result[i3] = (byte) (b_data[i3] ^ key[((key[x] & 255 ) + (key[y] & 255 )) & 255 ]); } return result; } |
对/assets/b.dex进行动态调试:
找到cryptcontent的值为 "l+x7fKd2FBaaEY4NV4309A==\n"
crypt中的mkey有改变 "kaokaonio" -> "keepGoing"
执行流程如下:
1 2 3 4 5 6 7 8 9 | 1. input 长度 16 2. byte[] result = crypt( input ) crypt方法中的 mkey = kaokaonio 3. crackjni_reslut = libcarack.so - >crackjni(reslut) 对 reslut 进行加密 4. reslut = crypt(crackjni_reslut) crypt方法中的 mkey = keepGoing 5. base64(reslut) 与 cryptcontent = "l+x7fKd2FBaaEY4NV4309A==\n" 进行比较 |
Native层分析
1、libcrack.so 使用了 aes 加密
S盒
2、Java_com_kanxue_crackme_MyCrack_crackjni
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 | int __fastcall Java_com_kanxue_crackme_MyCrack_crackjni(_JNIEnv * a1, int a2, int a3) { v25 = sub_CF79ECBC((void * ) 0xFFFFFF9C , "/proc/self/maps" , 0 , 0 ); / / frida anti if ( v25 > = 1 ) { while ( sub_CF7A2168(v25, &s, 0x200 ) > = 1 ) { if ( strstr(&s, "frida" ) ) MEMORY[ 0 ] = 0x63 ; if ( sscanf(&s, "%x-%lx %4s %lx %*s %*s %s" , &v31, &v30, &v33, &v32, &v39) = = 5 && v33 = = 0x72 && v34 = = 0x70 && !v32 && strlen(&v39) && v39 ! = 0x5B && (unsigned int )(v30 - v31) > 0xF4240 && !sub_CF7A22C0(&v39, ".oat" ) && sub_CF7A2228(v31) = = 1 && sub_CF7A20D2(v31, 0 , v30, v30 >> 0x1F ) = = 1 ) { MEMORY[ 0 ] = 0x63 ; break ; } } } ...... sub_CF79ED60(v5, "kaokaonikaokaoni" , v6); / / AES加密 ...... if ( dword_CF7D73E4 ) { if ( dword_CF7D73D8 ) { v12 = dword_CF7D73D8 + 0x16D3A6 ; v13 = * (_BYTE * )(dword_CF7D73D8 + 0x16D3A6 ); v14 = dword_CF7D73E4 + + ; * (_BYTE * )(dword_CF7D73D8 + 0x16D3A6 ) = v13 + v14; * (_BYTE * )(v12 + 1 ) = 0x3D ; v15 = sub_CF7A38C2(v29, "com/kanxue/crackme/MyCrack" ); v16 = sub_CF7A38EC(v29, v15, "crypt" , "Ljava/lang/String;" ); v17 = sub_CF7A3934(v29, "ZmxhZ3RyeWFnYWluP30=" ); sub_CF7A3960(v29, v15, v16, v17); } + + dword_CF7D73E4; } else { if ( dword_CF7D73D8 ) { v8 = dword_CF7D73D8 + 0x16D3A6 ; * (_BYTE * )(dword_CF7D73D8 + 0x16D3A6 ) = 0xD3u ; / / "kaokaonio" - > "keepGoing" * (_BYTE * )(v8 + 1 ) = 0x3D ; v9 = sub_CF7A38C2(v29, "com/kanxue/crackme/MyCrack" ); v10 = sub_CF7A38EC(v29, v9, "crypt" , "Ljava/lang/String;" ); v11 = sub_CF7A3934(v29, "l+x7fKd2FBaaEY4NV4309A==\n" ); / / "otVvmpP4ZI58pqB26OTaYw==" - > "l+x7fKd2FBaaEY4NV4309A==" sub_CF7A3960(v29, v9, v10, v11); } + + dword_CF7D73E4; } } |
AES扩展密钥算法
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 | int sub_CF79EDE8() { unsigned __int8 v0; / / ST04_1 unsigned int j; / / [sp + 8h ] [bp - 18h ] unsigned int i; / / [sp + Ch] [bp - 14h ] unsigned __int8 v4; / / [sp + 10h ] [bp - 10h ] unsigned __int8 v5; / / [sp + 11h ] [bp - Fh] unsigned __int8 v6; / / [sp + 12h ] [bp - Eh] unsigned __int8 v7; / / [sp + 13h ] [bp - Dh] for ( i = 0 ; i < = 3 ; + + i ) { byte_CF7B6318[ 4 * i] = * (_BYTE * )(dword_CF7B6314 + 4 * i); byte_CF7B6318[ 4 * i + 1 ] = * (_BYTE * )(dword_CF7B6314 + 4 * i + 1 ); byte_CF7B6318[ 4 * i + 2 ] = * (_BYTE * )(dword_CF7B6314 + 4 * i + 2 ); byte_CF7B6318[ 4 * i + 3 ] = * (_BYTE * )(dword_CF7B6314 + 4 * i + 3 ); } while ( i < = 0x2B ) { for ( j = 0 ; j < = 3 ; + + j ) * (&v4 + j) = byte_CF7B6318[ 4 * i - 4 + j]; if ( !((unsigned __int8)i << 0x1E ) ) { v0 = v4; v4 = v5; v5 = v6; v6 = v7; v7 = v0; v4 = sub_CF79F084(v4); v5 = sub_CF79F084(v5); v6 = sub_CF79F084(v6); v7 = sub_CF79F084(v7); v4 ^ = byte_CF7AFE5C[i >> 2 ]; } byte_CF7B6318[ 4 * i] = byte_CF7B6318[ 4 * i - 0x10 ] ^ v4; byte_CF7B6318[ 4 * i + 1 ] = byte_CF7B6318[ 4 * i - 0xF ] ^ v5; byte_CF7B6318[ 4 * i + 2 ] = byte_CF7B6318[ 4 * i - 0xE ] ^ v6; byte_CF7B6318[ 4 * i + 3 ] = byte_CF7B6318[ 4 * i - 0xD ] ^ v7; + + i; } return _stack_chk_guard; } |
获取flag
1、"l+x7fKd2FBaaEY4NV4309A==" -> bytes -> base64 -> crypto (mKey=keepGoing)
1 | 40 , - 128 , - 114 , - 30 , 10 , - 79 , 122 , 37 , - 62 , 22 , 120 , 86 , 58 , 74 , 127 , - 85 |
2、AES解密
3、解密字符串
crypto (mKey=kaokaonio)
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2020-11-24 07:56
被neilwu编辑
,原因:
赞赏
他的文章
看原图