吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 11201|回复: 66
上一主题 下一主题
收起左侧

[移动样本分析] 多层Android锁机样本分析5

  [复制链接]
跳转到指定楼层
楼主
小骚 发表于 2022-10-13 20:39 回帖奖励
使用论坛附件上传样本压缩包时必须使用压缩密码保护,压缩密码:52pojie,否则会导致论坛被杀毒软件等误报,论坛有权随时删除相关附件和帖子!
病毒分析分区附件样本、网址谨慎下载点击,可能对计算机产生破坏,仅供安全人员在法律允许范围内研究,禁止非法用途!
禁止求非法渗透测试、非法网络攻击、获取隐私等违法内容,即使对方是非法内容,也应向警方求助!
本帖最后由 小骚 于 2022-10-13 20:40 编辑

Contacts联系人

包名: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 {
    @Override  // 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();
    }
}
  • MyServiceonCreate 函数 执行了 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

免费评分

参与人数 15吾爱币 +20 热心值 +14 收起 理由
GNNU + 1 + 1 热心回复!
takeink + 1 + 1 热心回复!
v5le0n9 + 1 + 1 谢谢@Thanks!
gaosld + 1 + 1 谢谢@Thanks!
小菜鸟一枚 + 1 + 1 用心讨论,共获提升!
fengbolee + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
花残终将败 + 1 + 1 我很赞同!
努力加载中 + 1 + 1 谢谢@Thanks!
哇卡s + 1 + 1 我很赞同!
Null666yyds + 1 + 1 用心讨论,共获提升!
xiong930626 + 1 + 1 用心讨论,共获提升!
独行风云 + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
正己 + 4 + 1 热心回复!
allspark + 1 + 1 用心讨论,共获提升!
小郑 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
 楼主| 小骚 发表于 2022-10-14 08:46 |楼主
dragonxash 发表于 2022-10-14 08:28
请问师傅  Xposed Hook 反映射 是什么意思

这里用到的方法是 Xposed 通过 Hook 反射获取到参数,也可以通过其他方法,比如注入日志打印,或使用其他hook框架 如frida等,反正最终目的就是获取到想要的参数,哪个方便用哪个
推荐
nur11111 发表于 2022-10-16 19:13
bean0283 发表于 2022-10-13 21:14
三楼的锁机软件真多,5.6年前混迹3楼的时候,总会拿个破手机先试水,出问题了就刷机

因为锁机软件,多年前就弃坑了,本人技术菜折腾不起,吾爱就基本没有什么顾虑,我觉得氛围很好
3#
bean0283 发表于 2022-10-13 21:14
三楼的锁机软件真多,5.6年前混迹3楼的时候,总会拿个破手机先试水,出问题了就刷机
4#
无头草 发表于 2022-10-13 21:15
学习一下,看看
5#
agthe 发表于 2022-10-13 21:28
学习一下,看看
6#
88886 发表于 2022-10-13 21:54
好厉害&#128077;&#127995;
7#
mars2794 发表于 2022-10-14 01:58
感谢分享,学习了~~
8#
青春小韭菜 发表于 2022-10-14 03:37
学习了学习了
9#
smile1234 发表于 2022-10-14 07:01
受益匪浅
10#
dragonxash 发表于 2022-10-14 08:28
请问师傅  Xposed Hook 反映射 是什么意思
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-28 05:05

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表