目錄
1.樣本概況... 3
1.1 樣本資訊... 3
1.2 測試環境及工具... 3
1.3 分析目标... 3
2.具體分析... 4
2.1 加強情況... 4
2.2 代碼片段分析... 4
1.樣本概況
1.1 樣本資訊
名稱:dc3c4ec3ea5b7de2de4feb122e33b1a2e91d9ffa
MD5值:5d21be09f3a1fcf545afaf0f81844fea
SHA1值:dc3c4ec3ea5b7de2de4feb122e33b1a2e91d9ffa
CRC32:d6741def
主界面:

1.2 測試環境及工具
Nexus5 + IDA pro
1.3 分析目标
破解密碼
2.具體分析
2.1 加強情況
2.2 代碼片段分析
直接對樣本進行調試,使用apktool反編譯樣本,擷取包名及類名,确定JNI_OnLoad的偏移,在JNI_OnLoad中通過寄存器調用,可以确定是RegisterClass,檢視寄存器,在R2中調用了aMUMU,轉到記憶體可以确定對應的函數位址。如下圖所示:
如下所示為attachBaseContext位址,跳轉到該位址,并下斷點
如下所示為onCreate位址跳轉到該位址,并下斷點
在跟進到此處時跳出,程式直接運作起來,說明B loc_75252EAE裡加載了dex
重新啟動調試,後跟進這個跳轉,如下圖所示:
中斷後重新附加調試函數位址會改變,不能按照上一次斷點跟蹤,如下圖所示:
再次分析_Z9parse_dexP7_JNIEnvPx函數,該函數會在log中列印日志,顯示dex的記憶體位址及dex大小等資訊,如下下圖所示:
調用opendexfile, 如下圖所示:
可以根據寄存器R8的值知道dex的位置,然後根據dex檔案格式可知0x752A9028為dex檔案大小(0x19cf4),計算結束位址為:0x752C2CFC,如下圖所示:
執行完成之後進入onCreate函數,如下圖所示:
onCreate函數結束,進入libdvm.so子產品,
這個時候dex已經在上述的記憶體位址出還原,在_ZN3ali16dex_juicer_patchEPhjPKc函數中可以使用下圖所示關鍵字在ddms中過濾log資訊
在ddms中檢視log,如下所示:
根據上面分析的起始位址和偏移計算出結束位址,再使用IDC腳本将其dump到檔案中,
static main(void) { auto fp, begin, end, dexbyte; fp = fopen("d:\\dumpali.so", "wb"); begin = 0x752AA008; end = begin + 0x30090; for ( dexbyte = begin; dexbyte < end; dexbyte ++ ) fputc(Byte(dexbyte), fp); } |
然後使用jadx工具檢視dump出來的結果,代碼已經還原,如下圖所示:
脫殼成功,使用GDA檢測如下圖所示:
然後進行動态調試擷取密碼:通過動态調試smali擷取到加密後的字元串:
000a0a0a0a0202aa5458d715704493d8e6b9bd38f8b6be0e
key = 1f98ceab209770efa875c245853ece761f98ceab209770ef
根據以上分析和dump出的smali代碼,對解密代碼進行編寫:
import javax.crypto.*; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.io.UnsupportedEncodingException; import java.security.*; import java.security.spec.AlgorithmParameterSpec; public class Main { private static String a = "DESede"; private static Key b; private static int c = 5; public static byte[] step1_string(String arg9) { byte[] v1 = arg9.getBytes(); int v2 = v1.length; byte[] v3 = new byte[v2 / 2]; int v0; for(v0 = 0; v0 < v2; v0 += 2) { v3[v0 / 2] = ((byte)Integer.parseInt(new String(v1, v0, 2), 16)); } return v3; } public static String step3_byte(byte[] arg6) { StringBuffer v2 = new StringBuffer(); int v1; for(v1 = 0; v1 < arg6.length; ++v1) { System.out.print(arg6[v1] + " "); String v0 = Integer.toHexString(arg6[v1] & 255); if(v0.length() == 1) { v0 = String.valueOf('0') + v0; } v2.append(v0); } //System.out.println(v2); return v2.toString(); } public static byte[] step3_string(String arg6) { String arg16[] = new String[32]; byte [] abyte = new byte[32]; for (int i = 0; i < arg16.length; i = i+2){ arg16[i] = arg6.substring(i, i+2); Integer in = Integer.parseInt(arg16[i], 16); byte intnum = in.byteValue(); abyte[i] = (byte) (intnum & 255); System.out.print(abyte[i] + " "); } return abyte; } private static byte[] step2_key(byte[] arg7, byte[] arg8) { IvParameterSpec v0 = new IvParameterSpec(arg7); Cipher v1 = null; try { v1 = Cipher.getInstance(String.valueOf(a) + "/CBC/PKCS5Padding"); v1.init(1, b, ((AlgorithmParameterSpec)v0)); c = v1.getBlockSize(); byte[] v0_1 = v1.doFinal(arg8); byte[] v1_1 = new byte[v0_1.length + c]; System.arraycopy(arg7, 0, v1_1, 0, c); System.arraycopy(v0_1, 0, v1_1, c, v0_1.length); return v1_1; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); } return null; } private static byte[] step2_dekey(byte[] arg7, byte[] arg8) { IvParameterSpec v0 = new IvParameterSpec(arg7); Cipher v1 = null; try { v1 = Cipher.getInstance(String.valueOf(a) + "/CBC/NoPadding"); v1.init(Cipher.DECRYPT_MODE, b, ((AlgorithmParameterSpec)v0)); // 操作模式為解密,key為密鑰 byte[] sourceText = v1.doFinal(arg8); System.out.println(); for (int j = 0 ; j < sourceText.length; j++){ System.out.print(sourceText[j] + " "); } return sourceText; }catch (BadPaddingException e) { e.printStackTrace(); }catch (IllegalBlockSizeException e) { e.printStackTrace(); }catch (InvalidKeyException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); } return null; } public static Key get_key(byte[] arg4) { SecretKey v0_1 = null; try { if(arg4 == null) { KeyGenerator v0 = KeyGenerator.getInstance(a); v0.init(new SecureRandom()); v0_1 = v0.generateKey(); } else { SecretKeySpec v0_2 = new SecretKeySpec(arg4, a); return ((Key)v0_2); } } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return ((Key)v0_1); } public static void main(String []args){ //加密模拟 //1.給key b 指派 v0.a(v0.a(a.a(arg5))); //argc5 = 1f98ceab209770efa875c245853ece761f98ceab209770ef b = get_key(step1_string("1f98ceab209770efa875c245853ece761f98ceab209770ef")); //2.擷取 arg6 = a.a(v0.a(a.a("000a0a0a0a0202aa"), arg6.getBytes())); String result = step3_byte(step2_key(step1_string("000a0a0a0a0202aa"), "日天@土侸".getBytes())); System.out.println(result); //解密部分 //000a0a0a0a0202aa5458d715704493d8e6b9bd38f8b6be0e //step2_key傳回的位元組數組:84 88 -41 21 112 68 -109 -40 -26 -71 -67 56 -8 -74 -66 14 step3_string("5458d715704493d8e6b9bd38f8b6be0e"); //構造解密的位元組 byte[] bytedecode = new byte[16]; bytedecode[0] = 84; bytedecode[1] = 88; bytedecode[2] = -41; bytedecode[3] = 21; bytedecode[4] = 112; bytedecode[5] = 68; bytedecode[6] = -109; bytedecode[7] = -40; bytedecode[8] = -26; bytedecode[9] = -71; bytedecode[10] = -67; bytedecode[11] = 56; bytedecode[12] = -8; bytedecode[13] = -74; bytedecode[14] = -66; bytedecode[15] = 14; step2_dekey(step1_string("000a0a0a0a0202aa"), bytedecode); //-26 -105 -91 -27 -92 -87 64 -27 -100 -97 -28 -66 -72 3 3 3 byte[] sourcebyte = new byte[16]; sourcebyte[0] = -26; sourcebyte[1] = -105; sourcebyte[2] = -91; sourcebyte[3] = -27; sourcebyte[4] = -92; sourcebyte[5] = -87; sourcebyte[6] = 64; sourcebyte[7] = -27; sourcebyte[8] = -100; sourcebyte[9] = -97; sourcebyte[10] = -28; sourcebyte[11] = -66; sourcebyte[12] = -72; sourcebyte[13] = 3; sourcebyte[14] = 3; sourcebyte[15] = 3; try { String str = new String(sourcebyte, "utf-8"); System.out.println(str); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } System.out.println(); for (int i = 0; i < sourcebyte.length; i++){ System.out.print(sourcebyte[i] + " "); } } } |
運作結果如下所示: