Pine是一个在虚拟机层面、以Java方法为粒度的运行时动态hook框架,它可以拦截本进程内几乎所有的java方法调用。
目前它支持Android 4.4(只支持ART)~ 11.0 与 thumb-2/arm64 指令集。
关于它的实现原理,可以参考本文。
注:在Android 6.0 & 32位架构上,参数解析可能错误;另外在Android 9.0及以上,Pine会关闭系统的隐藏API限制策略。
JCenter似乎已停止接收新的包,请添加以下行到您的根build.gradle中:
repositories {
maven {
url "https://dl.bintray.com/canyie/pine"
}
}
Bintray 和 JCenter 即将停止服务. 我们正在寻找一个替代品,但在这之前,请使用bintray。
在 build.gradle 中添加如下依赖:
dependencies {
implementation 'top.canyie.pine:core:<version>'
}
配置一些基础信息:
PineConfig.debug = true; // 是否debug,true会输出较详细log
PineConfig.debuggable = BuildConfig.DEBUG; // 该应用是否可调试,建议和配置文件中的值保持一致,否则会出现问题
然后就可以开始使用了。
几个例子:
例子1:监控Activity onCreate(注:仅做测试使用,如果你真的有这个需求更建议使用registerActivityLifecycleCallbacks()
等接口)
Pine.hook(Activity.class.getDeclaredMethod("onCreate", Bundle.class), new MethodHook() {
@Override public void beforeCall(Pine.CallFrame callFrame) {
Log.i(TAG, "Before " + callFrame.thisObject + " onCreate()");
}
@Override public void afterCall(Pine.CallFrame callFrame) {
Log.i(TAG, "After " + callFrame.thisObject + " onCreate()");
}
});
Pine.CallFrame就相当于Xposed的MethodHookParams。
例子2:拦截所有java线程的创建与销毁:
final MethodHook runHook = new MethodHook() {
@Override public void beforeCall(Pine.CallFrame callFrame) throws Throwable {
Log.i(TAG, "Thread " + callFrame.thisObject + " started...");
}
@Override public void afterCall(Pine.CallFrame callFrame) throws Throwable {
Log.i(TAG, "Thread " + callFrame.thisObject + " exit...");
}
};
Pine.hook(Thread.class.getDeclaredMethod("start"), new MethodHook() {
@Override public void beforeCall(Pine.CallFrame callFrame) {
Pine.hook(ReflectionHelper.getMethod(callFrame.thisObject.getClass(), "run"), runHook);
}
});
例子3:允许任何线程更改UI(注:绝对不建议在任何APP中使用):
Method checkThread = Class.forName("android.view.ViewRootImpl").getDeclaredMethod("checkThread");
Pine.hook(checkThread, MethodReplacement.DO_NOTHING);
Pine支持以Xposed风格hook方法和加载Xposed模块(注:目前不支持资源hook等)。
添加依赖:
implementation 'top.canyie.pine:xposed:<version>'
(注:Xposed支持需要依赖core)
然后你可以直接以Xposed风格hook方法:
XposedHelpers.findAndHookMethod(TextView.class, "setText",
CharSequence.class, TextView.BufferType.class, boolean.class, int.class,
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
Log.e(TAG, "Before TextView.setText");
param.args[0] = "hooked";
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Log.e(TAG, "After TextView.setText");
}
});
也可以使用:
XposedBridge.hookMethod(target, callback);
也可以直接加载Xposed模块:
// 1. load modules
PineXposed.loadModule(new File(modulePath));
// 2. call all 'IXposedHookLoadPackage' callback
PineXposed.onPackageLoad(packageName, processName, appInfo, isFirstApp, classLoader);
借助Dobby, 你可以使用一些增强功能:
implementation 'top.canyie.pine:enhances:0.0.1'
- Delay hook (也称为pending hook), hook静态方法无需立刻初始化它所在的类,只需要加入以下代码:
PineEnhances.enableDelayHook();
-
可能不兼容部分设备/系统。
-
由于#11,我们建议尽量hook并发较少的方法,举个例子:
public static void method() {
synchronized (sLock) {
methodLocked();
}
}
private static void methodLocked() {
// ...
}
在这个例子里,我们更建议hook methodLocked
而非 method
。
- 更多请参见issues。
- SandHook
- Epic
- AndroidELF:本项目使用了的ELF符号搜索库
- FastHook
- YAHFA
- Dobby
- LSPosed
- libcxx-prefab
AndroidELF Copyright (c) Swift Gan
根据 反996许可证 1.0版 (下文称“此许可证”)获得许可。
除非遵守此许可证,否则不得使用本Pine项目。
您可以在以下位置找到此许可证的副本: