xposed概观与初步使用

前言

最近先后尝试了各种手写nativehook,开始还好,写到后面越发艰难,最后参看2011年的古河代码后无果,于是决定先使用好常用的hook框架,再针对开源的代码去研究轮子。
hook的好处十分多,如可以不修改不重打包逆向程序,而且可以避免反调试和各种壳,但hook时需要详细知道目标函数的符号等信息。

目前认准有三:
1、XPOSED 开源
优点:
1)、代码编写方便,开发速度较快。
2)、有许多现成的模块可以用,而且很多模块也是开源的,方便学习研究。
缺点:
1)、每次编写代码需要重启手机生效。
2)、不支持native的HOOK。
3)、独立性较差,需要依赖XPOSED installer,不易单独分发。

2、cydia substrate 不开源
这个Supported on versions 2.3 through 4.3的android。在ios上表现很好,android的2013年就停更了。
优点:
1)、比较擅长在native层的HOOK。
2)、独立性较好,实现的功能可以封装在单独APP里分发给用户使用,因此也是较大型外挂辅助工具的首选。
缺点:
1)、每次编写代码需要重启手机生效。
2)、开发效率较低,成本较高。

3、frida 开源
优点:
1)、无须重启手机和目标APP,这个可以节省很多时间,如果APP测试的点需要很复杂地搭建好环境,一旦重新启动就意味着很麻烦地再重新搭建环境,例如账号登录,进入特定关卡等。
2)、JS脚本编写,灵活方便,再也不用担心多参数个数和类型问题了。
3)、可以直接使用或修改对象的成员变量,非常方便。
4)、配合PC终端命令行使用,脚本编写出错也不会导致APP崩溃,只需修改后重新来过即可,有时会有问题,这个时候需要重启下APP或手机即可。

缺点:
1)、JS脚本套在python脚本里面,编写JS脚本时候不是很方便,容易出错,好在即使出错也不会导致APP崩溃掉,修改后重新来过即可。
2)、该工具配合PC终端使用,更适合专业者,不利于分发给用户使用。

接下来依次尝试之。

Xposed 原理

通过替换/system/bin/app_process程序控制zygote进程,使得app_process在启动过程中会加载XposedBridge.jar这个jar包,从而完成对Zygote进程及其创建的Dalvik虚拟机的劫持。

项目梳理:
XposedBridge.jar:XposedBridge.jar是Xposed提供的jar文件,负责在Native层与FrameWork层进行交互。/system/bin/app_process进程启动过程中会加载该jar包,其它的Modules的开发与运行都是基于该jar包的。
Xposed:Xposed的C++部分,主要是用来替换/system/bin/app_process,并为XposedBridge提供JNI方法。
XposedInstaller:Xposed的安装包,负责配置Xposed工作的环境并且提供对基于Xposed框架的Modules的管理。在安装XposedInstaller之后,app_process与XposedBridge.jar放置在了/data/data/de.robv.android.xposed.installer。

Xposed 安装

因为要修改系统文件,所以前提需要root
经实践发现supersu卡刷非常管用。

root后安装xposed installer ,进入应用,点击install安装框架(via那个是通过recovery模式安装)

到此hook框架已经安装完成。可以自己编写模块使用了

AS下的Xposed编程

创建工程

不必有activity,一个空项目就好

1导入包

俩种方式:

  1. 把下好的api-82.jar放到lib下,并添加到build.gradle路径中
  2. 由于以传至jcenter()库所以在build.gradle的dependencies下直接写compileOnly ‘de.robv.android.xposed:api:82’

注意接口包不能包含到插件项目的生成包中。

1
2
3
4
5
6
7
8
9
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
compileOnly 'de.robv.android.xposed:api:82'
compileOnly 'de.robv.android.xposed:api:82:sources' 方便Ctrl+Q快速查阅
}

注意为compileOnly,区别:
2.x(3.x)

  1. (implementation):只能在内部使用此模块,会参与打包,比如我在一个libiary中使用implementation依赖了gson库,然后我的主项目依赖了libiary,那么,我的主项目就无法访问gson库中的方法。
  2. compile(api):使用该方式依赖的库将会参与编译和打包。 也就是全部包含进dex中。又打包又用
  3. provided(compileOnly):只在编译时有效,不会参与打包 。运行时寻找android平台上的,只用不打包
  4. apk(runtimeOnly):只在生成apk的时候参与打包,编译时不会参与。不用只打包。
  5. testCompile(testImplementation):testCompile 只在单元测试代码的编译以及最终打包测试apk时有效。
  6. debugCompile(debugImplementation):debugCompile 只在debug模式的编译和最终的debug apk打包时有效
  7. releaseCompile:Release compile 仅仅针对Release 模式的编译和最终的Release apk打包。

API 类真正的实现则在 Xposed FramWork中。所以选择compileOnly
jar为.class集合。

2改manifest

AndroidManifest.xml中添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data
android:name="xposedmodule"
android:value="true"/>
<meta-data
android:name="xposeddescription"
android:value="Easy example"/>
<meta-data
android:name="xposedminversion"
android:value="54"/>
</application>

xposedmodule:代表的是Android程序作为Xposed中的一个模块,所以值为true;
xposeddescription:代表的是对本模块的功能的描述,可以自己简单叙述下就可以了;项目名是插件名,这是底下的描述
xposedminversion:代表的是本模块开发时用到的xposed的jar包的最低版本号;

3java中写类

只要新建一个实现IXposedHookLoadPackage接口的类,然后在handleLoadPackage回调方法中进行拦截操作即可,详细见下文。

1
2
3
4
5
6
7
8
9
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
public class main implements IXposedHookLoadPackage {
public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
XposedBridge.log("Loaded app: " + lpparam.packageName);
}
}

4添加模块入口

告诉Xposed框架一个模块中Hook的入口

  1. main下建assets文件夹
  2. assets文件夹下建xposed_init文件
  3. xposed_init中写包名.类名

main文件夹下的东西都会被打包

构建安装

构建安装apk至手机中,框架即可自动识别到模块,点击启动,重启后即可生效。

注意AS的Instant Run(闪电)是加快apk安装速度的功能,可能涉及的方面有:

  1. 优化apk大小,可能把不用的类优化掉了(xposed时小心)
  2. 热更新方法内代码
  3. 热更新资源
  4. 热更新新方法

api详解

首先是api官网:
https://api.xposed.info/reference/packages.html

android.app:有关当前应用程序信息的方法。
android.content.res:包含替换资源所需的类。
de.robv.android.xposed:包含Xposed框架的主要类。
de.robv.android.xposed.callbacks:包含回调的基类。
de.robv.android.xposed.services:包含Xposed框架提供的文件访问服务。

android.app

就一个AndroidAppHelper类,用于查询当前应用程序信息的各种方法

de.robv.android.xposed

这个是主要功能包
IXposedHookLoadPackage接口:这个接口应该由模块的主类来实现。Xposed会自动注册为回叫。在每个app加载时收到通知。其唯一方法在加载时调用:void handleLoadPackage (XC_LoadPackage.LoadPackageParam lpparam)参数为de.robv.android.xposed.callbacks包中XC_LoadPackage的子类,其为包装关于正在加载的应用程序的信息的类。可返回packageName,classLoader等

里面还有:XposedHelpers静态类用于简化hook如:findAndHookMethod

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
public static XC_MethodHook.Unhook findAndHookMethod (String className, ClassLoader classLoader, String methodName, Object... parameterTypesAndCallback)
参数为:
1. 类名
2. 类加载器
3. 目标方法名称
4. 参数类型与回调函数
官方示例:
public class Tutorial implements IXposedHookLoadPackage {
public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
if (!lpparam.packageName.equals("com.android.systemui"))
return;
findAndHookMethod("com.android.systemui.statusbar.policy.Clock", lpparam.classLoader, "updateClock", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
String oldText = (String) param.args[0];
Log.d("MyModule", oldText);
param.args[0] = "test";
param.args[1] = 42; // auto-boxing is working here
setBooleanField(param.args[2], "great", true);//设置类的字段XposedHelpers中
// 这样写不行,因为myclass编译时未知
// MyClass myClass = (MyClass) param.args[2];
// myClass.great = true;
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
TextView tv = (TextView) param.thisObject;
String text = tv.getText().toString();
tv.setText(text + " :)");
tv.setTextColor(Color.RED);
}
});
}
}

XC_MethodHook钩子类,其含俩个方法用于目标方法之前与之后调用,其有俩个内部类:
MethodHookParam可获得参数(字段args数组)与返回信息(方法)
XC_MethodHook.Unhook管理hook用。可用来删除回调

具体灵活使用还是需要系统框架源码知识和xposed源码实现原理。