前段时间用到点系统底层框架去HOOK安卓在JAVA层的流程函数,期间目标函数参数有简单类型也有复杂的数组参数,着实为HOOK时的传参头疼过一把,加上有个朋友之前也在某群问过相关的问题就组合当时网友给的提示自己来实现一次这个过程,顺便介绍下该框架插件的基本开发姿势,同时希望也可以为广大HOOK友们提供一点解决问题的根本办法。
上面说过用成熟的框架,现在在安卓上好用的扩展性框架不过两种:Xposed跟Cydia,由于本人只用过XPOSED框架所以在这篇文章中就用Xposed来给大家介绍使用,开发知识方面只要有基本的安卓经验皆可胜任,并没有什么技术含量。
一、HOOK 三要素:类对象、函数名、参数列表的获取。
二、构建XPOSED框架插件、编码完成测试。
这其中难点有两个,一个就是Xposed插件没开发过,网上的一些教程文章没有写得太详细,一些个小细节没有被重点提及导致一个小问题都要查找无数的资料,甚至还找不到问题所在,另一个就是网上示例都太过简单化,一般都用int\sting这种基本类型作为Demo,然而实际使用中难免会碰到一些稀奇古怪的函数参数,而没有经验的我们只能乱写一通,到最后只能不了了之,现在我想通过由浅入深的方式来记录下插件的开发过程,希望能为遇到这种情况的朋友们提供点小帮助吧。
一、HOOK JAVA层函数的三要素获取:
这其中目标类对象、函数名相信大家要拿到没有难度,问题的重点就在于函数的参数列表,在介绍插件开发步骤前,先来看看我们首要目标类及函数参数情况,截图如下:
目标类路径为:aqcxbom.xposedhooktarget;
函数名为:helloWorld
参数表:int,string
在xposedhooktarget的onCreate方法中调用输出
当前未hook前输出log前后如下:
我们要实现的目标是分别在前后调用输出入咱自己的日志信息,如下面两箭头所指:
好,明确了我们初步的目标后,现在咱来看看XPOSED框架插件开发步骤:
以provided 模式导入 lib 文件 XposedBridgeApi-54.jar(不参与编译到最终文件中)且用AS开发的你千万不要将其放在libs目录中,否则你会发现你的插件安装上却一直没有运行起来的尴尬情况(大坑一)。
在AndroidManifest.xml中添加框架信息。
<application>
<meta-data android:name="xposedmodule" android:value="true"/>
<meta-data android:name="xposeddescription" android:value="这里填写模块说明信息"/>
<meta-data android:name="xposedminversion" android:value="30"/>
</application>
xposedminversion这一项非常重要,必须与JAR内版本一致,否则模块不能运行。(大坑二)
你可以用RAR等压缩工具打开XposedBridgeApi-XX.jar包,在assets\version文件中包含了该包的版本号,这个版本号正常情况下会与jar包名内的版本保持一致。
IXposedHookLoadPackage
接口handleLoadPackage
函数方法:handleLoadPackage
函数的findAndHookMethod
方法我们要提供HOOK目标的信息,参数为(类全路径,当前的CLASSLOADER
,HOOK
的函数名,参数1类类型...参数N类类型,XC_MethodHook
的回调),具体代码如下:package aqcxbom.myxposed;
import android.util.Log;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
/**
* Created by AqCxBoM on 2016/12/24.
*/
//实现该类方法的类在注册为Xposed插件后会被框架自动调用
public class XposedMain implements IXposedHookLoadPackage
{
public String TAG = "AqCxBoM" ;
private final String mStrPackageName = "aqcxbom.xposedhooktarget"; //HOOK APP目标的包名
private final String mStrClassPath = "aqcxbom.xposedhooktarget.MyClass"; //HOOK 目标类全路径
private final String helloworld = "helloWorld"; //HOOK 目标函数名
private void LOGI(String ct){ Log.d(TAG, ct); }
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
//对比此时加载的包名是否与目标包名一致
if (loadPackageParam.packageName.equals(mStrPackageName)) {
LOGI("found target: " + loadPackageParam.packageName);
// findAndHookMethod方法用于查找匹配HOOK的函数方法,这里参数为HOOK的目标信息
XposedHelpers.findAndHookMethod(mStrClassPath, //类全路径
loadPackageParam.classLoader, //ClassLoader
helloworld, //HOOK目标函数名
int.class, //参数1类型
String.class, //参数2类型(这里目标函数有多少个参数就多少个,与HOOK目标函数保持一致)
new XC_MethodHook() { //最后一个参数为一个回调CALLBACK
@Override //故名思意,这个函数会在目标函数被调用前被调用
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
LOGI("beforeHook");
}
@Override//这个函数会在目标函数被调用后被调用
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
LOGI("afterHooke param: ");
}
});
}
}
}
新建assests 文件夹,并在其中新建 xposed_init 文件,写入插件入口类的信息
aqcxbom.myxposed.XposedMain
=============================我是墙裂的分割线================================================================
对于上面的函数参数为基本数据类型(INT\STRING)我们都能快速搞定,但如果函数的参数如果是数组、Map、ArrayList这种复杂类型大家是不是就瞬间懵逼了呢,下面我们就来假设有如下这个情况:
我们的目标MyClass类的fun1函数,先看一下参数原型声明:
public static boolean fun1(String[][] strAry, Map mp1, Map<String,String> mp2, Map<Integer, String> mp3,
ArrayList<String> al1, ArrayList<Integer> al2, ArgClass ac)
摆在我们面前的问题是这个参数该怎么写?
这个问题让我来解决的话,我会想让安卓APP告诉我该怎么写,所以用反射调用的方式(具体的调用方式可以查看示例(XposedHookTarget的ShowDeclaredMethods方法)打印出这个函数的参数列表输出如下:
([[Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/ArrayList;Ljava/util/ArrayList;Laqcxbom/xposedhooktarget/ArgClass;)
这一看很清晰嘛,总结如下:
String[][] ==> [[Ljava/lang/String;
Map数组不论何种形式 ==> Ljava/util/Map;
ArrayList 无论何种形式 ==> Ljava/util/ArrayList;
ArgClass ac 自定义类给个全路径的事==> Laqcxbom/xposedhooktarget/ArgClass;
但实际上并不是这么一回事,各种类找不到(Ljava/util/ArrayList; Ljava/util/Map; Laqcxbom/xposedhooktarget/ArgClass;)
那么正确的姿势该怎么呢?答案是通过上面找到的类路径,用Xposed自身提供的XposedHelpers的findClass方法加载每一个类,然后再将得到的类传递给hook函数作参数!
示例代码如下:
package aqcxbom.myxposed;
import android.util.Log;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
/**
* Created by AqCxBoM on 2016/12/24.
*/
public class XposedMain implements IXposedHookLoadPackage
{
public String TAG = "AqCxBoM" ;
private final String mStrPackageName = "aqcxbom.xposedhooktarget"; //HOOK APP目标的包名
private final String mStrClassPath = "aqcxbom.xposedhooktarget.MyClass"; //HOOK 目标类全路径
private final String mStrMethodName = "fun1"; //HOOK 目标函数名
private void LOGI(String ct){ Log.d(TAG, ct); }
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
//判断包名是否一致
if (loadPackageParam.packageName.equals(mStrPackageName)) {
LOGI("found target: " + loadPackageParam.packageName);
final Class<?> ArgClass= XposedHelpers.findClass("aqcxbom.xposedhooktarget.ArgClass", loadPackageParam.classLoader);
final Class<?> ArrayList= XposedHelpers.findClass("java.util.ArrayList", loadPackageParam.classLoader);
final Class<?> Map= XposedHelpers.findClass("java.util.Map", loadPackageParam.classLoader);
//包名一致时查找是否有匹配参数的类及函数
XposedHelpers.findAndHookMethod(mStrClassPath, //类路径
loadPackageParam.classLoader, //ClassLoader
mStrMethodName, //目标函数名
"[[Ljava.lang.String;", //参数1
Map, //参数2
Map, //参数3
Map, //参数4
ArrayList, //参数5
ArrayList, //参数6
ArgClass, //参数7
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param); //这个函数会在被hook的函数执行前执行
LOGI("beforeHook");
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);//这个函数会在被hook的函数执行后执行
LOGI("afterHooke param: ");
}
});
}
}
}
编译安装,重启并运行我们的target程序得到HOOK成功的效果图
至此,我想就算遇到再复杂的参数类型,朋友们都能游刃有余地解决了吧,如果答案是肯定的,那我这篇文件就算是达到目的了。
涉及到的源代码可以在我github上找到,有需要的朋友可以自行下载:
https://github.com/FuhuiLiu/XposedHookTarget.git
https://github.com/FuhuiLiu/MyXposed.git
PS:如果有需求想让被hook函数不执行的话可以在执行前使用 setResult(NULL)函数终止其在后续执行。
其它Xposed插件使用未详尽说明处请移步Xpose官网察看,这里就不再展开细述了。
在这里非常感谢我北京一个亦师亦友的哥们提供的资料及其零日安全论坛及团队所出品的安卓零基础逆向教材,正是有他们的引领我才能顺利开启Xposed插件开发的大门,同时也感谢网上热心网友提供的真知灼见,所查资料太多,并没有详细记录为此篇小文所翻阅的网文,只能列出一二以表谢意:
http://www.freebuf.com/articles/terminal/56453.html
http://bbs.pediy.com/showthread.php?t=202147&page=2
尤其是网友jzfcf提供的查找类对象并传参到hook函数的方法,非常的赞。