java的hook与so完全不同了,目前有xposed和substrate两种框架来帮助hook住java函数,我介绍下前者的使用,后者我使用过一次把机器搞成砖头了,囧,暂时不去碰他。(源码:http://pan.baidu.com/s/1o7wTIuI)
关于实现原理以后我研究好了再补充上去。
xposed文档:
xposed api jar包:
xposed 框架apk:
xposed框架采用了模块安装的方式来进行功能扩展,因此其提供了一个apk来管理功能模块,开发者可以自己写一个模块来实现对应功能,该apk内部还可以下载社区别人提交的模块。
环境:root过的手机
步骤:
1、安装xposed的框架apk,点击“框架”->“安装/更新”,然后重启(
这里最好选择稳定版本,见链接的“Release type”,如果某个xposed版本在你手机上有问题,就试试其他版本了,我用的是2.6.1版本);
这一步xposed会替换系统的一些程序,如system/bin/app_process,了解android的都知道这个程序是启动安卓程序的入口。
2、重启以后,如果界面上没有提示你“xposed框架未被激活...”之类的红色文字,就说明成功注入了xposed框架,
如果有红色错误提示,一般来说到“设置”->勾选“禁用资源钩子”就可以解决了;成功注入以后,可以选择到“下载模块”去下载模块,然后到“模块”下去勾选上模块,再次重启即可。
3、编写自己的模块:
3.1、eclipse创建一个工程,去掉Acyivity类,我们不需要界面;新建一个lib目录,把xposed api jar包加进去,然后右键“build path”->“add to build path”(
注意:不要把jar包放在libs目录下,否则会被exlipse编译到class文件里面去,这会导致后面运行出现IllegalAccessError错误)
3.2、创建模块入口类:
package com.example.xposedHook;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import de.robv.android.xposed.XposedHelpers;
/**
* Created by luowp@warthog.cn on 2015/12/21.
*/
public class Hook implements IXposedHookLoadPackage {
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
XposedBridge.log("Loaded app: " + lpparam.packageName);
XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", lpparam.classLoader, "getDeviceId", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
// this will be called before the clock was updated by the original method
XposedBridge.log("getDeviceId before\n");
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
// this will be called after the clock was updated by the original method
XposedBridge.log("getDeviceId after\n");
param.getResult();
param.setResult("luowp");
}
});
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import de.robv.android.xposed.XposedHelpers;
/**
* Created by luowp@warthog.cn on 2015/12/21.
*/
public class Hook implements IXposedHookLoadPackage {
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
XposedBridge.log("Loaded app: " + lpparam.packageName);
XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", lpparam.classLoader, "getDeviceId", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
// this will be called before the clock was updated by the original method
XposedBridge.log("getDeviceId before\n");
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
// this will be called after the clock was updated by the original method
XposedBridge.log("getDeviceId after\n");
param.getResult();
param.setResult("luowp");
}
});
//hook static variable with reflect
Field model = Build.class.getDeclaredField("MODEL");
model.setAccessible(true);
model.set(Build.class, "sbsbsb");
}
}
很简单,我这里hook的是TelephonyManager类的getDeviceId方法,两个重载的方法,before和after分别回调于call原始实现之前和之后,所以我们可以在before方法里面修改参数(param.args)或者在after方法里面修改返回值(param.setResult);
3.3、告知xposed框架我们的入口类,在assets目录下建一个文件xposed_init,里面用一行com.example.xposedHook.Hook来告知xposed;
然后,安装该木块到手机上,再到xposed的apk上,我们就可以在"模块"下看到我们的模块了,勾选上然后重启(囧:这里就是不断重启手机,比hook so蛋疼多了)。
好了,最后我们写一个测试app来测试下getDeviceId函数是否被成功hook了:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
InetSocketAddress net = new InetSocketAddress(9000);
int port = net.getPort();
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
String ua = tm.getDeviceId();
hook静态常量:
由于xposed是在每个虚拟机启动的时候来执行,因此我们可以借助它+反射机制来完成对系统常量的替换,如上面的代码替换掉了Build.MODEL的值