red1y 发表于 2022-10-23 19:04

某音adult_version防护分析&加密分析&邀请机制刷vip分析

本帖最后由 red1y 于 2022-10-23 19:08 编辑

### 0. 本文包括

- 防护分析:模拟器检测、root检测、反hook、反抓包等
- 加密分析:数据加密分析、身份验证的Token参数生成分析
- 设备注册逻辑分析:无限获得新帐号、绑定邀请码刷`vip`
- b站视频链接:https://www.bilibili.com/video/BV12e411V7a5/?vd_source=23b9de401c27e819abddbd5551eddbda

### 一、防护分析

1. 提示不能在模拟器里运行

   -

   - 定位检测代码

   入口:`com.niming.weipa.ui.splash.SplashActivity`

   ```java
   @Override// com.niming.weipa.base.BaseActivity
   protected void onCreate(@nullable Bundle arg2) {
         if(com.blankj.utilcode.util.e.d()) {
             com.blankj.utilcode.util.e.b(this, false);
         }
   
         super.onCreate(arg2);
         Intent v2 = this.getIntent();
         Intrinsics.checkExpressionValueIsNotNull(v2, "intent");
         if((v2.getFlags() & 0x400000) != 0) {
             this.finish();
         }
   ```

   两次`super`到父类的`onCreate`函数中,查看整个启动逻辑,定位到`initView`函数

   ```java
   @Override// androidx.appcompat.app.AppCompatActivity
   protected void onCreate(@Nullable Bundle arg5) {
         super.onCreate(arg5);
         this.supportRequestWindowFeature(1);
         /* other codes */
         this.activity = this;
         this.loadingDialogFragment = new com.niming.framework.widget.dialog.LoadingDialogFragment.a().a(true).a();
         this.pageStatusHelper = new PageStatusHelper(this, this.getPageBuilder());
         this.pageStatusHelper.a(this);
         this.init();
         this.initView(arg5); // key
   }
   ```

   回到`SplashActivity`的`initView`函数,发现`this.m()`函数

   ```java
   @Override// com.niming.weipa.base.BaseActivity
   public void initView(@Nullable Bundle arg1) {
         super.initView(arg1);
         v0.d(this);
         com.blankj.utilcode.util.e.d(this, false);
         com.blankj.utilcode.util.e.a(false);
         this.m(); // key
   }
   ```

   进入`this.m()`,发现检测逻辑

   ```java
   private final void m() {
             LogUtils.b("niming", new Object[]{"===AppUtils.isAppRoot():" + com.blankj.utilcode.util.c.isAppRoot() + " DeviceUtils.isDeviceRooted() " + w.isDeviceRoot()});
             if(!this.checkRoot() && !n.isEmulator(this.activity)) {
               if(this.checkProxy(this)) {
                     NoticeAppDialogFragment v0 = NoticeAppDialogFragment.a("检测到您使用了代{过}{滤}理软件,不允许继续使用");
                                     /* notice codes */
                     v0.c(this.activity);
                     return;
               }
   
               h.a().a("api_domain", "");
               this.i();
               return;
             }
   
             NoticeAppDialogFragment v0_1 = NoticeAppDialogFragment.a("检测到您使用的是模拟器或者设备已经root,不允许继续使用");
             /* notice codes */
             v0_1.c(this.activity);
         }
   ```

   - `root`检测方法

   1. 通过`getRuntime`尝试执行`su`命令

      ```java
      public static b a(String[] arg8, String[] arg9, boolean arg10, boolean arg11) {
            StringBuilder v8_2;
            StringBuilder v11;
            StringBuilder v10_2;
            Process v9 = null;
            BufferedReader v4 = null;
            BufferedReader v5 = null;
            DataOutputStream v10 = null;
            String v1 = "";
            int v2 = -1;
            if(arg8 != null && arg8.length != 0) {
                BufferedReader v3 = null;
                try {
                  Runtime v4_1 = Runtime.getRuntime();
                  String v10_1 = arg10 ? "su" : "sh";
                  v9 = v4_1.exec(v10_1, arg9, null);
                  v10 = new DataOutputStream(v9.getOutputStream());
                }
                        /* other codess */
      
                return new b(v2, v8_6, v1);
            }
      
            return new b(-1, "", "");
      }
      ```

   2. 检查特定目录下的`su`文件是否存在

      ```java
      public static boolean isDeviceRoot() {
            String[] v0 = {"/system/bin/", "/system/xbin/", "/sbin/", "/system/sd/xbin/", "/system/bin/failsafe/", "/data/local/xbin/", "/data/local/bin/", "/data/local/", "/system/sbin/", "/usr/bin/", "/vendor/bin/"};
            int v3;
            for(v3 = 0; v3 < v0.length; ++v3) {
                if(new File(v0 + "su").exists()) {
                  return true;
                }
            }
      
            return false;
      }
      ```

   - `emulator`检测方法

   1. 检测系统属性

      ```java
      private static final boolean c(Context arg1) {
            return "1".equals(n.a(arg1, "ro.kernel.qemu"));
      }
      ```

   2. 检测特征值

      ```java
      if((Build.MANUFACTURER.equals("unknown")) || (Build.MANUFACTURER.equals("Genymotion")) || (Build.MANUFACTURER.contains("Andy")) || (Build.MANUFACTURER.contains("MIT")) || (Build.MANUFACTURER.contains("nox")) || (Build.MANUFACTURER.contains("TiantianVM"))) {
            ++v15;
      }
      /* 很多特征值 */
      if((Build.HARDWARE.equals("goldfish")) || (Build.HARDWARE.equals("vbox86")) || (Build.HARDWARE.contains("nox")) || (Build.HARDWARE.contains("ttVM_x86"))) {
            ++v15;
      }
      /* 很多特征值 */
      if((Build.FINGERPRINT.contains("generic/sdk/generic")) || (Build.FINGERPRINT.contains("generic_x86/sdk_x86/generic_x86")) || (Build.FINGERPRINT.contains("Andy")) || (Build.FINGERPRINT.contains("ttVM_Hdragon")) || (Build.FINGERPRINT.contains("generic_x86_64")) || (Build.FINGERPRINT.contains("generic/google_sdk/generic")) || (Build.FINGERPRINT.contains("vbox86p")) || (Build.FINGERPRINT.contains("generic/vbox86p/vbox86p"))) {
            ++v15;
      }
      ```

   3. 检测`OPENGL`的属性值

      ```java
      try {
            String v2_1 = GLES20.glGetString(0x1F01);
            if(v2_1 != null) {
                if(v2_1.contains("Bluestacks")) {
                  goto label_260;
                }
                else {
                  boolean v2_2 = v2_1.contains("Translator");
                  goto label_257;
                }
            }
      }
      catch(Exception v2) {
            v2.printStackTrace();
      }
      goto label_262;
      label_257:
      if(v2_2) {
            v15 += 10;
            goto label_262;
            label_260:
            v15 += 10;
      }
      ```

   4. 检测共享文件夹

      ```java
         try {
             label_262:
             boolean v2_4 = new File(Environment.getExternalStorageDirectory().toString() + File.separatorChar + "windows" + File.separatorChar + "BstSharedFolder").exists();
         }
      catch(Exception v2_3) {
            v2_3.printStackTrace();
            n.b = v15;
            return n.b > 3;
      }
      ```

   - 处理:**hook**掉

2. **hook**失败,定位**反hook**代码

   - `SplashActivity`中没有发现相关代码,到`application`的`app` `com.niming.weipa.App` 的`onCreate`函数中寻找

   ```xml
   <application android:allowBackup="true" android:appComponentFactory="androidx.core.app.CoreComponentFactory" android:icon="@drawable/icon_douying_logo" android:label="抖x" android:name="com.niming.weipa.App"
   ```

   - 发现`disableXposed`函数 (名字当然是我改的...)

   ```java
   @Override// com.niming.framework.base_app.BaseApplication
   public void onCreate() {
         super.onCreate();
         App.u0 = this;
         if(this.a(this)) {
             g1.a(this);
             this.b();
             this.c();
             com.shuyu.gsyvideoplayer.i.c.a(com.niming.weipa.d.c.class);
             com.shuyu.gsyvideoplayer.f.a.a(com.niming.weipa.d.d.class);
                     /* other codes */
             com.lahm.library.d.disableXposed(); // 反hook
                     /* other codes */
         }
   }
   ```

   - 查看`disableXposed`实现,通过反射设置`disableHooks`字段为`true`

   ```java
   public boolean disableXposed() {
         try {
             Field v1_3 = ClassLoader.getSystemClassLoader().loadClass("de.robv.android.xposed.XposedBridge").getDeclaredField("disableHooks");
             v1_3.setAccessible(true);
             v1_3.set(null, Boolean.TRUE);
             return true;
         }
      /* exception codes return false */
   }
   ```

   - 处理:**hook掉**,在函数返回后,同样使用反射将`disableHooks`设置为`false`

3. 抓不到包,分析反抓包机制

   - 定位反抓包代码,从`app`的`onCreate`入手

   ```java
   @Override// com.niming.framework.base_app.BaseApplication
   public void onCreate() {
         super.onCreate();
         App.u0 = this;
         if(this.a(this)) {
             g1.a(this);
             this.b();
             this.c();
             com.shuyu.gsyvideoplayer.i.c.a(com.niming.weipa.d.c.class);
             com.shuyu.gsyvideoplayer.f.a.a(com.niming.weipa.d.d.class);
                     /* other codes */
             com.lahm.library.d.disableXposed(); // 反hook
                     /* other codes */
         }
   }
   ```

   - 进入`this.c()`,进行了大量关于`http`请求的配置,`AntiCapture`是我一开关注的类,后来发现这个类什么都没干;最终得出结论:抓不到包是因为设置了`NO_PROXY`属性,`app`不走系统代{过}{滤}理,因此抓不到包

   ```java
   private void c() {
         HttpHeaders v0 = new HttpHeaders();
         v0.put("User-Agent", "Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD62) AppleDart/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17");
         try {
             this.t0 = new b();
             this.t0.d(30000L, TimeUnit.MILLISECONDS);
             /* other codes */
             AntiCapture v1 = a.a(); // 这里获得有关ssl证书的参数,并在下一行设置
             this.t0.a(v1.a, v1.b); // 经过分析,这两个参数都没用,并不是反抓包的实现机制
             this.t0.a(new c());
             this.t0.a(new com.niming.weipa.app.a.a());
             this.t0.a(new com.niming.weipa.app.a.b());
             /* other codes */
             this.t0.a(new ProxySelector() {
               @Override
               public void connectFailed(URI arg1, SocketAddress arg2, IOException arg3) {
               }
   
               @Override
               public List select(URI arg1) {
                     /* 抓不到包的原因所在! */
                     return Collections.singletonList(Proxy.NO_PROXY);
                     /* 抓不到包的原因所在! */
               }
             });
             c.f.a.b.k().a(this).a(this.t0.a()).a(CacheMode.NO_CACHE).a(-1L).a(0).a(v0);
         }
         /* other codes */
   }
   ```

   - 处理:**hook掉**,在函数调用前,将参数设置为`Proxy.getDefault()`,默认走系统代{过}{滤}理

4. 签名校验

   - 生成可调试版本后,`app`会停在某个页面,通过查看日志发现是`native`层作了签名校验
   - 我一般不分析签名校验,有兴趣可以自己分析

5. 防护类分析

   - 通过`disableXposed`那个函数,发现了一个很完整的`java`层加密类,里面实现了很多的防护函数,这里完全拷贝下来,名称我都作了修改

   ```java
   package com.lahm.library;
   
   import android.content.Context;
   import android.content.Intent;
   import android.content.IntentFilter;
   import android.content.pm.PackageManager.NameNotFoundException;
   import android.content.pm.Signature;
   import android.os.Debug;
   import android.os.Process;
   import java.io.BufferedReader;
   import java.io.File;
   import java.io.FileReader;
   import java.io.IOException;
   import java.lang.reflect.Field;
   import java.net.InetAddress;
   import java.net.Socket;
   import java.net.UnknownHostException;
   import java.util.HashSet;
   import java.util.Iterator;
   
   public class i {
         static class b {
             private static final i a;
   
             static {
               b.a = new i(null);
             }
         }
   
         private static final String a = "de.robv.android.xposed.XposedHelpers";
         private static final String b = "de.robv.android.xposed.XposedBridge";
   
         private i() {
         }
   
         i(com.lahm.library.i.a arg1) {
         }
   
         public String getAppMetaData(Context arg1, String arg2) {
             return arg1.getApplicationInfo().metaData.getString(arg2);
         }
   
         public boolean isDebuggerConnected() { // 检测调试器是否连接
             return Debug.isDebuggerConnected();
         }
   
         public boolean isPortAvailable(int arg2) { // 检测端口是否被占用,可用于反调试、反hook
             try {
               return this.isNetAddressAvailable("127.0.0.1", arg2);
             }
             catch(Exception unused_ex) {
               return true;
             }
         }
   
         public boolean isApkDebuggable(Context arg1) { // 检测apk:debuggable属性是否为true
             return (arg1.getApplicationInfo().flags & 2) != 0;
         }
   
         public boolean isLibOrJarLoaded(String arg6) { // 检测加载的jar/so库
             try {
               HashSet v0 = new HashSet();
               BufferedReader v1 = new BufferedReader(new FileReader("/proc/" + Process.myPid() + "/maps"));
               while(true) {
                     String v2 = v1.readLine();
                     if(v2 != null) {
                         goto label_34;
                     }
   
                     v1.close();
                     Iterator v0_1 = v0.iterator();
                     while(true) {
                     label_24:
                         if(!v0_1.hasNext()) {
                           return false;
                         }
   
                         Object v1_1 = v0_1.next();
                         if(!((String)v1_1).contains(arg6)) {
                           goto label_24;
                         }
   
                         return true;
                     label_34:
                         if(!v2.endsWith(".so") && !v2.endsWith(".jar")) {
                           break;
                         }
   
                         v0.add(v2.substring(v2.lastIndexOf(" ") + 1));
                         break;
                     }
               }
             }
             catch(Exception unused_ex) {
               return false;
             }
         }
   
         public boolean isNetAddressAvailable(String arg2, int arg3) throws UnknownHostException {
             InetAddress v2 = InetAddress.getByName(arg2); // 检测网络地址是否可用
             try {
               new Socket(v2, arg3);
               return true;
             }
             catch(IOException unused_ex) {
               return false;
             }
         }
   
         public boolean isDeviceRooted() { //检测设备是否root,里面两个函数的实现在下面
             return this.isDeviceRootedByRoSecure() == 0 ? true : this.isDeviceRootedByFile();
         }
   
         public boolean isEmulatorByBattery(Context arg4) { // 通过检查电量检测模拟器
             Intent v4 = arg4.registerReceiver(null, new IntentFilter("android.intent.action.BATTERY_CHANGED"));
             return v4 == null ? false : v4.getIntExtra("plugged", -1) == 2;
         }
   
         public String getPackageSignature(Context arg5) { // 获取签名
             try {
               Signature[] v5_1 = arg5.getPackageManager().getPackageInfo(arg5.getPackageName(), 0x40).signatures;
               StringBuilder v0 = new StringBuilder();
               int v2;
               for(v2 = 0; v2 < v5_1.length; ++v2) {
                     v0.append(v5_1.toCharsString());
               }
   
               return v0.toString();
             }
             catch(PackageManager.NameNotFoundException v5) {
               v5.printStackTrace();
               return "";
             }
         }
   
         public boolean isXposedExistByStack() { // 通过异常栈检测Xposed框架
             try {
               throw new Exception("gg");
             }
             catch(Exception v0) {
               StackTraceElement[] v0_1 = v0.getStackTrace();
               int v3;
               for(v3 = 0; v3 < v0_1.length; ++v3) {
                     if(v0_1.getClassName().contains("de.robv.android.xposed.XposedBridge")) {
                         return true;
                     }
               }
   
               return false;
             }
         }
   
         @Deprecated
         public boolean isXposedExistByClassLoader() { // 通过类加载检测Xposed框架
             try {
               ClassLoader.getSystemClassLoader().loadClass("de.robv.android.xposed.XposedHelpers").newInstance();
             }
             catch(InstantiationException v0_1) {
               v0_1.printStackTrace();
               return true;
             }
             catch(IllegalAccessException v0) {
               v0.printStackTrace();
               return true;
             }
             catch(ClassNotFoundException v1) {
               v1.printStackTrace();
               return false;
             }
   
             try {
               ClassLoader.getSystemClassLoader().loadClass("de.robv.android.xposed.XposedBridge").newInstance();
               return true;
             }
             catch(InstantiationException v0_3) {
               v0_3.printStackTrace();
               return true;
             }
             catch(IllegalAccessException v0_2) {
               v0_2.printStackTrace();
               return true;
             }
             catch(ClassNotFoundException v1_1) {
               v1_1.printStackTrace();
               return false;
             }
         }
   
         public boolean isDebuggingByTarcePid() { // 通过TracePid检测程序是否出于被调试状态
             try {
               BufferedReader v1 = new BufferedReader(new FileReader("/proc/" + Process.myPid() + "/status"));
               String v2 = "";
               do {
               label_17:
                     String v3 = v1.readLine();
                     if(v3.contains("TracerPid")) {
                         v2 = v3.substring(v3.indexOf(":") + 1, v3.length()).trim();
                     }
                     else if(v3 != null) {
                         goto label_17;
                     }
   
                     break;
               }
               while(true);
   
               v1.close();
               return !"0".equals(v2);
             }
             catch(Exception unused_ex) {
               return false;
             }
         }
   
         public boolean disableXposed() { // disable xposed
             try {
               Field v1_3 = ClassLoader.getSystemClassLoader().loadClass("de.robv.android.xposed.XposedBridge").getDeclaredField("disableHooks");
               v1_3.setAccessible(true);
               v1_3.set(null, Boolean.TRUE);
               return true;
             }
             catch(NoSuchFieldException v1_2) {
               v1_2.printStackTrace();
               return false;
             }
             catch(ClassNotFoundException v1_1) {
               v1_1.printStackTrace();
               return false;
             }
             catch(IllegalAccessException v1) {
               v1.printStackTrace();
               return false;
             }
         }
   
         public static final i getInstance() {
             return b.a;
         }
   
         private int isDeviceDebuggable() { // ro.debuggable为1的设备可以调试任何应用,即时应用的debuggable属性为false
             String v0 = c.a().b("ro.debuggable");
             return v0 == null || !"0".equals(v0) ? 1 : 0;
         }
   
         private int isDeviceRootedByRoSecure() { // 检测ro.secure
             String v0 = c.a().b("ro.secure");
             return v0 == null || !"0".equals(v0) ? 1 : 0;
         }
   
         private boolean isDeviceRootedByFile() { // 通过文件检测设备是否root
             String[] v0 = {"/sbin/su", "/system/bin/su", "/system/xbin/su", "/data/local/xbin/su", "/data/local/bin/su", "/system/sd/xbin/su", "/system/bin/failsafe/su", "/data/local/su"};
             int v3;
             for(v3 = 0; v3 < v0.length; ++v3) {
               if(new File(v0).exists()) {
                     return true;
               }
             }
   
             return false;
         }
   
   }
   
   ```

### 二、加密分析

1. 定位加密代码

   - 这个`app`通过拦截器实现请求加密,以及携带特殊参数,通过`app`的`onCreate`,进入`this.c()`,接着定位到加密拦截器

   ```java
   private void c() {
         HttpHeaders v0 = new HttpHeaders();
         v0.put("User-Agent", "Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD62) AppleDart/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17");
         try {
            /* other codes */
             this.t0.a(new c()); // TOKEN拦截器
             this.t0.a(new com.niming.weipa.app.a.a()); // 加密拦截器
             this.t0.a(new com.niming.weipa.app.a.b());
            /* other codes */
         }
         catch(Exception v0_1) {
             v0_1.printStackTrace();
         }
   }
   ```

   - 进入`com.niming.weipa.app.a.a()`,发现其中的`b`函数

   ```java
   private b0 a(b0 arg9) {
         /* other codes */
         v1.put("data", v2);
         String v1_1 = g.a(v1);
         LogUtils.b(new Object[]{"===realParamsString: " + v1_1});
         String v1_2 = URLEncoder.encode(com.niming.weipa.utils.a.b(v1_1)); // 加密函数
         LogUtils.b(new Object[]{"===encrypt realParamsString: " + v1_2});
         new okhttp3.s.a().b("data", v1_2);
         return arg9;
   }
   ```

   - 定位到加密类`com.niming.weipa.utils.a`,使用`AES`加密,`ECB`模式,`PKCS7`的padding

   ```java
   package com.niming.weipa.utils;
   
   import android.text.TextUtils;
   import com.blankj.utilcode.util.y;
   
   public class a {
         private static String a = "";
         private static String b = "pcv#Cg1vbdl#r2hm";
         private static String c = "AES/ECB/PKCS7Padding"; // 加密算法、加密模式、padding模式
         private static String d; // 加密密钥
   
         static {
             /* other codes */
               v0 = TextUtils.equals("release", "staging") ? TestUtil.getSecretPre() : TestUtil.getSecret();
             a.d = v0;
         }
   
         public static String b(String arg3) {
             if(a.c.equals("AES/ECB/NoPadding")) {
               while(arg3.getBytes().length % 16 != 0) {
                     arg3 = arg3 + ' ';
               }
             }
   
             byte[] v0 = a.d.getBytes(); // 获得密钥
             String v1 = a.c; // 加密方式
             byte[] v3 = y.k(arg3.getBytes(), v0, v1, null);
             return v3 == null ? "" : new String(v3);
         }
   }
   ```

2. 获得加密密钥

   - 密钥通过`native`函数获得,可通过`hook`方式得到加密密钥

   ```java
   package com.niming.weipa.utils;
   public class TestUtil {
         static {
             System.loadLibrary("security");
         }
         public static native String getSecret() {
         }
         public static native String getSecret2() {
         }
         public static native String getSecret3() {
         }
         public static native String getSecretPre() {
         }
         public static native String getSecretVP() {
         }
   }
   ```

3. 验证加密算法

   - 没有改动加密算法及结果,可直接通过再现网站验证

   数据 `{"data":"SaiwLbHeTk0xAbNBv8Q9cnc4os2kD8foP+3Ie57JTkc=","handshake":"v20200429"}`

   

### 三、设备注册分析

1. 本地`sqlite`数据库

   - 用户信息存储在本地`sqlite`数据库中,可以通过`sqlite3`或者导出数据的方式查看数据库数据,数据库路径为`/data/data/package_name/database/db_name`

   ```java
   package com.niming.framework.basedb;
   
   import android.content.Context;
   import androidx.room.Database;
   import androidx.room.RoomDatabase;
   import androidx.room.q1;
   
   @Database(entities = {e.class, a.class}, version = 1)
   public abstract class BaseAppDatabase extends RoomDatabase {
         private static volatile BaseAppDatabase a;
   
         static BaseAppDatabase a(Context arg2) {
             Class v0 = BaseAppDatabase.class;
             if(BaseAppDatabase.a == null) {
               synchronized(v0) {
                     if(BaseAppDatabase.a == null) {
                         BaseAppDatabase.a = (BaseAppDatabase)q1.a(arg2.getApplicationContext(), v0, "base_database").a().b();
                     }
   
                     return BaseAppDatabase.a;
               }
             }
   
             return BaseAppDatabase.a;
         }
   }
   
   ```

   - 如果本地不存在数据库以及用户信息,会触发新设备注册逻辑,可以手动删除数据库进而触发该逻辑

2. 设备注册逻辑

   - 首次注册设备时,向服务器发送的未加密数据格式为,其中`device_no`唯一标识一个设备,且在客户端生成,可以随意修改

   ```json
   {"channel":"","code":"","device_no":"cd17c0a9-1d41-3377-8b3c-2599755976f8","device_type":"A","version":"4.0.5"}
   ```

   - 在服务器返回的响应中会包含`token`,与`device_no`对应,用于生成`XTOKEN`请求头参数,作为用户身份标识,后续所有请求需携带该字段

3. `XTOKEN`认证参数生成

   - 可直接通过搜索`XTOKEN`关键字定位到生成逻辑,很简单,通过注册设备时发送给服务器的`deivce`信息以及服务器返回的`token`信息,经序列化后加密即生成了最终的`X-TOKEN`

   ```java
   @Override// okhttp3.w
   public d0 a(a arg6) throws IOException {
         /* other codes */
         HashMap v2 = new HashMap();
         v2.put("token", v0_3);
         v2.put("device_no", h.a().c("device_id"));
         v2.put("device_type", "A");
         v2.put("version", "4.0.5");
         JSONObject v3 = new JSONObject(v2);
         if(!TextUtils.isEmpty(v0_3)) {
             v1.a("X-TOKEN", com.niming.weipa.utils.a.b(String.valueOf(v3)));
         }
         return arg6.a(v1.a());
   }
   ```

4. 获得新帐号、绑定邀请码、获得`vip`

   - 在以上分析的基础上,通过不同的`device_no`,生成相应的`XTOKEN`即可拥有新用户帐号,利用该`app`邀请码绑定送`vip`机制,可以获得大量用户凭证并绑定自己的邀请码,获得持续`vip`功能,演示可以观看`bilibili`视频

freehjx1982 发表于 2022-10-28 10:33

抖音最好别老是看,1分钟 3分钟给我们大脑一个刺激,长久 我们的大脑就会习惯这种短期刺激

4825516 发表于 2022-10-24 11:18

有成品吗?发这么多也看不懂啊

ysd254 发表于 2022-10-29 22:27

真不建议大家用。让伤害从我为止。。。。。

jayfox 发表于 2022-10-24 14:58

为了反破解 作者是煞费苦心啊   各种机制都用上了

怜渠客 发表于 2022-10-24 17:51

各种检测代码可以学一下

emailsina 发表于 2022-10-24 20:48

关注学习

jokertao 发表于 2022-10-24 20:48

感谢分享

戰龍在野 发表于 2022-10-24 21:21

虽然看不懂但是要支持楼主的分享

cdroad 发表于 2022-10-24 23:06

太牛皮了!很受用

jackymark 发表于 2022-10-25 06:04


太牛皮了!很受用

sanyi 发表于 2022-10-25 09:16

干货满满
页: [1] 2 3 4 5 6 7 8 9 10
查看完整版本: 某音adult_version防护分析&加密分析&邀请机制刷vip分析