目录
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] + " "); } } } |
运行结果如下所示: