├── .gitattributes
├── java
├── test
│ ├── libs
│ │ ├── x86
│ │ │ └── libandhook.so
│ │ ├── x86_64
│ │ │ └── libandhook.so
│ │ ├── arm64-v8a
│ │ │ └── libandhook.so
│ │ └── armeabi-v7a
│ │ │ └── libandhook.so
│ ├── res
│ │ ├── drawable-hdpi
│ │ │ └── ic_launcher.png
│ │ ├── drawable-mdpi
│ │ │ └── ic_launcher.png
│ │ ├── drawable-xhdpi
│ │ │ └── ic_launcher.png
│ │ ├── values
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ ├── values-v11
│ │ │ └── styles.xml
│ │ ├── values-v14
│ │ │ └── styles.xml
│ │ └── layout
│ │ │ └── activity_main.xml
│ ├── src
│ │ └── apk
│ │ │ └── andhook
│ │ │ ├── test
│ │ │ ├── A.java
│ │ │ ├── B.java
│ │ │ └── AndTest.java
│ │ │ ├── ui
│ │ │ ├── MainApplication.java
│ │ │ └── MainActivity.java
│ │ │ └── AndHook.java
│ ├── .classpath
│ ├── project.properties
│ ├── .settings
│ │ └── org.eclipse.jdt.core.prefs
│ ├── .project
│ └── AndroidManifest.xml
└── library
│ ├── libs
│ ├── x86
│ │ └── libandhook.so
│ ├── x86_64
│ │ └── libandhook.so
│ ├── arm64-v8a
│ │ └── libandhook.so
│ └── armeabi-v7a
│ │ └── libandhook.so
│ ├── AndroidManifest.xml
│ ├── .classpath
│ ├── .settings
│ └── org.eclipse.jdt.core.prefs
│ ├── project.properties
│ ├── .project
│ └── src
│ └── apk
│ └── andhook
│ └── AndHook.java
├── deprecated
├── andhook.vcxproj.filters
├── andhook.vcxproj
├── andhook.cpp
└── dalvik_vm.h
├── .gitignore
├── LICENSE
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.h linguist-language=C++
--------------------------------------------------------------------------------
/java/test/libs/x86/libandhook.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/AndHook/master/java/test/libs/x86/libandhook.so
--------------------------------------------------------------------------------
/java/library/libs/x86/libandhook.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/AndHook/master/java/library/libs/x86/libandhook.so
--------------------------------------------------------------------------------
/java/test/libs/x86_64/libandhook.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/AndHook/master/java/test/libs/x86_64/libandhook.so
--------------------------------------------------------------------------------
/java/library/libs/x86_64/libandhook.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/AndHook/master/java/library/libs/x86_64/libandhook.so
--------------------------------------------------------------------------------
/java/test/libs/arm64-v8a/libandhook.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/AndHook/master/java/test/libs/arm64-v8a/libandhook.so
--------------------------------------------------------------------------------
/java/test/libs/armeabi-v7a/libandhook.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/AndHook/master/java/test/libs/armeabi-v7a/libandhook.so
--------------------------------------------------------------------------------
/java/library/libs/arm64-v8a/libandhook.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/AndHook/master/java/library/libs/arm64-v8a/libandhook.so
--------------------------------------------------------------------------------
/java/library/libs/armeabi-v7a/libandhook.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/AndHook/master/java/library/libs/armeabi-v7a/libandhook.so
--------------------------------------------------------------------------------
/java/test/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/AndHook/master/java/test/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/java/test/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/AndHook/master/java/test/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/java/test/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YiuChoi/AndHook/master/java/test/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/java/test/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | AndHook
5 | Hello world!
6 |
7 |
8 |
--------------------------------------------------------------------------------
/deprecated/andhook.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/java/test/src/apk/andhook/test/A.java:
--------------------------------------------------------------------------------
1 | package apk.andhook.test;
2 |
3 | import android.util.Log;
4 |
5 | public final class A {
6 | public static String AA(final String s) {
7 | Log.d(A.class.toString(), "public static method A::AA hit!");
8 | return "return from A::AA with param " + s;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/java/test/src/apk/andhook/test/B.java:
--------------------------------------------------------------------------------
1 | package apk.andhook.test;
2 |
3 | import android.util.Log;
4 |
5 | public final class B {
6 | public static String BB(final String s) {
7 | Log.d(B.class.toString(), "public static method B::BB hit!");
8 | return "return from B::BB with param " + s;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/java/test/src/apk/andhook/ui/MainApplication.java:
--------------------------------------------------------------------------------
1 | package apk.andhook.ui;
2 |
3 | import android.app.Application;
4 |
5 | public final class MainApplication extends Application {
6 |
7 | @Override
8 | public void onCreate() {
9 | android.util.Log.d(MainApplication.class.toString(), "onCreate");
10 |
11 | apk.andhook.test.AndTest.RunTest(this, this.getContentResolver());
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/java/test/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Compiled Object files
5 | *.slo
6 | *.lo
7 | *.o
8 | *.obj
9 |
10 | # Precompiled Headers
11 | *.gch
12 | *.pch
13 |
14 | # Compiled Dynamic libraries
15 | *.dylib
16 | *.dll
17 |
18 | # Fortran module files
19 | *.mod
20 | *.smod
21 |
22 | # Compiled Static libraries
23 | *.lai
24 | *.la
25 | *.a
26 | *.lib
27 |
28 | # Executables
29 | *.exe
30 | *.out
31 | *.app
32 |
--------------------------------------------------------------------------------
/java/library/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
9 |
10 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/java/test/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/java/test/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/java/library/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/java/test/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-19
15 |
--------------------------------------------------------------------------------
/java/library/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
5 | org.eclipse.jdt.core.compiler.compliance=1.7
6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate
7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate
8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate
9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
11 | org.eclipse.jdt.core.compiler.source=1.7
12 |
--------------------------------------------------------------------------------
/java/test/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
5 | org.eclipse.jdt.core.compiler.compliance=1.7
6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate
7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate
8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate
9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
11 | org.eclipse.jdt.core.compiler.source=1.7
12 |
--------------------------------------------------------------------------------
/java/library/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android-optimize.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-19
15 | android.library=false
16 |
--------------------------------------------------------------------------------
/java/test/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/java/test/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
11 |
12 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/java/test/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | AndHook
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/java/library/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | AndHookLib
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/java/test/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/java/test/src/apk/andhook/ui/MainActivity.java:
--------------------------------------------------------------------------------
1 | package apk.andhook.ui;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.provider.Settings.Secure;
6 | import apk.andhook.ui.R;
7 |
8 | public class MainActivity extends Activity {
9 | @Override
10 | protected void onCreate(Bundle savedInstanceState) {
11 | super.onCreate(savedInstanceState);
12 | setContentView(R.layout.activity_main);
13 |
14 | android.widget.Button hookbutton = (android.widget.Button) findViewById(R.id.hookbutton);
15 | hookbutton.setOnClickListener(new android.view.View.OnClickListener() {
16 | @Override
17 | public void onClick(android.view.View v) {
18 | android.util.Log.d(MainActivity.class.toString(), "begin...");
19 | for (int i = 0; i < 3; ++i) {
20 | apk.andhook.test.AndTest.a1(i + "");
21 | Secure.getString(MainActivity.this.getContentResolver(),
22 | Secure.ANDROID_ID);
23 | }
24 | android.util.Log.d(MainActivity.class.toString(), "end.");
25 | }
26 | });
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 AndHook
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AndHook
2 | AndHook is a lightweight java method hook framework for android, which supports both dalvik and art environment. It is primarily written in C++ so as to achieve optimal performance, but has java friendly apis as well.
3 |
4 | # Support
5 | Android 4.x or later, most of the ROMs and devices (armeabi-v7a, arm64-v8a, x86, x86_64).
6 |
7 | # Structure
8 | AndHook consists of only one java file (AndHook.java) and binaries for specified architectures, no other dependencies.
9 | - AndHook.java provides an optional bridge class of ArtHook and DalvikHook, and an inner class HookHelper to help simplify method backup.
10 |
11 | # Usage
12 | Just put AndHook.java and binaries (*.so files) into proper directories, and do what you want. You don't need to compile jni code yourself as precompiled binaries is provided, and everyone who wants to contribute to it please contact me, thanks.
13 | - makes sure that all the classes involved are initialized, e.g. non-system classes. To prevent GC collections, AndHook will keep global reference of the class as well.
14 | ```java
15 | AndHook.ensureClassInitialized(A.class);
16 | AndHook.ensureClassInitialized(B.class);
17 | ```
18 | - simply replaces a method (compatible with all Android version, but may encounter some issues such as NoSuchMethodError. `You should try this first to see if it meets your requirements`):
19 | ```java
20 | AndHook.replaceMethod(final Method origin, final Method replacement);
21 | ```
22 | - replaces a method and applys workaround for known issues mentioned above (with limited self-adapting capabilities, needs more tests):
23 | ```java
24 | AndHook.hookNoBackup(final Method origin, final Method replacement);
25 | ```
26 | - additional method backup (allows you to invoke orginal method anywhere):
27 | ```java
28 | // AndHook saves original method internally,
29 | // and returns just primitive index to reduce memory usage.
30 | int slot = AndHook.hook(final Method origin, final Method replacement);
31 | // Invokes original method.
32 | // The box/unbox operations are done by AndHook in dalvik-vm mode while JVM in art mode.
33 | AndHook.invokeXXXMethod(slot, ...);
34 | // Or, you can use HookHelper, which saves the slot automatically for you.
35 | ```
36 | For concrete usage, please see [AndTest.java](https://raw.githubusercontent.com/rrrfff/AndHook/master/java/test/src/apk/andhook/test/AndTest.java)
37 |
38 | # Reference
39 | [《Android热修复升级探索——追寻极致的代码热替换》](https://yq.aliyun.com/articles/74598)
40 | [Android N混合编译与对热补丁影响解析](https://github.com/WeMobileDev/article/blob/master/Android_N混合编译与对热补丁影响解析.md)
41 | [Implementing ART Just-In-Time (JIT) Compiler](https://source.android.com/devices/tech/dalvik/jit-compiler)
42 |
--------------------------------------------------------------------------------
/java/test/src/apk/andhook/test/AndTest.java:
--------------------------------------------------------------------------------
1 | package apk.andhook.test;
2 |
3 | import java.lang.reflect.Method;
4 |
5 | import android.content.ContentResolver;
6 | import android.os.Bundle;
7 | import android.provider.Settings.Secure;
8 | import android.util.Log;
9 | import apk.andhook.AndHook.HookHelper;
10 |
11 | public class AndTest {
12 | void onCreate(final Bundle savedInstanceState) {
13 | Log.d(this.getClass().toString(), "Activity::onCreate start");
14 | HookHelper.callVoidOrigin(this, savedInstanceState);
15 | Log.d(this.getClass().toString(), "Activity::onCreate end");
16 | }
17 |
18 | private static void testHookActivity_onCreate() {
19 | try {
20 | final Method m1 = android.app.Activity.class.getDeclaredMethod(
21 | "onCreate", Bundle.class);
22 | final Method m2 = AndTest.class.getDeclaredMethod("onCreate",
23 | Bundle.class);
24 | HookHelper.hook(m1, m2);
25 | } catch (NoSuchMethodException e) {
26 | e.printStackTrace();
27 | }
28 | }
29 |
30 | private static void testHookStaticMethodFromDifferentClass() {
31 | try {
32 | // The following code should be called once and only once
33 | // as A.class and B.class may not have been initialized and
34 | // AndHook will keep global reference of them to prevent GC
35 | // collections.
36 | apk.andhook.AndHook.ensureClassInitialized(A.class);
37 | apk.andhook.AndHook.ensureClassInitialized(B.class);
38 |
39 | final Method m1 = A.class.getDeclaredMethod("AA", String.class);
40 | final Method m2 = B.class.getDeclaredMethod("BB", String.class);
41 | Log.d(AndTest.class.toString(),
42 | "begin hook public static method A::AA...");
43 | HookHelper.hook(m1, m2);
44 | Log.d(AndTest.class.toString(),
45 | "end hook public static method A::AA");
46 |
47 | Log.d(AndTest.class.toString(),
48 | "calling public static method A::AA...");
49 | Log.d(AndTest.class.toString(),
50 | "public static method A::AA returns [" + A.AA("test") + "]");
51 | } catch (Exception e) {
52 | e.printStackTrace();
53 | }
54 | }
55 |
56 | public static String a1(final String s) {
57 | Log.d(AndTest.class.toString(), "public static method a1 hit!");
58 | return "return from a1 with param " + s;
59 | }
60 |
61 | public static String a2(final String s) {
62 | Log.d(AndTest.class.toString(), "public static method a2 hit!");
63 | try {
64 | final Object obj = HookHelper.callStaticObjectOrigin(AndTest.class,
65 | s + "+a2");
66 | Log.d(AndTest.class.toString(), "callStaticObjectOrigin return "
67 | + obj);
68 | obj.toString();
69 | } catch (Exception e) {
70 | e.printStackTrace();
71 | }
72 | return "return from a2 with param " + s;
73 | }
74 |
75 | private static void testHookStaticMethod() {
76 | try {
77 | final Method m1 = AndTest.class.getDeclaredMethod("a1",
78 | String.class);
79 | final Method m2 = AndTest.class.getDeclaredMethod("a2",
80 | String.class);
81 | Log.d(AndTest.class.toString(),
82 | "begin hook public static method a1...");
83 | HookHelper.hook(m1, m2);
84 | Log.d(AndTest.class.toString(), "end hook public static method a1");
85 |
86 | Log.d(AndTest.class.toString(),
87 | "calling public static method a1...");
88 | Log.d(AndTest.class.toString(), "public static method a1 returns ["
89 | + a1("test") + "]");
90 | } catch (Exception e) {
91 | e.printStackTrace();
92 | }
93 | }
94 |
95 | public String b1(final String s) {
96 | Log.d(AndTest.class.toString(), "public method b1 hit!");
97 | Log.d(AndTest.class.toString(), "this class is "
98 | + this.getClass().getName());
99 | return "return from b1 with param " + s;
100 | }
101 |
102 | public String b2(final String s) {
103 | Log.d(AndTest.class.toString(), "public method b2 hit!");
104 | Log.d(AndTest.class.toString(), "this class is "
105 | + this.getClass().getName());
106 | try {
107 | final Object obj = HookHelper.callObjectOrigin(this, s + "+b2");
108 | Log.d(AndTest.class.toString(), "callObjectOrigin return " + obj);
109 | } catch (Exception e) {
110 | e.printStackTrace();
111 | }
112 | return "return from b2 with param " + s;
113 | }
114 |
115 | private static void testHookMethod() {
116 | try {
117 | final Method m1 = AndTest.class.getDeclaredMethod("b1",
118 | String.class);
119 | final Method m2 = AndTest.class.getDeclaredMethod("b2",
120 | String.class);
121 | Log.d(AndTest.class.toString(), "begin hook public method b1...");
122 | HookHelper.hook(m1, m2);
123 | Log.d(AndTest.class.toString(), "end hook public method b1");
124 |
125 | Log.d(AndTest.class.toString(), "calling public method b1...");
126 | Log.d(AndTest.class.toString(), "public method b1 returns ["
127 | + (new AndTest()).b1("test") + "]");
128 | } catch (Exception e) {
129 | e.printStackTrace();
130 | }
131 | }
132 |
133 | public static String getString(final ContentResolver resolver,
134 | final String name) {
135 | Log.d(AndTest.class.toString(), "hit name = " + name);
136 | return (String) HookHelper.callStaticObjectOrigin(Secure.class,
137 | resolver, name);
138 | }
139 |
140 | private static void testHookSystemStaticMethod() {
141 | final String target = "getString";
142 | try {
143 | final Method origin = Secure.class.getDeclaredMethod(target,
144 | ContentResolver.class, String.class);
145 | final Method fake = AndTest.class.getDeclaredMethod(target,
146 | ContentResolver.class, String.class);
147 | HookHelper.hook(origin, fake);
148 | } catch (Exception e) {
149 | e.printStackTrace();
150 | }
151 | }
152 |
153 | public static void RunTest(final android.content.Context context,
154 | final android.content.ContentResolver resolver) {
155 | testHookActivity_onCreate();
156 | testHookStaticMethodFromDifferentClass();
157 | testHookStaticMethod();
158 | testHookMethod();
159 |
160 | Log.d("SecureHook", Secure.getString(resolver, Secure.ANDROID_ID));
161 | testHookSystemStaticMethod();
162 | Log.d("SecureHook", Secure.getString(resolver, Secure.ANDROID_ID));
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/deprecated/andhook.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | ARM
7 |
8 |
9 | Release
10 | ARM
11 |
12 |
13 | Debug
14 | ARM64
15 |
16 |
17 | Release
18 | ARM64
19 |
20 |
21 | Debug
22 | x64
23 |
24 |
25 | Release
26 | x64
27 |
28 |
29 | Debug
30 | x86
31 |
32 |
33 | Release
34 | x86
35 |
36 |
37 |
38 | {6875cc72-d4b8-4358-acf5-e7fd337efa7b}
39 | Android
40 | andhook
41 | 14.0
42 | Android
43 | 1.0
44 |
45 |
46 |
47 | DynamicLibrary
48 | true
49 | Clang_3_6
50 | android-19
51 | system
52 |
53 |
54 | DynamicLibrary
55 | false
56 | Clang_3_6
57 | android-19
58 | system
59 |
60 |
61 | DynamicLibrary
62 | true
63 | Clang_3_6
64 | system
65 |
66 |
67 | DynamicLibrary
68 | false
69 | Clang_3_6
70 | system
71 |
72 |
73 | DynamicLibrary
74 | true
75 | Clang_3_6
76 | android-19
77 | system
78 |
79 |
80 | DynamicLibrary
81 | false
82 | Clang_3_6
83 | android-19
84 | system
85 |
86 |
87 | DynamicLibrary
88 | true
89 | Clang_3_6
90 | system
91 |
92 |
93 | DynamicLibrary
94 | false
95 | Clang_3_6
96 | system
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 | c++1y
114 | false
115 | -fvisibility=hidden -fvisibility-inlines-hidden %(AdditionalOptions)
116 |
117 |
118 |
119 |
120 |
121 | $(IntermediateOutputPath)%(Filename).obj;%(Outputs)
122 | $(ToolchainPrebuiltPath)\bin\$(ToolchainPrefix)as.exe --strip-local-absolute -o $(IntermediateOutputPath)%(Filename).obj %(FullPath)
123 | %(Identity)
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | c++1y
132 | false
133 | -fvisibility=hidden -fvisibility-inlines-hidden %(AdditionalOptions)
134 |
135 |
136 |
137 |
138 |
139 | $(IntermediateOutputPath)%(Filename).obj;%(Outputs)
140 | $(ToolchainPrebuiltPath)\bin\$(ToolchainPrefix)as.exe --strip-local-absolute -o $(IntermediateOutputPath)%(Filename).obj %(FullPath)
141 | %(Identity)
142 |
143 |
144 |
145 |
146 | OmitAllSymbolInformation
147 |
148 |
149 |
150 |
151 |
152 | c++1y
153 | false
154 | -fvisibility=hidden -fvisibility-inlines-hidden %(AdditionalOptions)
155 |
156 |
157 |
158 |
159 |
160 | $(IntermediateOutputPath)%(Filename).obj;%(Outputs)
161 | $(ToolchainPrebuiltPath)\bin\$(ToolchainPrefix)as.exe --strip-local-absolute -o $(IntermediateOutputPath)%(Filename).obj %(FullPath)
162 | %(Identity)
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 | c++1y
171 | false
172 | -fvisibility=hidden -fvisibility-inlines-hidden %(AdditionalOptions)
173 |
174 |
175 |
176 |
177 |
178 | $(IntermediateOutputPath)%(Filename).obj;%(Outputs)
179 | $(ToolchainPrebuiltPath)\bin\$(ToolchainPrefix)as.exe --strip-local-absolute -o $(IntermediateOutputPath)%(Filename).obj %(FullPath)
180 | %(Identity)
181 |
182 |
183 |
184 |
185 | OmitAllSymbolInformation
186 |
187 |
188 |
189 |
190 |
191 | c++1y
192 | false
193 | -fvisibility=hidden -fvisibility-inlines-hidden %(AdditionalOptions)
194 |
195 |
196 |
197 |
198 |
199 | $(IntermediateOutputPath)%(Filename).obj;%(Outputs)
200 | $(ToolchainPrebuiltPath)\bin\$(ToolchainPrefix)as.exe --strip-local-absolute -o $(IntermediateOutputPath)%(Filename).obj %(FullPath)
201 | %(Identity)
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 | c++1y
210 | false
211 | -fvisibility=hidden -fvisibility-inlines-hidden %(AdditionalOptions)
212 |
213 |
214 |
215 |
216 |
217 | $(IntermediateOutputPath)%(Filename).obj;%(Outputs)
218 | $(ToolchainPrebuiltPath)\bin\$(ToolchainPrefix)as.exe --strip-local-absolute -o $(IntermediateOutputPath)%(Filename).obj %(FullPath)
219 | %(Identity)
220 |
221 |
222 |
223 |
224 | OmitAllSymbolInformation
225 |
226 |
227 |
228 |
229 |
230 | c++1y
231 | false
232 | -fvisibility=hidden -fvisibility-inlines-hidden %(AdditionalOptions)
233 |
234 |
235 |
236 |
237 |
238 | $(IntermediateOutputPath)%(Filename).obj;%(Outputs)
239 | $(ToolchainPrebuiltPath)\bin\$(ToolchainPrefix)as.exe --strip-local-absolute -o $(IntermediateOutputPath)%(Filename).obj %(FullPath)
240 | %(Identity)
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 | c++1y
249 | false
250 | -fvisibility=hidden -fvisibility-inlines-hidden %(AdditionalOptions)
251 |
252 |
253 |
254 |
255 |
256 | $(IntermediateOutputPath)%(Filename).obj;%(Outputs)
257 | $(ToolchainPrebuiltPath)\bin\$(ToolchainPrefix)as.exe --strip-local-absolute -o $(IntermediateOutputPath)%(Filename).obj %(FullPath)
258 | %(Identity)
259 |
260 |
261 |
262 |
263 | OmitAllSymbolInformation
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
--------------------------------------------------------------------------------
/java/test/src/apk/andhook/AndHook.java:
--------------------------------------------------------------------------------
1 | package apk.andhook;
2 |
3 | import java.lang.reflect.Method;
4 | import java.util.concurrent.ConcurrentHashMap;
5 |
6 | import android.util.Pair;
7 |
8 | /**
9 | * @author rrrfff
10 | * @version 2.0.0
11 | *
12 | */
13 | public class AndHook {
14 | static {
15 | System.loadLibrary("andhook");
16 | }
17 |
18 | public static final class HookHelper {
19 | private static final ConcurrentHashMap, Integer> sBackups = new ConcurrentHashMap<>();
20 |
21 | public static void hook(final Method origin, final Method replace) {
22 | final Pair origin_key = Pair.create(origin
23 | .getDeclaringClass().getName(), origin.getName());
24 | final Pair target_key = Pair.create(replace
25 | .getDeclaringClass().getName(), replace.getName());
26 | final Integer slot = AndHook.hook(origin, replace);
27 | sBackups.put(origin_key, slot);
28 | sBackups.put(target_key, slot);
29 | }
30 |
31 | private static int getBackupSlot() {
32 | final StackTraceElement currentStack = Thread.currentThread()
33 | .getStackTrace()[4];
34 | return sBackups.get(Pair.create(currentStack.getClassName(),
35 | currentStack.getMethodName()));
36 | }
37 |
38 | public static void callVoidOrigin(final Object receiver,
39 | final Object... params) {
40 | AndHook.invokeVoidMethod(getBackupSlot(), receiver, params);
41 | }
42 |
43 | public static void callStaticVoidOrigin(final Class> clazz,
44 | final Object... params) {
45 | AndHook.invokeVoidMethod(getBackupSlot(), clazz, params);
46 | }
47 |
48 | public static boolean callBooleanOrigin(final Object receiver,
49 | final Object... params) {
50 | return AndHook.invokeBooleanMethod(getBackupSlot(), receiver,
51 | params);
52 | }
53 |
54 | public static boolean callStaticBooleanOrigin(final Class> clazz,
55 | final Object... params) {
56 | return AndHook.invokeBooleanMethod(getBackupSlot(), clazz, params);
57 | }
58 |
59 | public static byte callByteOrigin(final Object receiver,
60 | final Object... params) {
61 | return AndHook.invokeByteMethod(getBackupSlot(), receiver, params);
62 | }
63 |
64 | public static byte callStaticByteOrigin(Class> clazz,
65 | final Object... params) {
66 | return AndHook.invokeByteMethod(getBackupSlot(), clazz, params);
67 | }
68 |
69 | public static short callShortOrigin(final Object receiver,
70 | final Object... params) {
71 | return AndHook.invokeShortMethod(getBackupSlot(), receiver, params);
72 | }
73 |
74 | public static short callStaticShortOrigin(final Class> clazz,
75 | final Object... params) {
76 | return AndHook.invokeShortMethod(getBackupSlot(), clazz, params);
77 | }
78 |
79 | public static char callCharOrigin(final Object receiver,
80 | final Object... params) {
81 | return AndHook.invokeCharMethod(getBackupSlot(), receiver, params);
82 | }
83 |
84 | public static char callStaticCharOrigin(final Class> clazz,
85 | final Object... params) {
86 | return AndHook.invokeCharMethod(getBackupSlot(), clazz, params);
87 | }
88 |
89 | public static int callIntOrigin(final Object receiver,
90 | final Object... params) {
91 | return AndHook.invokeIntMethod(getBackupSlot(), receiver, params);
92 | }
93 |
94 | public static int callStaticIntOrigin(final Class> clazz,
95 | final Object... params) {
96 | return AndHook.invokeIntMethod(getBackupSlot(), clazz, params);
97 | }
98 |
99 | public static long callLongOrigin(final Object receiver,
100 | final Object... params) {
101 | return AndHook.invokeLongMethod(getBackupSlot(), receiver, params);
102 | }
103 |
104 | public static long callStaticLongOrigin(final Class> clazz,
105 | final Object... params) {
106 | return AndHook.invokeLongMethod(getBackupSlot(), clazz, params);
107 | }
108 |
109 | public static float callFloatOrigin(final Object receiver,
110 | final Object... params) {
111 | return AndHook.invokeFloatMethod(getBackupSlot(), receiver, params);
112 | }
113 |
114 | public static float callStaticFloatOrigin(final Class> clazz,
115 | final Object... params) {
116 | return AndHook.invokeFloatMethod(getBackupSlot(), clazz, params);
117 | }
118 |
119 | public static double callDoubleOrigin(final Object receiver,
120 | final Object... params) {
121 | return AndHook
122 | .invokeDoubleMethod(getBackupSlot(), receiver, params);
123 | }
124 |
125 | public static double callStaticDoubleOrigin(final Class> clazz,
126 | final Object... params) {
127 | return AndHook.invokeDoubleMethod(getBackupSlot(), clazz, params);
128 | }
129 |
130 | public static Object callObjectOrigin(final Object receiver,
131 | final Object... params) {
132 | return AndHook
133 | .invokeObjectMethod(getBackupSlot(), receiver, params);
134 | }
135 |
136 | public static Object callStaticObjectOrigin(final Class> clazz,
137 | final Object... params) {
138 | return AndHook.invokeObjectMethod(getBackupSlot(), clazz, params);
139 | }
140 |
141 | public static Method findMethod(final Class> cls, final String name,
142 | final Class>... parameterTypes) {
143 | try {
144 | return cls.getDeclaredMethod(name, parameterTypes);
145 | } catch (NoSuchMethodException e) {
146 | e.printStackTrace();
147 | return null;
148 | }
149 | }
150 | }
151 |
152 | public static native void replaceMethod(final Method origin,
153 | final Method replace);
154 |
155 | public static native int hook(final Method origin, final Method replace);
156 |
157 | public static native void hookNoBackup(final Method origin,
158 | final Method replace);
159 |
160 | public static native void ensureClassInitialized(final Class> origin);
161 |
162 | public static void invokeVoidMethod(final int slot, final Object receiver,
163 | final Object... params) {
164 | if (android.os.Build.VERSION.SDK_INT <= 19) {
165 | DalvikHook.invokeVoidMethod(slot, receiver, params);
166 | } else {
167 | ArtHook.invokeMethod(slot, receiver, params);
168 | }
169 | }
170 |
171 | public static void invokeStaticVoidMethod(final int slot,
172 | final Class> clazz, final Object... params) {
173 | if (android.os.Build.VERSION.SDK_INT <= 19) {
174 | DalvikHook.invokeVoidMethod(slot, clazz, params);
175 | } else {
176 | ArtHook.invokeMethod(slot, null, params);
177 | }
178 | }
179 |
180 | public static boolean invokeBooleanMethod(final int slot,
181 | final Object receiver, final Object... params) {
182 | if (android.os.Build.VERSION.SDK_INT <= 19) {
183 | return DalvikHook.invokeBooleanMethod(slot, receiver, params);
184 | } else {
185 | return (boolean) ArtHook.invokeMethod(slot, receiver, params);
186 | }
187 | }
188 |
189 | public static boolean invokeStaticBooleanMethod(final int slot,
190 | final Class> clazz, final Object... params) {
191 | if (android.os.Build.VERSION.SDK_INT <= 19) {
192 | return DalvikHook.invokeBooleanMethod(slot, clazz, params);
193 | } else {
194 | return (boolean) ArtHook.invokeMethod(slot, null, params);
195 | }
196 | }
197 |
198 | public static byte invokeByteMethod(final int slot, final Object receiver,
199 | final Object... params) {
200 | if (android.os.Build.VERSION.SDK_INT <= 19) {
201 | return DalvikHook.invokeByteMethod(slot, receiver, params);
202 | } else {
203 | return (byte) ArtHook.invokeMethod(slot, receiver, params);
204 | }
205 | }
206 |
207 | public static byte invokeStaticByteMethod(final int slot, Class> clazz,
208 | final Object... params) {
209 | if (android.os.Build.VERSION.SDK_INT <= 19) {
210 | return DalvikHook.invokeByteMethod(slot, clazz, params);
211 | } else {
212 | return (byte) ArtHook.invokeMethod(slot, null, params);
213 | }
214 | }
215 |
216 | public static short invokeShortMethod(final int slot,
217 | final Object receiver, final Object... params) {
218 | if (android.os.Build.VERSION.SDK_INT <= 19) {
219 | return DalvikHook.invokeShortMethod(slot, receiver, params);
220 | } else {
221 | return (short) ArtHook.invokeMethod(slot, receiver, params);
222 | }
223 | }
224 |
225 | public static short invokeStaticShortMethod(final int slot,
226 | final Class> clazz, final Object... params) {
227 | if (android.os.Build.VERSION.SDK_INT <= 19) {
228 | return DalvikHook.invokeShortMethod(slot, clazz, params);
229 | } else {
230 | return (short) ArtHook.invokeMethod(slot, null, params);
231 | }
232 | }
233 |
234 | public static char invokeCharMethod(final int slot, final Object receiver,
235 | final Object... params) {
236 | if (android.os.Build.VERSION.SDK_INT <= 19) {
237 | return DalvikHook.invokeCharMethod(slot, receiver, params);
238 | } else {
239 | return (char) ArtHook.invokeMethod(slot, receiver, params);
240 | }
241 | }
242 |
243 | public static char invokeStaticCharMethod(final int slot,
244 | final Class> clazz, final Object... params) {
245 | if (android.os.Build.VERSION.SDK_INT <= 19) {
246 | return DalvikHook.invokeCharMethod(slot, clazz, params);
247 | } else {
248 | return (char) ArtHook.invokeMethod(slot, null, params);
249 | }
250 | }
251 |
252 | public static int invokeIntMethod(final int slot, final Object receiver,
253 | final Object... params) {
254 | if (android.os.Build.VERSION.SDK_INT <= 19) {
255 | return DalvikHook.invokeIntMethod(slot, receiver, params);
256 | } else {
257 | return (int) ArtHook.invokeMethod(slot, receiver, params);
258 | }
259 | }
260 |
261 | public static int invokeStaticIntMethod(final int slot,
262 | final Class> clazz, final Object... params) {
263 | if (android.os.Build.VERSION.SDK_INT <= 19) {
264 | return DalvikHook.invokeIntMethod(slot, clazz, params);
265 | } else {
266 | return (int) ArtHook.invokeMethod(slot, null, params);
267 | }
268 | }
269 |
270 | public static long invokeLongMethod(final int slot, final Object receiver,
271 | final Object... params) {
272 | if (android.os.Build.VERSION.SDK_INT <= 19) {
273 | return DalvikHook.invokeLongMethod(slot, receiver, params);
274 | } else {
275 | return (long) ArtHook.invokeMethod(slot, receiver, params);
276 | }
277 | }
278 |
279 | public static long invokeStaticLongMethod(final int slot,
280 | final Class> clazz, final Object... params) {
281 | if (android.os.Build.VERSION.SDK_INT <= 19) {
282 | return DalvikHook.invokeLongMethod(slot, clazz, params);
283 | } else {
284 | return (long) ArtHook.invokeMethod(slot, null, params);
285 | }
286 | }
287 |
288 | public static float invokeFloatMethod(final int slot,
289 | final Object receiver, final Object... params) {
290 | if (android.os.Build.VERSION.SDK_INT <= 19) {
291 | return DalvikHook.invokeFloatMethod(slot, receiver, params);
292 | } else {
293 | return (float) ArtHook.invokeMethod(slot, receiver, params);
294 | }
295 | }
296 |
297 | public static float invokeStaticFloatMethod(final int slot,
298 | final Class> clazz, final Object... params) {
299 | if (android.os.Build.VERSION.SDK_INT <= 19) {
300 | return DalvikHook.invokeFloatMethod(slot, clazz, params);
301 | } else {
302 | return (float) ArtHook.invokeMethod(slot, null, params);
303 | }
304 | }
305 |
306 | public static double invokeDoubleMethod(final int slot,
307 | final Object receiver, final Object... params) {
308 | if (android.os.Build.VERSION.SDK_INT <= 19) {
309 | return DalvikHook.invokeDoubleMethod(slot, receiver, params);
310 | } else {
311 | return (double) ArtHook.invokeMethod(slot, receiver, params);
312 | }
313 | }
314 |
315 | public static double invokeStaticDoubleMethod(final int slot,
316 | final Class> clazz, final Object... params) {
317 | if (android.os.Build.VERSION.SDK_INT <= 19) {
318 | return DalvikHook.invokeDoubleMethod(slot, clazz, params);
319 | } else {
320 | return (double) ArtHook.invokeMethod(slot, null, params);
321 | }
322 | }
323 |
324 | public static Object invokeObjectMethod(final int slot,
325 | final Object receiver, final Object... params) {
326 | if (android.os.Build.VERSION.SDK_INT <= 19) {
327 | return DalvikHook.invokeObjectMethod(slot, receiver, params);
328 | } else {
329 | return ArtHook.invokeMethod(slot, receiver, params);
330 | }
331 | }
332 |
333 | public static Object invokeStaticObjectMethod(final int slot,
334 | final Class> clazz, final Object... params) {
335 | if (android.os.Build.VERSION.SDK_INT <= 19) {
336 | return DalvikHook.invokeObjectMethod(slot, clazz, params);
337 | } else {
338 | return ArtHook.invokeMethod(slot, null, params);
339 | }
340 | }
341 |
342 | protected static final class Native {
343 | private static native void a();
344 |
345 | private static native void b();
346 | }
347 |
348 | private static final class ArtHook {
349 | public static native Object invokeMethod(final int slot,
350 | final Object receiver, final Object... params);
351 | }
352 |
353 | private static final class DalvikHook {
354 | public static native void invokeVoidMethod(final int slot,
355 | final Object receiver, final Object... params);
356 |
357 | public static native boolean invokeBooleanMethod(final int slot,
358 | final Object receiver, final Object... params);
359 |
360 | public static native byte invokeByteMethod(final int slot,
361 | final Object receiver, final Object... params);
362 |
363 | public static native short invokeShortMethod(final int slot,
364 | final Object receiver, final Object... params);
365 |
366 | public static native char invokeCharMethod(final int slot,
367 | final Object receiver, final Object... params);
368 |
369 | public static native int invokeIntMethod(final int slot,
370 | final Object receiver, final Object... params);
371 |
372 | public static native long invokeLongMethod(final int slot,
373 | final Object receiver, final Object... params);
374 |
375 | public static native float invokeFloatMethod(final int slot,
376 | final Object receiver, final Object... params);
377 |
378 | public static native double invokeDoubleMethod(final int slot,
379 | final Object receiver, final Object... params);
380 |
381 | public static native Object invokeObjectMethod(final int slot,
382 | final Object receiver, final Object... params);
383 | }
384 | }
385 |
--------------------------------------------------------------------------------
/java/library/src/apk/andhook/AndHook.java:
--------------------------------------------------------------------------------
1 | package apk.andhook;
2 |
3 | import java.lang.reflect.Method;
4 | import java.util.concurrent.ConcurrentHashMap;
5 |
6 | import android.util.Pair;
7 |
8 | /**
9 | * @author rrrfff
10 | * @version 2.0.0
11 | *
12 | */
13 | public class AndHook {
14 | static {
15 | System.loadLibrary("andhook");
16 | }
17 |
18 | public static final class HookHelper {
19 | private static final ConcurrentHashMap, Integer> sBackups = new ConcurrentHashMap<>();
20 |
21 | public static void hook(final Method origin, final Method replace) {
22 | final Pair origin_key = Pair.create(origin
23 | .getDeclaringClass().getName(), origin.getName());
24 | final Pair target_key = Pair.create(replace
25 | .getDeclaringClass().getName(), replace.getName());
26 | final Integer slot = AndHook.hook(origin, replace);
27 | sBackups.put(origin_key, slot);
28 | sBackups.put(target_key, slot);
29 | }
30 |
31 | private static int getBackupSlot() {
32 | final StackTraceElement currentStack = Thread.currentThread()
33 | .getStackTrace()[4];
34 | return sBackups.get(Pair.create(currentStack.getClassName(),
35 | currentStack.getMethodName()));
36 | }
37 |
38 | public static void callVoidOrigin(final Object receiver,
39 | final Object... params) {
40 | AndHook.invokeVoidMethod(getBackupSlot(), receiver, params);
41 | }
42 |
43 | public static void callStaticVoidOrigin(final Class> clazz,
44 | final Object... params) {
45 | AndHook.invokeVoidMethod(getBackupSlot(), clazz, params);
46 | }
47 |
48 | public static boolean callBooleanOrigin(final Object receiver,
49 | final Object... params) {
50 | return AndHook.invokeBooleanMethod(getBackupSlot(), receiver,
51 | params);
52 | }
53 |
54 | public static boolean callStaticBooleanOrigin(final Class> clazz,
55 | final Object... params) {
56 | return AndHook.invokeBooleanMethod(getBackupSlot(), clazz, params);
57 | }
58 |
59 | public static byte callByteOrigin(final Object receiver,
60 | final Object... params) {
61 | return AndHook.invokeByteMethod(getBackupSlot(), receiver, params);
62 | }
63 |
64 | public static byte callStaticByteOrigin(Class> clazz,
65 | final Object... params) {
66 | return AndHook.invokeByteMethod(getBackupSlot(), clazz, params);
67 | }
68 |
69 | public static short callShortOrigin(final Object receiver,
70 | final Object... params) {
71 | return AndHook.invokeShortMethod(getBackupSlot(), receiver, params);
72 | }
73 |
74 | public static short callStaticShortOrigin(final Class> clazz,
75 | final Object... params) {
76 | return AndHook.invokeShortMethod(getBackupSlot(), clazz, params);
77 | }
78 |
79 | public static char callCharOrigin(final Object receiver,
80 | final Object... params) {
81 | return AndHook.invokeCharMethod(getBackupSlot(), receiver, params);
82 | }
83 |
84 | public static char callStaticCharOrigin(final Class> clazz,
85 | final Object... params) {
86 | return AndHook.invokeCharMethod(getBackupSlot(), clazz, params);
87 | }
88 |
89 | public static int callIntOrigin(final Object receiver,
90 | final Object... params) {
91 | return AndHook.invokeIntMethod(getBackupSlot(), receiver, params);
92 | }
93 |
94 | public static int callStaticIntOrigin(final Class> clazz,
95 | final Object... params) {
96 | return AndHook.invokeIntMethod(getBackupSlot(), clazz, params);
97 | }
98 |
99 | public static long callLongOrigin(final Object receiver,
100 | final Object... params) {
101 | return AndHook.invokeLongMethod(getBackupSlot(), receiver, params);
102 | }
103 |
104 | public static long callStaticLongOrigin(final Class> clazz,
105 | final Object... params) {
106 | return AndHook.invokeLongMethod(getBackupSlot(), clazz, params);
107 | }
108 |
109 | public static float callFloatOrigin(final Object receiver,
110 | final Object... params) {
111 | return AndHook.invokeFloatMethod(getBackupSlot(), receiver, params);
112 | }
113 |
114 | public static float callStaticFloatOrigin(final Class> clazz,
115 | final Object... params) {
116 | return AndHook.invokeFloatMethod(getBackupSlot(), clazz, params);
117 | }
118 |
119 | public static double callDoubleOrigin(final Object receiver,
120 | final Object... params) {
121 | return AndHook
122 | .invokeDoubleMethod(getBackupSlot(), receiver, params);
123 | }
124 |
125 | public static double callStaticDoubleOrigin(final Class> clazz,
126 | final Object... params) {
127 | return AndHook.invokeDoubleMethod(getBackupSlot(), clazz, params);
128 | }
129 |
130 | public static Object callObjectOrigin(final Object receiver,
131 | final Object... params) {
132 | return AndHook
133 | .invokeObjectMethod(getBackupSlot(), receiver, params);
134 | }
135 |
136 | public static Object callStaticObjectOrigin(final Class> clazz,
137 | final Object... params) {
138 | return AndHook.invokeObjectMethod(getBackupSlot(), clazz, params);
139 | }
140 |
141 | public static Method findMethod(final Class> cls, final String name,
142 | final Class>... parameterTypes) {
143 | try {
144 | return cls.getDeclaredMethod(name, parameterTypes);
145 | } catch (NoSuchMethodException e) {
146 | e.printStackTrace();
147 | return null;
148 | }
149 | }
150 | }
151 |
152 | public static native void replaceMethod(final Method origin,
153 | final Method replace);
154 |
155 | public static native int hook(final Method origin, final Method replace);
156 |
157 | public static native void hookNoBackup(final Method origin,
158 | final Method replace);
159 |
160 | public static native void ensureClassInitialized(final Class> origin);
161 |
162 | public static void invokeVoidMethod(final int slot, final Object receiver,
163 | final Object... params) {
164 | if (android.os.Build.VERSION.SDK_INT <= 19) {
165 | DalvikHook.invokeVoidMethod(slot, receiver, params);
166 | } else {
167 | ArtHook.invokeMethod(slot, receiver, params);
168 | }
169 | }
170 |
171 | public static void invokeStaticVoidMethod(final int slot,
172 | final Class> clazz, final Object... params) {
173 | if (android.os.Build.VERSION.SDK_INT <= 19) {
174 | DalvikHook.invokeVoidMethod(slot, clazz, params);
175 | } else {
176 | ArtHook.invokeMethod(slot, null, params);
177 | }
178 | }
179 |
180 | public static boolean invokeBooleanMethod(final int slot,
181 | final Object receiver, final Object... params) {
182 | if (android.os.Build.VERSION.SDK_INT <= 19) {
183 | return DalvikHook.invokeBooleanMethod(slot, receiver, params);
184 | } else {
185 | return (boolean) ArtHook.invokeMethod(slot, receiver, params);
186 | }
187 | }
188 |
189 | public static boolean invokeStaticBooleanMethod(final int slot,
190 | final Class> clazz, final Object... params) {
191 | if (android.os.Build.VERSION.SDK_INT <= 19) {
192 | return DalvikHook.invokeBooleanMethod(slot, clazz, params);
193 | } else {
194 | return (boolean) ArtHook.invokeMethod(slot, null, params);
195 | }
196 | }
197 |
198 | public static byte invokeByteMethod(final int slot, final Object receiver,
199 | final Object... params) {
200 | if (android.os.Build.VERSION.SDK_INT <= 19) {
201 | return DalvikHook.invokeByteMethod(slot, receiver, params);
202 | } else {
203 | return (byte) ArtHook.invokeMethod(slot, receiver, params);
204 | }
205 | }
206 |
207 | public static byte invokeStaticByteMethod(final int slot, Class> clazz,
208 | final Object... params) {
209 | if (android.os.Build.VERSION.SDK_INT <= 19) {
210 | return DalvikHook.invokeByteMethod(slot, clazz, params);
211 | } else {
212 | return (byte) ArtHook.invokeMethod(slot, null, params);
213 | }
214 | }
215 |
216 | public static short invokeShortMethod(final int slot,
217 | final Object receiver, final Object... params) {
218 | if (android.os.Build.VERSION.SDK_INT <= 19) {
219 | return DalvikHook.invokeShortMethod(slot, receiver, params);
220 | } else {
221 | return (short) ArtHook.invokeMethod(slot, receiver, params);
222 | }
223 | }
224 |
225 | public static short invokeStaticShortMethod(final int slot,
226 | final Class> clazz, final Object... params) {
227 | if (android.os.Build.VERSION.SDK_INT <= 19) {
228 | return DalvikHook.invokeShortMethod(slot, clazz, params);
229 | } else {
230 | return (short) ArtHook.invokeMethod(slot, null, params);
231 | }
232 | }
233 |
234 | public static char invokeCharMethod(final int slot, final Object receiver,
235 | final Object... params) {
236 | if (android.os.Build.VERSION.SDK_INT <= 19) {
237 | return DalvikHook.invokeCharMethod(slot, receiver, params);
238 | } else {
239 | return (char) ArtHook.invokeMethod(slot, receiver, params);
240 | }
241 | }
242 |
243 | public static char invokeStaticCharMethod(final int slot,
244 | final Class> clazz, final Object... params) {
245 | if (android.os.Build.VERSION.SDK_INT <= 19) {
246 | return DalvikHook.invokeCharMethod(slot, clazz, params);
247 | } else {
248 | return (char) ArtHook.invokeMethod(slot, null, params);
249 | }
250 | }
251 |
252 | public static int invokeIntMethod(final int slot, final Object receiver,
253 | final Object... params) {
254 | if (android.os.Build.VERSION.SDK_INT <= 19) {
255 | return DalvikHook.invokeIntMethod(slot, receiver, params);
256 | } else {
257 | return (int) ArtHook.invokeMethod(slot, receiver, params);
258 | }
259 | }
260 |
261 | public static int invokeStaticIntMethod(final int slot,
262 | final Class> clazz, final Object... params) {
263 | if (android.os.Build.VERSION.SDK_INT <= 19) {
264 | return DalvikHook.invokeIntMethod(slot, clazz, params);
265 | } else {
266 | return (int) ArtHook.invokeMethod(slot, null, params);
267 | }
268 | }
269 |
270 | public static long invokeLongMethod(final int slot, final Object receiver,
271 | final Object... params) {
272 | if (android.os.Build.VERSION.SDK_INT <= 19) {
273 | return DalvikHook.invokeLongMethod(slot, receiver, params);
274 | } else {
275 | return (long) ArtHook.invokeMethod(slot, receiver, params);
276 | }
277 | }
278 |
279 | public static long invokeStaticLongMethod(final int slot,
280 | final Class> clazz, final Object... params) {
281 | if (android.os.Build.VERSION.SDK_INT <= 19) {
282 | return DalvikHook.invokeLongMethod(slot, clazz, params);
283 | } else {
284 | return (long) ArtHook.invokeMethod(slot, null, params);
285 | }
286 | }
287 |
288 | public static float invokeFloatMethod(final int slot,
289 | final Object receiver, final Object... params) {
290 | if (android.os.Build.VERSION.SDK_INT <= 19) {
291 | return DalvikHook.invokeFloatMethod(slot, receiver, params);
292 | } else {
293 | return (float) ArtHook.invokeMethod(slot, receiver, params);
294 | }
295 | }
296 |
297 | public static float invokeStaticFloatMethod(final int slot,
298 | final Class> clazz, final Object... params) {
299 | if (android.os.Build.VERSION.SDK_INT <= 19) {
300 | return DalvikHook.invokeFloatMethod(slot, clazz, params);
301 | } else {
302 | return (float) ArtHook.invokeMethod(slot, null, params);
303 | }
304 | }
305 |
306 | public static double invokeDoubleMethod(final int slot,
307 | final Object receiver, final Object... params) {
308 | if (android.os.Build.VERSION.SDK_INT <= 19) {
309 | return DalvikHook.invokeDoubleMethod(slot, receiver, params);
310 | } else {
311 | return (double) ArtHook.invokeMethod(slot, receiver, params);
312 | }
313 | }
314 |
315 | public static double invokeStaticDoubleMethod(final int slot,
316 | final Class> clazz, final Object... params) {
317 | if (android.os.Build.VERSION.SDK_INT <= 19) {
318 | return DalvikHook.invokeDoubleMethod(slot, clazz, params);
319 | } else {
320 | return (double) ArtHook.invokeMethod(slot, null, params);
321 | }
322 | }
323 |
324 | public static Object invokeObjectMethod(final int slot,
325 | final Object receiver, final Object... params) {
326 | if (android.os.Build.VERSION.SDK_INT <= 19) {
327 | return DalvikHook.invokeObjectMethod(slot, receiver, params);
328 | } else {
329 | return ArtHook.invokeMethod(slot, receiver, params);
330 | }
331 | }
332 |
333 | public static Object invokeStaticObjectMethod(final int slot,
334 | final Class> clazz, final Object... params) {
335 | if (android.os.Build.VERSION.SDK_INT <= 19) {
336 | return DalvikHook.invokeObjectMethod(slot, clazz, params);
337 | } else {
338 | return ArtHook.invokeMethod(slot, null, params);
339 | }
340 | }
341 |
342 | protected static final class Native {
343 | private static native void a();
344 |
345 | private static native void b();
346 | }
347 |
348 | private static final class ArtHook {
349 | public static native Object invokeMethod(final int slot,
350 | final Object receiver, final Object... params);
351 | }
352 |
353 | private static final class DalvikHook {
354 | public static native void invokeVoidMethod(final int slot,
355 | final Object receiver, final Object... params);
356 |
357 | public static native boolean invokeBooleanMethod(final int slot,
358 | final Object receiver, final Object... params);
359 |
360 | public static native byte invokeByteMethod(final int slot,
361 | final Object receiver, final Object... params);
362 |
363 | public static native short invokeShortMethod(final int slot,
364 | final Object receiver, final Object... params);
365 |
366 | public static native char invokeCharMethod(final int slot,
367 | final Object receiver, final Object... params);
368 |
369 | public static native int invokeIntMethod(final int slot,
370 | final Object receiver, final Object... params);
371 |
372 | public static native long invokeLongMethod(final int slot,
373 | final Object receiver, final Object... params);
374 |
375 | public static native float invokeFloatMethod(final int slot,
376 | final Object receiver, final Object... params);
377 |
378 | public static native double invokeDoubleMethod(final int slot,
379 | final Object receiver, final Object... params);
380 |
381 | public static native Object invokeObjectMethod(final int slot,
382 | final Object receiver, final Object... params);
383 | }
384 | }
385 |
--------------------------------------------------------------------------------
/deprecated/andhook.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * @author : rrrfff@foxmail.com
4 | *
5 | */
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include "dalvik_vm.h"
12 | #define MAX_BACKUP_SLOTS 32
13 | #define MAX_PARAMS_ALLOWED 8
14 | #define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, __FUNCTION__, __VA_ARGS__))
15 | #define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, __FUNCTION__, __VA_ARGS__))
16 | #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, __FUNCTION__, __VA_ARGS__))
17 | #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, __FUNCTION__, __VA_ARGS__))
18 | #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, __FUNCTION__, __VA_ARGS__))
19 | #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, __FUNCTION__, __VA_ARGS__))
20 | #define LOGF(...) ((void)__android_log_print(ANDROID_LOG_FATAL, __FUNCTION__, __VA_ARGS__))
21 | #define __LIBC_INLINE__ __attribute__((always_inline))
22 | #define LIKELY(exp) (__builtin_expect((exp) != 0, true))
23 | #define UNLIKELY(exp) (__builtin_expect((exp) != 0, false))
24 | #define METHOD_PTR(p) reinterpret_cast(p)
25 | #define NATIVE_METHOD(n, s) #n, s, reinterpret_cast(n)
26 | #define PLoad(lib) ::dlopen(lib, RTLD_LAZY)
27 | #define PFree(handle) ::dlclose(handle)
28 | #define PInvoke(so, symbol) __PInvoke<__typeof__(symbol)>(so, SYMBOL_##symbol, #symbol)
29 | template __LIBC_HIDDEN__ __LIBC_INLINE__ func *__PInvoke(void *handle, const char *mangled_symbol, const char *symbol)
30 | {
31 | void *sym = ::dlsym(handle, mangled_symbol);
32 | if (UNLIKELY(sym == NULL)) sym = ::dlsym(handle, symbol);
33 | return reinterpret_cast(sym);
34 | }
35 |
36 | //-------------------------------------------------------------------------
37 |
38 | static volatile int g_slotindex = 0;
39 | static void *g_dvm;
40 | static Method g_backups[MAX_BACKUP_SLOTS];
41 | static __typeof__(&dvmFindPrimitiveClass) g_dvmFindPrimitiveClass;
42 | static __typeof__(&dvmBoxPrimitive) g_dvmBoxPrimitive;
43 | static __typeof__(&dvmUnboxPrimitive) g_dvmUnboxPrimitive;
44 | static __typeof__(&dvmDecodeIndirectRef) g_dvmDecodeIndirectRef;
45 | static __typeof__(&dvmReleaseTrackedAlloc) g_dvmReleaseTrackedAlloc;
46 | static __typeof__(&dvmThreadSelf) g_dvmThreadSelf;
47 |
48 | //-------------------------------------------------------------------------
49 |
50 | static int __native_hook(JNIEnv *env, Method *vm_origin, Method *vm_target)
51 | {
52 | // Method *vm_origin = reinterpret_cast(env->FromReflectedMethod(origin));
53 | // Method *vm_target = reinterpret_cast(env->FromReflectedMethod(target));
54 |
55 | // Dalvik puts private, static, and constructors into non-virtual table
56 | // g_dvmIsDirectMethod(vm_origin)
57 | if (IS_METHOD_FLAG_SET(vm_origin, ACC_PRIVATE) ||
58 | IS_METHOD_FLAG_SET(vm_origin, ACC_STATIC) || *vm_origin->name == '<') {
59 | LOGI("%s: hook direct %s%s -> %s%s", __FUNCTION__,
60 | vm_origin->clazz->descriptor, vm_origin->name,
61 | vm_target->clazz->descriptor, vm_target->name);
62 | // fixs for NoSuchMethodError
63 | const char *vm_name = vm_origin->name;
64 | *vm_origin = *vm_target;
65 | vm_origin->name = vm_name;
66 | return 1;
67 | } //if
68 |
69 | if (IS_METHOD_FLAG_SET(vm_origin, ACC_ABSTRACT) ||
70 | vm_origin->methodIndex >= vm_origin->clazz->vtableCount) {
71 | LOGE("%s: hook failed %s%s -> %s%s", __FUNCTION__,
72 | vm_origin->clazz->descriptor, vm_origin->name,
73 | vm_target->clazz->descriptor, vm_target->name);
74 | return -1;
75 | } //if
76 |
77 | LOGI("%s: hook virtual %s%s -> %s%s", __FUNCTION__,
78 | vm_origin->clazz->descriptor, vm_origin->name,
79 | vm_target->clazz->descriptor, vm_target->name);
80 | vm_origin->clazz->vtable[vm_origin->methodIndex] = vm_target;
81 | return 0;
82 | }
83 |
84 | //-------------------------------------------------------------------------
85 |
86 | static void JNICALL dvmHookNativeNoBackup(JNIEnv *env, jclass, jobject origin, jobject target)
87 | {
88 | Method *vm_origin = reinterpret_cast(env->FromReflectedMethod(origin));
89 | Method *vm_target = reinterpret_cast(env->FromReflectedMethod(target));
90 | __native_hook(env, vm_origin, vm_target);
91 | }
92 |
93 | //-------------------------------------------------------------------------
94 |
95 | static jint JNICALL dvmHookNative(JNIEnv *env, jclass, jobject origin, jobject target)
96 | {
97 | int slot = __atomic_inc(&g_slotindex);
98 | if (UNLIKELY(slot < 0 || slot >= NELEM(g_backups))) {
99 | LOGW("%s: slots limit exceeded %d", __FUNCTION__, slot);
100 | return -1;
101 | } //if
102 |
103 | Method *vm_origin = reinterpret_cast(env->FromReflectedMethod(origin));
104 | g_backups[slot] = *vm_origin;
105 | Method *vm_target = reinterpret_cast(env->FromReflectedMethod(target));
106 | if (__native_hook(env, vm_origin, vm_target) == 0) {
107 | CLEAR_METHOD_FLAG(&g_backups[slot], ACC_PUBLIC);
108 | SET_METHOD_FLAG(&g_backups[slot], ACC_PRIVATE);
109 |
110 | // fixs for Java.NullPointerException when looking for
111 | // backup method by stack method name, but target method may not be found later
112 | vm_target->name = vm_origin->name;
113 | } //if
114 |
115 | return slot;
116 | }
117 |
118 | //-------------------------------------------------------------------------
119 |
120 | static jvalue JNICALL __invoke_backup(JNIEnv *env, jint slot, jobject receiver, jobjectArray params)
121 | {
122 | jvalue ret; ret.j = 0L;
123 |
124 | if (UNLIKELY(slot < 0 || slot >= NELEM(g_backups))) {
125 | LOGW("%s: slots limit exceeded %d", __FUNCTION__, slot);
126 | return ret;
127 | } //if
128 |
129 | jvalue ps[MAX_PARAMS_ALLOWED];
130 | int np = env->GetArrayLength(params);
131 | if (UNLIKELY(np >= NELEM(ps))) {
132 | LOGW("%s: params limit exceeded %d", __FUNCTION__, np);
133 | return ret;
134 | } //if
135 |
136 | auto shorty = g_backups[slot].shorty;
137 | auto self = g_dvmThreadSelf();
138 | while (--np >= 0) {
139 | ps[np].l = env->GetObjectArrayElement(params, np);
140 | if (shorty[np + 1] == 'L') continue; // 'shorty' descr uses L for all refs, incl array
141 |
142 | auto typeCls = g_dvmFindPrimitiveClass(shorty[np + 1]);
143 | if (typeCls != NULL) {
144 | auto obj = g_dvmDecodeIndirectRef(self, ps[np].l);
145 | if (UNLIKELY(obj == NULL)) {
146 | LOGW("%s: decode indirect ref %p failed", __FUNCTION__, ps[np].l);
147 | return ret;
148 | } //if
149 | if (UNLIKELY(!g_dvmUnboxPrimitive(obj, typeCls, reinterpret_cast(&ps[np])))) {
150 | LOGW("%s: unbox primitive param %p failed", __FUNCTION__, obj);
151 | return ret;
152 | } //if
153 | } //if
154 | }
155 |
156 | auto originalMethod = reinterpret_cast(&g_backups[slot]);
157 | bool isStaticMethod = IS_METHOD_FLAG_SET(&g_backups[slot], ACC_STATIC);
158 | // ClassObject *retType = g_dvmFindPrimitiveClass(shorty[0]);
159 | switch (shorty[0]) {
160 | case 'V':
161 | isStaticMethod ?
162 | env->CallStaticVoidMethodA(reinterpret_cast(receiver), originalMethod, ps) :
163 | env->CallVoidMethodA(receiver, originalMethod, ps);
164 | return ret;
165 | case 'Z':
166 | ret.z = isStaticMethod ?
167 | env->CallStaticBooleanMethodA(reinterpret_cast(receiver), originalMethod, ps) :
168 | env->CallBooleanMethodA(receiver, originalMethod, ps);
169 | break;
170 | case 'B':
171 | ret.b = isStaticMethod ?
172 | env->CallStaticByteMethodA(reinterpret_cast(receiver), originalMethod, ps) :
173 | env->CallByteMethodA(receiver, originalMethod, ps);
174 | break;
175 | case 'S':
176 | ret.s = isStaticMethod ?
177 | env->CallStaticShortMethodA(reinterpret_cast(receiver), originalMethod, ps) :
178 | env->CallShortMethodA(receiver, originalMethod, ps);
179 | break;
180 | case 'C':
181 | ret.c = isStaticMethod ?
182 | env->CallStaticCharMethodA(reinterpret_cast(receiver), originalMethod, ps) :
183 | env->CallCharMethodA(receiver, originalMethod, ps);
184 | break;
185 | case 'I':
186 | ret.i = isStaticMethod ?
187 | env->CallStaticIntMethodA(reinterpret_cast(receiver), originalMethod, ps) :
188 | env->CallIntMethodA(receiver, originalMethod, ps);
189 | break;
190 | case 'J':
191 | ret.j = isStaticMethod ?
192 | env->CallStaticLongMethodA(reinterpret_cast(receiver), originalMethod, ps) :
193 | env->CallLongMethodA(receiver, originalMethod, ps);
194 | break;
195 | case 'F':
196 | ret.f = isStaticMethod ?
197 | env->CallStaticFloatMethodA(reinterpret_cast(receiver), originalMethod, ps) :
198 | env->CallFloatMethodA(receiver, originalMethod, ps);
199 | break;
200 | case 'D':
201 | ret.d = isStaticMethod ?
202 | env->CallStaticDoubleMethodA(reinterpret_cast(receiver), originalMethod, ps) :
203 | env->CallDoubleMethodA(receiver, originalMethod, ps);
204 | break;
205 | default: // objects case 'L' and '['
206 | ret.l = isStaticMethod ?
207 | env->CallStaticObjectMethodA(reinterpret_cast(receiver), originalMethod, ps) :
208 | env->CallObjectMethodA(receiver, originalMethod, ps);
209 | }
210 |
211 | // auto obj = g_dvmBoxPrimitive(ret, retType);
212 | // return g_dvmReleaseTrackedAlloc(obj, self), g_addLocalReference(self, reinterpret_cast