# 某查 Token Xposed+Sekiro 升级方案

Xposed Frida 对比

当涉及到安卓逆向工程中的Xposed和Frida时,它们都有各自的优点和缺点。下面是对它们进行详细比较:

Xposed Frida
实现原理 通过修改应用程序的DEX文件来实现对应用程序的修改和扩展 通过在应用程序中注入JavaScript代码来实现对应用程序的修改和扩展
安装配置 需要安装Xposed框架和相应的模块 需要在设备上安装Frida服务器和Frida客户端
功能定制 通过选择和启用/禁用不同的Xposed模块来实现功能定制 可以使用JavaScript代码实现对应用程序的定制
兼容性 需要与特定版本的安卓系统兼容 支持多种安卓版本和架构
开发门槛 需要了解Xposed框架和模块开发的基本知识 需要了解JavaScript和Frida的API
功能强大性 提供丰富的Xposed模块和功能扩展 具有更灵活的动态插桩和功能定制能力
性能影响 可能对应用程序的性能产生一定影响 对应用程序的性能影响较小

Xposed的优势在于它提供了丰富的Xposed模块,可以直接选择和启用/禁用这些模块来实现功能定制。它的兼容性取决于与特定版本的安卓系统的兼容性,但在兼容的情况下,它可以对应用程序进行较为深入的修改。

Frida的优势在于它具有更灵活的动态插桩和功能定制能力。通过注入JavaScript代码,开发者可以对应用程序的函数进行替换、监视和调用,实现更细粒度的修改。Frida支持多种安卓版本和架构,因此在兼容性方面更加灵活。

Xposed 开发

创建项目

打开 AndroidStudio,简单的 Xposed 插件不需要任何Activity。

image-20230719191310926

image-20230719191455045

选择 Project 模式

image-20230719191536460

熟悉目录

目录如下

image-20230719191932153

下面是对上述文件夹目录的详细介绍:

  • app 目录是 Android 项目的主要目录,包含应用的主要代码和资源文件。

    • build.gradle 是应用的构建脚本,用于配置构建过程和依赖项。
    • libs 目录用于存放应用所需的第三方库文件(例如 JAR 文件)。
    • proguard-rules.pro 是 ProGuard 的规则文件,用于代码混淆和优化。
    • src 目录包含应用的源代码和资源文件。
      • androidTest 目录用于存放应用的 Android 测试代码。
        • java 目录是存放 Android 测试代码的 Java 源代码目录。
      • main 目录是主要的源代码目录,包含应用的主要逻辑和资源。
        • AndroidManifest.xml 是 Android 应用的清单文件,包含应用的配置信息和组件声明。
        • java 目录是存放应用的 Java 源代码的目录。
          • com.example.app 是你在创建项目时指定的包名,你的 Java 代码文件应该放在这个目录或其子目录中。
        • res 目录是存放应用的资源文件的目录。
      • test 目录用于存放应用的单元测试代码。
        • java 目录是存放应用的单元测试代码的 Java 源代码目录。
  • build.gradle 是项目的根级构建脚本,用于配置整个项目的构建过程和依赖项。

  • gradle 目录是存放 Gradle 构建工具的目录。

    • wrapper 目录包含 Gradle Wrapper 相关的文件,用于自动下载和运行指定版本的 Gradle。
      • gradle-wrapper.jar 是 Gradle Wrapper 的 JAR 文件。
      • gradle-wrapper.properties 是 Gradle Wrapper 的配置文件。
  • gradle.properties 是项目的 Gradle 配置文件,用于定义项目级的属性和变量。

  • gradlewgradlew.bat 是可执行的 Gradle Wrapper 脚本,用于在命令行中运行 Gradle 命令。

  • local.properties 是本地配置文件,用于指定 Android SDK 的路径。

  • settings.gradle 是项目的设置文件,用于配置项目的模块和构建选项。

初始配置

引入 Jar包

将下载好的 Jar 包直接拉入 app/libs

image-20230719193010637

然后右键选这个再点 Ok ,这样才能在代码中引入Jar 包

image-20230719193208927

build.gradle

打开 app 目录下的 build.gradle

会发现dependencies多了两行,为了只编译不打包,节省空间,删掉这行

1
2
implementation files('libs/XposedBridgeApi-82.jar')
implementation files('libs/sekiro-open-demo-0.0.1.jar')

然后引入

1
2
3
implementation 'com.virjar:sekiro-api:1.0.1'
compileOnly 'de.robv.android.xposed:api:82' // 设置只编译不打包
implementation('cn.iinti.sekiro3.business:sekiro-business-api:1.1')

最终是

1
2
3
4
5
6
7
8
dependencies {
implementation 'com.virjar:sekiro-api:1.0.1'
compileOnly 'de.robv.android.xposed:api:82' // 设置只编译不打包
implementation('cn.iinti.sekiro3.business:sekiro-business-api:1.1')
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
testImplementation 'junit:junit:4.13.2'
}

在 android 下增加packagingOptions

最终是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
android {
namespace 'com.example.tychook'
compileSdk 33

packagingOptions {

exclude'META-INF/INDEX.LIST'
exclude'META-INF/io.netty.versions.properties'

}

defaultConfig {
applicationId "com.example.tychook"
minSdk 24
targetSdk 33
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

settings.gradle

打开根目录下的settings.gradle文件,我们需要引入Xposed和 Sekiro的库

在dependencyResolutionManagement下的repositories添加

1
2
3
4
5
6
repositories {
google()
mavenCentral()
maven { url 'https://api.xposed.info/' }
maven { url "https://nexus.iinti.cn/repository/maven-public/" }
}

AndroidManifest.xml

在 app/src/main/AndroidManifest.xml 添加 xposed文件描述,并指出这是一个 xposed 插件,直接复制即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
tools:targetApi="31" >
<!-- 是否为Xposed模块 -->
<meta-data
android:name="xposedmodule"
android:value="true"/>
<!-- 模块的简介(在框架中显示) -->
<meta-data
android:name="xposeddescription"
android:value="我是Xposed模块简介" />
<!-- 模块最低支持的Api版本 一般填54即可 -->
<meta-data
android:name="xposedminversion"
android:value="82"/>
</application>

</manifest>
  • xposedmodule 表明是一个xposed模块
  • xposeddescription 描述
  • xposedminversion API version(一般等于构建它的Xposed的version)

核心代码

Class 文件

右键,新建一个 ClassHookStart

image-20230719194859725

Sekiro 代码

Sekiro 长链接代码参考 官网 demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class XposedMain implements IXposedHookLoadPackage {

@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) {
if (loadPackageParam.processName.equals("cn.iinti.sekiroApp")) {// 请注意,一般sekiro只作用于特定的app
new SekiroClient("test_xposed", UUID.randomUUID().toString())
.setupSekiroRequestInitializer((sekiroRequest, handlerRegistry) ->
handlerRegistry.registerSekiroHandler(new ActionHandler() {
@Override
public String action() {
return "testAction";
}

@Override
public void handleRequest(SekiroRequest sekiroRequest, SekiroResponse sekiroResponse) {
sekiroResponse.success("ok");// 接口处理逻辑,我们不做任何处理,直接返回字符串:ok
}
})
).start();
}
}
}

不一样的是,我们需要用SekiroClient另一个重写版本,直接看源码即可,直接看截图

image-20230719195656473

最终Hook代码

写入我们的 Hook 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.example.testxp;
import android.util.Log;
import java.util.UUID;
import cn.iinti.sekiro3.business.api.SekiroClient;
import cn.iinti.sekiro3.business.api.interfaze.ActionHandler;
import cn.iinti.sekiro3.business.api.interfaze.SekiroRequest;
import cn.iinti.sekiro3.business.api.interfaze.SekiroResponse;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
public class HookStart implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
// 过滤不必要的应用
if (!loadPackageParam.packageName.equals("com.tianyancha.skyeye")) return;
new SekiroClient("xposed", UUID.randomUUID().toString(),"自己的服务器地址",5621)
.setupSekiroRequestInitializer((sekiroRequest, handlerRegistry) ->
handlerRegistry.registerSekiroHandler(new ActionHandler() {
@Override
public String action() {
return "tycHeaderAuth";
}
@Override
public void handleRequest(SekiroRequest sekiroRequest, SekiroResponse sekiroResponse) {
// 主动调用 com.tianyancha.base.utils.g3 下的 a0 方法
Class<?> targetClass = XposedHelpers.findClass("com.tianyancha.base.utils.g3", loadPackageParam.classLoader);
String res = (String) XposedHelpers.callStaticMethod(targetClass, "a0");
sekiroResponse.success(res);
}
})
).start();
Log.e("zyb","注入连接成功!");

}
}

xposed_init

告诉XposedBridge hook入口在哪里,在app/src/main目录下创建assets文件夹,在assets文件夹内创建文件xposed_init, 该文件每行包含一个class的全限定名,在这里文件内容为:

1
com.example.testxp.HookStart

构建

如图,右上角构建完成后,如果显示 finished,就直接去文件夹找 app-debug.apk,此时一个 xposed 插件就已经开发完成了。

image-20230719200138925

结尾

将 插件安装到手机后看到 Logcat 输出链接成功,即可!

image-20230719201058345

此时我们调用一下 Sekiro 接口

image-20230719201200621

大功告成了~