canyie / pine

Dynamic java method hook framework on ART. Allowing you to change almost all java methods' behavior dynamically.
1.03k stars 194 forks source link
android aop aop-framework art art-runtime hook hook-framework hooking java-hook xposed

Pine LICENSE

中文版本

Introduction

Pine is a dynamic java method hook framework on ART runtime, which can intercept almost all java method calls in the current process.

Currently it supports Android 4.4(ART only) ~ 15 Beta 4 with thumb-2/arm64 architecture.

About its working principle, you can refer to this Chinese article.

Note: For Android 6.0 devices with arm32/thumb-2 architectures, the arguments may be wrong; and for Android 9.0+, pine will disable the hidden api restriction policy.

The name, Pine, represents a class of antipsychotic drugs represented by Quetiapine and Clozapine. It is also an acronym for "Pine Is Not Epic".

Usage

Basic Usage

Download

Add dependencies in build.gradle (like this):

dependencies {
    implementation 'top.canyie.pine:core:<version>'
}

Basic configuration:

PineConfig.debug = true; // Do we need to print more detailed logs?
PineConfig.debuggable = BuildConfig.DEBUG; // Is this process debuggable?

Example 1: monitor the creation of activities

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()");
    }
});

Example 2: monitor the creation and destroy of all java threads

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);
    }
});

Example 3: force allow any threads to modify ui:

Method checkThread = Class.forName("android.view.ViewRootImpl").getDeclaredMethod("checkThread");
Pine.hook(checkThread, MethodReplacement.DO_NOTHING);

Xposed Support

Download

Pine supports hooking methods in Xposed-style and loading Xposed modules. (Only java method hooking is supported. Modules using unsupported features like Resource-hooking won't work.)

implementation 'top.canyie.pine:xposed:<version>'

Directly hook methods in Xposed-style:

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");
                    }
                });

or like this:

XposedBridge.hookMethod(target, callback);

and you can load xposed modules (resources hook is not supported now):

// 1. load modules
PineXposed.loadModule(new File(modulePath));

// 2. call all 'IXposedHookLoadPackage' callback
PineXposed.onPackageLoad(packageName, processName, appInfo, isFirstApp, classLoader);

Note:

  1. Hooks will only take effect in the current process. If you want hooks take effect in other processes, inject your code into them first. There's nothing to do with us.
  2. Modules that use unsupported features (e.g. Resources hook or XSharedPreferences) will not work.

Enhanced Features

Download

With Dobby, you can use some enhanced features:

implementation 'top.canyie.pine:enhances:<version>'

ProGuard

If you use Xposed features and Xposed APIs need to be called outside your module (e.g. you call PineXposed.loadModule() to load external modules):

# Keep Xposed APIs
-keep class de.robv.android.xposed.** { *; }
-keep class android.** { *; }

Known issues

private static void methodLocked() { // ... }


In the example, we recommend you to hook `methodLocked` instead of `method`.

- Pine will disable hidden api policy on initialization by default. Due to an ART bug, if a thread changes hidden api policy while another thread is calling a API that lists members of a class, a out-of-bounds write may occur and causes crashes. We have no way to fix system bugs, so the only way is, initialize our library before other threads is started to avoid the race condition. For more info, see tiann/FreeReflection#60.

- For more, see [issues](https://github.com/canyie/pine/issues).

## Discussion
[QQ Group:949888394](https://shang.qq.com/wpa/qunwpa?idkey=25549719b948d2aaeb9e579955e39d71768111844b370fcb824d43b9b20e1c04)
[Telegram Group: @DreamlandFramework](https://t.me/DreamlandFramework)

## Credits
- [SandHook](https://github.com/ganyao114/SandHook)
- [Epic](https://github.com/tiann/epic)
- [AndroidELF](https://github.com/ganyao114/AndroidELF)
- [FastHook](https://github.com/turing-technician/FastHook)
- [YAHFA](https://github.com/PAGalaxyLab/YAHFA)
- [Dobby](https://github.com/jmpews/Dobby)
- [LSPosed](https://github.com/LSPosed/LSPosed)
- [libcxx-prefab](https://github.com/RikkaW/libcxx-prefab)

## License
[Pine](https://github.com/canyie/pine) Copyright (c) [canyie](http://github.com/canyie)

[AndroidELF](https://github.com/ganyao114/AndroidELF)  Copyright (c) [Swift Gan](https://github.com/ganyao114)

[Dobby](https://github.com/jmpews/Dobby)  Copyright (c) [jmpews](https://github.com/jmpews)

Licensed under the Anti 996 License, Version 1.0 (the "License");

you may not use this "Pine" project except in compliance with the License.

You may obtain a copy of the License at

https://github.com/996icu/996.ICU/blob/master/LICENSE