【移动样本分析】多层Android锁机样本分析5
2022-10-14 12:26:42 Author: mp.weixin.qq.com(查看原文) 阅读量:3 收藏

作者坛账号:小骚

 复制代码 隐藏代码
包名:com.fock.lock
MD5值:0c298c0f5a8847753dd6d352d7a30be8
文件大小:936.80 KB
来源:某三楼

用到的工具

  • 模拟器+Xposed

  • android studio(看日志和运算结果)

  • jeb或者任何可以反编译apk工具

入口分析

  • 从 AndroidManifest.xml 分析入口以及服务 主启动页面是 MainActivity 进去看看

 复制代码 隐藏代码

<application
android:allowBackup="true"
android:debuggable="true"
android:icon="@drawable/MT_Bin"
android:label="@string/MT_Bin"
android:theme="@style/MT_Bin">

    <activity android:name=".MainActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
      </intent-filter>
    </activity>

    <service android:enabled="true" android:exported="true" android:name=".MyService"/>

    <receiver android:exported="true" android:name=".AutoBroadcast">
    <intent-filter android:priority="2147483647">
        <action android:name="com.fock.lock.js"/>
        <action android:name="android.intent.action.BATTERY_CHANGED"/>
        <action android:name="android.intent.action.DATA_ACTIVITY"/>
        <action android:name="android.intent.action.DATA_STATE"/>
        <action android:name="android.intent.action.DATE_CHANGED"/>
        <action android:name="android.server.checkin.FOTA_CANCEL"/>
        <action android:name="android.intent.action.MEDIABUTTON"/>
        <action android:name="android.intent.action.MEDIA_MOUNTED"/>
        <action android:name="android.intent.action.MEDIA_SCANNER_STARTED"/>
        <action android:name="android.intent.action.MEDIA_SCANNER_FINISHED"/>
        <action android:name="android.intent.action.TIME_SET"/>
        <action android:name="android.intent.action.TIME_TICK"/>
        <action android:name="android.intent.action.UMS_CONNECTED"/>
        <action android:name="android.intent.action.WALLPAPER_CHANGED"/>
        <action android:name="android.intent.action.PACKAGE_ADDED"/>
        <action android:name="android.intent.action.PACKAGE_REMOVED"/>
        <action android:name="android.intent.action.PHONE_STATE"/>
        <action android:name="android.intent.action.SCREEN_OFF"/>
        <action android:name="android.intent.action.SCREEN_ON"/>
        <action android:name="android.intent.action.SERVICE_STATE"/>
        <action android:name="android.intent.action.SIG_STR"/>
        <action android:name="android.intent.category.ALTERNATIVE"/>
        <action android:name="android.intent.action.SETTINGS"/>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
        <action android:name="android.net.wifi.WIFI_STATE_CHANGED"/>
        <action android:name="android.net.wifi.STATE_CHANGE"/>
        <action android:name="android.intent.action.REBOOT"/>
        <action android:name="android.intent.action.USER_PRESENT"/>
        <category android:name="android.intent.category.HOME"/>
      </intent-filter>
</receiver>
  </application>

  • MainActivity 里面就启动一个服务,到 MyService 这个服务里面看看

 复制代码 隐藏代码

public class MainActivity extends Activity {
    home.php?mod=space&uid=1892347  // android.app.Activity
    protected void onCreate(Bundle bundle0) {
        LogCatBroadcaster.start(this);
        super.onCreate(bundle0);
        this.startService(new Intent(this, MyService.class));
    }

    @Override  // android.app.Activity
    protected void onDestroy() {
        super.onDestroy();
    }
}

  • MyService 的 onCreate 函数 执行了 L 方法,发现这个就是第一层的代码

 复制代码 隐藏代码

    @Override  // android.app.Service
    public void onCreate() {
        super.onCreate();
        this.fv = new FloatView(this.getApplicationContext());
        this.L();
    }

第一层分析

  • 先看初始化了哪些东西

  • 到点击事件分析,发现解锁算法用到了两个参数

 复制代码 隐藏代码

        @Override  // android.view.View$OnClickListener
        public void onClick(View view0) {
            if(MyService.this.lp.getText().toString().trim().length() == 0) {
                return;
            }

            // 解锁算法
            if(MyService.this.lp.getText().toString().equals("" + (MyService.this.ck / this.val$Admin ^ MyService.sb(Integer.parseInt(this.val$清))))) {
                MyService.this.fv.removeView();
                MyService.this.Z();
                return;
            }

            MyService.this.密码错误.setVisibility(0);
            MyService.this.密码错误.setText("密码错误联系半支烟QQxxxxxxxx解锁");
            Runnable runnable0 = MyService.this.runn;
            MyService.this.hand.postDelayed(runnable0, 2000L);
        }

  • 使用 YukiHookAPI(Xposed) Hook 获取关键参数

 复制代码 隐藏代码

// 类名
findClass("com.fock.lock.MyService\$100000012").hook {
                injectMember {
                    method {
                        // 方法名
                        name = "onClick"
                        // 参数
                        param(ViewClass)
                        // 返回值
                        returnType = UnitType
                    }
                    // 方法执行后
                    afterHook {
                        // 反射获取
                        val admin = instance.getParam<Int>("val\$Admin")
                        val 清 = instance.getParam<String>("val\$清")
                        打印结果
                        loggerE(msg = "admin: $admin\n清: $清")
                    }
                }

            }

  • 还原最终密码运算

 复制代码 隐藏代码

// Kotlin 写法
private fun 第一层() {
        // 识别码
        val ck = 56983
        // 参数1
        val arg1 = 14
        // 参数2
        val arg2 = sb(7)
        // 识别码 除以 参数1 异或运算 参数2
        val pass = ck / arg1 xor arg2
        "第一层密码: $pass".logd()
    }


第二层分析

  • 看看初始化了哪些

  • 直接就是一堆让人头大的运算

 复制代码 隐藏代码

        @Override  // android.view.View$OnClickListener
        public void onClick(View view0) {
            int v15;
            int[][] arr2_v = {new int[]{4, 6, 8, 10, 13, 16, 17, 18, 21, 23, 27, 29, 0x1F, 33, 41, 45, 52, 54, 56, 61, 67, 69, 71, 73, 74, 76, 78, 80, 82, 84, 85, 86}};
            int[][] arr2_v1 = new int[arr2_v[0].length][arr2_v.length];
            int v;
            for(v = 0; v < arr2_v.length; ++v) {
                int v1;
                for(v1 = 0; v1 < arr2_v[0].length; ++v1) {
                    arr2_v1[v1][v] = arr2_v[v][v1];
                }
            }

            int[][] arr2_v2 = {new int[]{14, 16, 18, 19, 23, 24, 28, 29, 0x1F, 35, 37, 39, 41, 43, 0x2F, 0x30, 49, 51, 53, 57, 59, 62, 0x40, 66, 69, 73, 76, 0x4F, 81, 83, 85, 87, 0x6F, 0x83, 0x9C}};
            int[][] arr2_v3 = new int[arr2_v2[0].length][arr2_v2.length];
            int v2;
            for(v2 = 0; v2 < arr2_v2.length; ++v2) {
                int v3;
                for(v3 = 0; v3 < arr2_v2[0].length; ++v3) {
                    arr2_v3[v3][v2] = arr2_v2[v2][v3];
                }
            }

            int v4;
            for(v4 = 0; v4 < arr2_v1.length; ++v4) {
                int v5 = MyService.this.b + arr2_v1[MyService.this.b][MyService.this.b];
                MyService.this.c = v5;
                int v6;
                for(v6 = 0; v6 < arr2_v3[arr2_v1[MyService.this.b][MyService.this.b]][MyService.this.b]; ++v6) {
                    int v7 = MyService.this.d + arr2_v1[MyService.this.b][MyService.this.b] + arr2_v3[arr2_v3[MyService.this.b][MyService.this.b]][MyService.this.b];
                    MyService.this.d = v7;
                }
            }

            int v8 = 2 * MyService.this.po1;
            int v9 = MyService.this.a;
            int v10 = 11 + 4 * MyService.this.b + v9;
            int v11 = MyService.this.a * 6 ^ v10;
            int v12 = MyService.this.po1 - v8 + v11;
            MyService.this.po2 = v12;
            int v13 = MyService.this.po2;
            int v14 = MyService.this.b;
            if(MyService.this.po1 >= v14 + arr2_v3[MyService.this.b][MyService.this.b]) {
                v15 = MyService.sb(MyService.this.po2);
            }
            else {
                int v16 = MyService.this.c;
                int v17 = 5 + 2 * MyService.this.po2 + v16;
                v15 = MyService.this.po2 ^ v17;
            }

            int v18 = v13 + v15 + MyService.this.a ^ 25 >> MyService.sb(20 - MyService.this.b >> 99);
            int v19 = Integer.parseInt("" + (MyService.this.cl ^ MyService.sb(16 * v18 ^ 3))) / 999;
            if(MyService.this.lp.getText().toString().equals("" + (v19 * 2 ^ MyService.this.cl))) {
                MyService.this.fv.removeView();
                MyService.this.X();
            }
        }

  • 先使用 Xposed Hook 反射获取用到 MyService 里面的几个参数

 复制代码 隐藏代码
// 同上
findClass("com.fock.lock.MyService\$100000024").hook {
                injectMember {
                    method {
                        name = "onClick"
                        param(ViewClass)
                        returnType = UnitType
                    }

                    afterHook {
                        val myService = instance.getParam<Any>("this\$0")
                        myService?.let {
                            val a = it.getParam<Int>("a")
                            val b = it.getParam<Int>("b")
                            val c = it.getParam<Int>("c")
                            val d = it.getParam<Int>("d")
                            val cl = it.getParam<Int>("cl")
                            val po1 = it.getParam<Int>("po1")
                            val po2 = it.getParam<Int>("po2")
                            loggerE(msg = "a: $a\nb: $b\nc: $c\nd: $d\ncl: $cl\npo1: $po1\npo2: $po2")
                        }
                    }
                }
            }

  • 然后把获取到的参数复制到自己代码里面运行一下

 复制代码 隐藏代码

public class IntArray {
    public static int[][] arr2_v  = {new int[]{4, 6, 8, 10, 13, 16, 17, 18, 21, 23, 27, 29, 0x1F, 33, 41, 45, 52, 54, 56, 61, 67, 69, 71, 73, 74, 76, 78, 80, 82, 84, 85, 86}};
    public static int[][] arr2_v1 = new int[arr2_v[0].length][arr2_v.length];

    public static int[][] arr2_v2 = {new int[]{14, 16, 18, 19, 23, 24, 28, 29, 0x1F, 35, 37, 39, 41, 43, 0x2F, 0x30, 49, 51, 53, 57, 59, 62, 0x40, 66, 69, 73, 76, 0x4F, 81, 83, 85, 87, 0x6F, 0x83, 0x9C}};
    public static int[][] arr2_v3 = new int[arr2_v2[0].length][arr2_v2.length];

    static int d = 37536;

    private static final int po1 = 0;

    private static final int a = 0;

    private static int po2 = 0;

    private static int c = 4;

    static {
        int v;
        for (v = 0; v < arr2_v.length; ++v) {
            int v1;
            for (v1 = 0; v1 < arr2_v[0].length; ++v1) {
                arr2_v1[v1][v] = arr2_v[v][v1];
            }
        }

        int v2;
        for (v2 = 0; v2 < arr2_v2.length; ++v2) {
            int v3;
            for (v3 = 0; v3 < arr2_v2[0].length; ++v3) {
                arr2_v3[v3][v2] = arr2_v2[v2][v3];
            }
        }

        int v4;
        for (v4 = 0; v4 < arr2_v1.length; ++v4) {
            int v5 = 0 + arr2_v1[0][0];
            c = v5;
            int v6;
            for (v6 = 0; v6 < arr2_v3[arr2_v1[0][0]][0]; ++v6) {
                int v7 = d + arr2_v1[0][0] + arr2_v3[arr2_v3[0][0]][0];
                d = v7;
            }
        }
        Log.d("xihantest", "\nd: " + d);
        int v8 = 2 * po1;
        int v9 = a;
        int v10 = 11 + 4 * 0 + v9;
        int v11 = a * 6 ^ v10;
        int v12 = po1 - v8 + v11;
        po2 = v12;
        int v13 = po2;
        int v14 = 0;
        int v15;
        if(po1 >= v14 + arr2_v3[0][0]) {
            v15 = sb(po2);
        }else {
            int v16 = c;
            int v17 = 5 + 2 * po2 + v16;
            v15 = po2 ^ v17;
        }
        int v18 = v13 + v15 + a ^ 25 >> sb(20 - 0 >> 99);
        Log.d("xihantest", "v18: " + v18);

    }
}

  • 获取到最终固定的的v18 = 658,运算方法也显而易见了

 复制代码 隐藏代码

private fun 第二层() {
        // 识别码
        val cl = 44722
        // (识别码 异或运算 658) 除以 999
        val v19 = (cl xor 658) / 999
        // v19 乘以 2 异或运算 识别码
        val pass = v19 * 2 xor cl
        "第二层密码: $pass".logd()
    }


第三层分析

  • 初始化控件和第二层一样,直接来到点击事件这里分析,这里解锁的关键是获取 v1 的值

 复制代码 隐藏代码

        @Override  // android.view.View$OnClickListener
        public void onClick(View view0) {
            // 使用了 aes 加密
            byte[] arr_b = MyService.this.aes.cipher("Android SignApk".getBytes());
            StringBuffer stringBuffer0 = new StringBuffer();
            int v;
            for(v = 0; v < 16; ++v) {
                if((arr_b[v] & 0xFF) > 15) {
                    stringBuffer0.append(String.format("%x", new Byte(arr_b[v])));
                }
                else {
                    stringBuffer0.append(String.format("0%x", new Byte(arr_b[v])));
                }

                stringBuffer0.append(" ");
            }
            // 获取到这个值 离解锁就差一步
            int v1 = MyService.this.letterToNumber(((String)"" + stringBuffer0.subSequence(3, 36))) / 3000;
            if(MyService.this.lp.getText().toString().trim().length() == 0) {
                return;
            }
            // 解锁方式1: 会强行重启配合开机自启服务再坑一波钱
            if(MyService.this.lp.getText().toString().equals("6" + (v1 ^ MyService.this.cz))) {
                MyService.this.fv.removeView();
                new Timer().schedule(new 100000036(this), 1500L);
                return;
            }

            // 解锁方式2: 直接删除当前view 也就是可以回到桌面卸载应用
            if(MyService.this.lp.getText().toString().equals("" + (v1 ^ MyService.this.cz))) {
                MyService.this.fv.removeView();
                return;
            }

            MyService.this.解锁.setVisibility(0);
            MyService.this.解锁.setText("密码错误,手机恢复正常失败/nManifest-Version: 1.0Created-By: 1.0 (Android SignApk)");
            Runnable runnable0 = MyService.this.runn3;
            MyService.this.hand3.postDelayed(runnable0, 2000L);
        }

  • Aes类就是用dex转jar大法,把这个jar以及代码复制过来修一修

 复制代码 隐藏代码

// 这是我写的 Kotlin 函数 直接获取结果
fun aes(): Int {
    val aes = Clown(Clown.KeySize.Bits192, keys)
    val arr_b = aes.cipher("Android SignApk".toByteArray())
    val stringBuffer0 = StringBuffer()
    var v = 0
    while (v < 16) {
        if (arr_b[v].toInt() and 0xFF > 15) {
            stringBuffer0.append(String.format("%x", arr_b[v]))
        } else {
            stringBuffer0.append(String.format("0%x", arr_b[v]))
        }
        stringBuffer0.append(" ")
        ++v
    }
    val v1 = letterToNumber("" + stringBuffer0.subSequence(3, 36)) / 3000
    return v1
}
  • 最终密码运算

 复制代码 隐藏代码

private fun 第三层() {
        // 识别码
        val cz = 158718
        // 上面获取到的 v1 异或运算 识别码
        val pass = "${aes() xor cz}"
        "第三层密码: $pass".logd()
    }

样本下载地址:https://xihan.lanzouv.com/iRgfI0dt60ed 解压密码:52pj

-官方论坛

www.52pojie.cn

--推荐给朋友

公众微信号:吾爱破解论坛

或搜微信号:pojie_52


文章来源: https://mp.weixin.qq.com/s?__biz=MjM5Mjc3MDM2Mw==&mid=2651138526&idx=1&sn=3a711c3e2cbaa17ca6576987b12a91a6&chksm=bd50b98a8a27309ccaf2fb527954a57f8af1eae7bda3740416a63e2424e89dbfb02fbee9403b#rd
如有侵权请联系:admin#unsafe.sh