Repository: tiann/epic Branch: master Commit: c67d0d3e3769 Files: 137 Total size: 349.2 KB Directory structure: gitextract_6vz_tr23/ ├── .github/ │ ├── FUNDING.yml │ └── workflows/ │ └── android.yml ├── .gitignore ├── LICENSE ├── README.md ├── README_cn.md ├── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── me/ │ │ └── weishu/ │ │ └── epic/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── me/ │ │ │ └── weishu/ │ │ │ └── epic/ │ │ │ └── samples/ │ │ │ ├── MainActivity.java │ │ │ ├── MainApplication.java │ │ │ └── tests/ │ │ │ ├── CallingConventationTest.java │ │ │ ├── LogMethodHook.java │ │ │ ├── TestCase.java │ │ │ ├── TestManager.java │ │ │ ├── TestSuite.java │ │ │ ├── arguments/ │ │ │ │ ├── AbsArgStaticCase.java │ │ │ │ ├── ArgStatic0.java │ │ │ │ ├── ArgStatic4.java │ │ │ │ ├── ArgStatic44.java │ │ │ │ ├── ArgStatic444.java │ │ │ │ ├── ArgStatic4444.java │ │ │ │ ├── ArgStatic4448.java │ │ │ │ ├── ArgStatic448.java │ │ │ │ ├── ArgStatic4484.java │ │ │ │ ├── ArgStatic4488.java │ │ │ │ ├── ArgStatic48.java │ │ │ │ ├── ArgStatic484.java │ │ │ │ ├── ArgStatic4844.java │ │ │ │ ├── ArgStatic4848.java │ │ │ │ ├── ArgStatic488.java │ │ │ │ ├── ArgStatic4884.java │ │ │ │ ├── ArgStatic4888.java │ │ │ │ ├── ArgStatic8.java │ │ │ │ ├── ArgStatic84.java │ │ │ │ ├── ArgStatic844.java │ │ │ │ ├── ArgStatic8444.java │ │ │ │ ├── ArgStatic8448.java │ │ │ │ ├── ArgStatic848.java │ │ │ │ ├── ArgStatic8484.java │ │ │ │ ├── ArgStatic8488.java │ │ │ │ ├── ArgStatic88.java │ │ │ │ ├── ArgStatic884.java │ │ │ │ ├── ArgStatic8844.java │ │ │ │ ├── ArgStatic8848.java │ │ │ │ ├── ArgStatic888.java │ │ │ │ ├── ArgStatic8884.java │ │ │ │ ├── ArgStatic8888.java │ │ │ │ └── ArgumentTarget.java │ │ │ ├── custom/ │ │ │ │ ├── Case.java │ │ │ │ ├── Case1.java │ │ │ │ ├── Case10_Default_Constructor.java │ │ │ │ ├── Case11_SuspendAll.java │ │ │ │ ├── Case12_MultiCallback.java │ │ │ │ ├── Case13_FastNative.java │ │ │ │ ├── Case14_GC.java │ │ │ │ ├── Case15_StopJit.java │ │ │ │ ├── Case16_SameEntry.java │ │ │ │ ├── Case17_SameMethod.java │ │ │ │ ├── Case18_returnConst.java │ │ │ │ ├── Case2.java │ │ │ │ ├── Case3.java │ │ │ │ ├── Case4.java │ │ │ │ ├── Case5.java │ │ │ │ ├── Case6.java │ │ │ │ ├── Case7.java │ │ │ │ ├── Case8_Activity_onCreate.java │ │ │ │ ├── Case9_ThreadMonitor.java │ │ │ │ ├── CaseManager.java │ │ │ │ └── Target.java │ │ │ ├── invoketype/ │ │ │ │ ├── InvokeConstructor.java │ │ │ │ └── InvokeTypeTarget.java │ │ │ └── returntype/ │ │ │ ├── BooleanType.java │ │ │ ├── ByteType.java │ │ │ ├── CharType.java │ │ │ ├── CustomType.java │ │ │ ├── DoubleType.java │ │ │ ├── FloatType.java │ │ │ ├── IntType.java │ │ │ ├── LongType.java │ │ │ ├── ReturnTypeTarget.java │ │ │ ├── ShortType.java │ │ │ ├── StringArrayType.java │ │ │ ├── StringType.java │ │ │ └── VoidType.java │ │ └── res/ │ │ ├── layout/ │ │ │ ├── activity_main.xml │ │ │ ├── child_layout.xml │ │ │ └── parent_layout.xml │ │ └── values/ │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test/ │ └── java/ │ └── me/ │ └── weishu/ │ └── epic/ │ └── ExampleUnitTest.java ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── library/ │ ├── .gitignore │ ├── CMakeCache.txt │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── cpp/ │ │ ├── .gitignore │ │ ├── CMakeLists.txt │ │ ├── art.cpp │ │ ├── art.h │ │ ├── build_with_cmake │ │ ├── epic.cpp │ │ ├── fake_dlfcn.cpp │ │ └── fake_dlfcn.h │ ├── java/ │ │ ├── com/ │ │ │ └── taobao/ │ │ │ └── android/ │ │ │ └── dexposed/ │ │ │ ├── ClassUtils.java │ │ │ ├── DeviceCheck.java │ │ │ └── utility/ │ │ │ ├── Debug.java │ │ │ ├── Logger.java │ │ │ ├── NeverCalled.java │ │ │ ├── NougatPolicy.java │ │ │ ├── Platform.java │ │ │ ├── Runtime.java │ │ │ └── Unsafe.java │ │ ├── de/ │ │ │ └── robv/ │ │ │ └── android/ │ │ │ └── xposed/ │ │ │ └── DexposedBridge.java │ │ └── me/ │ │ └── weishu/ │ │ └── epic/ │ │ └── art/ │ │ ├── Epic.java │ │ ├── EpicNative.java │ │ ├── Trampoline.java │ │ ├── arch/ │ │ │ ├── Arm64.java │ │ │ ├── Arm64_2.java │ │ │ ├── ShellCode.java │ │ │ └── Thumb2.java │ │ ├── entry/ │ │ │ ├── Entry.java │ │ │ ├── Entry64.java │ │ │ └── Entry64_2.java │ │ └── method/ │ │ ├── ArtMethod.java │ │ └── Offset.java │ └── res/ │ └── values/ │ └── strings.xml └── settings.gradle ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: # replace patreon: weishu open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username custom: http://paypal.me/virtualxposed ================================================ FILE: .github/workflows/android.yml ================================================ name: Android CI on: [push] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - name: set up JDK 1.8 uses: actions/setup-java@v1 with: java-version: 1.8 - name: Build with Gradle run: ./gradlew build ================================================ FILE: .gitignore ================================================ *.iml .gradle /local.properties /.idea/workspace.xml /.idea/libraries .DS_Store /build /captures .externalNativeBuild .idea ================================================ FILE: LICENSE ================================================ Original work Copyright (c) 2005-2008, The Android Open Source Project Modified work Copyright (c) 2013, rovo89 and Tungstwenty Modified work Copyright (c) 2015, Alibaba Mobile Infrastructure (Android) Team Modified work Copyright (c) 2017, weishu Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS ================================================ FILE: README.md ================================================ [![Download](https://api.bintray.com/packages/twsxtd/maven/epic/images/download.svg) ](https://bintray.com/twsxtd/maven/epic/_latestVersion) [![Join the chat at https://gitter.im/android-hacker/epic](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/android-hacker/epic?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [中文文档入口](README_cn.md "中文") What is it? ----------- Epic is the continuation of [Dexposed](https://github.com/alibaba/dexposed) on ART (Supports 5.0 ~ 11). > Dexposed is a powerful yet non-invasive runtime [AOP (Aspect-oriented Programming)](http://en.wikipedia.org/wiki/Aspect-oriented_programming) framework for Android app development, based on the work of open-source [Xposed](https://github.com/rovo89/Xposed) [framework](https://github.com/rovo89/XposedBridge) project. > > The AOP of Dexposed is implemented purely non-invasive, without any annotation processor, weaver or bytecode rewriter. The integration is as simple as loading a small JNI library in just one line of code at the initialization phase of your app. > > Not only the code of your app, but also the code of Android framework that running in your app process can be hooked. Epic keeps the same API and all capability of Dexposed, you can do anything which is supported by Dexposed. Typical use-cases ----------------- * Classic AOP programming * Instrumentation (for testing, performance monitoring and etc.) * Security audit (sensitive api check,Smash shell) * Just for fun :) Integration ----------- Directly add epic aar to your project as compile libraries, Gradle dependency like following(jitpack): ```groovy dependencies { compile 'com.github.tiann:epic:0.11.2' } ``` Everything is ready. Basic usage ----------- There are three injection points for a given method: *before*, *after*, *origin*. Example 1: monitor the creation and destroy of java thread ```java class ThreadMethodHook extends XC_MethodHook{ @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); Thread t = (Thread) param.thisObject; Log.i(TAG, "thread:" + t + ", started.."); } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); Thread t = (Thread) param.thisObject; Log.i(TAG, "thread:" + t + ", exit.."); } } DexposedBridge.hookAllConstructors(Thread.class, new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); Thread thread = (Thread) param.thisObject; Class clazz = thread.getClass(); if (clazz != Thread.class) { Log.d(TAG, "found class extend Thread:" + clazz); DexposedBridge.findAndHookMethod(clazz, "run", new ThreadMethodHook()); } Log.d(TAG, "Thread: " + thread.getName() + " class:" + thread.getClass() + " is created."); } }); DexposedBridge.findAndHookMethod(Thread.class, "run", new ThreadMethodHook()); ``` Example 2: Intercept the dex loading behavior ```java DexposedBridge.findAndHookMethod(DexFile.class, "loadDex", String.class, String.class, int.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); String dex = (String) param.args[0]; String odex = (String) param.args[1]; Log.i(TAG, "load dex, input:" + dex + ", output:" + odex); } }); ``` Checkout the `sample` project to find out more. Support ---------- Epic supports ART thumb2 and arm64 architecture from Android 5.0 ~ 11. arm32, x86, x86_64 and mips are not supported now (Thus it cannot work on android emulator). Known Issues ------------- 1. Short method (instruction less 8 bytes on thumb2 or less 16bytes in ARM64) are not supported. 2. Fully inline methods are not supported. Contribute ---------- We are open to constructive contributions from the community, especially pull request and quality bug report. **Currently, the implementation for ART is not proved in large scale, we value your help to test or improve the implementation.** You can clone this project, build and install the sample app, just make some click in your device, if some bugs/crash occurs, please file an issue or a pull request, I would appreciate it :) Thanks ------- 1. [Dexposed](https://github.com/alibaba/dexposed) 2. [Xposed](http://repo.xposed.info/module/de.robv.android.xposed.installer) 3. [mar-v-in/ArtHook](https://github.com/mar-v-in/ArtHook) 4. [Nougat_dlfunctions](https://github.com/avs333/Nougat_dlfunctions.git) Contact me ---------- twsxtd@gmail.com [Join discussion](https://gitter.im/android-hacker/epic?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ================================================ FILE: README_cn.md ================================================ ## 简介 Epic 是一个在虚拟机层面、以 Java Method 为粒度的 **运行时** AOP Hook 框架。简单来说,Epic 就是 ART 上的 [Dexposed](https://github.com/alibaba/dexposed)(支持 Android 5.0 ~ 11)。它可以拦截本进程内部几乎任意的 Java 方法调用,可用于实现 AOP 编程、运行时插桩、性能分析、安全审计等。 Epic 被 [VirtualXposed](https://github.com/android-hacker/VirtualXposed) 以及 [太极](https://www.coolapk.com/apk/me.weishu.exp) 使用,用来实现非 Root 场景下的 Xposed 功能,已经经过了相当广泛的验证。 关于 Epic 的实现原理,可以参考 [本文](http://weishu.me/2017/11/23/dexposed-on-art/)。 ## 使用 ### 添加依赖 在你项目的 build.gradle 中添加如下依赖(jitpack 仓库): ```groovy dependencies { compile 'com.github.tiann:epic:0.11.2' } ``` 然后就可以使用了。 ### 几个例子 1. 监控 Java 线程的创建和销毁: ```java class ThreadMethodHook extends XC_MethodHook{ @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); Thread t = (Thread) param.thisObject; Log.i(TAG, "thread:" + t + ", started.."); } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); Thread t = (Thread) param.thisObject; Log.i(TAG, "thread:" + t + ", exit.."); } } DexposedBridge.hookAllConstructors(Thread.class, new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); Thread thread = (Thread) param.thisObject; Class clazz = thread.getClass(); if (clazz != Thread.class) { Log.d(TAG, "found class extend Thread:" + clazz); DexposedBridge.findAndHookMethod(clazz, "run", new ThreadMethodHook()); } Log.d(TAG, "Thread: " + thread.getName() + " class:" + thread.getClass() + " is created."); } }); DexposedBridge.findAndHookMethod(Thread.class, "run", new ThreadMethodHook()); ``` 以上代码拦截了 `Thread` 类以及 `Thread` 类所有子类的 `run`方法,在 `run` 方法开始执行和退出的时候进行拦截,就可以知道进程内部所有 Java 线程创建和销毁的时机;更进一步,你可以结合 Systrace 等工具,来生成整个过程的执行流程图,比如: 2. 监控 dex 文件的加载: ```java DexposedBridge.findAndHookMethod(DexFile.class, "loadDex", String.class, String.class, int.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); String dex = (String) param.args[0]; String odex = (String) param.args[1]; Log.i(TAG, "load dex, input:" + dex + ", output:" + odex); } }); ``` ## 支持情况 目前 Epic 支持 Android 5.0 ~ 11 的 Thumb-2/ARM64 指令集,arm32/x86/x86_64/mips/mips64 不支持。本项目被 [VirtualXposed](https://github.com/android-hacker/VirtualXposed) 和 [太极](http://taichi.cool) 以及大量企业级用户使用,经过了数千万用户的验证,已经被证明非常稳定。目前,手机 QQ 已经在产品中使用 Epic。 ## 已知问题 1. 受限于 inline hook 本身,短方法 (Thumb-2 下指令小于 8 个字节,ARM64 小于 16 字节) 无法支持。 2. 被完全内联的方法不支持。 ## 致谢 1. [Dexposed](https://github.com/alibaba/dexposed) 2. [Xposed](http://repo.xposed.info/module/de.robv.android.xposed.installer) 3. [mar-v-in/ArtHook](https://github.com/mar-v-in/ArtHook) 4. [Nougat_dlfunctions](https://github.com/avs333/Nougat_dlfunctions.git) ## 联系我 twsxtd@gmail.com ================================================ FILE: app/.gitignore ================================================ /build ================================================ FILE: app/build.gradle ================================================ apply plugin: 'com.android.application' android { compileSdkVersion 30 defaultConfig { applicationId "me.weishu.epic.samples" minSdkVersion 21 targetSdkVersion 30 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" externalNativeBuild { ndkBuild { abiFilters "armeabi-v7a", "x86" } } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } sourceSets { main { jniLibs.srcDirs = ['libs'] } } lintOptions { abortOnError false } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation project(":library") implementation 'com.qmuiteam:qmui:1.0.4' } ================================================ FILE: app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in /Users/weishu/Library/Android/sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: app/src/androidTest/java/me/weishu/epic/ExampleInstrumentedTest.java ================================================ //package me.weishu.epic; // //import android.content.Context; //import android.support.test.InstrumentationRegistry; //import android.support.test.runner.AndroidJUnit4; // //import org.junit.Test; //import org.junit.runner.RunWith; // //import static junit.framework.Assert.assertEquals; //import static org.junit.Assert.*; // ///** // * Instrumentation test, which will execute on an Android device. // * // * @see Testing documentation // */ //@RunWith(AndroidJUnit4.class) //public class ExampleInstrumentedTest { // @Test // public void useAppContext() throws Exception { // // Context of the app under test. // Context appContext = InstrumentationRegistry.getTargetContext(); // // assertEquals("me.weishu.epic", appContext.getPackageName()); // } //} ================================================ FILE: app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: app/src/main/java/me/weishu/epic/samples/MainActivity.java ================================================ package me.weishu.epic.samples; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.BaseExpandableListAdapter; import android.widget.Button; import android.widget.ExpandableListAdapter; import android.widget.ExpandableListView; import android.widget.ImageView; import android.widget.TextView; import java.util.List; import me.weishu.epic.samples.tests.TestCase; import me.weishu.epic.samples.tests.TestManager; import me.weishu.epic.samples.tests.TestSuite; public class MainActivity extends Activity { private static final String TAG = "MainActivity"; ExpandableListView listView; List allSuites; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.i(TAG, "savedInstance:" + savedInstanceState); setContentView(R.layout.activity_main); setTitle("Epic Test"); listView = findViewById(R.id.list); allSuites = TestManager.getInstance().getAllSuites(); ExpandableListAdapter adapter = new MyAdapter(); listView.setAdapter(adapter); } private class MyAdapter extends BaseExpandableListAdapter { @Override public int getGroupCount() { return allSuites.size(); } @Override public int getChildrenCount(int groupPosition) { return allSuites.get(groupPosition).getAllCases().size(); } @Override public TestSuite getGroup(int groupPosition) { return allSuites.get(groupPosition); } @Override public TestCase getChild(int groupPosition, int childPosition) { return allSuites.get(groupPosition).getAllCases().get(childPosition); } @Override public long getGroupId(int groupPosition) { return 0; } @Override public long getChildId(int groupPosition, int childPosition) { return 0; } @Override public boolean hasStableIds() { return false; } @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { View parentView = View.inflate(parent.getContext(), R.layout.parent_layout, null); TextView t = parentView.findViewById(R.id.text); t.setText(getGroup(groupPosition).getName()); ImageView indicator = parentView.findViewById(R.id.indicator); if (isExpanded) { indicator.setImageResource(R.drawable.arrow_down); } else { indicator.setImageResource(R.drawable.arrow_up); } return parentView; } @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { final TestCase child = getChild(groupPosition, childPosition); final View childView = View.inflate(parent.getContext(), R.layout.child_layout, null); final TextView title = childView.findViewById(R.id.label); title.setText(child.getName()); Button test = childView.findViewById(R.id.test); test.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { child.test(); } }); Button validate = childView.findViewById(R.id.validate); validate.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { boolean validate = child.validate(); final int color = v.getContext().getResources().getColor(validate ? android.R.color.holo_green_light : android.R.color.holo_red_light); childView.setBackgroundColor(color); } }); return childView; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return false; } } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/MainApplication.java ================================================ package me.weishu.epic.samples; import android.app.Application; import android.content.Context; /** * Created by weishu on 17/10/31. */ public class MainApplication extends Application { private static Context sContext; public static Context getAppContext() { return sContext; } @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); sContext = base; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/CallingConventationTest.java ================================================ package me.weishu.epic.samples.tests; import me.weishu.epic.samples.tests.arguments.ArgumentTarget; /** * Created by weishu on 17/11/15. */ public class CallingConventationTest { public static void longParams1() { // r0 = ArtMethod.this // r1 = 4 // r2 = 8 // r3 = parital 12 // sp + 16 = partial 12 ArgumentTarget.arg3(4, 8, 12L); } public static void longParams2() { // r0 = ArtMethod // r1, r2 = 1024L // r3 = bbcc1122 // sp + 16 = 0xffaa ArgumentTarget.arg2(1024L, 0xffaabbcc1122L); } public static void longParams3() { ArgumentTarget.arg2(123, 0xffaabbcc1122L); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/LogMethodHook.java ================================================ package me.weishu.epic.samples.tests; import android.util.Log; import java.util.Arrays; import de.robv.android.xposed.XC_MethodHook; /** * Created by weishu on 17/11/13. */ public class LogMethodHook extends XC_MethodHook { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); Log.i(getClass().getSimpleName(), "beforeHookedMethod() called with: param = [" + paramToString(param) + "]"); } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); Log.i(getClass().getSimpleName(), "afterHookedMethod() called with: param = [" + paramToString(param) + "]"); } private static String paramToString(MethodHookParam param) { StringBuilder sb = new StringBuilder(param.getClass().getSimpleName()).append("{"); sb.append("method = ").append(param.method.getName()).append(", "); sb.append("this = ").append(param.thisObject).append(", "); sb.append("args = ").append(Arrays.toString(param.args)).append(","); sb.append("result = ").append(param.getResult()).append("}"); return sb.toString(); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/TestCase.java ================================================ package me.weishu.epic.samples.tests; import android.util.Log; import android.widget.Toast; import me.weishu.epic.samples.MainApplication; /** * Created by weishu on 17/11/13. */ public abstract class TestCase { private static final String TAG = "TestCase"; protected String name; public TestCase(String name) { this.name = name; } public abstract void test(); public abstract boolean predicate(); public boolean validate() { boolean validate; try { validate = predicate(); } catch (Throwable e) { validate = false; Log.e(TAG, "error happened:", e); } if (!validate) { Toast.makeText(MainApplication.getAppContext(), "测试不通过。", Toast.LENGTH_SHORT).show(); } return validate; } public String getName() { return name; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/TestManager.java ================================================ package me.weishu.epic.samples.tests; import android.os.Build; import java.util.ArrayList; import java.util.List; import java.util.Set; import me.weishu.epic.samples.tests.arguments.ArgStatic0; import me.weishu.epic.samples.tests.arguments.ArgStatic4; import me.weishu.epic.samples.tests.arguments.ArgStatic44; import me.weishu.epic.samples.tests.arguments.ArgStatic444; import me.weishu.epic.samples.tests.arguments.ArgStatic4444; import me.weishu.epic.samples.tests.arguments.ArgStatic4448; import me.weishu.epic.samples.tests.arguments.ArgStatic448; import me.weishu.epic.samples.tests.arguments.ArgStatic4484; import me.weishu.epic.samples.tests.arguments.ArgStatic48; import me.weishu.epic.samples.tests.arguments.ArgStatic484; import me.weishu.epic.samples.tests.arguments.ArgStatic4844; import me.weishu.epic.samples.tests.arguments.ArgStatic488; import me.weishu.epic.samples.tests.arguments.ArgStatic4888; import me.weishu.epic.samples.tests.arguments.ArgStatic8; import me.weishu.epic.samples.tests.arguments.ArgStatic84; import me.weishu.epic.samples.tests.arguments.ArgStatic844; import me.weishu.epic.samples.tests.arguments.ArgStatic8444; import me.weishu.epic.samples.tests.arguments.ArgStatic8448; import me.weishu.epic.samples.tests.arguments.ArgStatic848; import me.weishu.epic.samples.tests.arguments.ArgStatic8484; import me.weishu.epic.samples.tests.arguments.ArgStatic8488; import me.weishu.epic.samples.tests.arguments.ArgStatic88; import me.weishu.epic.samples.tests.arguments.ArgStatic884; import me.weishu.epic.samples.tests.arguments.ArgStatic8844; import me.weishu.epic.samples.tests.arguments.ArgStatic8848; import me.weishu.epic.samples.tests.arguments.ArgStatic888; import me.weishu.epic.samples.tests.arguments.ArgStatic8884; import me.weishu.epic.samples.tests.arguments.ArgStatic8888; import me.weishu.epic.samples.tests.custom.Case1; import me.weishu.epic.samples.tests.custom.Case10_Default_Constructor; import me.weishu.epic.samples.tests.custom.Case11_SuspendAll; import me.weishu.epic.samples.tests.custom.Case12_MultiCallback; import me.weishu.epic.samples.tests.custom.Case13_FastNative; import me.weishu.epic.samples.tests.custom.Case14_GC; import me.weishu.epic.samples.tests.custom.Case17_SameMethod; import me.weishu.epic.samples.tests.custom.Case18_returnConst; import me.weishu.epic.samples.tests.custom.Case2; import me.weishu.epic.samples.tests.custom.Case3; import me.weishu.epic.samples.tests.custom.Case4; import me.weishu.epic.samples.tests.custom.Case5; import me.weishu.epic.samples.tests.custom.Case6; import me.weishu.epic.samples.tests.custom.Case7; import me.weishu.epic.samples.tests.custom.Case8_Activity_onCreate; import me.weishu.epic.samples.tests.custom.Case9_ThreadMonitor; import me.weishu.epic.samples.tests.custom.CaseManager; import me.weishu.epic.samples.tests.invoketype.InvokeConstructor; import me.weishu.epic.samples.tests.returntype.BooleanType; import me.weishu.epic.samples.tests.returntype.ByteType; import me.weishu.epic.samples.tests.returntype.CharType; import me.weishu.epic.samples.tests.returntype.CustomType; import me.weishu.epic.samples.tests.returntype.DoubleType; import me.weishu.epic.samples.tests.returntype.FloatType; import me.weishu.epic.samples.tests.returntype.IntType; import me.weishu.epic.samples.tests.returntype.LongType; import me.weishu.epic.samples.tests.returntype.ShortType; import me.weishu.epic.samples.tests.returntype.StringArrayType; import me.weishu.epic.samples.tests.returntype.StringType; import me.weishu.epic.samples.tests.returntype.VoidType; /** * Created by weishu on 17/11/13. */ public class TestManager { private static TestManager sManager = new TestManager(); private List suites = new ArrayList<>(); private TestManager() { initAllSuites(); } public static TestManager getInstance() { return sManager; } public void addSuite(TestSuite suite) { suites.add(suite); } public List getAllSuites() { return suites; } private void initAllSuites() { TestSuite returnType = new TestSuite("返回值测试"); returnType.addCase(new VoidType()); returnType.addCase(new ByteType()); returnType.addCase(new ShortType()); returnType.addCase(new CharType()); returnType.addCase(new IntType()); returnType.addCase(new FloatType()); returnType.addCase(new LongType()); returnType.addCase(new DoubleType()); returnType.addCase(new BooleanType()); returnType.addCase(new StringType()); returnType.addCase(new StringArrayType()); returnType.addCase(new CustomType()); addSuite(returnType); TestSuite arguments = new TestSuite("参数测试"); arguments.addCase(new ArgStatic0()); arguments.addCase(new ArgStatic4()); arguments.addCase(new ArgStatic8()); arguments.addCase(new ArgStatic44()); arguments.addCase(new ArgStatic48()); arguments.addCase(new ArgStatic84()); arguments.addCase(new ArgStatic88()); arguments.addCase(new ArgStatic444()); arguments.addCase(new ArgStatic448()); arguments.addCase(new ArgStatic484()); arguments.addCase(new ArgStatic844()); arguments.addCase(new ArgStatic488()); arguments.addCase(new ArgStatic848()); arguments.addCase(new ArgStatic884()); arguments.addCase(new ArgStatic888()); arguments.addCase(new ArgStatic4444()); arguments.addCase(new ArgStatic4448()); arguments.addCase(new ArgStatic4484()); arguments.addCase(new ArgStatic4844()); arguments.addCase(new ArgStatic8444()); arguments.addCase(new ArgStatic8844()); arguments.addCase(new ArgStatic8484()); arguments.addCase(new ArgStatic8448()); arguments.addCase(new ArgStatic8884()); arguments.addCase(new ArgStatic8848()); arguments.addCase(new ArgStatic8488()); arguments.addCase(new ArgStatic4888()); arguments.addCase(new ArgStatic8888()); addSuite(arguments); TestSuite invokeType = new TestSuite("调用类型"); invokeType.addCase(new InvokeConstructor()); addSuite(invokeType); TestSuite custom = new TestSuite("自定义"); CaseManager.getInstance().getCase(Case1.class); CaseManager.getInstance().getCase(Case2.class); CaseManager.getInstance().getCase(Case3.class); CaseManager.getInstance().getCase(Case4.class); CaseManager.getInstance().getCase(Case4.class); CaseManager.getInstance().getCase(Case5.class); CaseManager.getInstance().getCase(Case6.class); CaseManager.getInstance().getCase(Case7.class); CaseManager.getInstance().getCase(Case8_Activity_onCreate.class); CaseManager.getInstance().getCase(Case9_ThreadMonitor.class); CaseManager.getInstance().getCase(Case10_Default_Constructor.class); CaseManager.getInstance().getCase(Case12_MultiCallback.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { CaseManager.getInstance().getCase(Case11_SuspendAll.class); CaseManager.getInstance().getCase(Case14_GC.class); // CaseManager.getInstance().getCase(Case15_StopJit.class); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { CaseManager.getInstance().getCase(Case13_FastNative.class); } // CaseManager.getInstance().getCase(Case16_SameEntry.class); CaseManager.getInstance().getCase(Case17_SameMethod.class); CaseManager.getInstance().getCase(Case18_returnConst.class); final Set> cases = CaseManager.getInstance().getCases(); for (final Class aCase : cases) { custom.addCase(new TestCase(aCase.getSimpleName()) { @Override public void test() { CaseManager.getInstance().getCase(aCase).hook(); } @Override public boolean predicate() { return CaseManager.getInstance().getCase(aCase).validate(); } }); } addSuite(custom); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/TestSuite.java ================================================ package me.weishu.epic.samples.tests; import java.util.ArrayList; import java.util.List; /** * Created by weishu on 17/11/13. */ public class TestSuite { private String name; private List cases = new ArrayList<>(); public TestSuite(String name) { this.name = name; } public void addCase(TestCase caze) { cases.add(caze); } public String getName() { return name; } public List getAllCases() { return cases; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/AbsArgStaticCase.java ================================================ package me.weishu.epic.samples.tests.arguments; import android.util.Log; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Random; import de.robv.android.xposed.DexposedBridge; import de.robv.android.xposed.XposedHelpers; import me.weishu.epic.samples.tests.LogMethodHook; import me.weishu.epic.samples.tests.TestCase; /** * @author weishu * @date 17/11/14. */ public abstract class AbsArgStaticCase extends TestCase { private final String TAG = getClass().getSimpleName(); final long[] args; private Random r = new Random(); public AbsArgStaticCase() { super(null); args = new long[8]; for (int i = 0; i < args.length; i++) { args[i] = 0L; } name = getClass().getSimpleName(); } @Override public void test() { DexposedBridge.hookMethod(getTargetMethod(), new LogMethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); int length = param.args.length; if (length > 0) { for (int i = 0; i < length; i++) { long tmp = ((Number) param.args[i]).longValue(); args[i] = tmp; } } } }); } @Override public boolean predicate() { long[] arguments = getArguments(); Log.i(TAG, "call arguments: " + Arrays.toString(toHex(arguments))); makeCall(arguments); boolean ret = true; int length = getArgumentNumber(); for (int i = 0; i < length; i++) { if (arguments[i] != args[i]) { ret = false; Log.i(TAG, "hooked arguments: " + Arrays.toString(toHex(args))); } } return ret; } private long[] getArguments() { final int argumentNumber = getArgumentNumber(); long[] arguments = new long[argumentNumber]; for (int i = 0; i < arguments.length; i++) { arguments[i] = nextLong(); } return arguments; } protected Method getTargetMethod() { final int argumentNumber = getArgumentNumber(); String methodName = "arg" + argumentNumber; Method method = XposedHelpers.findMethodExact(ArgumentTarget.class, methodName, getParamsSignature()); Log.i(TAG, "find target Method:" + method); return method; } protected int getArgumentNumber() { return getParamsSignature().length; } protected void makeCall(long... args) { Log.i(TAG, getName() + " make call with arguments:" + Arrays.toString(args)); } private long nextLong() { int ret = r.nextInt(); return ret; } private Class[] getParamsSignature() { String className = getClass().getSimpleName(); String signature = className.substring("ArgStatic".length()); final int length = signature.length(); Class[] clazz = new Class[length]; for (int i = 0; i < length; i++) { final char c = signature.charAt(i); if (c == '4') { clazz[i] = int.class; } else if (c == '8') { clazz[i] = long.class; } else { throw new RuntimeException("Unknown signature!!"); } } return clazz; } private String[] toHex(long[] value) { String[] ret = new String[value.length]; for (int i = 0; i < value.length; i++) { ret[i] = Long.toHexString(value[i]); } return ret; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic0.java ================================================ package me.weishu.epic.samples.tests.arguments; import de.robv.android.xposed.DexposedBridge; import de.robv.android.xposed.XC_MethodHook; import me.weishu.epic.samples.tests.LogMethodHook; import me.weishu.epic.samples.tests.TestCase; /** * @author weishu * @date 17/11/14. */ public class ArgStatic0 extends TestCase { boolean beforeCalled = false; boolean afterCalled = false; public ArgStatic0() { super("ArgStatic0"); } @Override public void test() { DexposedBridge.findAndHookMethod(ArgumentTarget.class, "arg0", new LogMethodHook() { @Override protected void beforeHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); beforeCalled = true; } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); afterCalled = true; } }); } @Override public boolean predicate() { ArgumentTarget.arg0(); return beforeCalled && afterCalled; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic4.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * @author weishu * @date 17/11/14. */ public class ArgStatic4 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg1((int)args[0]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic44.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * @author weishu * @date 17/11/14. */ public class ArgStatic44 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg2((int) args[0], (int) args[1]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic444.java ================================================ package me.weishu.epic.samples.tests.arguments; import android.util.Log; import java.util.Arrays; /** * Created by weishu on 17/11/14. */ public class ArgStatic444 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { Log.i("mylog", "make call args:" + Arrays.toString(args)); ArgumentTarget.arg3((int) args[0], (int) args[1], (int) args[2]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic4444.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic4444 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg4((int)args[0], (int)args[1], (int)args[2], (int)args[3]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic4448.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic4448 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg4((int) args[0], (int)args[1], (int)args[2], args[3]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic448.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic448 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg3((int) args[0], (int) args[1], args[2]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic4484.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic4484 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg4((int)args[0], (int)args[1], args[2], (int) args[3]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic4488.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic4488 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg4((int)args[0], (int)args[1], args[2], args[3]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic48.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * @author weishu * @date 17/11/14. */ public class ArgStatic48 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg2((int) args[0], args[1]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic484.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic484 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg3((int) args[0], args[1], (int) args[2]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic4844.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic4844 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg4((int) args[0], args[1], (int)args[2], (int)args[3]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic4848.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic4848 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg4((int)args[0], args[1], (int)args[2], args[3]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic488.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic488 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg3((int) args[0], args[1], args[2]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic4884.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic4884 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg4((int)args[0], args[1], args[2], (int)args[3]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic4888.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic4888 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg4((int)args[0], args[1], args[2], args[3]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic8.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * @author weishu * @date 17/11/14. */ public class ArgStatic8 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg1(args[0]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic84.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * @author weishu * @date 17/11/14. */ public class ArgStatic84 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg2(args[0], (int)args[1]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic844.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic844 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg3(args[0], (int) args[1], (int) args[2]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic8444.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic8444 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg4(args[0], (int)args[1], (int)args[2], (int)args[3]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic8448.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic8448 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg4(args[0], (int)args[1], (int)args[2], args[3]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic848.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic848 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg3(args[0], (int) args[1], args[2]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic8484.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic8484 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg4(args[0], (int)args[1], args[2], (int)args[3]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic8488.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic8488 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg4(args[0], (int)args[1], args[2], args[3]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic88.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * @author weishu * @date 17/11/14. */ public class ArgStatic88 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { super.makeCall(args); ArgumentTarget.arg2(args[0], args[1]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic884.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic884 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg3(args[0], args[1], (int) args[2]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic8844.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic8844 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg4(args[0], args[1], (int)args[2], (int)args[3]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic8848.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic8848 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg4(args[0], args[1], (int)args[2], args[3]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic888.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic888 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg3(args[0], args[1], args[2]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic8884.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic8884 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg4(args[0], args[1], args[2], (int)args[3]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgStatic8888.java ================================================ package me.weishu.epic.samples.tests.arguments; /** * Created by weishu on 17/11/14. */ public class ArgStatic8888 extends AbsArgStaticCase { @Override protected void makeCall(long... args) { ArgumentTarget.arg4(args[0], args[1], args[2], args[3]); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/arguments/ArgumentTarget.java ================================================ package me.weishu.epic.samples.tests.arguments; import android.util.Log; /** * @author weishu * @date 17/11/13. */ public class ArgumentTarget { private static final String TAG = "ArgumentTarget"; //region ---------------static--------------- public static void arg0() { Log.i(TAG, "arg0() called"); } public static void arg1(int v1) { Log.i(TAG, "arg1() called with: v1 = [" + v1 + "]"); } public static void arg1(long v1) { Log.i(TAG, "arg1() called with: v1 = [" + v1 + "]"); } public static void arg2(int v1, int v2) { Log.i(TAG, "arg2() called with: v1 = [" + v1 + "], v2 = [" + v2 + "]"); } public static void arg2(int v1, long v2) { Log.i(TAG, "arg2() called with: v1 = [" + v1 + "], v2 = [" + v2 + "]"); } public static void arg2(long v1, int v2) { Log.i(TAG, "arg2() called with: v1 = [" + v1 + "], v2 = [" + v2 + "]"); } public static void arg2(long v1, long v2) { Log.i(TAG, "arg2() called with: v1 = [" + v1 + "], v2 = [" + v2 + "]"); } public static void arg3(int v1, int v2, int v3) { Log.i(TAG, "arg3() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "]"); } public static void arg3(long v1, int v2, int v3) { Log.i(TAG, "arg3() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "]"); } public static void arg3(int v1, long v2, int v3) { Log.i(TAG, "arg3() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "]"); } public static void arg3(int v1, int v2, long v3) { Log.i(TAG, "arg3() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "]"); } public static void arg3(long v1, long v2, int v3) { Log.i(TAG, "arg3() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "]"); } public static void arg3(long v1, int v2, long v3) { Log.i(TAG, "arg3() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "]"); } public static void arg3(int v1, long v2, long v3) { Log.i(TAG, "arg3() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "]"); } public static void arg3(long v1, long v2, long v3) { Log.i(TAG, "arg3() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "]"); } public static void arg4(int v1, int v2, int v3, int v4) { Log.i(TAG, "arg4() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "]"); } public static void arg4(long v1, int v2, int v3, int v4) { Log.i(TAG, "arg4() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "]"); } public static void arg4(int v1, long v2, int v3, int v4) { Log.i(TAG, "arg4() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "]"); } public static void arg4(int v1, int v2, long v3, int v4) { Log.i(TAG, "arg4() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "]"); } public static void arg4(int v1, int v2, int v3, long v4) { Log.i(TAG, "arg4() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "]"); } public static void arg4(long v1, long v2, int v3, int v4) { Log.i(TAG, "arg4() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "]"); } public static void arg4(long v1, int v2, long v3, int v4) { Log.i(TAG, "arg4() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "]"); } public static void arg4(long v1, int v2, int v3, long v4) { Log.i(TAG, "arg4() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "]"); } public static void arg4(int v1, long v2, long v3, int v4) { Log.i(TAG, "arg4() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "]"); } public static void arg4(int v1, long v2, int v3, long v4) { Log.i(TAG, "arg4() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "]"); } public static void arg4(int v1, int v2, long v3, long v4) { Log.i(TAG, "arg4() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "]"); } public static void arg4(int v1, long v2, long v3, long v4) { Log.i(TAG, "arg4() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "]"); } public static void arg4(long v1, int v2, long v3, long v4) { Log.i(TAG, "arg4() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "]"); } public static void arg4(long v1, long v2, int v3, long v4) { Log.i(TAG, "arg4() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "]"); } public static void arg4(long v1, long v2, long v3, int v4) { Log.i(TAG, "arg4() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "]"); } public static void arg4(long v1, long v2, long v3, long v4) { Log.i(TAG, "arg4() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "]"); } public static void arg5(int v1, int v2, int v3, int v4, int v5) { Log.i(TAG, "arg5() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "], v5 = [" + v5 + "]"); } public static void arg5(long v1, long v2, long v3, long v4, long v5) { Log.i(TAG, "arg5() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "], v5 = [" + v5 + "]"); } public static void arg6(int v1, int v2, int v3, int v4, int v5, int v6) { Log.i(TAG, "arg6() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "], v5 = [" + v5 + "], v6 = [" + v6 + "]"); } public static void arg6(long v1, long v2, long v3, long v4, long v5, long v6) { Log.i(TAG, "arg6() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "], v5 = [" + v5 + "], v6 = [" + v6 + "]"); } public static void arg7(int v1, int v2, int v3, int v4, int v5, int v6, int v7) { Log.i(TAG, "arg7() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "], v5 = [" + v5 + "], v6 = [" + v6 + "], v7 = [" + v7 + "]"); } public static void arg7(long v1, long v2, long v3, long v4, long v5, long v6, long v7) { Log.i(TAG, "arg7() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "], v4 = [" + v4 + "], v5 = [" + v5 + "], v6 = [" + v6 + "], v7 = [" + v7 + "]"); } //endregion //region ---------------non static--------------- public void iarg0() { Log.i(TAG, "arg0() called"); } public void iarg1(int v1) { Log.i(TAG, "arg1() called with: v1 = [" + v1 + "]"); } public void iarg1(long v1) { Log.i(TAG, "arg1() called with: v1 = [" + v1 + "]"); } public void iarg2(int v1, int v2) { Log.i(TAG, "arg2() called with: v1 = [" + v1 + "], v2 = [" + v2 + "]"); } public void iarg2(int v1, long v2) { Log.i(TAG, "arg2() called with: v1 = [" + v1 + "], v2 = [" + v2 + "]"); } public void iarg2(long v1, long v2) { Log.i(TAG, "arg2() called with: v1 = [" + v1 + "], v2 = [" + v2 + "]"); } public void iarg3(int v1, int v2, int v3) { Log.i(TAG, "arg3() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "]"); } public void iarg3(long v1, int v2, int v3) { Log.i(TAG, "arg3() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "]"); } public void iarg3(int v1, long v2, int v3) { Log.i(TAG, "arg3() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "]"); } public void iarg3(int v1, int v2, long v3) { Log.i(TAG, "arg3() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "]"); } public void iarg3(long v1, long v2, int v3) { Log.i(TAG, "arg3() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "]"); } public void iarg3(long v1, int v2, long v3) { Log.i(TAG, "arg3() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "]"); } public void iarg3(int v1, long v2, long v3) { Log.i(TAG, "arg3() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "]"); } public void iarg3(long v1, long v2, long v3) { Log.i(TAG, "arg3() called with: v1 = [" + v1 + "], v2 = [" + v2 + "], v3 = [" + v3 + "]"); } //endregion } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/custom/Case.java ================================================ package me.weishu.epic.samples.tests.custom; /** * Created by weishu on 17/11/6. */ public interface Case { void hook(); boolean validate(Object... args); } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/custom/Case1.java ================================================ package me.weishu.epic.samples.tests.custom; import android.os.SystemClock; import android.util.Log; import java.lang.reflect.Field; import de.robv.android.xposed.DexposedBridge; import de.robv.android.xposed.XC_MethodHook; /** * Created by weishu on 17/11/6. */ public class Case1 implements Case { static Field sThread$target; static { try { // Thread#target sThread$target = Thread.class.getDeclaredField("target"); sThread$target.setAccessible(true); } catch (Exception e) { e.printStackTrace(); } } private static final String TAG = "Case1"; @Override public void hook() { DexposedBridge.findAndHookMethod(Thread.class, "run", new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); Log.i(TAG, "afterHookedMethod: " + param.thisObject); Thread thread = (Thread) param.thisObject; Runnable target = (Runnable) sThread$target.get(thread); // start|threadName|priority|class|startTime|stacktrace Log.i(TAG, "runnable target:" + target); } @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); Log.i(TAG, "beforeHookedMethod: " + param.thisObject); } }); } @Override public boolean validate(Object...args) { Thread t1 = new Thread(new Runnable() { @Override public void run() { Log.i(TAG, "before sleep"); SystemClock.sleep(3000); Log.i(TAG, "after sleep"); } }); t1.start(); class MyThread extends Thread { @Override public void run() { super.run(); Log.i(TAG, "before sleep"); SystemClock.sleep(3000); Log.i(TAG, "after sleep"); } } Thread t2 = new MyThread(); t2.start(); return true; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/custom/Case10_Default_Constructor.java ================================================ package me.weishu.epic.samples.tests.custom; import android.util.Log; import java.lang.reflect.Constructor; import de.robv.android.xposed.DexposedBridge; import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XposedHelpers; /** * Created by weishu on 17/11/13. */ public class Case10_Default_Constructor implements Case { private static final String TAG = "Case10_Default_Constructor"; @Override public void hook() { Constructor constructor = XposedHelpers.findConstructorExact(Target.class); DexposedBridge.hookMethod(constructor, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); Log.i(TAG, "Target constructor called"); } }); } @Override public boolean validate(Object... args) { new Target(); return true; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/custom/Case11_SuspendAll.java ================================================ package me.weishu.epic.samples.tests.custom; import android.os.Build; import android.os.SystemClock; import android.util.Log; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import me.weishu.epic.art.EpicNative; /** * Created by weishu on 17/11/18. */ public class Case11_SuspendAll implements Case { private static final String TAG = "Case11_SuspendAll"; @Override public void hook() { Executor executor = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++) { executor.execute(new Runnable() { @Override public void run() { int j = 0; while (true) { Log.i(TAG, "I am:" + Thread.currentThread().getName() + ", count:" + (j++)); SystemClock.sleep(1000); if (j > 3) { break; } } } }); } } @Override public boolean validate(Object... args) { if (Build.VERSION.SDK_INT < 24) { Log.i(TAG, "resume/suspend only support Android N+ now."); return false; } long cookie = EpicNative.suspendAll(); for (Thread thread : Thread.getAllStackTraces().keySet()) { Log.i(TAG, thread.getName() + " status:" + thread.getState()); } EpicNative.resumeAll(cookie); return true; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/custom/Case12_MultiCallback.java ================================================ package me.weishu.epic.samples.tests.custom; import android.util.Log; import de.robv.android.xposed.DexposedBridge; import de.robv.android.xposed.XC_MethodHook; /** * Created by weishu on 17/11/21. */ public class Case12_MultiCallback implements Case { private static final String TAG = "Case12_MultiCallback"; int beforeCount = 0; int afterCount = 0; XC_MethodHook callback1 = new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); Log.i(TAG, "beforeHookMethod 1"); beforeCount++; } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); Log.i(TAG, "afterHookMethod 1"); afterCount++; } }; XC_MethodHook callback2 = new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); Log.i(TAG, "beforeHookMethod 2 lalala "); beforeCount++; } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); Log.i(TAG, "afterHookMethod 2 lalala"); afterCount++; } }; XC_MethodHook callback3 = new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); Log.i(TAG, "beforeHookMethod 3 zezeze"); beforeCount++; } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); Log.i(TAG, "afterHookMethod 3 zezeze"); afterCount++; } }; @Override public void hook() { DexposedBridge.findAndHookMethod(Target.class, "test1", Object.class, int.class, callback1); DexposedBridge.findAndHookMethod(Target.class, "test1", Object.class, int.class, callback2); DexposedBridge.findAndHookMethod(Target.class, "test1", Object.class, int.class, callback3); } @Override public boolean validate(Object... args) { new Target().test1("123", 1); boolean ret = beforeCount == 3 && afterCount == 3; // reset. beforeCount = 0; afterCount = 0; return ret; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/custom/Case13_FastNative.java ================================================ package me.weishu.epic.samples.tests.custom; import android.util.Log; import java.lang.reflect.Method; import de.robv.android.xposed.XposedHelpers; /** * Created by weishu on 17/12/13. */ public class Case13_FastNative implements Case { @Override public void hook() { // DexposedBridge.findAndHookMethod(Target.class, "longRunMethod", new LogMethodHook()); final Method invoke = XposedHelpers.findMethodExact(Method.class, "invoke", Object.class, Object[].class); Log.i("mylog", "invole: " + invoke); } @Override public boolean validate(Object... args) { new Target().longRunMethod(); return true; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/custom/Case14_GC.java ================================================ package me.weishu.epic.samples.tests.custom; import de.robv.android.xposed.DexposedBridge; import me.weishu.epic.samples.tests.LogMethodHook; import me.weishu.epic.samples.tests.returntype.ReturnTypeTarget; /** * Created by weishu on 17/12/13. */ public class Case14_GC implements Case { @Override public void hook() { DexposedBridge.findAndHookMethod(ReturnTypeTarget.class, "returnString", String.class, new LogMethodHook()); System.gc(); } @Override public boolean validate(Object... args) { return "123".equals(ReturnTypeTarget.returnString(new String("123"))); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/custom/Case15_StopJit.java ================================================ package me.weishu.epic.samples.tests.custom; import me.weishu.epic.art.EpicNative; /** * Created by weishu on 17/12/13. */ public class Case15_StopJit implements Case { long cookie; @Override public void hook() { cookie = EpicNative.stopJit(); } @Override public boolean validate(Object... args) { EpicNative.startJit(cookie); return true; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/custom/Case16_SameEntry.java ================================================ package me.weishu.epic.samples.tests.custom; import android.util.Log; import com.taobao.android.dexposed.utility.Debug; import java.lang.reflect.Method; import de.robv.android.xposed.DexposedBridge; import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XposedHelpers; import me.weishu.epic.art.method.ArtMethod; /** * Created by weishu on 18/1/8. */ public class Case16_SameEntry implements Case { private static final String TAG = "Case16_SameEntry"; @Override public void hook() { final Method add = XposedHelpers.findMethodExact(Target.class, "add", int.class, int.class); final Method plus = XposedHelpers.findMethodExact(Target.class, "plus", int.class, int.class); ArtMethod artMethod3 = ArtMethod.of(add); ArtMethod artMethod4 = ArtMethod.of(plus); Log.i(TAG, "plus: addr: " + Debug.addrHex(artMethod3.getAddress()) + ", entry:" + Debug.addrHex(artMethod3.getEntryPointFromQuickCompiledCode())); Log.i(TAG, "milus: addr: " + Debug.addrHex(artMethod4.getAddress()) + ", entry:" + Debug.addrHex(artMethod4.getEntryPointFromQuickCompiledCode())); DexposedBridge.hookMethod(add, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); Log.d(TAG, "beforeHookedMethod() called with: param = [" + param + "]"); } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); Log.d(TAG, "afterHookedMethod() called with: param = [" + param + "]"); } }); DexposedBridge.hookMethod(plus, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); Log.d(TAG, "beforeHookedMethod() called with: param = [" + param + "]"); } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); Log.d(TAG, "afterHookedMethod() called with: param = [" + param + "]"); } }); } @Override public boolean validate(Object... args) { Target target = new Target(); int add = target.add(1, 2); Log.i(TAG, "1 + 2 = " + add); int plus = target.plus(3, 4); Log.i(TAG, "3 + 4 = " + plus); return true; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/custom/Case17_SameMethod.java ================================================ package me.weishu.epic.samples.tests.custom; import android.util.Log; import de.robv.android.xposed.DexposedBridge; import de.robv.android.xposed.XC_MethodHook; /** * Created by weishu on 18/1/11. */ public class Case17_SameMethod implements Case { private static final String TAG = "Case17_SameMethod"; @Override public void hook() { DexposedBridge.findAndHookMethod(Target.class, "add", int.class, int.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); Log.d(TAG, "beforeHookedMethod() called with: param = [" + param + "]"); } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); Log.d(TAG, "afterHookedMethod() called with: param = [" + param + "]"); } }); DexposedBridge.findAndHookMethod(Target.class, "add", int.class, int.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); Log.d(TAG, "beforeHookedMethod2() called with: param = [" + param + "]"); } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); Log.d(TAG, "afterHookedMethod2() called with: param = [" + param + "]"); } }); } @Override public boolean validate(Object... args) { new Target().add(1, 2); new Target().add(3, 4); return false; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/custom/Case18_returnConst.java ================================================ package me.weishu.epic.samples.tests.custom; import android.util.Log; import java.util.Arrays; import de.robv.android.xposed.DexposedBridge; import de.robv.android.xposed.XC_MethodHook; /** * Created by weishu on 18/1/11. */ public class Case18_returnConst implements Case { private static final String TAG = "Case18_returnConst"; @Override public void hook() { DexposedBridge.findAndHookMethod(Target.class, "returnConst", int.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); param.setResult(124); Log.d(TAG, "beforeHookedMethod() called with: param = [" + Arrays.toString(param.args) + "]"); } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); Log.d(TAG, "afterHookedMethod() called with: param = [" + Arrays.toString(param.args) + "]"); } }); } @Override public boolean validate(Object... args) { int i = new Target().returnConst(123); Log.i(TAG, "return : " + i); return (i == 124); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/custom/Case2.java ================================================ package me.weishu.epic.samples.tests.custom; /** * Created by weishu on 17/11/6. */ public class Case2 implements Case{ private static final String TAG = "Case2"; @Override public void hook() { // DexposedBridge.findAndHookMethod(Target.class, "add", int.class, int.class, new XC_MethodHook() { // @Override // protected void beforeHookedMethod(MethodHookParam param) throws Throwable { // Log.i(TAG, "before add hooked:" + Arrays.toString(param.args)); // param.setResult(4); // super.beforeHookedMethod(param); // } // }); // // DexposedBridge.findAndHookMethod(Target.class, "test4", int.class, new XC_MethodHook() { // @Override // protected void beforeHookedMethod(MethodHookParam param) throws Throwable { // super.beforeHookedMethod(param); // Log.i("mylog", "before", new RuntimeException("stack")); // Log.i("mylog", "this:" + param.thisObject); // Log.i("mylog", "method:" + param.method); // Log.i("mylog", "args:" + Arrays.toString(param.args)); // // } // // @Override // protected void afterHookedMethod(MethodHookParam param) throws Throwable { // super.afterHookedMethod(param); // Log.i("mylog", "after"); // } // }); } @Override public boolean validate(Object... args) { // Log.i(TAG, "1 + 2: " + Target.add(1, 2)); // return Target.add(1, 2) == 4; Target.validate(); return true; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/custom/Case3.java ================================================ package me.weishu.epic.samples.tests.custom; import android.util.Log; import de.robv.android.xposed.DexposedBridge; import de.robv.android.xposed.XC_MethodHook; /** * Created by weishu on 17/11/6. */ public class Case3 implements Case { private static final String TAG = "Case3"; @Override public void hook() { DexposedBridge.findAndHookMethod(System.class, "currentTimeMillis", new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); Log.i("mylog", "before currentTimeMillis"); } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); Log.i("mylog", "after currentTimeMillis"); } }); } @Override public boolean validate(Object... args) { Log.i(TAG, "currentTimeMillis: " + System.currentTimeMillis()); return true; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/custom/Case4.java ================================================ package me.weishu.epic.samples.tests.custom; import android.text.TextUtils; import android.util.Log; import de.robv.android.xposed.DexposedBridge; import de.robv.android.xposed.XC_MethodHook; /** * Created by weishu on 17/11/6. */ public class Case4 implements Case { private static final String TAG = "Case4"; @Override public void hook() { DexposedBridge.findAndHookMethod(TextUtils.class, "equals", CharSequence.class, CharSequence.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { Log.i(TAG, "beforeHookedMethod: this:" + param.thisObject, new RuntimeException("stack")); Log.i(TAG, "beforeHookedMethod: String1:" + param.args[0]); Log.i(TAG, "beforeHookedMethod: String2:" + param.args[1]); param.setResult(false); super.beforeHookedMethod(param); } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); } }); } @Override public boolean validate(Object... args) { String a1 = new String("123"); String a2 = new String("123"); Log.i(TAG, " '123' equals '123' ? " + TextUtils.equals(a1, a2)); return true; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/custom/Case5.java ================================================ package me.weishu.epic.samples.tests.custom; import android.util.Log; import android.widget.TextView; import com.taobao.android.dexposed.utility.Unsafe; import java.lang.reflect.Method; import de.robv.android.xposed.DexposedBridge; import de.robv.android.xposed.XC_MethodHook; import me.weishu.epic.art.EpicNative; /** * Created by weishu on 17/11/6. */ public class Case5 implements Case { @Override public void hook() { DexposedBridge.findAndHookMethod(TextView.class, "setPadding", int.class, int.class, int.class, int.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); if (param.thisObject != null) { Log.i("mylog", "this:" + Long.toHexString(Unsafe.getObjectAddress(param.thisObject))); } if (param.method != null) { Log.i("mylog", "mehod:" + Long.toHexString(EpicNative.getMethodAddress((Method) param.method))); } if (param.args != null) { for (Object arg : param.args) { Log.i("mylog", "param:" + arg); if (arg != null) { Log.i("mylog", "<" + arg.getClass() + "> : 0x" + Long.toHexString(Unsafe.getObjectAddress(arg)) + ", value: " + arg); } else { Log.i("mylog", "param: null"); } } } } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); Log.i("mylog", "after"); } }); } @Override public boolean validate(Object... args) { return true; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/custom/Case6.java ================================================ package me.weishu.epic.samples.tests.custom; import android.os.SystemClock; import android.util.Log; import com.taobao.android.dexposed.utility.Debug; import com.taobao.android.dexposed.utility.Unsafe; import java.lang.reflect.Method; import de.robv.android.xposed.XposedHelpers; import me.weishu.epic.art.EpicNative; import me.weishu.epic.art.method.ArtMethod; /** * Created by weishu on 17/11/6. */ public class Case6 implements Case { private static final String TAG = "Case6"; @Override public void hook() { Object test = new Object(); Log.i(TAG, "test object:" + test); long testAddr = Unsafe.getObjectAddress(test); Log.i(TAG, "test object address :" + testAddr); Log.i(TAG, "test object :" + EpicNative.getObject(XposedHelpers.getLongField(Thread.currentThread(), "nativePeer"), testAddr)); // Log.i(TAG, "object:" + EpicNative.getObject()) final Method nanoTime = XposedHelpers.findMethodExact(System.class, "nanoTime"); final Method uptimeMillis = XposedHelpers.findMethodExact(SystemClock.class, "uptimeMillis"); final Method map = XposedHelpers.findMethodExact(Target.class, "test1", Object.class, int.class); final Method malloc = XposedHelpers.findMethodExact(Target.class, "test3", Object.class, int.class); ArtMethod artMethod1 = ArtMethod.of(nanoTime); ArtMethod artMethod2 = ArtMethod.of(uptimeMillis); ArtMethod artMethod3 = ArtMethod.of(map); ArtMethod artMethod4 = ArtMethod.of(malloc); Log.i(TAG, "nanoTime: addr: 0x" + artMethod1.getAddress() + ", entry:" + Debug.addrHex(artMethod1.getEntryPointFromQuickCompiledCode())); Log.i(TAG, "uptimeMills: addr: 0x" + artMethod2.getAddress() + ", entry:" + Debug.addrHex(artMethod2.getEntryPointFromQuickCompiledCode())); Log.i(TAG, "map : addr: 0x" + artMethod3.getAddress() + ", entry:" + Debug.addrHex(artMethod3.getEntryPointFromQuickCompiledCode())); Log.i(TAG, "malloc: addr: 0x" + artMethod4.getAddress() + ", entry:" + Debug.addrHex(artMethod4.getEntryPointFromQuickCompiledCode())); } @Override public boolean validate(Object... args) { return true; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/custom/Case7.java ================================================ package me.weishu.epic.samples.tests.custom; import android.util.Log; import java.util.Arrays; import de.robv.android.xposed.DexposedBridge; import de.robv.android.xposed.XC_MethodHook; /** * Created by weishu on 17/11/8. */ public class Case7 implements Case { private static final String TAG = "Case7"; @Override public void hook() { Log.i(TAG, "hook test1"); DexposedBridge.findAndHookMethod(Target.class, "test1", Object.class, int.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { Log.i(TAG, "before add hooked:" + Arrays.toString(param.args)); param.setResult(4); super.beforeHookedMethod(param); } }); } @Override public boolean validate(Object... args) { Target t = new Target(); t.test1(t, 123); return true; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/custom/Case8_Activity_onCreate.java ================================================ package me.weishu.epic.samples.tests.custom; import android.os.Bundle; import android.util.Log; import de.robv.android.xposed.DexposedBridge; import de.robv.android.xposed.XC_MethodHook; import me.weishu.epic.samples.MainActivity; /** * Created by weishu on 17/11/9. */ public class Case8_Activity_onCreate implements Case { private static final String TAG = "Case8_Activity_onCreate"; @Override public void hook() { DexposedBridge.findAndHookMethod(MainActivity.class, "onCreate", Bundle.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); Log.i(TAG, "before hooked"); if (param.args[0] == null) { param.args[0] = new Bundle(); } Bundle b = (Bundle) param.args[0]; Log.i(TAG, "bundle: " + param.args[0]); b.putString("hehe", "hacked"); } }); } @Override public boolean validate(Object... args) { return true; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/custom/Case9_ThreadMonitor.java ================================================ package me.weishu.epic.samples.tests.custom; import android.util.Log; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import de.robv.android.xposed.DexposedBridge; import de.robv.android.xposed.XC_MethodHook; /** * Created by weishu on 17/11/10. */ public class Case9_ThreadMonitor implements Case { private static final String TAG = "Case9_ThreadMonitor"; @Override public void hook() { try { class ThreadMethodHook extends XC_MethodHook { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); Thread t = (Thread) param.thisObject; Log.i(TAG, "thread:" + t + ", started.."); } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); Thread t = (Thread) param.thisObject; Log.i(TAG, "thread:" + t + ", exit.."); } } DexposedBridge.hookAllConstructors(Thread.class, new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); Thread thread = (Thread) param.thisObject; Class clazz = thread.getClass(); if (clazz != Thread.class) { Log.d(TAG, "found class extend Thread:" + clazz); DexposedBridge.findAndHookMethod(clazz, "run", new ThreadMethodHook()); } Log.d(TAG, "Thread: " + thread.getName() + " class:" + thread.getClass() + " is created."); } }); DexposedBridge.findAndHookMethod(Thread.class, "run", new ThreadMethodHook()); } catch (Throwable e) { Log.e(TAG, "hook failed", e); } } @Override public boolean validate(Object... args) { new Thread(new Runnable() { @Override public void run() { Log.i(TAG, "I am started.."); } }).start(); new MyThread().start(); final ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 4; i++) { // final int num = i; executorService.execute(new Runnable() { @Override public void run() { Log.i(TAG, " lalala"); } }); } return true; } static class MyThread extends Thread { @Override public void run() { Log.i(TAG, "dang dang dang.."); } } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/custom/CaseManager.java ================================================ package me.weishu.epic.samples.tests.custom; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** * Created by weishu on 17/11/6. */ public class CaseManager { private static volatile CaseManager INSTANCE = new CaseManager(); private Map, Case> caseMap = new ConcurrentHashMap<>(); public static synchronized CaseManager getInstance() { return INSTANCE; } public synchronized Case getCase(Class clazz) { Case caze = caseMap.get(clazz); if (caze != null) { return caze; } else { try { caze = (Case) clazz.newInstance(); caseMap.put(clazz, caze); } catch (Throwable e) { throw new RuntimeException("can not get case !!", e); } } return caze; } public synchronized Set> getCases() { return caseMap.keySet(); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/custom/Target.java ================================================ package me.weishu.epic.samples.tests.custom; import android.os.SystemClock; import android.util.Log; import java.lang.reflect.Method; import de.robv.android.xposed.XposedHelpers; import me.weishu.epic.art.method.ArtMethod; /** * Created by weishu on 17/11/3. */ public class Target { public Target() { } public int test1(Object a, int b) { Log.i("mylog", "test1, arg1: " + a + " , arg2:" + b); new Runnable() { @Override public void run() { final Method enclosingMethod = getClass().getEnclosingMethod(); long entry = ArtMethod.of(enclosingMethod).getEntryPointFromQuickCompiledCode(); if (entry != ArtMethod.getQuickToInterpreterBridge()) { Log.w("mylog", "method compiled...."); } Log.i("mylog", enclosingMethod + "entry: point: 0x" + Long.toHexString(entry)); } }.run(); return a.hashCode() + b; } public int returnConst(int a) { return a; } public int add(int a, int b) { return a + b; } public int plus(int a, int b) { return a + b; } public int test3(Object a, int b) { Log.i("mylog", "test1, arg1: " + a + " , arg2:" + b); return a.hashCode() + b; } public static int test4(int a) { return Integer.valueOf(a).hashCode(); } public static float add(int a, float b) { return a + b; } public static int test2(Object a, int b) { Log.i("mylog", "test1, arg1: " + a + " , arg2:" + b); return a.hashCode() + b; } public long longRunMethod() { SystemClock.sleep(4000); return SystemClock.elapsedRealtime(); } public static void validate() { final Method validate = XposedHelpers.findMethodExact(Target.class, "validate"); long entry = ArtMethod.of(validate).getEntryPointFromQuickCompiledCode(); if (entry != ArtMethod.getQuickToInterpreterBridge()) { Log.w("mylog", "method compiled...."); new Target().test1("123", 1); } Log.i("mylog", validate + "entry: point: 0x" + Long.toHexString(entry)); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/invoketype/InvokeConstructor.java ================================================ package me.weishu.epic.samples.tests.invoketype; import de.robv.android.xposed.DexposedBridge; import de.robv.android.xposed.XposedHelpers; import me.weishu.epic.samples.tests.LogMethodHook; import me.weishu.epic.samples.tests.TestCase; /** * Created by weishu on 17/11/14. */ public class InvokeConstructor extends TestCase { boolean callBefore = false; boolean callAfter = false; public InvokeConstructor() { super("Constructor"); } @Override public void test() { DexposedBridge.hookMethod(XposedHelpers.findConstructorExact(InvokeTypeTarget.class), new LogMethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); callBefore = true; } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); callAfter = true; } }); } @Override public boolean predicate() { new InvokeTypeTarget(); return callBefore && callAfter; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/invoketype/InvokeTypeTarget.java ================================================ package me.weishu.epic.samples.tests.invoketype; /** * Created by weishu on 17/11/14. */ public class InvokeTypeTarget { } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/returntype/BooleanType.java ================================================ package me.weishu.epic.samples.tests.returntype; import de.robv.android.xposed.DexposedBridge; import me.weishu.epic.samples.tests.LogMethodHook; import me.weishu.epic.samples.tests.TestCase; /** * Created by weishu on 17/11/13. */ public class BooleanType extends TestCase { final boolean returnType = Boolean.FALSE; final boolean returnTypeModified = !returnType; public BooleanType() { super("Boolean"); } @Override public void test() { DexposedBridge.findAndHookMethod(ReturnTypeTarget.class, "returnBoolean", boolean.class, new LogMethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { param.setResult(returnTypeModified); super.beforeHookedMethod(param); } }); } @Override public boolean predicate() { return ReturnTypeTarget.returnBoolean(returnType) == returnTypeModified; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/returntype/ByteType.java ================================================ package me.weishu.epic.samples.tests.returntype; import de.robv.android.xposed.DexposedBridge; import me.weishu.epic.samples.tests.LogMethodHook; import me.weishu.epic.samples.tests.TestCase; /** * Created by weishu on 17/11/13. */ public class ByteType extends TestCase { final byte returnType = Byte.MAX_VALUE; final byte returnTypeModified = Byte.MAX_VALUE - 1; public ByteType() { super("Byte"); } @Override public void test() { DexposedBridge.findAndHookMethod(ReturnTypeTarget.class, "returnByte", byte.class, new LogMethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { param.setResult(returnTypeModified); super.beforeHookedMethod(param); } }); } @Override public boolean predicate() { final byte raw = ReturnTypeTarget.returnByte(returnType); return raw == returnTypeModified; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/returntype/CharType.java ================================================ package me.weishu.epic.samples.tests.returntype; import de.robv.android.xposed.DexposedBridge; import me.weishu.epic.samples.tests.LogMethodHook; import me.weishu.epic.samples.tests.TestCase; /** * Created by weishu on 17/11/13. */ public class CharType extends TestCase { final char returnType = Character.MAX_VALUE; final char returnTypeModified = returnType - 1; public CharType() { super("Char"); } @Override public void test() { DexposedBridge.findAndHookMethod(ReturnTypeTarget.class, "returnChar", char.class, new LogMethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { param.setResult(returnTypeModified); super.beforeHookedMethod(param); } }); } @Override public boolean predicate() { return ReturnTypeTarget.returnChar(returnType) == returnTypeModified; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/returntype/CustomType.java ================================================ package me.weishu.epic.samples.tests.returntype; import de.robv.android.xposed.DexposedBridge; import me.weishu.epic.samples.tests.LogMethodHook; import me.weishu.epic.samples.tests.TestCase; /** * Created by weishu on 17/11/13. */ public class CustomType extends TestCase { final ReturnTypeTarget returnType = new ReturnTypeTarget(); final ReturnTypeTarget returnTypeModified = new ReturnTypeTarget(); public CustomType() { super("Custom"); } @Override public void test() { DexposedBridge.findAndHookMethod(ReturnTypeTarget.class, "returnCustom", ReturnTypeTarget.class, new LogMethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { param.setResult(returnTypeModified); super.beforeHookedMethod(param); } }); } @Override public boolean predicate() { return ReturnTypeTarget.returnCustom(returnType) == returnTypeModified; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/returntype/DoubleType.java ================================================ package me.weishu.epic.samples.tests.returntype; import de.robv.android.xposed.DexposedBridge; import me.weishu.epic.samples.tests.LogMethodHook; import me.weishu.epic.samples.tests.TestCase; /** * Created by weishu on 17/11/13. */ public class DoubleType extends TestCase { final double returnType = 12343748.12435; final double returnTypeModified = returnType - 1; public DoubleType() { super("Double"); } @Override public void test() { DexposedBridge.findAndHookMethod(ReturnTypeTarget.class, "returnDouble", double.class, new LogMethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { param.setResult(returnTypeModified); super.beforeHookedMethod(param); } }); } @Override public boolean predicate() { return ReturnTypeTarget.returnDouble(returnType) == returnTypeModified; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/returntype/FloatType.java ================================================ package me.weishu.epic.samples.tests.returntype; import de.robv.android.xposed.DexposedBridge; import me.weishu.epic.samples.tests.LogMethodHook; import me.weishu.epic.samples.tests.TestCase; /** * Created by weishu on 17/11/13. */ public class FloatType extends TestCase { final float returnType = 12545.212f; final float returnTypeModified = returnType - 1; public FloatType() { super("Float"); } @Override public void test() { DexposedBridge.findAndHookMethod(ReturnTypeTarget.class, "returnFloat", float.class, new LogMethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { param.setResult(returnTypeModified); super.beforeHookedMethod(param); } }); } @Override public boolean predicate() { return ReturnTypeTarget.returnFloat(returnType) == returnTypeModified; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/returntype/IntType.java ================================================ package me.weishu.epic.samples.tests.returntype; import de.robv.android.xposed.DexposedBridge; import me.weishu.epic.samples.tests.LogMethodHook; import me.weishu.epic.samples.tests.TestCase; /** * Created by weishu on 17/11/13. */ public class IntType extends TestCase { final int returnType = Integer.MAX_VALUE; final int returnTypeModified = returnType - 1; public IntType() { super("Int"); } @Override public void test() { DexposedBridge.findAndHookMethod(ReturnTypeTarget.class, "returnInt", int.class, new LogMethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { param.setResult(returnTypeModified); super.beforeHookedMethod(param); } }); } @Override public boolean predicate() { final int i = ReturnTypeTarget.returnInt(returnType); return i == returnTypeModified; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/returntype/LongType.java ================================================ package me.weishu.epic.samples.tests.returntype; import de.robv.android.xposed.DexposedBridge; import me.weishu.epic.samples.tests.LogMethodHook; import me.weishu.epic.samples.tests.TestCase; /** * Created by weishu on 17/11/13. */ public class LongType extends TestCase { final long returnType = Long.MAX_VALUE / 2; final long returnTypeModified = returnType - 1; public LongType() { super("Long"); } @Override public void test() { DexposedBridge.findAndHookMethod(ReturnTypeTarget.class, "returnLong", long.class, new LogMethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { param.setResult(returnTypeModified); super.beforeHookedMethod(param); } }); } @Override public boolean predicate() { return ReturnTypeTarget.returnLong(returnType) == returnTypeModified; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/returntype/ReturnTypeTarget.java ================================================ package me.weishu.epic.samples.tests.returntype; import android.util.Log; /** * Created by weishu on 17/11/13. */ public class ReturnTypeTarget { private static final String TAG = "ReturnTypeTarget"; public static void returnVoid() { Log.d(TAG, "returnVoid() called"); } public static byte returnByte(byte b) { Log.i(TAG, "returnByte() called"); return b; } public static char returnChar(char c) { Log.i(TAG, "returnChar() called"); return c; } public static short returnShort(short s) { Log.i(TAG, "returnShort() called"); return s; } public static int returnInt(int i) { Log.i(TAG, "returnInt() called"); return i; } public static long returnLong(long l) { Log.i(TAG, "returnLong() called"); return l; } public static float returnFloat(float f) { Log.i(TAG, "returnFloat() called"); return f; } public static double returnDouble(double d) { Log.i(TAG, "returnDouble() called"); return d; } public static boolean returnBoolean(boolean b) { Log.i(TAG, "returnBoolean() called"); return b; } public static String returnString(String s) { Log.i(TAG, "returnString() called with: s = [" + s + "]"); return s; } public static String[] returnStringArray(String[] a) { Log.i(TAG, "returnStringArray() called with: a = [" + a + "]"); return a; } public static ReturnTypeTarget returnCustom(ReturnTypeTarget r) { Log.i(TAG, "returnCustom() called with: r = [" + r + "]"); return r; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/returntype/ShortType.java ================================================ package me.weishu.epic.samples.tests.returntype; import de.robv.android.xposed.DexposedBridge; import me.weishu.epic.samples.tests.LogMethodHook; import me.weishu.epic.samples.tests.TestCase; /** * Created by weishu on 17/11/13. */ public class ShortType extends TestCase { final short returnType = Short.MAX_VALUE / 2; final short returnTypeModified = returnType - 1; public ShortType() { super("Short"); } @Override public void test() { DexposedBridge.findAndHookMethod(ReturnTypeTarget.class, "returnShort", short.class, new LogMethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { param.setResult(returnTypeModified); super.beforeHookedMethod(param); } }); } @Override public boolean predicate() { return ReturnTypeTarget.returnShort(returnType) == returnTypeModified; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/returntype/StringArrayType.java ================================================ package me.weishu.epic.samples.tests.returntype; import de.robv.android.xposed.DexposedBridge; import me.weishu.epic.samples.tests.LogMethodHook; import me.weishu.epic.samples.tests.TestCase; /** * Created by weishu on 17/11/13. */ public class StringArrayType extends TestCase { final String[] returnType = new String[]{"123", "456"}; final String[] returnTypeModified = new String[]{"123", "456", "678"}; public StringArrayType() { super("StringArray"); } @Override public void test() { DexposedBridge.findAndHookMethod(ReturnTypeTarget.class, "returnStringArray", String[].class, new LogMethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { param.setResult(returnTypeModified); super.beforeHookedMethod(param); } }); } @Override public boolean predicate() { return ReturnTypeTarget.returnStringArray(returnType) == returnTypeModified; } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/returntype/StringType.java ================================================ package me.weishu.epic.samples.tests.returntype; import de.robv.android.xposed.DexposedBridge; import me.weishu.epic.samples.tests.LogMethodHook; import me.weishu.epic.samples.tests.TestCase; /** * Created by weishu on 17/11/13. */ public class StringType extends TestCase { final String returnType = "123455"; final String returnTypeModified = "784fsgiulfodsg"; public StringType() { super("String"); } @Override public void test() { DexposedBridge.findAndHookMethod(ReturnTypeTarget.class, "returnString", String.class, new LogMethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { param.setResult(returnTypeModified); super.beforeHookedMethod(param); } }); } @Override public boolean predicate() { return ReturnTypeTarget.returnString(returnType).equals(returnTypeModified); } } ================================================ FILE: app/src/main/java/me/weishu/epic/samples/tests/returntype/VoidType.java ================================================ package me.weishu.epic.samples.tests.returntype; import android.util.Log; import de.robv.android.xposed.DexposedBridge; import de.robv.android.xposed.XC_MethodHook; import me.weishu.epic.samples.tests.TestCase; /** * Created by weishu on 17/11/13. */ public class VoidType extends TestCase { private static final String TAG = "VoidType"; boolean callBefore = false; boolean callAfter = false; public VoidType() { super("无返回值"); } @Override public void test() { DexposedBridge.findAndHookMethod(ReturnTypeTarget.class, "returnVoid", new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); callBefore = true; } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); callAfter = true; } }); } @Override public boolean predicate() { ReturnTypeTarget.returnVoid(); Log.i(TAG, "callBefore:" + callBefore + ", callAfter:" + callAfter); return callBefore && callAfter; } } ================================================ FILE: app/src/main/res/layout/activity_main.xml ================================================ ================================================ FILE: app/src/main/res/layout/child_layout.xml ================================================