├── .gitignore ├── ApoloPlugin ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── jni.properties │ ├── java │ └── org │ │ └── apolo │ │ ├── ArtEngine.java │ │ ├── ArtHookInternal.java │ │ ├── HookClass.java │ │ ├── HookConstructor.java │ │ ├── HookName.java │ │ ├── MethodEntity.java │ │ └── ThisObject.java │ └── jniLibs │ ├── arm64-v8a │ └── libapolo.so │ └── armeabi-v7a │ └── libapolo.so ├── LICENSE ├── README-zh-CN.md ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── jni.properties │ ├── java │ ├── com │ │ ├── apolo │ │ │ └── helper │ │ │ │ ├── FileLogUtils.java │ │ │ │ ├── ProcessUtils.java │ │ │ │ └── RefUtils.java │ │ └── example │ │ │ └── apolo │ │ │ ├── ButtonActivity.java │ │ │ ├── DemoApplication.java │ │ │ ├── HookInject.java │ │ │ └── MainActivity.java │ └── hook │ │ ├── Test.java │ │ ├── android │ │ ├── app │ │ │ ├── ActivityManagerProxy.java │ │ │ ├── ActivityTaskManagerProxy.java │ │ │ ├── ActivityThread.java │ │ │ ├── ApplicationPackageManager.java │ │ │ └── ContextImpl.java │ │ ├── os │ │ │ ├── HandlerProxy.java │ │ │ └── ProcessProxy.java │ │ └── provider │ │ │ └── Settings.java │ │ ├── douyin │ │ ├── EncryptorUtilProxy.java │ │ └── TTEncryptUtilsProxy.java │ │ ├── java │ │ ├── io │ │ │ └── FileProxy.java │ │ └── lang │ │ │ ├── StringBuilder.java │ │ │ └── StringProxy.java │ │ ├── javax │ │ └── net │ │ │ └── ssl │ │ │ └── HttpsURLConnection.java │ │ └── utils │ │ └── Slog.java │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ └── ic_launcher_background.xml │ ├── layout │ └── activity_main.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-mdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-xhdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-xxhdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-xxxhdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── values-night │ └── themes.xml │ └── values │ ├── colors.xml │ ├── strings.xml │ └── themes.xml ├── build.gradle ├── docs ├── Apolo插件优化-支持trace过滤.md ├── Apolo插件实战-ROM环境注入app分析其行为.md ├── Apolo插件实战-dex反优化后trace代码.md └── assets │ ├── Application_entry.png │ ├── StringBuilder_toString.png │ ├── WaxMoon_wechat.png │ ├── log_Handler_sendMsg.png │ ├── log_HttpsUrlConn.png │ ├── log_StringBuilder_toString.png │ ├── log_StringProxy.png │ ├── patch_appFilter.png │ ├── patch_bindApp.png │ ├── patch_bindApp_2.png │ ├── qq_scan.png │ ├── qq_trace.png │ └── trace_filter.png ├── gradle.properties ├── gradle ├── publish.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── xposed ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src └── main ├── AndroidManifest.xml └── java ├── com └── android │ ├── dx │ ├── AppDataDirGuesser.java │ ├── BinaryOp.java │ ├── Code.java │ ├── Comparison.java │ ├── Constants.java │ ├── DexMaker.java │ ├── FieldId.java │ ├── Label.java │ ├── Local.java │ ├── MethodId.java │ ├── TypeId.java │ ├── TypeList.java │ └── UnaryOp.java │ └── internal │ └── util │ └── XmlUtils.java ├── core └── apolo │ └── xposed │ ├── DynamicBridge.java │ ├── HookerDexMaker.java │ ├── ProxyClassLoader.java │ ├── XposedCompat.java │ ├── XposedLog.java │ └── util │ ├── ActivityThreadCompat.java │ ├── DexMakerUtil.java │ └── FileUtils.java ├── de └── robv │ └── android │ └── xposed │ ├── DexCreator.java │ ├── IXposedHookCmdInit.java │ ├── IXposedHookInitPackageResources.java │ ├── IXposedHookLoadPackage.java │ ├── IXposedHookZygoteInit.java │ ├── IXposedMod.java │ ├── SELinuxHelper.java │ ├── XC_MethodHook.java │ ├── XC_MethodReplacement.java │ ├── XSharedPreferences.java │ ├── XposedBridge.java │ ├── XposedHelpers.java │ ├── XposedInit.java │ ├── callbacks │ ├── IXUnhook.java │ ├── XC_InitPackageResources.java │ ├── XC_LayoutInflated.java │ ├── XC_LoadPackage.java │ ├── XCallback.java │ └── package-info.java │ └── services │ ├── BaseService.java │ ├── BinderService.java │ ├── DirectAccessService.java │ ├── FileResult.java │ └── ZygoteService.java └── external └── org └── apache └── commons └── lang3 ├── ArrayUtils.java ├── CharSequenceUtils.java ├── CharUtils.java ├── ClassUtils.java ├── JavaVersion.java ├── ObjectUtils.java ├── StringUtils.java ├── SystemUtils.java ├── Validate.java ├── builder ├── Builder.java ├── CompareToBuilder.java ├── EqualsBuilder.java ├── HashCodeBuilder.java ├── IDKey.java ├── ReflectionToStringBuilder.java ├── ToStringBuilder.java └── ToStringStyle.java ├── exception └── CloneFailedException.java ├── mutable ├── Mutable.java └── MutableInt.java ├── reflect ├── MemberUtils.java └── MethodUtils.java └── tuple ├── ImmutablePair.java └── Pair.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | src/debug/* 17 | src/release/* 18 | -------------------------------------------------------------------------------- /ApoloPlugin/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /ApoloPlugin/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.library' 3 | } 4 | 5 | ext { 6 | POM_ARTIFACT_ID = "ApoloPlugin" 7 | POM_NAME = "ApoloPlugin" 8 | POM_DESCRIPTION = "ApoloPlugin is a lightweight java hook module on android which supports armeabi-v7a, arm64-v8a." 9 | } 10 | 11 | android { 12 | compileSdk rootProject.ext.compileSdkVersion 13 | buildToolsVersion rootProject.ext.buildToolsVersion 14 | ndkVersion rootProject.ext.ndkVersion 15 | 16 | defaultConfig { 17 | minSdk rootProject.ext.minSdkVersion 18 | targetSdk rootProject.ext.targetSdkVersion 19 | 20 | consumerProguardFiles "consumer-rules.pro" 21 | } 22 | 23 | buildTypes { 24 | debug { 25 | minifyEnabled false 26 | } 27 | release { 28 | minifyEnabled false 29 | // proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 30 | } 31 | } 32 | 33 | compileOptions { 34 | sourceCompatibility JavaVersion.VERSION_1_8 35 | targetCompatibility JavaVersion.VERSION_1_8 36 | } 37 | } 38 | 39 | dependencies { 40 | } 41 | 42 | apply from: rootProject.file('gradle/publish.gradle') 43 | -------------------------------------------------------------------------------- /ApoloPlugin/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaxMoon/ApoloPlugin/9d2e1cd99120202b08ee75c4ae101e37ffd5976e/ApoloPlugin/consumer-rules.pro -------------------------------------------------------------------------------- /ApoloPlugin/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /ApoloPlugin/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /ApoloPlugin/src/main/assets/jni.properties: -------------------------------------------------------------------------------- 1 | JniBridgeEntry=org.apolo.ArtEngine -------------------------------------------------------------------------------- /ApoloPlugin/src/main/java/org/apolo/ArtEngine.java: -------------------------------------------------------------------------------- 1 | package org.apolo; 2 | 3 | import static java.lang.annotation.ElementType.ANNOTATION_TYPE; 4 | import static java.lang.annotation.RetentionPolicy.SOURCE; 5 | 6 | import android.os.Build; 7 | import android.util.Log; 8 | 9 | import java.lang.annotation.Retention; 10 | import java.lang.annotation.Target; 11 | import java.lang.reflect.Member; 12 | import java.lang.reflect.Method; 13 | import java.util.HashMap; 14 | 15 | public class ArtEngine { 16 | private static final String TAG = "ApoloEngine"; 17 | @IntDef({ 18 | MODE_SIMPLE, 19 | MODE_TRAMPOLINE, 20 | MODE_INTERPRET 21 | }) 22 | public @interface MODE {} 23 | public static final int MODE_SIMPLE = 0x1; 24 | public static final int MODE_TRAMPOLINE = 0x1 << 1; 25 | public static final int MODE_INTERPRET = 0x1 << 2; 26 | 27 | private static volatile int sInterpretMode = 0; 28 | private static volatile boolean sInterpretLogOn = false; 29 | private static volatile String sInterpretFilter = null; 30 | private static volatile boolean sAlreadyHooked = false; 31 | 32 | public static void preLoad() { 33 | System.loadLibrary("apolo"); 34 | Log.d(TAG, "preLoad success!"); 35 | } 36 | 37 | public static void setHookMode(@MODE int mode) { 38 | sInterpretMode = mode; 39 | } 40 | 41 | public static void enableInterpretLog() { 42 | sInterpretLogOn = true; 43 | } 44 | 45 | public static void setInterpretFilterRegex(String regex) { 46 | sInterpretFilter = regex; 47 | } 48 | 49 | public static void addHooker(Class cls) { 50 | try { 51 | ArtHookInternal.addHooker(cls.getClassLoader(), cls, false); 52 | } catch (Throwable throwable) { 53 | throwable.printStackTrace(); 54 | } 55 | } 56 | 57 | public static void addHook(Member member, Method proxyMethod) { 58 | ArtHookInternal.addHook(member, proxyMethod); 59 | } 60 | 61 | public static void addHookers(ClassLoader loader, Class... classes) { 62 | try { 63 | for (Class cls : classes) { 64 | ArtHookInternal.addHooker(loader, cls, false); 65 | } 66 | 67 | } catch (Throwable throwable) { 68 | throwable.printStackTrace(); 69 | } 70 | } 71 | 72 | public static boolean contains(Member hookMethod) { 73 | return ArtHookInternal.contains(hookMethod); 74 | } 75 | 76 | public static boolean startHook() { 77 | if (sAlreadyHooked) { 78 | Log.e(TAG, "already hooked! only can be called once!"); 79 | return false; 80 | } 81 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) { 82 | Log.e(TAG, "hooked failed! platform not support!"); 83 | return false; 84 | } 85 | sAlreadyHooked = true; 86 | return nativeStartHook(ArtHookInternal.methods, sInterpretMode, sInterpretLogOn, sInterpretFilter); 87 | } 88 | 89 | /** 90 | * @param instance If origin method is static, you can pass null 91 | * @param args params must match it's signature 92 | * @param Type of return 93 | * @return Cast return to T 94 | */ 95 | public static T callOrigin(Object instance/*Nullable*/, Object... args) { 96 | return (T) nativeCallOrigin(instance, args); 97 | } 98 | 99 | /** 100 | * Note: Only the current thread is affected! 101 | *

102 | * If you want to disable hook-status in the current thread, pass true. 103 | * HookTransition(true); 104 | *

105 | * enable hook-status in the current thread, Pass false 106 | * HookTransition(false); 107 | * 108 | * @param originMode Represents whether the original function is executed when method enter 109 | * true: call originMethod 110 | * false: call proxyMethod 111 | */ 112 | public static native void hookTransition(boolean originMode); 113 | 114 | private static native Object nativeCallOrigin(Object instance/*Nullable*/, Object[] args); 115 | 116 | /** 117 | * @param proxyMethods 118 | * @param mode {@link MODE} 119 | * @param interpretLogOn 120 | * @param filterRegex 121 | * @return If hook success, will return true 122 | */ 123 | private static native boolean nativeStartHook(HashMap proxyMethods, @MODE int mode, boolean interpretLogOn, String filterRegex); 124 | 125 | private static native void reserve0(); 126 | 127 | private static native void reserve1(); 128 | 129 | @Retention(SOURCE) 130 | @Target({ANNOTATION_TYPE}) 131 | @interface IntDef { 132 | int[] value() default {}; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /ApoloPlugin/src/main/java/org/apolo/ArtHookInternal.java: -------------------------------------------------------------------------------- 1 | package org.apolo; 2 | 3 | import android.util.Log; 4 | 5 | import java.lang.annotation.Annotation; 6 | import java.lang.reflect.Constructor; 7 | import java.lang.reflect.Member; 8 | import java.lang.reflect.Method; 9 | import java.util.HashMap; 10 | 11 | class ArtHookInternal { 12 | final static HashMap methods = new HashMap<>(); 13 | 14 | private static final String TAG = "ArtHookInternal"; 15 | 16 | public static void addHooker(ClassLoader loader, Class cls, boolean ignoreException) throws Throwable { 17 | if (loader == null) { 18 | loader = ArtHookInternal.class.getClassLoader(); 19 | } 20 | Class target = getHookTarget(loader, cls); 21 | 22 | Method[] methods = cls.getDeclaredMethods(); 23 | 24 | for (Method method : methods) { 25 | try { 26 | Annotation[][] annotations = method.getParameterAnnotations(); 27 | MethodEntity entity = new MethodEntity(target, method); 28 | 29 | HookName name = method.getAnnotation(HookName.class); 30 | if (name != null) { 31 | entity.name = name.value(); 32 | entity._constructor = HookName.CONSTRUCTOR.contains(entity.name); 33 | } else { 34 | HookConstructor constructor = method.getAnnotation(HookConstructor.class); 35 | if (constructor != null) { 36 | entity.name = ""; 37 | entity._constructor = true; 38 | } 39 | } 40 | if (entity.name == null) continue; 41 | 42 | if (annotations.length > 0) { 43 | for (int i = 0; i < annotations[0].length; i++) { 44 | if (annotations[0][i].annotationType() == ThisObject.class) { 45 | entity._static = true; 46 | break; 47 | } 48 | 49 | } 50 | } 51 | int paramIndex = 0; 52 | if (entity._static) { 53 | paramIndex++; 54 | } 55 | Class[] types = method.getParameterTypes(); 56 | entity.paramTypes = new Class[types.length - paramIndex]; 57 | for (int i = paramIndex; i < annotations.length; i++) { 58 | int index = i - paramIndex; 59 | for (int j = 0; j < annotations[i].length; j++) { 60 | if (annotations[i][j].annotationType() == HookName.class) { 61 | HookName hookName = (HookName) annotations[i][j]; 62 | entity.paramTypes[index] = loadClass(loader, hookName.value()); 63 | } 64 | } 65 | if (entity.paramTypes[index] == null) { 66 | entity.paramTypes[index] = types[i]; 67 | } 68 | } 69 | 70 | if (entity._constructor) { 71 | Constructor constructor = entity.declaredClass.getDeclaredConstructor(entity.paramTypes); 72 | constructor.setAccessible(true); 73 | entity.member = constructor; 74 | } else { 75 | Method m = entity.declaredClass.getDeclaredMethod(entity.name, entity.paramTypes); 76 | m.setAccessible(true); 77 | entity.member = m; 78 | } 79 | Log.d(TAG, String.format("addHooker: %s.%s", entity.declaredClass.getName(), entity.name)); 80 | ArtHookInternal.methods.put(entity.member, method); 81 | } catch (Throwable e) { 82 | if (!ignoreException) { 83 | throw e; 84 | } 85 | Log.w(TAG, "addHooker: failed " + e); 86 | } 87 | 88 | 89 | } 90 | } 91 | 92 | private static Class getHookTarget(ClassLoader loader, Class cls) throws Throwable { 93 | HookClass targetAno = cls.getAnnotation(HookClass.class); 94 | Class target = null; 95 | 96 | if (targetAno != null) { 97 | target = targetAno.value(); 98 | } else { 99 | HookName name = cls.getAnnotation(HookName.class); 100 | if (name != null) { 101 | target = loadClass(loader, name.value()); 102 | } 103 | } 104 | return target; 105 | } 106 | 107 | private static Class loadClass(ClassLoader loader, String name) throws Throwable { 108 | return loader.loadClass(name); 109 | } 110 | 111 | public static void addHook(Member member, Method proxyMethod) { 112 | methods.put(member, proxyMethod); 113 | } 114 | 115 | public static boolean contains(Member member) { 116 | return methods.containsKey(member); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /ApoloPlugin/src/main/java/org/apolo/HookClass.java: -------------------------------------------------------------------------------- 1 | package org.apolo; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR}) 10 | public @interface HookClass { 11 | Class value(); 12 | } 13 | -------------------------------------------------------------------------------- /ApoloPlugin/src/main/java/org/apolo/HookConstructor.java: -------------------------------------------------------------------------------- 1 | package org.apolo; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ElementType.CONSTRUCTOR}) 10 | public @interface HookConstructor { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ApoloPlugin/src/main/java/org/apolo/HookName.java: -------------------------------------------------------------------------------- 1 | package org.apolo; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER}) 10 | public @interface HookName { 11 | String CONSTRUCTOR = ""; 12 | 13 | String value(); 14 | } 15 | -------------------------------------------------------------------------------- /ApoloPlugin/src/main/java/org/apolo/MethodEntity.java: -------------------------------------------------------------------------------- 1 | package org.apolo; 2 | 3 | import java.lang.reflect.Member; 4 | import java.lang.reflect.Method; 5 | 6 | class MethodEntity { 7 | boolean _static; 8 | boolean _constructor; 9 | Class[] paramTypes; 10 | String name; 11 | Class declaredClass; 12 | Member member; 13 | Method proxyMethod; 14 | 15 | public MethodEntity(Class target, Method method) { 16 | declaredClass = target; 17 | proxyMethod = method; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ApoloPlugin/src/main/java/org/apolo/ThisObject.java: -------------------------------------------------------------------------------- 1 | package org.apolo; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ElementType.PARAMETER}) 10 | public @interface ThisObject { 11 | } 12 | -------------------------------------------------------------------------------- /ApoloPlugin/src/main/jniLibs/arm64-v8a/libapolo.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaxMoon/ApoloPlugin/9d2e1cd99120202b08ee75c4ae101e37ffd5976e/ApoloPlugin/src/main/jniLibs/arm64-v8a/libapolo.so -------------------------------------------------------------------------------- /ApoloPlugin/src/main/jniLibs/armeabi-v7a/libapolo.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaxMoon/ApoloPlugin/9d2e1cd99120202b08ee75c4ae101e37ffd5976e/ApoloPlugin/src/main/jniLibs/armeabi-v7a/libapolo.so -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 WaxMoon 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 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | } 4 | 5 | android { 6 | compileSdk rootProject.ext.compileSdkVersion 7 | buildToolsVersion rootProject.ext.buildToolsVersion 8 | ndkVersion rootProject.ext.ndkVersion 9 | 10 | defaultConfig { 11 | applicationId "com.example.apolo" 12 | minSdk rootProject.ext.minSdkVersion 13 | targetSdk rootProject.ext.targetSdkVersion 14 | versionCode 1 15 | versionName "1.0" 16 | ndk { 17 | setAbiFilters(["armeabi-v7a", "arm64-v8a"]) 18 | } 19 | } 20 | 21 | buildTypes { 22 | release { 23 | minifyEnabled false 24 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 25 | signingConfig signingConfigs.create("release") 26 | signingConfig.initWith(buildTypes.debug.signingConfig) 27 | } 28 | } 29 | compileOptions { 30 | sourceCompatibility rootProject.ext.javaVersion 31 | targetCompatibility rootProject.ext.javaVersion 32 | } 33 | } 34 | 35 | dependencies { 36 | 37 | implementation 'androidx.appcompat:appcompat:1.4.1' 38 | implementation 'com.google.android.material:material:1.5.0' 39 | implementation 'androidx.constraintlayout:constraintlayout:2.1.3' 40 | 41 | if (rootProject.ext.useLocalLibrary) { 42 | implementation project(':ApoloPlugin') 43 | implementation project(':xposed') 44 | } else { 45 | implementation "io.github.waxmoon:ApoloPlugin:${POM_VERSION_NAME}" 46 | implementation "io.github.waxmoon:xposed:${POM_VERSION_NAME}" 47 | } 48 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/assets/jni.properties: -------------------------------------------------------------------------------- 1 | JniBridgeEntry=org.apolo.ArtEngine 2 | #only used when use repack.sh 3 | InjectEntry=com.example.apolo.HookInject 4 | -------------------------------------------------------------------------------- /app/src/main/java/com/apolo/helper/FileLogUtils.java: -------------------------------------------------------------------------------- 1 | package com.apolo.helper; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import java.io.File; 7 | import java.io.FileNotFoundException; 8 | import java.io.FileOutputStream; 9 | import java.io.IOException; 10 | import java.io.RandomAccessFile; 11 | import java.text.SimpleDateFormat; 12 | import java.util.Date; 13 | 14 | public class FileLogUtils { 15 | private static final String TAG = FileLogUtils.class.getSimpleName(); 16 | private static FileLogUtils instance; 17 | 18 | private Context mAppContext; 19 | private File mSaveDir; 20 | 21 | private final String mLogFile = "log.txt"; 22 | 23 | private FileLogUtils() { 24 | 25 | } 26 | 27 | public static FileLogUtils getInstance() { 28 | if (instance == null) { 29 | synchronized (FileLogUtils.class) { 30 | if (instance == null) { 31 | instance = new FileLogUtils(); 32 | } 33 | } 34 | } 35 | return instance; 36 | } 37 | 38 | public void init(Context context) { 39 | mAppContext = context; 40 | mSaveDir = mAppContext.getExternalCacheDir(); 41 | } 42 | 43 | private void initSaveDirIfNeed() { 44 | if (mSaveDir == null) { 45 | synchronized (this) { 46 | if (mSaveDir == null) { 47 | mSaveDir = ProcessUtils.getMainApplication().getExternalCacheDir(); 48 | } 49 | } 50 | } 51 | } 52 | 53 | 54 | /** 55 | * 清空Log 56 | */ 57 | public void clearLogs() { 58 | initSaveDirIfNeed(); 59 | File file_log = new File(mSaveDir, mLogFile); 60 | if (!file_log.exists()) { 61 | return; 62 | } 63 | FileOutputStream fos = null; 64 | try { 65 | fos = new FileOutputStream(file_log); 66 | fos.write("".getBytes()); 67 | } catch (FileNotFoundException e) { 68 | e.printStackTrace(); 69 | } catch (IOException e) { 70 | e.printStackTrace(); 71 | } finally { 72 | if (fos != null) { 73 | try { 74 | fos.close(); 75 | } catch (IOException e) { 76 | e.printStackTrace(); 77 | } 78 | } 79 | } 80 | } 81 | 82 | 83 | /** 84 | * 追加保存Log 85 | */ 86 | public void saveLog(String content) { 87 | initSaveDirIfNeed(); 88 | if (!mSaveDir.exists()) { 89 | Log.e(TAG, "saveLogs mkdir"); 90 | mSaveDir.mkdir(); 91 | } 92 | 93 | Log.e(TAG, "SaveDir=" + mSaveDir); 94 | 95 | RandomAccessFile randomAccessFile = null; 96 | 97 | try { 98 | 99 | StringBuffer stringBuffer = new StringBuffer(); 100 | stringBuffer.setLength(0); 101 | //拼接一个日期 102 | stringBuffer.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS").format(new Date())); 103 | stringBuffer.append(" "); 104 | stringBuffer.append(content); 105 | stringBuffer.append("\n"); 106 | 107 | File file_log = new File(mSaveDir, mLogFile); 108 | if (!file_log.exists()) { 109 | file_log.createNewFile(); 110 | } 111 | 112 | randomAccessFile = new RandomAccessFile(file_log, "rw"); 113 | randomAccessFile.seek(file_log.length()); 114 | randomAccessFile.write(stringBuffer.toString().getBytes("UTF-8")); 115 | 116 | } catch (IOException e) { 117 | e.printStackTrace(); 118 | } finally { 119 | if (randomAccessFile != null) { 120 | try { 121 | randomAccessFile.close(); 122 | } catch (IOException e) { 123 | e.printStackTrace(); 124 | } 125 | } 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /app/src/main/java/com/apolo/helper/ProcessUtils.java: -------------------------------------------------------------------------------- 1 | package com.apolo.helper; 2 | 3 | import android.app.ActivityManager; 4 | import android.app.Application; 5 | import android.content.Context; 6 | import android.os.Process; 7 | import android.text.TextUtils; 8 | import android.util.Log; 9 | 10 | import java.util.List; 11 | 12 | 13 | public class ProcessUtils { 14 | private static final String TAG = ProcessUtils.class.getSimpleName(); 15 | private static String sCurProcessName; 16 | private static Application sMainApplication; 17 | public static String getCurProcessName(Context context) { 18 | String procName = sCurProcessName; 19 | if (!TextUtils.isEmpty(procName)) { 20 | return procName; 21 | } 22 | try { 23 | int selfPid = Process.myPid(); 24 | ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 25 | for (ActivityManager.RunningAppProcessInfo info : mActivityManager.getRunningAppProcesses()) { 26 | if (info.pid == selfPid) { 27 | sCurProcessName = info.processName; 28 | return sCurProcessName; 29 | } 30 | } 31 | } catch (Exception e) { 32 | Log.e(TAG, "getCurProcessName failed", e); 33 | } 34 | return sCurProcessName; 35 | } 36 | 37 | public static Application getMainApplication() { 38 | if (sMainApplication != null) { 39 | return sMainApplication; 40 | } 41 | RefUtils.MethodRef methodRef_currentActivityThread = new RefUtils.MethodRef( 42 | "android.app.ActivityThread", true, 43 | "currentActivityThread", new Class[0] 44 | ); 45 | RefUtils.FieldRef> fieldRef_mAllApplications = new RefUtils.FieldRef>( 46 | "android.app.ActivityThread", false, "mAllApplications" 47 | ); 48 | Object activityThread = methodRef_currentActivityThread.invoke(null, new Object[0]); 49 | List allApplications = fieldRef_mAllApplications.get(activityThread); 50 | 51 | if (allApplications != null && allApplications.size() > 0) { 52 | for (int i = 0; i < allApplications.size(); i++) { 53 | Application tmp = allApplications.get(i); 54 | if (TextUtils.equals(tmp.getApplicationInfo().processName, 55 | ProcessUtils.getCurProcessName(tmp))) { 56 | sMainApplication = tmp; 57 | Log.d(TAG, "getMainApplication success"); 58 | break; 59 | } 60 | } 61 | } else { 62 | Log.e(TAG, "getMainApplication fail"); 63 | } 64 | 65 | return sMainApplication; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/com/apolo/helper/RefUtils.java: -------------------------------------------------------------------------------- 1 | package com.apolo.helper; 2 | 3 | import java.lang.reflect.Field; 4 | import java.lang.reflect.Method; 5 | 6 | public class RefUtils { 7 | public static Field getField(Class refClass, boolean isStatic, String filedName) { 8 | if (refClass == null || filedName == null) { 9 | return null; 10 | } 11 | try { 12 | return refClass.getDeclaredField(filedName); 13 | } catch (NoSuchFieldException e) { 14 | 15 | } 16 | return null; 17 | } 18 | 19 | public static Method getMethod(Class refClass, boolean isStatic, String funcName, Class[] paramTypes) { 20 | if (refClass == null || funcName == null) { 21 | return null; 22 | } 23 | try { 24 | return refClass.getDeclaredMethod(funcName, paramTypes); 25 | } catch (NoSuchMethodException e) { 26 | 27 | } 28 | return null; 29 | } 30 | 31 | public static class FieldRef { 32 | boolean mIsStatic; 33 | Field mField; 34 | public FieldRef(Class refClass, boolean isStatic, String name) { 35 | mIsStatic = isStatic; 36 | mField = getField(refClass, isStatic, name); 37 | if (mField != null) { 38 | mField.setAccessible(true); 39 | } 40 | } 41 | public FieldRef(String className, boolean isStatic, String name) { 42 | try { 43 | Class targetClass = Class.forName(className); 44 | mField = getField(targetClass, isStatic, name); 45 | } catch (ClassNotFoundException e) { 46 | } 47 | mIsStatic = isStatic; 48 | if (mField != null) { 49 | mField.setAccessible(true); 50 | } 51 | } 52 | 53 | public boolean isValid() { 54 | return mField != null; 55 | } 56 | 57 | public T get(Object instance) { 58 | try { 59 | return (T) mField.get(instance); 60 | } catch (Exception e) { 61 | 62 | } 63 | return null; 64 | } 65 | public void set(Object instance, T value) { 66 | try { 67 | mField.set(instance, value); 68 | } catch (Exception e) { 69 | 70 | } 71 | } 72 | } 73 | 74 | public static class MethodRef { 75 | Method mMethod; 76 | public MethodRef(String className, boolean isStatic, String funcName, Class[] paramsTypes) { 77 | try { 78 | Class targetClass = Class.forName(className); 79 | mMethod = getMethod(targetClass, isStatic, funcName, paramsTypes); 80 | } catch (Exception e) { 81 | } 82 | if (mMethod != null) { 83 | mMethod.setAccessible(true); 84 | } 85 | } 86 | public MethodRef(Class refClass, boolean isStatic, String funcName, Class[] paramsTypes) { 87 | mMethod = getMethod(refClass, isStatic, funcName, paramsTypes); 88 | if (mMethod != null) { 89 | mMethod.setAccessible(true); 90 | } 91 | } 92 | 93 | public boolean isValid() { 94 | return mMethod != null; 95 | } 96 | 97 | public T invoke(Object instance, Object[] args) { 98 | try { 99 | return (T) mMethod.invoke(instance, args); 100 | } catch (Exception e) { 101 | } 102 | return null; 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/apolo/ButtonActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.apolo; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.util.Log; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.Button; 9 | import android.widget.FrameLayout; 10 | import android.widget.LinearLayout; 11 | import android.widget.ScrollView; 12 | 13 | import androidx.appcompat.app.AppCompatActivity; 14 | 15 | import java.util.UUID; 16 | 17 | public class ButtonActivity extends AppCompatActivity { 18 | protected String TAG = "Button." + getClass().getSimpleName(); 19 | 20 | private LinearLayout mContainer; 21 | 22 | public Intent withIntent(Class cls) { 23 | Intent intent = new Intent(this, cls); 24 | intent.putExtra("serial", UUID.randomUUID().toString()); 25 | return intent; 26 | } 27 | 28 | public Intent withIntent(Class cls, int flags) { 29 | Intent intent = new Intent(this, cls); 30 | intent.putExtra("serial", UUID.randomUUID().toString()); 31 | intent.addFlags(flags); 32 | return intent; 33 | } 34 | 35 | public Intent withIntent(Intent intent, int flags) { 36 | intent.putExtra("serial", UUID.randomUUID().toString()); 37 | intent.addFlags(flags); 38 | return intent; 39 | } 40 | 41 | public String serial(Intent intent) { 42 | return intent.getStringExtra("serial"); 43 | } 44 | 45 | @Override 46 | protected void onNewIntent(Intent intent) { 47 | super.onNewIntent(intent); 48 | Log.d(TAG, "onNewIntent: " + serial(intent) + " " + getTaskId()); 49 | } 50 | 51 | @Override 52 | protected void onCreate(Bundle savedInstanceState) { 53 | super.onCreate(savedInstanceState); 54 | Log.d(TAG, "onCreate: " + serial(getIntent()) + " " + getTaskId()); 55 | mContainer = new LinearLayout(this); 56 | mContainer.setOrientation(LinearLayout.VERTICAL); 57 | ScrollView scrollView = new ScrollView(this); 58 | scrollView.addView(mContainer); 59 | setContentView(scrollView); 60 | addButton(getClass().getName() + " " + getTaskId(), null); 61 | } 62 | 63 | @Override 64 | protected void onStart() { 65 | super.onStart(); 66 | Log.d(TAG, "onStart: "); 67 | } 68 | 69 | @Override 70 | protected void onRestart() { 71 | super.onRestart(); 72 | Log.d(TAG, "onRestart: "); 73 | } 74 | 75 | @Override 76 | protected void onResume() { 77 | super.onResume(); 78 | Log.d(TAG, "onResume: "); 79 | } 80 | 81 | @Override 82 | protected void onPause() { 83 | super.onPause(); 84 | Log.d(TAG, "onPause: "); 85 | } 86 | 87 | @Override 88 | protected void onStop() { 89 | super.onStop(); 90 | Log.d(TAG, "onStop: "); 91 | } 92 | 93 | @Override 94 | protected void onDestroy() { 95 | super.onDestroy(); 96 | Log.d(TAG, "onDestroy: "); 97 | } 98 | 99 | protected Button addButton(final String text, final View.OnClickListener clickListener) { 100 | Button button = new Button(this); 101 | button.setText(text); 102 | button.setAllCaps(false); 103 | button.setOnClickListener(clickListener); 104 | mContainer.addView(button, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); 105 | return button; 106 | } 107 | 108 | 109 | } 110 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/apolo/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.apolo; 2 | 3 | import android.app.Activity; 4 | import android.app.Application; 5 | import android.os.Bundle; 6 | import android.util.Log; 7 | 8 | import com.apolo.helper.FileLogUtils; 9 | import com.apolo.helper.ProcessUtils; 10 | 11 | import org.apolo.ArtEngine; 12 | 13 | import de.robv.android.xposed.XC_MethodHook; 14 | import de.robv.android.xposed.XposedHelpers; 15 | import hook.Test; 16 | import hook.android.app.ActivityManagerProxy; 17 | import hook.android.app.ActivityTaskManagerProxy; 18 | import hook.android.app.ActivityThread; 19 | import hook.android.app.ApplicationPackageManager; 20 | import hook.android.app.ContextImpl; 21 | import hook.android.os.HandlerProxy; 22 | import hook.android.os.ProcessProxy; 23 | import hook.android.provider.Settings; 24 | import hook.douyin.EncryptorUtilProxy; 25 | import hook.douyin.TTEncryptUtilsProxy; 26 | import hook.java.io.FileProxy; 27 | import hook.java.lang.StringProxy; 28 | import hook.javax.net.ssl.HttpsURLConnection; 29 | 30 | 31 | public class DemoApplication extends Application { 32 | 33 | private static final String TAG = DemoApplication.class.getSimpleName(); 34 | 35 | private static Application sApp; 36 | 37 | @Override 38 | public void onCreate() { 39 | super.onCreate(); 40 | sApp = this; 41 | FileLogUtils.getInstance().init(this); 42 | FileLogUtils.getInstance().clearLogs(); 43 | HookInject.main(); 44 | } 45 | 46 | public static Application getMyApplication() { 47 | return sApp; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/apolo/HookInject.java: -------------------------------------------------------------------------------- 1 | package com.example.apolo; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.util.Log; 6 | 7 | import org.apolo.ArtEngine; 8 | 9 | import de.robv.android.xposed.XC_MethodHook; 10 | import de.robv.android.xposed.XposedHelpers; 11 | import hook.Test; 12 | import hook.android.app.ActivityManagerProxy; 13 | import hook.android.app.ActivityTaskManagerProxy; 14 | import hook.android.app.ActivityThread; 15 | import hook.android.app.ApplicationPackageManager; 16 | import hook.android.app.ContextImpl; 17 | import hook.android.os.HandlerProxy; 18 | import hook.android.os.ProcessProxy; 19 | import hook.android.provider.Settings; 20 | import hook.java.io.FileProxy; 21 | import hook.javax.net.ssl.HttpsURLConnection; 22 | 23 | public class HookInject { 24 | static { 25 | //init ArtHook 26 | ArtEngine.preLoad(); 27 | } 28 | 29 | public static void main() { 30 | ArtEngine.addHookers(DemoApplication.class.getClassLoader(), 31 | // StringProxy.class, 32 | // StringBuilder.class,//尽量不hook StringBuilder 33 | FileProxy.class, 34 | ProcessProxy.class, 35 | HandlerProxy.class, 36 | ActivityThread.class, 37 | ApplicationPackageManager.class, 38 | ContextImpl.class, 39 | Settings.Global.class, 40 | Test.class); 41 | 42 | ArtEngine.addHooker(ActivityManagerProxy.class); 43 | ArtEngine.addHooker(ActivityTaskManagerProxy.class); 44 | 45 | 46 | //try inject douyin 47 | // try { 48 | // ArtEngine.addHookers(ProcessUtils.getMainApplication().getClassLoader(), 49 | // EncryptorUtilProxy.class, 50 | // TTEncryptUtilsProxy.class); 51 | // } catch (Exception e) { 52 | // e.printStackTrace(); 53 | // } 54 | 55 | ArtEngine.addHooker(HttpsURLConnection.class); 56 | 57 | XposedHelpers.findAndHookMethod(Activity.class, "onResume", new XC_MethodHook() { 58 | @Override 59 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 60 | super.beforeHookedMethod(param); 61 | Log.e("XposedCompat", "beforeHookedMethod: " + param.method.getName()); 62 | } 63 | 64 | @Override 65 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 66 | super.afterHookedMethod(param); 67 | Log.e("XposedCompat", "afterHookedMethod: " + param.method.getName()); 68 | } 69 | }); 70 | 71 | XposedHelpers.findAndHookMethod(Activity.class, "onCreate", Bundle.class, new XC_MethodHook() { 72 | @Override 73 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 74 | super.beforeHookedMethod(param); 75 | Log.e("XposedCompat", "beforeHookedMethod: " + param.method.getName()); 76 | } 77 | 78 | @Override 79 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 80 | super.afterHookedMethod(param); 81 | Log.e("XposedCompat", "afterHookedMethod: " + param.method.getName()); 82 | } 83 | }); 84 | //split ',' 85 | //ArtEngine.setInterpretFilterRegex("android.app.*,android.os.*"); 86 | //ArtEngine.enableInterpretLog(); 87 | ArtEngine.setHookMode(ArtEngine.MODE_INTERPRET);//如果已声明debuggable=true,此处不需要再调用 88 | ArtEngine.startHook(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/apolo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.apolo; 2 | 3 | import android.os.Bundle; 4 | import android.os.Handler; 5 | import android.util.Log; 6 | import android.view.View; 7 | 8 | import java.io.IOException; 9 | import java.util.List; 10 | 11 | import hook.Test; 12 | 13 | 14 | public class MainActivity extends ButtonActivity { 15 | 16 | final static String TAG = "MainActivity"; 17 | 18 | @Override 19 | protected void onCreate(Bundle savedInstanceState) { 20 | super.onCreate(savedInstanceState); 21 | addButton("getPackageManager", new View.OnClickListener() { 22 | @Override 23 | public void onClick(View v) { 24 | Log.d(TAG, "getInstalledPackages called before+++++++"); 25 | List xx = getPackageManager().getInstalledPackages(0); 26 | Log.d(TAG, "getInstalledPackages called end--------" + xx); 27 | } 28 | }); 29 | 30 | addButton("test io exception", new View.OnClickListener() { 31 | @Override 32 | public void onClick(View v) { 33 | try { 34 | new Test().test(); 35 | } catch (IOException e) { 36 | e.printStackTrace(); 37 | } 38 | } 39 | }); 40 | 41 | addButton("Handler enqueueMessage", new View.OnClickListener() { 42 | @Override 43 | public void onClick(View v) { 44 | Log.d(TAG, "Handler post begin++++"); 45 | new Handler().post(new Runnable() { 46 | @Override 47 | public void run() { 48 | Log.d(TAG, "runnable execute..."); 49 | } 50 | }); 51 | Log.d(TAG, "Handler post end----"); 52 | } 53 | }); 54 | 55 | } 56 | } -------------------------------------------------------------------------------- /app/src/main/java/hook/Test.java: -------------------------------------------------------------------------------- 1 | package hook; 2 | 3 | import java.io.IOException; 4 | import org.apolo.ArtEngine; 5 | import org.apolo.HookClass; 6 | import org.apolo.HookName; 7 | import org.apolo.ThisObject; 8 | import hook.utils.Slog; 9 | 10 | @HookClass(Test.class) 11 | public class Test { 12 | @HookName("test") 13 | public static void test(@ThisObject Object o) { 14 | Slog.d("test", "test: " + o); 15 | ArtEngine.callOrigin(o); 16 | } 17 | 18 | public void test() throws IOException { 19 | throw new IOException("test"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/hook/android/app/ActivityManagerProxy.java: -------------------------------------------------------------------------------- 1 | package hook.android.app; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | 7 | import org.apolo.ArtEngine; 8 | import org.apolo.HookName; 9 | import org.apolo.ThisObject; 10 | 11 | import hook.utils.Slog; 12 | 13 | @HookName("android.app.ActivityManager") 14 | public class ActivityManagerProxy { 15 | private static final String TAG = ActivityManagerProxy.class.getSimpleName(); 16 | 17 | @HookName("startActivity") 18 | public void startActivity(@ThisObject Object thiz, Context context, Intent intent, Bundle options) { 19 | 20 | Slog.d(TAG, "startActivity " + intent, new Exception()); 21 | ArtEngine.callOrigin(thiz, context, intent, options); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/hook/android/app/ActivityTaskManagerProxy.java: -------------------------------------------------------------------------------- 1 | package hook.android.app; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.os.IBinder; 6 | 7 | import org.apolo.ArtEngine; 8 | import org.apolo.HookName; 9 | import org.apolo.ThisObject; 10 | 11 | import hook.utils.Slog; 12 | 13 | @HookName("android.app.IActivityTaskManager$Stub$Proxy") 14 | public class ActivityTaskManagerProxy { 15 | 16 | private static final String TAG = ActivityTaskManagerProxy.class.getSimpleName(); 17 | 18 | //android11.0+ 19 | @HookName("startActivity") 20 | public static int startActivity(@ThisObject Object thiz, 21 | @HookName("android.app.IApplicationThread") Object appThread, 22 | String callingPackage, String xx, Intent intent, 23 | String resolvedType, IBinder resultTo, String resultWho, 24 | int requestCode, int flags, 25 | @HookName("android.app.ProfilerInfo") Object profilerInfo, 26 | Bundle options) { 27 | 28 | Slog.d(TAG, "startActivity called " + intent, new Exception()); 29 | return ArtEngine.callOrigin(thiz, appThread, callingPackage, xx, intent, 30 | resolvedType, resultTo, resultWho, requestCode, flags, profilerInfo, options); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/hook/android/app/ActivityThread.java: -------------------------------------------------------------------------------- 1 | package hook.android.app; 2 | 3 | import org.apolo.ArtEngine; 4 | import org.apolo.HookName; 5 | import hook.utils.Slog; 6 | 7 | @HookName("android.app.ActivityThread") 8 | public class ActivityThread { 9 | 10 | private static final String TAG = ActivityThread.class.getSimpleName(); 11 | 12 | @HookName("currentActivityThread") 13 | public static Object currentActivityThread() { 14 | Slog.d(TAG, "proxy_currentActivityThread called", new Exception()); 15 | return ArtEngine.callOrigin(null); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/hook/android/app/ApplicationPackageManager.java: -------------------------------------------------------------------------------- 1 | package hook.android.app; 2 | 3 | import android.content.pm.PackageInfo; 4 | import android.content.pm.PackageManager; 5 | import android.widget.Toast; 6 | 7 | import com.example.apolo.DemoApplication; 8 | 9 | import java.util.Collections; 10 | import java.util.List; 11 | 12 | 13 | import org.apolo.ArtEngine; 14 | import org.apolo.HookName; 15 | import org.apolo.ThisObject; 16 | import hook.utils.Slog; 17 | 18 | @HookName("android.app.ApplicationPackageManager") 19 | public class ApplicationPackageManager { 20 | 21 | private static final String TAG = ApplicationPackageManager.class.getSimpleName(); 22 | 23 | @HookName("getInstalledPackages") 24 | public static List getInstalledPackages(@ThisObject PackageManager pm, int flags) { 25 | Slog.d(TAG, "proxy_getInstalledPackages called+++ ", new Throwable()); 26 | List pkgInfos = ArtEngine.callOrigin(pm, flags); 27 | Slog.d(TAG, "proxy_getInstalledPackages origin list.size: " + pkgInfos.size()); 28 | 29 | Toast.makeText(DemoApplication.getMyApplication(), "proxy_getInstalledPackages called", Toast.LENGTH_SHORT).show(); 30 | 31 | Slog.d(TAG, "proxy_getInstalledPackages force return empty result"); 32 | return Collections.emptyList(); 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/hook/android/app/ContextImpl.java: -------------------------------------------------------------------------------- 1 | package hook.android.app; 2 | 3 | import org.apolo.ArtEngine; 4 | import org.apolo.HookName; 5 | import org.apolo.ThisObject; 6 | import hook.utils.Slog; 7 | 8 | @HookName("android.app.ContextImpl") 9 | public class ContextImpl { 10 | private static final String TAG = ContextImpl.class.getSimpleName(); 11 | 12 | @HookName("getSystemService") 13 | public static Object getSystemService(@ThisObject Object thiz, String serviceName) { 14 | Slog.d(TAG, "proxy_getSystemService for %s", new Exception(), serviceName); 15 | return ArtEngine.callOrigin(thiz, serviceName); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/hook/android/os/HandlerProxy.java: -------------------------------------------------------------------------------- 1 | package hook.android.os; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | import android.os.MessageQueue; 6 | 7 | import org.apolo.ArtEngine; 8 | import org.apolo.HookClass; 9 | import org.apolo.HookName; 10 | import org.apolo.ThisObject; 11 | 12 | import hook.utils.Slog; 13 | 14 | @HookClass(Handler.class) 15 | public class HandlerProxy { 16 | private static final String TAG = HandlerProxy.class.getSimpleName(); 17 | 18 | @HookName("sendMessageAtTime") 19 | public static boolean sendMessageAtTime(@ThisObject Object obj, Message msg, long uptimeMillis) { 20 | Slog.d(TAG, "proxy_sendMessageAtTime called: " + msg); 21 | return ArtEngine.callOrigin(obj, msg, uptimeMillis); 22 | } 23 | 24 | @HookName("enqueueMessage") 25 | public static boolean enqueueMessage(@ThisObject Handler handler, MessageQueue msgQueue, 26 | Message msg, long uptimeMillis) { 27 | Slog.d(TAG, "proxy_enqueueMessage called"); 28 | return ArtEngine.callOrigin(handler, msgQueue, msg, uptimeMillis); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/hook/android/os/ProcessProxy.java: -------------------------------------------------------------------------------- 1 | package hook.android.os; 2 | 3 | import android.os.Process; 4 | 5 | import org.apolo.ArtEngine; 6 | import org.apolo.HookClass; 7 | import org.apolo.HookName; 8 | 9 | import hook.utils.Slog; 10 | 11 | @HookClass(Process.class) 12 | public class ProcessProxy { 13 | 14 | private static final String TAG = "ProcessProxy"; 15 | @HookName("killProcess") 16 | public static final void killProcess(int pid) { 17 | Slog.d(TAG, "killProcess", new Exception()); 18 | ArtEngine.callOrigin(null, pid); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/hook/android/provider/Settings.java: -------------------------------------------------------------------------------- 1 | package hook.android.provider; 2 | 3 | import android.content.ContentResolver; 4 | 5 | import org.apolo.ArtEngine; 6 | import org.apolo.HookName; 7 | import hook.utils.Slog; 8 | 9 | public class Settings { 10 | @HookName("android.provider.Settings$Global") 11 | public static class Global { 12 | private static final String TAG = "Settings.Global"; 13 | 14 | public static String getString(ContentResolver cr, String key) { 15 | String ret = ArtEngine.callOrigin(null, cr, key); 16 | Slog.d(TAG, "proxy_getString key: %s value: %s", key, ret); 17 | return ret; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/hook/douyin/EncryptorUtilProxy.java: -------------------------------------------------------------------------------- 1 | package hook.douyin; 2 | 3 | import org.apolo.ArtEngine; 4 | import org.apolo.HookName; 5 | 6 | import hook.utils.Slog; 7 | 8 | @HookName("com.bytedance.frameworks.encryptor.EncryptorUtil") 9 | public class EncryptorUtilProxy { 10 | 11 | private static final String TAG = "EncryptorUtilProxy"; 12 | 13 | @HookName("LIZ") 14 | public static byte[] LIZ(byte[] arg1, int arg2) { 15 | Slog.d(TAG, "LIZ called"); 16 | return ArtEngine.callOrigin(null, arg1, arg2); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/hook/douyin/TTEncryptUtilsProxy.java: -------------------------------------------------------------------------------- 1 | package hook.douyin; 2 | 3 | import org.apolo.ArtEngine; 4 | import org.apolo.HookName; 5 | 6 | import hook.utils.Slog; 7 | 8 | @HookName("com.bytedance.frameworks.core.encrypt.TTEncryptUtils") 9 | public class TTEncryptUtilsProxy { 10 | private static final String TAG = TTEncryptUtilsProxy.class.getSimpleName(); 11 | 12 | @HookName("encrypt") 13 | public static byte[] encrypt(byte[] bytes, int arg) { 14 | Slog.d(TAG, "encrypt called"); 15 | return ArtEngine.callOrigin(bytes, arg); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/hook/java/io/FileProxy.java: -------------------------------------------------------------------------------- 1 | package hook.java.io; 2 | 3 | import org.apolo.ArtEngine; 4 | import org.apolo.HookClass; 5 | import org.apolo.HookName; 6 | import org.apolo.ThisObject; 7 | 8 | import java.io.File; 9 | 10 | import hook.utils.Slog; 11 | 12 | @HookClass(File.class) 13 | public class FileProxy { 14 | 15 | private static final String TAG = "FileProxy"; 16 | 17 | @HookName("mkdir") 18 | public static boolean mkdir(@ThisObject File thiz) { 19 | Slog.d(TAG, "proxy_mkdir " + thiz.getPath(), new Exception()); 20 | return ArtEngine.callOrigin(thiz); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/hook/java/lang/StringBuilder.java: -------------------------------------------------------------------------------- 1 | package hook.java.lang; 2 | 3 | import org.apolo.ArtEngine; 4 | import org.apolo.HookName; 5 | import org.apolo.ThisObject; 6 | import hook.utils.Slog; 7 | 8 | @HookName("java.lang.StringBuilder") 9 | public class StringBuilder { 10 | 11 | private static final String TAG = StringBuilder.class.getSimpleName(); 12 | 13 | @HookName("toString") 14 | public static String toString(@ThisObject Object sb) { 15 | String ret = ArtEngine.callOrigin(sb); 16 | ArtEngine.hookTransition(true); 17 | Slog.d(TAG, "proxy_toString :" + ret); 18 | ArtEngine.hookTransition(false); 19 | return ret; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/hook/java/lang/StringProxy.java: -------------------------------------------------------------------------------- 1 | package hook.java.lang; 2 | 3 | import org.apolo.ArtEngine; 4 | import org.apolo.HookClass; 5 | import org.apolo.HookName; 6 | import org.apolo.ThisObject; 7 | import hook.utils.Slog; 8 | 9 | @HookClass(String.class) 10 | public class StringProxy { 11 | 12 | private static final String TAG = StringProxy.class.getSimpleName(); 13 | @HookName("equals") 14 | public static boolean equals(@ThisObject String str1, Object str2) { 15 | Slog.d(TAG, "proxy_equals called %s vs %s", str1, str2); 16 | return ArtEngine.callOrigin(str1, str2); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/hook/javax/net/ssl/HttpsURLConnection.java: -------------------------------------------------------------------------------- 1 | package hook.javax.net.ssl; 2 | 3 | import javax.net.ssl.HostnameVerifier; 4 | import javax.net.ssl.SSLSocketFactory; 5 | 6 | import org.apolo.ArtEngine; 7 | import org.apolo.HookName; 8 | import org.apolo.ThisObject; 9 | import hook.utils.Slog; 10 | 11 | @HookName("javax.net.ssl.HttpsURLConnection") 12 | public class HttpsURLConnection { 13 | private static final String TAG = HttpsURLConnection.class.getSimpleName(); 14 | 15 | @HookName("getDefaultSSLSocketFactory") 16 | public static SSLSocketFactory getDefaultSSLSocketFactory() { 17 | Slog.d(TAG, "proxy_getDefaultSSLSocketFactory called", new Exception()); 18 | return ArtEngine.callOrigin(null); 19 | } 20 | 21 | @HookName("setSSLSocketFactory") 22 | public static void setSSLSocketFactory(@ThisObject Object thiz, SSLSocketFactory sf) { 23 | Slog.d(TAG, "proxy_setSSLSocketFactory called", new Exception()); 24 | ArtEngine.callOrigin(thiz, sf); 25 | } 26 | 27 | @HookName("setHostnameVerifier") 28 | public static void setHostnameVerifier(@ThisObject Object thiz, HostnameVerifier v) { 29 | Slog.d(TAG, "proxy_setHostnameVerifier called", new Exception()); 30 | ArtEngine.callOrigin(thiz, v); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/hook/utils/Slog.java: -------------------------------------------------------------------------------- 1 | package hook.utils; 2 | 3 | import android.util.Log; 4 | 5 | import com.apolo.helper.FileLogUtils; 6 | 7 | import org.apolo.ArtEngine; 8 | 9 | public class Slog { 10 | private static final boolean LOG_TO_FILE = false; 11 | public static void d(String tag, String format, Object... args) { 12 | ArtEngine.hookTransition(true); 13 | if (LOG_TO_FILE) { 14 | FileLogUtils.getInstance().saveLog(tag + ": " + String.format(format, args)); 15 | } else { 16 | Log.d(tag, String.format(format, args)); 17 | } 18 | ArtEngine.hookTransition(false); 19 | } 20 | 21 | public static void d(String tag, String format, Throwable thr, Object... args) { 22 | ArtEngine.hookTransition(true); 23 | if (LOG_TO_FILE) { 24 | FileLogUtils.getInstance().saveLog(String.format(format, args)); 25 | } else { 26 | Log.d(tag, String.format(format, args), thr); 27 | } 28 | ArtEngine.hookTransition(false); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 |