Thresher 发表于 2022-10-17 21:05:31

多层Android锁机样本分析5

# 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 {
    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.length];
            int v;
            for(v = 0; v < arr2_v.length; ++v) {
                int v1;
                for(v1 = 0; v1 < arr2_v.length; ++v1) {
                  arr2_v1 = arr2_v;
                }
            }

            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.length];
            int v2;
            for(v2 = 0; v2 < arr2_v2.length; ++v2) {
                int v3;
                for(v3 = 0; v3 < arr2_v2.length; ++v3) {
                  arr2_v3 = arr2_v2;
                }
            }

            int v4;
            for(v4 = 0; v4 < arr2_v1.length; ++v4) {
                int v5 = MyService.this.b + arr2_v1;
                MyService.this.c = v5;
                int v6;
                for(v6 = 0; v6 < arr2_v3]; ++v6) {
                  int v7 = MyService.this.d + arr2_v1 + arr2_v3];
                  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) {
                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.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.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.length; ++v1) {
                arr2_v1 = arr2_v;
            }
      }

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

      int v4;
      for (v4 = 0; v4 < arr2_v1.length; ++v4) {
            int v5 = 0 + arr2_v1;
            c = v5;
            int v6;
            for (v6 = 0; v6 < arr2_v3]; ++v6) {
                int v7 = d + arr2_v1 + arr2_v3];
                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) {
            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 & 0xFF) > 15) {
                  stringBuffer0.append(String.format("%x", new Byte(arr_b)));
                }
                else {
                  stringBuffer0.append(String.format("0%x", new Byte(arr_b)));
                }

                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.toInt() and 0xFF > 15) {
            stringBuffer0.append(String.format("%x", arr_b))
      } else {
            stringBuffer0.append(String.format("0%x", arr_b))
      }
      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()
    }
```



yuwenming 发表于 2023-9-14 20:44:02

很顶啊这个帖子{:6_176:}
页: [1]
查看完整版本: 多层Android锁机样本分析5