├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── colors.xml │ │ │ │ └── styles.xml │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── layout │ │ │ │ └── activity_main.xml │ │ │ ├── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ │ └── drawable │ │ │ │ └── ic_launcher_background.xml │ │ ├── cpp │ │ │ ├── Hook │ │ │ │ ├── Readme.md │ │ │ │ ├── LogHex.h │ │ │ │ ├── instruction │ │ │ │ │ ├── MipsInstruction.cpp │ │ │ │ │ ├── Mips64Instruction.cpp │ │ │ │ │ ├── MipsInstruction.h │ │ │ │ │ ├── Mips64Instruction.h │ │ │ │ │ ├── Arm64Instruction.h │ │ │ │ │ ├── Instruction.h │ │ │ │ │ ├── Instruction.cpp │ │ │ │ │ ├── ArmInstruction.h │ │ │ │ │ ├── IntelDisasm.h │ │ │ │ │ ├── ArmInstruction.cpp │ │ │ │ │ ├── ThumbInstruction.h │ │ │ │ │ ├── IntelInstruction.cpp │ │ │ │ │ ├── IntelInstruction.h │ │ │ │ │ ├── ThumbInstruction.cpp │ │ │ │ │ ├── IntelDisasm.cpp │ │ │ │ │ └── Arm64Instruction.cpp │ │ │ │ ├── Helper.h │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── HookHelper.h │ │ │ │ ├── LogHex.cpp │ │ │ │ ├── Helper.cpp │ │ │ │ ├── HookInfo.h │ │ │ │ ├── main.cpp │ │ │ │ └── HookHelper.cpp │ │ │ └── jnihook │ │ │ │ ├── fake_dlfcn.h │ │ │ │ ├── VM.h │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── Main.cpp │ │ │ │ ├── fake_dlfcn.cpp │ │ │ │ ├── JniHook.h │ │ │ │ └── JNIInterface.h │ │ ├── java │ │ │ └── xiaobai │ │ │ │ └── com │ │ │ │ └── jnihook │ │ │ │ └── MainActivity.java │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── xiaobai │ │ │ └── com │ │ │ └── jnihook │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── xiaobai │ │ └── com │ │ └── jnihook │ │ └── ExampleInstrumentedTest.java ├── CMakeLists.txt ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── test.png ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .idea ├── dictionaries │ └── xiaobaiyey.xml ├── runConfigurations.xml ├── gradle.xml ├── codeStyles │ └── Project.xml └── misc.xml ├── .gitignore ├── gradle.properties ├── gradlew.bat ├── readme.md └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaobaiyey/jnihook/HEAD/test.png -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | jnihook 3 | 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaobaiyey/jnihook/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.idea/dictionaries/xiaobaiyey.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaobaiyey/jnihook/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaobaiyey/jnihook/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaobaiyey/jnihook/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaobaiyey/jnihook/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaobaiyey/jnihook/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaobaiyey/jnihook/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaobaiyey/jnihook/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaobaiyey/jnihook/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaobaiyey/jnihook/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaobaiyey/jnihook/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches/build_file_checksums.ser 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | .DS_Store 9 | /build 10 | /captures 11 | .externalNativeBuild 12 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/Readme.md: -------------------------------------------------------------------------------- 1 | ### 模块说明 2 | hook 方案来自F8的hook: (https://github.com/F8LEFT/FAInHook)[https://github.com/F8LEFT/FAInHook] 3 | Arm64hook 方案来自:(https://github.com/Rprop/And64InlineHook)[https://github.com/Rprop/And64InlineHook] 4 | 5 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # For more information about using CMake with Android Studio, read the 2 | # documentation: https://d.android.com/studio/projects/add-native-code.html 3 | 4 | # Sets the minimum version of CMake required to build the native library. 5 | 6 | cmake_minimum_required(VERSION 3.4.1) 7 | ADD_SUBDIRECTORY(src/main/cpp/jnihook) -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/cpp/jnihook/fake_dlfcn.h: -------------------------------------------------------------------------------- 1 | #ifndef DEXPOSED_DLFCN_H 2 | #define DEXPOSED_DLFCN_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | extern "C" { 9 | 10 | void *fake_dlopen(const char *libpath, int flags); 11 | void *fake_dlsym(void *handle, const char *name); 12 | 13 | }; 14 | #endif //DEXPOSED_DLFCN_H -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/LogHex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class LogHex { 6 | public: 7 | static void PrintHex(const void *vdata, size_t size, const char *mark); 8 | 9 | static void PrintHexEx(const void *vdata, size_t size, size_t stride, const char *mark); 10 | 11 | static void DumpHex(const void *vdata, size_t size); 12 | }; -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/xiaobai/com/jnihook/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package xiaobai.com.jnihook; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/instruction/MipsInstruction.cpp: -------------------------------------------------------------------------------- 1 | //===------------------------------------------------------------*- C++ -*-===// 2 | // 3 | // Created by F8LEFT on 2017/6/19. 4 | // Copyright (c) 2017. All rights reserved. 5 | //===----------------------------------------------------------------------===// 6 | // 7 | //===----------------------------------------------------------------------===// 8 | 9 | 10 | #include "MipsInstruction.h" 11 | 12 | bool MipsInstruction::createStub(HookInfo *info) { 13 | return false; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/instruction/Mips64Instruction.cpp: -------------------------------------------------------------------------------- 1 | //===------------------------------------------------------------*- C++ -*-===// 2 | // 3 | // Created by F8LEFT on 2017/6/19. 4 | // Copyright (c) 2017. All rights reserved. 5 | //===----------------------------------------------------------------------===// 6 | // 7 | //===----------------------------------------------------------------------===// 8 | 9 | 10 | #include "Mips64Instruction.h" 11 | 12 | bool Mips64Instruction::createStub(HookInfo *info) { 13 | return false; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/java/xiaobai/com/jnihook/MainActivity.java: -------------------------------------------------------------------------------- 1 | package xiaobai.com.jnihook; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.widget.TextView; 6 | 7 | public class MainActivity extends AppCompatActivity { 8 | 9 | // Used to load the 'native-lib' library on application startup. 10 | static { 11 | System.loadLibrary("jnihook"); 12 | } 13 | 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | setContentView(R.layout.activity_main); 18 | 19 | // Example of a call to a native method 20 | TextView tv = (TextView) findViewById(R.id.sample_text); 21 | tv.setText("hi"); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/instruction/MipsInstruction.h: -------------------------------------------------------------------------------- 1 | //===------------------------------------------------------------*- C++ -*-===// 2 | // 3 | // Created by F8LEFT on 2017/6/19. 4 | // Copyright (c) 2017. All rights reserved. 5 | //===----------------------------------------------------------------------===// 6 | // Instruction helper for mips 7 | //===----------------------------------------------------------------------===// 8 | 9 | 10 | #ifndef FAINHOOK_MIPSINSTRUCTION_H 11 | #define FAINHOOK_MIPSINSTRUCTION_H 12 | 13 | #include "Instruction.h" 14 | 15 | class MipsInstruction : public Instruction { 16 | public: 17 | ~MipsInstruction() {} 18 | 19 | bool createStub(HookInfo *info); 20 | }; 21 | 22 | 23 | #endif //FAINHOOK_MIPSINSTRUCTION_H 24 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/instruction/Mips64Instruction.h: -------------------------------------------------------------------------------- 1 | //===------------------------------------------------------------*- C++ -*-===// 2 | // 3 | // Created by F8LEFT on 2017/6/19. 4 | // Copyright (c) 2017. All rights reserved. 5 | //===----------------------------------------------------------------------===// 6 | // Instruction Helper for mips64 7 | //===----------------------------------------------------------------------===// 8 | 9 | 10 | #ifndef FAINHOOK_MIPS64INSTRUCTION_H 11 | #define FAINHOOK_MIPS64INSTRUCTION_H 12 | 13 | #include "Instruction.h" 14 | 15 | class Mips64Instruction : public Instruction { 16 | public: 17 | ~Mips64Instruction() {} 18 | 19 | bool createStub(HookInfo *info); 20 | }; 21 | 22 | 23 | #endif //FAINHOOK_MIPS64INSTRUCTION_H 24 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/xiaobai/com/jnihook/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package xiaobai.com.jnihook; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("xiaobai.com.jnihook", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/Helper.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @ name unpacker 3 | * @ author xiaobaiyey 4 | * @ email xiaobaiyey@outlook.com 5 | * @ time 2018/9/5 上午4:30 6 | * @ class this code copy from FAinline hook so just for study 7 | */ 8 | 9 | #ifndef UNPACKER_HELPER_H 10 | #define UNPACKER_HELPER_H 11 | 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | class Helper { 19 | public: 20 | static bool isFunctionAddr(void *addr); 21 | 22 | /* remove write protect*/ 23 | static bool unProtectMemory(void *addr, uint32_t size); 24 | 25 | /* add write protect*/ 26 | static bool protectMemory(void *addr, uint32_t size); 27 | 28 | /* get a executable memory*/ 29 | static void *createExecMemory(uint32_t size); 30 | 31 | Helper(); 32 | 33 | ~Helper(); 34 | 35 | private: 36 | std::vector alloc_memory_page_; 37 | void *current_page = nullptr; 38 | uint32_t page_ptr_ = 0; 39 | 40 | static uint32_t page_size; 41 | }; 42 | 43 | 44 | #endif //UNPACKER_HELPER_H 45 | -------------------------------------------------------------------------------- /app/src/main/cpp/jnihook/VM.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @ name jnihook 3 | * @ author xiaobaiyey 4 | * @ email xiaobaiyey@outlook.com 5 | * @ time 2018/10/31 11:16 AM 6 | * @ class describe 7 | */ 8 | 9 | #ifndef JNIHOOK_VM_H 10 | #define JNIHOOK_VM_H 11 | 12 | #include 13 | 14 | class VM { 15 | public: 16 | static VM *getInstance(); 17 | 18 | 19 | void hookLoadNativeLibary(void *newFunPtr, bool beforecall); 20 | 21 | const char *getClasstName(jclass clazz); 22 | 23 | const char *getObjectName(jobject object); 24 | 25 | /** 26 | * you must delete return value 27 | */ 28 | char *getMethodName(jmethodID jmethodID1); 29 | 30 | /** 31 | * you must delete return value 32 | */ 33 | char *getFiledName(jfieldID jfieldID1); 34 | 35 | void closeOptClass(); 36 | 37 | void hookDexFileParse(void *newFunPtr, bool beforecall); 38 | 39 | public: 40 | 41 | 42 | private: 43 | VM(); 44 | 45 | int getSdkVersion(); 46 | 47 | void *Current(); 48 | 49 | private: 50 | int sdk_version; 51 | void *vm_handle; 52 | 53 | 54 | }; 55 | 56 | 57 | #endif //JNIHOOK_VM_H 58 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(ProjectName Hook) 2 | 3 | if (ANDROID_ABI MATCHES "armeabi(-v7a)?") 4 | set(INSTRUCTION instruction/Instruction.cpp 5 | instruction/ThumbInstruction.cpp 6 | instruction/ArmInstruction.cpp) 7 | elseif (ANDROID_ABI STREQUAL "arm64-v8a") 8 | set(INSTRUCTION instruction/Instruction.cpp 9 | instruction/Arm64Instruction.cpp) 10 | elseif (ANDROID_ABI MATCHES "x86(_64)?") 11 | 12 | set(INSTRUCTION instruction/Instruction.cpp 13 | instruction/IntelInstruction.cpp 14 | instruction/IntelDisasm.cpp) 15 | elseif (ANDROID_ABI STREQUAL "mips") 16 | set(INSTRUCTION instruction/Instruction.cpp 17 | instruction/MipsInstruction.cpp) 18 | elseif (ANDROID_ABI STREQUAL "mips64") 19 | set(INSTRUCTION instruction/Instruction.cpp 20 | instruction/Mips64Instruction.cpp) 21 | endif () 22 | 23 | set(HOOKSRC HookHelper.cpp Helper.cpp) 24 | 25 | add_library(hooktest SHARED ${HOOKSRC} ${INSTRUCTION}) 26 | 27 | #if(CMAKE_BUILD_TYPE MATCHES "Debug") 28 | # set(FA_EXTLIB log) 29 | #endif() 30 | 31 | 32 | #添加系统库文件 33 | find_library(log-lib 34 | log 35 | ) 36 | find_library(dl-lib 37 | dl 38 | ) 39 | 40 | 41 | target_link_libraries(hooktest 42 | 43 | ${log-lib} 44 | ${dl-lib} 45 | ) 46 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | defaultConfig { 6 | applicationId "xiaobai.com.jnihook" 7 | minSdkVersion 15 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | externalNativeBuild { 13 | cmake { 14 | cppFlags "-std=c++11 -Wno-error=format-security" 15 | abiFilters "armeabi-v7a" 16 | } 17 | } 18 | } 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | externalNativeBuild { 26 | cmake { 27 | path "CMakeLists.txt" 28 | } 29 | } 30 | } 31 | 32 | dependencies { 33 | implementation fileTree(dir: 'libs', include: ['*.jar']) 34 | implementation 'com.android.support:appcompat-v7:28.0.0' 35 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 36 | testImplementation 'junit:junit:4.12' 37 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 38 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/instruction/Arm64Instruction.h: -------------------------------------------------------------------------------- 1 | //===------------------------------------------------------------*- C++ -*-===// 2 | // 3 | // Created by F8LEFT on 2017/6/19. 4 | // Copyright (c) 2017. All rights reserved. 5 | //===----------------------------------------------------------------------===// 6 | // instruction helper for arm64 7 | //===----------------------------------------------------------------------===// 8 | 9 | 10 | #ifndef FAINHOOK_ARM64INSTRUCTION_H 11 | #define FAINHOOK_ARM64INSTRUCTION_H 12 | 13 | #include "Instruction.h" 14 | #include 15 | #include 16 | #include 17 | 18 | #define FLOG_TAG "ARM64" 19 | 20 | #include 21 | 22 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, FLOG_TAG, __VA_ARGS__) 23 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, FLOG_TAG, __VA_ARGS__) 24 | #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, FLOG_TAG, __VA_ARGS__) 25 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, FLOG_TAG, __VA_ARGS__) 26 | #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, FLOG_TAG, __VA_ARGS__) 27 | #define A64_MAX_BACKUPS 256 28 | 29 | class Arm64Instruction : public Instruction { 30 | public: 31 | ~Arm64Instruction() {} 32 | 33 | bool createStub(HookInfo *info); 34 | 35 | bool createCallOriginalStub(HookInfo *info); 36 | 37 | private: 38 | 39 | bool repairCallOriginIns(HookInfo *info, uint8_t repair[], uint32_t &repairLen); 40 | 41 | 42 | }; 43 | 44 | 45 | #endif //FAINHOOK_ARM64INSTRUCTION_H 46 | -------------------------------------------------------------------------------- /app/src/main/cpp/jnihook/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.4.1) 2 | 3 | 4 | # 添加hook库支持 5 | if (ANDROID_ABI MATCHES "armeabi(-v7a)?") 6 | set(INSTRUCTION ./../Hook/instruction/Instruction.cpp 7 | ./../Hook/instruction/ThumbInstruction.cpp 8 | ./../Hook/instruction/ArmInstruction.cpp) 9 | elseif (ANDROID_ABI STREQUAL "arm64-v8a") 10 | set(INSTRUCTION ./../Hook/instruction/Instruction.cpp 11 | ./../Hook/instruction/Arm64Instruction.cpp) 12 | elseif (ANDROID_ABI MATCHES "x86(_64)?") 13 | 14 | set(INSTRUCTION ./../Hook/instruction/Instruction.cpp 15 | ./../Hook/instruction/IntelInstruction.cpp 16 | ./../Hook/instruction/IntelDisasm.cpp) 17 | elseif (ANDROID_ABI STREQUAL "mips") 18 | set(INSTRUCTION ./../Hook/instruction/Instruction.cpp 19 | ./../Hook/instruction/MipsInstruction.cpp) 20 | elseif (ANDROID_ABI STREQUAL "mips64") 21 | set(INSTRUCTION ./../Hook/instruction/Instruction.cpp 22 | ./../Hook/instruction/Mips64Instruction.cpp) 23 | endif () 24 | #添加hook库头文件支持 25 | include_directories(./../Hook) 26 | 27 | set(HOOKSRC ./../Hook/Helper.cpp 28 | ./../Hook/HookHelper.cpp 29 | ${INSTRUCTION}) 30 | 31 | 32 | set(JNISRC JniHook.cpp main.cpp fake_dlfcn.cpp VM.cpp) 33 | 34 | add_library(jnihook 35 | SHARED 36 | ${HOOKSRC} 37 | ${JNISRC} 38 | ) 39 | #添加系统库文件 40 | find_library(log-lib 41 | log 42 | ) 43 | find_library(z-lib 44 | z 45 | ) 46 | #链接静态库 47 | 48 | #生成文件 49 | target_link_libraries(jnihook 50 | ${log-lib} 51 | ${z-lib} 52 | ) 53 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/HookHelper.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @ name unpacker 3 | * @ author xiaobaiyey 4 | * @ email xiaobaiyey@outlook.com 5 | * @ time 2018/9/5 上午10:03 6 | * @ class describe 7 | */ 8 | 9 | #ifndef UNPACKER_HOOKHELPER_H 10 | #define UNPACKER_HOOKHELPER_H 11 | 12 | #include 13 | #include "HookInfo.h" 14 | 15 | enum HOOK_STATUS { 16 | FERROR_UNKNOWN = -1, 17 | FERROR_SUCCESS = 0, 18 | FERROR_NOT_REGISTERED, 19 | FERROR_NOT_EXECUTABLE, 20 | FERROR_ALREADY_HOOKED, 21 | FERROR_MEMORY, 22 | }; 23 | 24 | 25 | class HookHelper { 26 | public: 27 | static HookHelper *getInstance(); 28 | 29 | /* you must register a func before hook. 30 | * callOrigin pointer to call origin funcation, not support yet!!!*/ 31 | HOOK_STATUS registerHook(void *orginalFunAddr, void *newFunAddr, 32 | void **callOrigin); 33 | 34 | HookHelper(); 35 | 36 | ~HookHelper(); 37 | 38 | public: 39 | bool hook(void *originalFunAddr); 40 | 41 | HookInfo *getHookInfo(void *origFunAddr); 42 | 43 | /* do unhook func*/ 44 | bool unhook(void *originalFuncAddr); 45 | 46 | 47 | void hookAll(); 48 | 49 | void unhookAll(); 50 | 51 | /* check whether func is hooked.*/ 52 | bool isAlreadyHooked(void *originalFunAddr); 53 | 54 | /* if func is hooked, return call original address.*/ 55 | void *getCallOriginFuncAddr(void *originalFunAddr); 56 | 57 | /* if func is hooked, return hook func address*/ 58 | void *getNewFunAddr(void *originalFunAddr); 59 | 60 | int getHookedCount(); 61 | 62 | private: 63 | std::map hook_map; 64 | 65 | /* hook function and flash memory*/ 66 | bool Hook(HookInfo *info); 67 | 68 | /* unhook funciton and flash memory*/ 69 | bool UnHook(HookInfo *info); 70 | 71 | void addHookInfo(HookInfo *info); 72 | 73 | bool delHookInfo(HookInfo *info); 74 | }; 75 | 76 | 77 | #endif //UNPACKER_HOOKHELPER_H 78 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/instruction/Instruction.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @ name unpacker 3 | * @ author xiaobaiyey 4 | * @ email xiaobaiyey@outlook.com 5 | * @ time 2018/9/11 下午2:47 6 | * @ class describe 7 | */ 8 | 9 | #ifndef UNPACKER_INSTRUCTION_H 10 | #define UNPACKER_INSTRUCTION_H 11 | 12 | 13 | #include 14 | #include "../HookInfo.h" 15 | 16 | class Instruction { 17 | public: 18 | virtual ~Instruction() {} 19 | 20 | static void *getOriginalAddr(HookInfo *info); 21 | 22 | /*create jump stub to jump to new func*/ 23 | virtual bool createStub(HookInfo *info) = 0; 24 | 25 | /*create original jump stub to jump to old func*/ 26 | virtual bool createCallOriginalStub(HookInfo *info) { 27 | info->setCallOriginalIns(nullptr); 28 | assert(false && "not support yet"); 29 | return false; 30 | }; 31 | 32 | /*create back stub*/ 33 | bool createBackStub(HookInfo *info); 34 | 35 | 36 | /*make jump stub enable(patch func stub))*/ 37 | static bool enableJumpStub(HookInfo *info); 38 | 39 | /*make jump stub disable(restore old func)*/ 40 | static bool disableJumpStub(HookInfo *info); 41 | 42 | static FunctionType getFunctionType(void *functionAddr) { 43 | #if defined(__arm__) 44 | if (0 == functionAddr) { 45 | return ERRTYPE; 46 | } else if (((unsigned) functionAddr & 3) == 0) { 47 | return ARM; 48 | } else { 49 | return THUMB; 50 | } 51 | #elif defined(__aarch64__) 52 | return ARM64; 53 | #elif defined(__i386__) 54 | return X86; 55 | #elif defined(__x86_64__) 56 | return X64; 57 | #elif defined(__mips64__) /* mips64el-* toolchain defines __mips__ too */ 58 | return MIPS64; 59 | #elif defined(__mips__) 60 | return MIPS; 61 | #endif 62 | } 63 | 64 | static bool patchMemory(void *dest, void *src, uint32_t len); 65 | }; 66 | 67 | 68 | #endif //UNPACKER_INSTRUCTION_H 69 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/instruction/Instruction.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "Instruction.h" 4 | #include "../Helper.h" 5 | #include 6 | #include 7 | 8 | bool Instruction::enableJumpStub(HookInfo *info) { 9 | auto origAddr = getOriginalAddr(info); 10 | auto len = info->getJumpStubLen(); 11 | auto stubAddr = info->getJumpStubBack(); 12 | return patchMemory(origAddr, stubAddr, len); 13 | } 14 | 15 | bool Instruction::disableJumpStub(HookInfo *info) { 16 | auto origAddr = getOriginalAddr(info); 17 | auto len = info->getBackLen(); 18 | auto stubAddr = info->getOriginalStubBack(); 19 | return patchMemory(origAddr, stubAddr, len); 20 | } 21 | 22 | bool Instruction::patchMemory(void *dest, void *src, uint32_t len) { 23 | if (dest == nullptr || src == nullptr || len == 0) { 24 | return false; 25 | } 26 | if (!Helper::unProtectMemory(dest, len)) { 27 | return false; 28 | } 29 | 30 | memcpy(dest, src, len); 31 | Helper::protectMemory(dest, len); 32 | #ifdef __arm__ 33 | cacheflush((unsigned long) dest, (unsigned long) dest + len, 0); 34 | #endif 35 | 36 | #if defined(__aarch64__) 37 | #define __flush_cache(c, n) __builtin___clear_cache(reinterpret_cast(c), reinterpret_cast(c) + n) 38 | __flush_cache((unsigned long) dest, len); 39 | #endif 40 | 41 | return true; 42 | } 43 | 44 | bool Instruction::createBackStub(HookInfo *info) { 45 | auto len = info->getJumpStubLen(); 46 | if (len == 0) { 47 | return false; 48 | } 49 | auto stub = new uint8_t[len]; 50 | info->setOriginalStubBack(stub); 51 | info->setBackLen(len); 52 | memcpy(stub, getOriginalAddr(info), len); 53 | return true; 54 | } 55 | 56 | void *Instruction::getOriginalAddr(HookInfo *info) { 57 | auto addr = info->getOriginalAddr(); 58 | if (info->getOriginalFunctionType() == THUMB) { 59 | addr = (void *) ((unsigned long) addr & (~0x1L)); 60 | } 61 | return addr; 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/LogHex.cpp: -------------------------------------------------------------------------------- 1 | #include "LogHex.h" 2 | #include 3 | #include 4 | 5 | static char _MSHexChar(uint8_t value) { 6 | return value < 0x20 || value >= 0x80 ? '.' : value; 7 | } 8 | 9 | #define HexWidth_ 16 10 | #define HexDepth_ 4 11 | #define LOGDH(...) __android_log_print(ANDROID_LOG_ERROR,"LogHex.cpp" ,__VA_ARGS__) 12 | #define MSLog(level, format, ...) do { \ 13 | LOGDH(format, ## __VA_ARGS__); \ 14 | } while (false) 15 | 16 | #define lprintf(format, ...) \ 17 | MSLog(format, ## __VA_ARGS__) 18 | 19 | 20 | void LogHex::PrintHex(const void *vdata, size_t size, const char *mark) { 21 | return PrintHexEx(vdata, size, 1, mark); 22 | } 23 | 24 | void LogHex::PrintHexEx(const void *vdata, size_t size, size_t stride, const char *mark) { 25 | const uint8_t *data((const uint8_t *) vdata); 26 | 27 | size_t i(0), j; 28 | 29 | char d[256]; 30 | size_t b(0); 31 | d[0] = '\0'; 32 | 33 | while (i != size) { 34 | if (i % HexWidth_ == 0) { 35 | if (mark != NULL) 36 | b += sprintf(d + b, "[%s] ", mark); 37 | b += sprintf(d + b, "0x%.3zx:", i); 38 | } 39 | 40 | b += sprintf(d + b, " "); 41 | 42 | for (size_t q(0); q != stride; ++q) 43 | b += sprintf(d + b, "%.2x", data[i + stride - q - 1]); 44 | 45 | i += stride; 46 | 47 | for (size_t q(1); q != stride; ++q) 48 | b += sprintf(d + b, " "); 49 | 50 | if (i % HexDepth_ == 0) 51 | b += sprintf(d + b, " "); 52 | 53 | if (i % HexWidth_ == 0) { 54 | b += sprintf(d + b, " "); 55 | for (j = i - HexWidth_; j != i; ++j) 56 | b += sprintf(d + b, "%c", _MSHexChar(data[j])); 57 | 58 | lprintf("%s", d); 59 | b = 0; 60 | d[0] = '\0'; 61 | } 62 | } 63 | 64 | if (i % HexWidth_ != 0) { 65 | for (j = i % HexWidth_; j != HexWidth_; ++j) 66 | b += sprintf(d + b, " "); 67 | for (j = 0; j != (HexWidth_ - i % HexWidth_ + HexDepth_ - 1) / HexDepth_; ++j) 68 | b += sprintf(d + b, " "); 69 | b += sprintf(d + b, " "); 70 | for (j = i / HexWidth_ * HexWidth_; j != i; ++j) 71 | b += sprintf(d + b, "%c", _MSHexChar(data[j])); 72 | 73 | lprintf("%s", d); 74 | b = 0; 75 | d[0] = '\0'; 76 | } 77 | } 78 | 79 | void LogHex::DumpHex(const void *vdata, size_t size) { 80 | char name[16]; 81 | sprintf(name, "%p", vdata); 82 | PrintHex(vdata, size, name); 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/instruction/ArmInstruction.h: -------------------------------------------------------------------------------- 1 | //===------------------------------------------------------------*- C++ -*-===// 2 | // 3 | // Created by F8LEFT on 2017/6/19. 4 | // Copyright (c) 2017. All rights reserved. 5 | //===----------------------------------------------------------------------===// 6 | // Instruction helper for arm. Base on GodInHook 7 | //===----------------------------------------------------------------------===// 8 | 9 | 10 | #ifndef FAINHOOK_ARMINSTRUCTION_H 11 | #define FAINHOOK_ARMINSTRUCTION_H 12 | 13 | #include "Instruction.h" 14 | #include 15 | 16 | enum A$r { 17 | A$r0, A$r1, A$r2, A$r3, 18 | A$r4, A$r5, A$r6, A$r7, 19 | A$r8, A$r9, A$r10, A$r11, 20 | A$r12, A$r13, A$r14, A$r15, 21 | A$sp = A$r13, 22 | A$lr = A$r14, 23 | A$pc = A$r15 24 | }; 25 | 26 | enum A$c { 27 | A$eq, A$ne, A$cs, A$cc, 28 | A$mi, A$pl, A$vs, A$vc, 29 | A$hi, A$ls, A$ge, A$lt, 30 | A$gt, A$le, A$al, 31 | A$hs = A$cs, 32 | A$lo = A$cc 33 | }; 34 | #define A$mrs_rm_cpsr(rd) /* mrs rd, cpsr */ \ 35 | (0xe10f0000 | ((rd) << 12)) 36 | #define A$msr_cpsr_f_rm(rm) /* msr cpsr_f, rm */ \ 37 | (0xe128f000 | (rm)) 38 | static __inline int abss(int __n) { return (__n < 0) ? -__n : __n; } 39 | 40 | #define A$ldr_rd_$rn_im$(rd, rn, im) /* ldr rd, [rn, #im] */ \ 41 | (0xe5100000 | ((im) < 0 ? 0 : 1 << 23) | ((rn) << 16) | ((rd) << 12) | abss(im)) 42 | #define A$str_rd_$rn_im$(rd, rn, im) /* sr rd, [rn, #im] */ \ 43 | (0xe5000000 | ((im) < 0 ? 0 : 1 << 23) | ((rn) << 16) | ((rd) << 12) | abss(im)) 44 | #define A$sub_rd_rn_$im(rd, rn, im) /* sub, rd, rn, #im */ \ 45 | (0xe2400000 | ((rn) << 16) | ((rd) << 12) | (im & 0xff)) 46 | #define A$blx_rm(rm) /* blx rm */ \ 47 | (0xe12fff30 | (rm)) 48 | #define A$mov_rd_rm(rd, rm) /* mov rd, rm */ \ 49 | (0xe1a00000 | ((rd) << 12) | (rm)) 50 | #define A$ldmia_sp$_$rs$(rs) /* ldmia sp!, {rs} */ \ 51 | (0xe8b00000 | (A$sp << 16) | (rs)) 52 | #define A$stmdb_sp$_$rs$(rs) /* stmdb sp!, {rs} */ \ 53 | (0xe9200000 | (A$sp << 16) | (rs)) 54 | #define A$stmia_sp$_$r0$ 0xe8ad0001 /* stmia sp!, {r0} */ 55 | #define A$bx_r0 0xe12fff10 /* bx r0 */ 56 | 57 | 58 | class ArmInstruction : public Instruction { 59 | public: 60 | ~ArmInstruction() {} 61 | 62 | bool createStub(HookInfo *info); 63 | 64 | bool createCallOriginalStub(HookInfo *info); 65 | 66 | private: 67 | 68 | static bool A$pcrel$r(uint32_t ic) { 69 | return (ic & 0x0c000000) == 0x04000000 && (ic & 0xf0000000) != 0xf0000000 && 70 | (ic & 0x000f0000) == 0x000f0000; 71 | } 72 | }; 73 | 74 | 75 | #endif //FAINHOOK_ARMINSTRUCTION_H 76 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ### 用途 2 | 3 | 用于hook JNI相关函数 4 | 5 | ### 用法 6 | 7 | 可以参考jnihook 目录下的Main.cpp文件 8 | 9 | * 创建回调类需要继承JNIInterface如下:并在回调类中实现要hook的方法 10 | 11 | ```c++ 12 | 13 | /** 14 | * 创建一个类继承JNIInterface 15 | * 用于实现所要hook的方法 16 | */ 17 | class Test : public JNIInterface { 18 | public: 19 | 20 | void NewStringUTF(JNIEnv *env, const char *string) override { 21 | JNIInterface::NewStringUTF(env, string); 22 | //此处用编写拦截 代码 23 | LOGI("%s",string); 24 | } 25 | 26 | void 27 | GetMethodID(JNIEnv *env, jclass jclass1, const char *string, const char *string1) override { 28 | JNIInterface::GetMethodID(env, jclass1, string, string1); 29 | VM *vm = VM::getInstance(); 30 | const char *class_name = vm->getClasstName(jclass1); 31 | LOGI("Class:%s Method:%s%s", class_name, string, string1); 32 | } 33 | 34 | void GetFieldID(JNIEnv *env, jclass jclass1, const char *string, const char *string1) override { 35 | JNIInterface::GetFieldID(env, jclass1, string, string1); 36 | VM *vm = VM::getInstance(); 37 | const char *class_name = vm->getClasstName(jclass1); 38 | LOGI("Class:%s Field:%s:%s", class_name, string, string1); 39 | } 40 | 41 | void FindClass(JNIEnv *env, const char *string) override { 42 | JNIInterface::FindClass(env, string); 43 | LOGI("%s",string); 44 | } 45 | 46 | void CallObjectMethodV(JNIEnv *env, jobject jobject1, jmethodID id, va_list list) override { 47 | JNIInterface::CallObjectMethodV(env, jobject1, id, list); 48 | VM *vm = VM::getInstance(); 49 | const char *class_name = vm->getObjectName(jobject1); 50 | char *method_name = vm->getMethodName(id); 51 | LOGI("Class:%s Method:%s", class_name, method_name); 52 | delete method_name; 53 | 54 | } 55 | 56 | void CallObjectMethodA(JNIEnv *env, jobject jobject1, jmethodID id, jvalue *jvalue1) override { 57 | JNIInterface::CallObjectMethodA(env, jobject1, id, jvalue1); 58 | VM *vm = VM::getInstance(); 59 | const char *class_name = vm->getObjectName(jobject1); 60 | char *method_name = vm->getMethodName(id); 61 | LOGI("Class:%s Method:%s", class_name, method_name); 62 | delete method_name; 63 | } 64 | }; 65 | 66 | ``` 67 | 68 | * 调用JniHook中的相关方法对指定方法进行hook,如: 69 | 70 | ```c++ 71 | 72 | //获取实例 传入参数 73 | JniHook *jniHook = JniHook::getInstance(env, test); 74 | //hook 对应方法 75 | jniHook->hookNewStringUTF(); 76 | 77 | ``` 78 | 79 | * enjoy it 80 | 81 | ### 效果图 82 | 83 | ![](./test.png) 84 | 85 | 86 | ### 参考 87 | 88 | Hook方案来自:[https://github.com/F8LEFT/FAInHook](https://github.com/F8LEFT/FAInHook) 89 | Arm64hook方案来自:[https://github.com/Rprop/And64InlineHook](https://github.com/Rprop/And64InlineHook) 90 | 91 | -------------------------------------------------------------------------------- /app/src/main/cpp/jnihook/Main.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @ name jnihook 3 | * @ author xiaobaiyey 4 | * @ email xiaobaiyey@outlook.com 5 | * @ time 2018/10/30 3:36 PM 6 | * @ class 测试类 7 | */ 8 | #include 9 | #include 10 | #include "JNIInterface.h" 11 | #include "JniHook.h" 12 | #include "VM.h" 13 | 14 | #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, __FUNCTION__, __VA_ARGS__)) 15 | #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, __FUNCTION__,__VA_ARGS__)) 16 | #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, __FUNCTION__, __VA_ARGS__)) 17 | #define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, __FUNCTION__,__VA_ARGS__)) 18 | 19 | /** 20 | * 创建一个类继承JNIInterface 21 | * 用于实现所要hook的方法 22 | */ 23 | class Test : public JNIInterface { 24 | public: 25 | 26 | void NewStringUTF(JNIEnv *env, const char *string) override { 27 | JNIInterface::NewStringUTF(env, string); 28 | //此处用编写拦截 代码 29 | LOGI(string); 30 | } 31 | 32 | void 33 | GetMethodID(JNIEnv *env, jclass jclass1, const char *string, const char *string1) override { 34 | JNIInterface::GetMethodID(env, jclass1, string, string1); 35 | VM *vm = VM::getInstance(); 36 | const char *class_name = vm->getClasstName(jclass1); 37 | LOGI("Class:%s Method:%s%s", class_name, string, string1); 38 | } 39 | 40 | void GetFieldID(JNIEnv *env, jclass jclass1, const char *string, const char *string1) override { 41 | JNIInterface::GetFieldID(env, jclass1, string, string1); 42 | VM *vm = VM::getInstance(); 43 | const char *class_name = vm->getClasstName(jclass1); 44 | LOGI("Class:%s Field:%s:%s", class_name, string, string1); 45 | } 46 | 47 | void FindClass(JNIEnv *env, const char *string) override { 48 | JNIInterface::FindClass(env, string); 49 | LOGI(string); 50 | } 51 | 52 | void CallObjectMethodV(JNIEnv *env, jobject jobject1, jmethodID id, va_list list) override { 53 | JNIInterface::CallObjectMethodV(env, jobject1, id, list); 54 | VM *vm = VM::getInstance(); 55 | const char *class_name = vm->getObjectName(jobject1); 56 | char *method_name = vm->getMethodName(id); 57 | LOGI("Class:%s Method:%s", class_name, method_name); 58 | delete method_name; 59 | 60 | } 61 | 62 | void CallObjectMethodA(JNIEnv *env, jobject jobject1, jmethodID id, jvalue *jvalue1) override { 63 | JNIInterface::CallObjectMethodA(env, jobject1, id, jvalue1); 64 | VM *vm = VM::getInstance(); 65 | const char *class_name = vm->getObjectName(jobject1); 66 | char *method_name = vm->getMethodName(id); 67 | LOGI("Class:%s Method:%s", class_name, method_name); 68 | delete method_name; 69 | } 70 | }; 71 | 72 | 73 | void jnihook(JNIEnv *env) { 74 | //new 75 | Test *test = new Test; 76 | //获取实例 传入参数 77 | JniHook *jniHook = JniHook::getInstance(env, test); 78 | //hook 对应方法 79 | //jniHook->hookNewStringUTF(); 80 | jniHook->hookGetMethodID(); 81 | jniHook->hookGetFieldID(); 82 | jniHook->hookFindClass(); 83 | jniHook->hookCallObjectMethodA(); 84 | jniHook->hookCallObjectMethodV(); 85 | 86 | } 87 | 88 | 89 | JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { 90 | JNIEnv *env = NULL; 91 | if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) { 92 | return -1; 93 | } 94 | LOGD("in jni onload"); 95 | jnihook(env); 96 | return JNI_VERSION_1_4; 97 | } -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/Helper.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @ name unpacker 3 | * @ author xiaobaiyey 4 | * @ email xiaobaiyey@outlook.com 5 | * @ time 2018/9/5 上午4:30 6 | * @ class describe 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "Helper.h" 17 | 18 | #define maps "/proc/self/maps" 19 | #define MAX_BUF 128 20 | Helper gMemHelper; 21 | uint32_t Helper::page_size; 22 | 23 | /** 24 | * Check if the target address is executable 25 | * @param addr target address to hook 26 | * @return nothing to do 27 | */ 28 | bool Helper::isFunctionAddr(void *addr) { 29 | char buf[MAX_BUF]; 30 | auto fp = fopen(maps, "r"); 31 | if (nullptr == fp) { 32 | return false; 33 | } 34 | while (fgets(buf, MAX_BUF, fp)) { 35 | if (strstr(buf, "r-xp") != nullptr) { 36 | void *startAddr = (void *) strtoul(strtok(buf, "-"), nullptr, 16); 37 | void *endAddr = (void *) strtoul(strtok(nullptr, " "), nullptr, 16); 38 | if (addr >= startAddr && addr <= endAddr) { 39 | fclose(fp); 40 | return true; 41 | } 42 | } 43 | } 44 | fclose(fp); 45 | return false; 46 | } 47 | 48 | /** 49 | * reomve a writable attribute to the target address 50 | * @param addr target address 51 | * @param size memory size to change 52 | * @return 53 | */ 54 | bool Helper::unProtectMemory(void *addr, uint32_t size) { 55 | //page align 56 | auto align = ((size_t) addr) % page_size; 57 | return mprotect((uint8_t *) addr - align, size + align, PROT_READ | PROT_WRITE | PROT_EXEC) != 58 | -1; 59 | } 60 | 61 | /** 62 | * add a writable attribute to the target address 63 | * @param addr target address 64 | * @param size memory size to change 65 | * @return 66 | */ 67 | bool Helper::protectMemory(void *addr, uint32_t size) { 68 | auto align = ((size_t) addr) % page_size; 69 | return mprotect((uint8_t *) addr - align, size + align, PROT_READ | PROT_EXEC) != -1; 70 | } 71 | 72 | /** 73 | * 74 | * @param size 75 | * @return 76 | */ 77 | void *Helper::createExecMemory(uint32_t size) { 78 | if (size & 1) { 79 | size++; 80 | } 81 | if (size > page_size) { 82 | return nullptr; 83 | } 84 | if (gMemHelper.current_page != nullptr && page_size - gMemHelper.page_ptr_ >= size) { 85 | auto funPtr = (void *) ((size_t) gMemHelper.current_page + gMemHelper.page_ptr_); 86 | gMemHelper.page_ptr_ += size; 87 | // Align 4 88 | while (gMemHelper.page_ptr_ & 0x3) { 89 | gMemHelper.page_ptr_++; 90 | } 91 | return funPtr; 92 | } 93 | // scroll to next page 94 | auto newPage = mmap(nullptr, page_size, PROT_READ | PROT_WRITE | PROT_EXEC, 95 | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 96 | if (newPage != MAP_FAILED) { 97 | gMemHelper.alloc_memory_page_.push_back(newPage); 98 | 99 | gMemHelper.current_page = newPage; 100 | gMemHelper.page_ptr_ = 0; 101 | return createExecMemory(size); 102 | } 103 | return nullptr; 104 | } 105 | 106 | 107 | Helper::Helper() { 108 | // get system page size 109 | page_size = sysconf(_SC_PAGESIZE); 110 | } 111 | 112 | Helper::~Helper() { 113 | for (auto *page : alloc_memory_page_) { 114 | munmap(page, page_size); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/HookInfo.h: -------------------------------------------------------------------------------- 1 | //===------------------------------------------------------------*- C++ -*-===// 2 | // 3 | // Created by F8LEFT on 2017/6/9. 4 | // Copyright (c) 2017. All rights reserved. 5 | //===-------------------------------------------------------------------------- 6 | // Save hook func information 7 | //===----------------------------------------------------------------------===// 8 | 9 | #ifndef FAINHOOK_HOOKINFO_H 10 | #define FAINHOOK_HOOKINFO_H 11 | 12 | 13 | #include 14 | 15 | enum HookStatus { 16 | ERRSTATUS = 0, 17 | REGISTERED, 18 | HOOKED, 19 | }; 20 | 21 | enum FunctionType { 22 | ERRTYPE = 0, 23 | ARM, 24 | THUMB, 25 | ARM64, 26 | X86, 27 | X64, 28 | MIPS, 29 | MIPS64, 30 | }; 31 | 32 | class HookInfo { 33 | public: 34 | HookInfo(void *originalAddr, void *hookAddr) 35 | : original_addr_(originalAddr), hook_addr_(hookAddr), 36 | original_stub_back_(nullptr), back_len_(0), call_original_ins_(nullptr), 37 | hook_status_(ERRSTATUS), 38 | original_function_type_(ERRTYPE), hook_function_type_(ERRTYPE) {} 39 | 40 | ~HookInfo() { 41 | if (jump_stub_back_ != nullptr) { 42 | delete[] (uint8_t *) jump_stub_back_; 43 | } 44 | if (original_stub_back_ != nullptr) { 45 | delete[] (uint8_t *) original_stub_back_; 46 | } 47 | } 48 | 49 | private: 50 | void *original_addr_; 51 | void *hook_addr_; 52 | 53 | // used for hook, to store jump stub 54 | uint8_t *jump_stub_back_ = nullptr; // record jump opcode 55 | uint32_t stub_len_; 56 | 57 | // used for unhook, to restore opcodes. 58 | uint8_t *original_stub_back_ = nullptr; // record original opcode 59 | uint32_t back_len_; // orginal opcode size 60 | uint8_t *call_original_ins_; // new opcode, to jump into hookAddr 61 | 62 | HookStatus hook_status_; 63 | FunctionType original_function_type_; 64 | FunctionType hook_function_type_; 65 | 66 | public: 67 | void *getOriginalAddr() { return original_addr_; } 68 | 69 | void *getHookAddr() { return hook_addr_; } 70 | 71 | void setJumpStubBack(uint8_t *addr) { jump_stub_back_ = addr; } 72 | 73 | uint8_t *getJumpStubBack() { return jump_stub_back_; } 74 | 75 | void setJumpStubLen(uint32_t len) { stub_len_ = len; } 76 | 77 | uint32_t getJumpStubLen() { return stub_len_; } 78 | 79 | void setOriginalStubBack(uint8_t *addr) { original_stub_back_ = addr; } 80 | 81 | uint8_t *getOriginalStubBack() { return original_stub_back_; } 82 | 83 | void setBackLen(uint32_t len) { back_len_ = len; } 84 | 85 | uint32_t getBackLen() { return back_len_; } 86 | 87 | void setCallOriginalIns(uint8_t *addr) { call_original_ins_ = addr; } 88 | 89 | uint8_t *getCallOriginalIns() { return call_original_ins_; } 90 | 91 | void setHookStatus(HookStatus status) { hook_status_ = status; } 92 | 93 | HookStatus getHookStatus() { return hook_status_; } 94 | 95 | void setOriginalFunctionType(FunctionType type) { original_function_type_ = type; } 96 | 97 | FunctionType getOriginalFunctionType() { return original_function_type_; } 98 | 99 | void setHookFunctionType(FunctionType type) { hook_function_type_ = type; } 100 | 101 | FunctionType getHookFunctionType() { return hook_function_type_; } 102 | }; 103 | 104 | 105 | #endif //FAINHOOK_HOOKINFO_H 106 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/instruction/IntelDisasm.h: -------------------------------------------------------------------------------- 1 | //===------------------------------------------------------------*- C++ -*-===// 2 | // 3 | // Created by F8LEFT on 2017/6/23. 4 | // Copyright (c) 2017. All rights reserved. 5 | //===----------------------------------------------------------------------===// 6 | // MiniDisasm for Intell x86/x64 7 | //===----------------------------------------------------------------------===// 8 | 9 | 10 | #ifndef FAINHOOK_INTELDISASM_H 11 | #define FAINHOOK_INTELDISASM_H 12 | 13 | /* 14 | * Hacker Disassembler Engine 64 C 15 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 16 | * All rights reserved. 17 | * 18 | */ 19 | #define C_NONE 0x00 20 | #define C_MODRM 0x01 21 | #define C_IMM8 0x02 22 | #define C_IMM16 0x04 23 | #define C_IMM_P66 0x10 24 | #define C_REL8 0x20 25 | #define C_REL32 0x40 26 | #define C_GROUP 0x80 27 | #define C_ERROR 0xff 28 | 29 | #define PRE_ANY 0x00 30 | #define PRE_NONE 0x01 31 | #define PRE_F2 0x02 32 | #define PRE_F3 0x04 33 | #define PRE_66 0x08 34 | #define PRE_67 0x10 35 | #define PRE_LOCK 0x20 36 | #define PRE_SEG 0x40 37 | #define PRE_ALL 0xff 38 | 39 | #define DELTA_OPCODES 0x4a 40 | #define DELTA_FPU_REG 0xfd 41 | #define DELTA_FPU_MODRM 0x104 42 | #define DELTA_PREFIXES 0x13c 43 | #define DELTA_OP_LOCK_OK 0x1ae 44 | #define DELTA_OP2_LOCK_OK 0x1c6 45 | #define DELTA_OP_ONLY_MEM 0x1d8 46 | #define DELTA_OP2_ONLY_MEM 0x1e7 47 | 48 | /* stdint.h - C99 standard header 49 | * http://en.wikipedia.org/wiki/stdint.h 50 | * 51 | * if your compiler doesn't contain "stdint.h" header (for 52 | * example, Microsoft Visual C++), you can download file: 53 | * http://www.azillionmonkeys.com/qed/pstdint.h 54 | * and change next line to: 55 | * #include "pstdint.h" 56 | */ 57 | #include 58 | 59 | #define F_MODRM 0x00000001 60 | #define F_SIB 0x00000002 61 | #define F_IMM8 0x00000004 62 | #define F_IMM16 0x00000008 63 | #define F_IMM32 0x00000010 64 | #define F_IMM64 0x00000020 65 | #define F_DISP8 0x00000040 66 | #define F_DISP16 0x00000080 67 | #define F_DISP32 0x00000100 68 | #define F_RELATIVE 0x00000200 69 | #define F_ERROR 0x00001000 70 | #define F_ERROR_OPCODE 0x00002000 71 | #define F_ERROR_LENGTH 0x00004000 72 | #define F_ERROR_LOCK 0x00008000 73 | #define F_ERROR_OPERAND 0x00010000 74 | #define F_PREFIX_REPNZ 0x01000000 75 | #define F_PREFIX_REPX 0x02000000 76 | #define F_PREFIX_REP 0x03000000 77 | #define F_PREFIX_66 0x04000000 78 | #define F_PREFIX_67 0x08000000 79 | #define F_PREFIX_LOCK 0x10000000 80 | #define F_PREFIX_SEG 0x20000000 81 | #define F_PREFIX_REX 0x40000000 82 | #define F_PREFIX_ANY 0x7f000000 83 | 84 | #define PREFIX_SEGMENT_CS 0x2e 85 | #define PREFIX_SEGMENT_SS 0x36 86 | #define PREFIX_SEGMENT_DS 0x3e 87 | #define PREFIX_SEGMENT_ES 0x26 88 | #define PREFIX_SEGMENT_FS 0x64 89 | #define PREFIX_SEGMENT_GS 0x65 90 | #define PREFIX_LOCK 0xf0 91 | #define PREFIX_REPNZ 0xf2 92 | #define PREFIX_REPX 0xf3 93 | #define PREFIX_OPERAND_SIZE 0x66 94 | #define PREFIX_ADDRESS_SIZE 0x67 95 | 96 | struct hde64s { 97 | uint8_t len; 98 | uint8_t p_rep; 99 | uint8_t p_lock; 100 | uint8_t p_seg; 101 | uint8_t p_66; 102 | uint8_t p_67; 103 | uint8_t rex; 104 | uint8_t rex_w; 105 | uint8_t rex_r; 106 | uint8_t rex_x; 107 | uint8_t rex_b; 108 | uint8_t opcode; 109 | uint8_t opcode2; 110 | uint8_t modrm; 111 | uint8_t modrm_mod; 112 | uint8_t modrm_reg; 113 | uint8_t modrm_rm; 114 | uint8_t sib; 115 | uint8_t sib_scale; 116 | uint8_t sib_index; 117 | uint8_t sib_base; 118 | union { 119 | uint8_t imm8; 120 | uint16_t imm16; 121 | uint32_t imm32; 122 | uint64_t imm64; 123 | } imm; 124 | union { 125 | uint8_t disp8; 126 | uint16_t disp16; 127 | uint32_t disp32; 128 | } disp; 129 | uint32_t flags; 130 | }__attribute__((packed)); 131 | 132 | uint32_t hde64_disasm(const void *code, hde64s *hs); 133 | 134 | size_t hde64_getInsWidth(void *start); 135 | 136 | 137 | #endif //FAINHOOK_INTELDISASM_H 138 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/instruction/ArmInstruction.cpp: -------------------------------------------------------------------------------- 1 | //===------------------------------------------------------------*- C++ -*-===// 2 | // 3 | // Created by F8LEFT on 2017/6/19. 4 | // Copyright (c) 2017. All rights reserved. 5 | //===----------------------------------------------------------------------===// 6 | // 7 | //===----------------------------------------------------------------------===// 8 | 9 | 10 | #include "ArmInstruction.h" 11 | #include "../Helper.h" 12 | 13 | 14 | bool ArmInstruction::createStub(HookInfo *info) { 15 | auto stubsize = 8; 16 | auto *stub = new uint32_t[2]; 17 | *(uint32_t *) &stub[0] = 0xe51ff004; // ldr pc, addr 18 | *(uint32_t *) &stub[4] = (uint32_t) info->getHookAddr(); 19 | 20 | stub[0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); // ldr pc, pc, -4 21 | stub[1] = reinterpret_cast(info->getHookAddr()); 22 | 23 | info->setJumpStubLen(stubsize); 24 | info->setJumpStubBack((uint8_t *) stub); 25 | return true; 26 | } 27 | 28 | bool ArmInstruction::createCallOriginalStub(HookInfo *info) { 29 | uint32_t *area(reinterpret_cast(info->getOriginalAddr())); 30 | uint32_t *arm(area); 31 | 32 | const size_t used(8); 33 | 34 | uint32_t backup[used / sizeof(uint32_t)] = {arm[0], arm[1]}; 35 | 36 | 37 | if (backup[0] == A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8)) { // ldr pc, pc, -4 38 | info->setCallOriginalIns(reinterpret_cast(backup[1])); 39 | return true; 40 | } 41 | 42 | size_t length(used); 43 | for (unsigned offset(0); offset != used / sizeof(uint32_t); ++offset) 44 | if (A$pcrel$r(backup[offset])) { 45 | if ((backup[offset] & 0x02000000) == 0 || 46 | (backup[offset] & 0x0000f000 >> 12) != (backup[offset] & 0x0000000f)) 47 | length += 2 * sizeof(uint32_t); 48 | else 49 | length += 4 * sizeof(uint32_t); 50 | } 51 | 52 | length += 2 * sizeof(uint32_t); 53 | 54 | uint32_t *buffer = (uint32_t *) Helper::createExecMemory(length); 55 | if (buffer == nullptr) { 56 | return false; 57 | } 58 | 59 | 60 | size_t start(0), end(length / sizeof(uint32_t)); 61 | uint32_t *trailer(reinterpret_cast(buffer + end)); 62 | for (unsigned offset(0); offset != used / sizeof(uint32_t); ++offset) 63 | if (A$pcrel$r(backup[offset])) { 64 | union { 65 | uint32_t value; 66 | 67 | struct { 68 | uint32_t rm : 4; 69 | uint32_t : 1; 70 | uint32_t shift : 2; 71 | uint32_t shiftamount : 5; 72 | uint32_t rd : 4; 73 | uint32_t rn : 4; 74 | uint32_t l : 1; 75 | uint32_t w : 1; 76 | uint32_t b : 1; 77 | uint32_t u : 1; 78 | uint32_t p : 1; 79 | uint32_t mode : 1; 80 | uint32_t type : 2; 81 | uint32_t cond : 4; 82 | }; 83 | } bits = {backup[offset + 0]}, copy(bits); 84 | 85 | bool guard; 86 | if (bits.mode == 0 || bits.rd != bits.rm) { 87 | copy.rn = bits.rd; 88 | guard = false; 89 | } else { 90 | copy.rn = bits.rm != A$r0 ? A$r0 : A$r1; 91 | guard = true; 92 | } 93 | 94 | if (guard) 95 | buffer[start++] = A$stmdb_sp$_$rs$((1 << copy.rn)); 96 | 97 | buffer[start + 0] = A$ldr_rd_$rn_im$(copy.rn, A$pc, (end - 1 - (start + 0)) * 4 - 8); 98 | buffer[start + 1] = copy.value; 99 | 100 | start += 2; 101 | 102 | if (guard) 103 | buffer[start++] = A$ldmia_sp$_$rs$((1 << copy.rn)); 104 | 105 | *--trailer = reinterpret_cast(area + offset) + 8; 106 | end -= 1; 107 | } else 108 | buffer[start++] = backup[offset]; 109 | 110 | buffer[start + 0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); 111 | buffer[start + 1] = reinterpret_cast(area + used / sizeof(uint32_t)); 112 | 113 | info->setCallOriginalIns((uint8_t *) buffer); 114 | 115 | return true; 116 | } 117 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/main.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @ name unpacker 3 | * @ author xiaobaiyey 4 | * @ email xiaobaiyey@outlook.com 5 | * @ time 2018/9/17 下午11:53 6 | * @ class describe 7 | */ 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | #include "HookHelper.h" 14 | #include "LogHex.h" 15 | 16 | #define TOSTR(fmt) #fmt 17 | #define FLFMT(fmt) TOSTR([%s:%d]fmt) 18 | 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #define FLOG_TAG "loig" 26 | 27 | #ifdef EXEC 28 | #define LOGE(...) printf(__VA_ARGS__ );printf("\n"); 29 | #define LOGD(...) printf(__VA_ARGS__ );printf("\n"); 30 | #define LOGW(...) printf(__VA_ARGS__ );printf("\n"); 31 | #define LOGI(...)printf(__VA_ARGS__ );printf("\n"); 32 | #define LOGV(...) printf(__VA_ARGS__ );printf("\n"); 33 | #else 34 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, FLOG_TAG, __VA_ARGS__) 35 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, FLOG_TAG, __VA_ARGS__) 36 | #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, FLOG_TAG, __VA_ARGS__) 37 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, FLOG_TAG, __VA_ARGS__) 38 | #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, FLOG_TAG, __VA_ARGS__) 39 | #endif 40 | 41 | 42 | #define FLOGE(fmt, ...) __android_log_print(ANDROID_LOG_ERROR, FLOG_TAG, FLFMT(fmt), __FUNCTION__, __LINE__, ##__VA_ARGS__) 43 | #define FLOGD(fmt, ...) __android_log_print(ANDROID_LOG_DEBUG, FLOG_TAG, FLFMT(fmt), __FUNCTION__, __LINE__, ##__VA_ARGS__) 44 | #define FLOGW(fmt, ...) __android_log_print(ANDROID_LOG_WARN, FLOG_TAG, FLFMT(fmt), __FUNCTION__, __LINE__, ##__VA_ARGS__) 45 | #define FLOGI(fmt, ...) __android_log_print(ANDROID_LOG_INFO, FLOG_TAG, FLFMT(fmt), __FUNCTION__, __LINE__, ##__VA_ARGS__) 46 | #define FLOGV(fmt, ...) __android_log_print(ANDROID_LOG_VERBOSE, FLOG_TAG, FLFMT(fmt), __FUNCTION__, __LINE__, ##__VA_ARGS__) 47 | 48 | #include 49 | 50 | int (*p_open)(const char *name, int flags, ...) = nullptr; 51 | 52 | int f_open(const char *name, int flags, ...) { 53 | LOGI("start open"); 54 | mode_t mode = 0; 55 | if ((flags & O_CREAT) != 0) { 56 | va_list args; 57 | va_start(args, flags); 58 | mode = static_cast(va_arg(args, int)); 59 | va_end(args); 60 | } 61 | auto rel = p_open(name, flags, mode); 62 | FLOGE(%d = open %s %d %d, rel, name, flags, mode); 63 | return rel; 64 | } 65 | 66 | pid_t (*p_fork)(); 67 | 68 | pid_t f_fork() { 69 | LOGI("start f hook"); 70 | pid_t forkd = p_fork(); 71 | LOGI("fork res: %d", forkd); 72 | return forkd; 73 | } 74 | 75 | ssize_t (*p_read)(int fd, void *dest, size_t request); 76 | 77 | ssize_t f_read(int fd, void *dest, size_t request) { 78 | LOGI("start read"); 79 | LOGI("read data %d at %p: %d", fd, dest, request); 80 | return p_read(fd, dest, request); 81 | } 82 | 83 | JNIEXPORT jint JNI_OnLoads(JavaVM *vm, void *reserved) { 84 | 85 | JNIEnv *env = NULL; 86 | if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) { 87 | return -1; 88 | } 89 | 90 | return JNI_VERSION_1_4; 91 | } 92 | 93 | 94 | extern "C" JNIEXPORT jstring 95 | 96 | JNICALL 97 | Java_com_android_arm64hook_MainActivity_stringFromJNI( 98 | JNIEnv *env, 99 | jobject /* this */) { 100 | std::string hello = "Hello from C++"; 101 | HookHelper *helper = HookHelper::getInstance(); 102 | auto libc = dlopen("system/lib/libc.so", RTLD_NOW); 103 | void *resl = dlsym(libc, "read"); 104 | LOGI("lic:%p", &fork); 105 | LOGI("ric:%p", &resl); 106 | LOGI("f_fork:%p", &f_fork); 107 | LOGI("p_fork:%p", &p_fork); 108 | helper->registerHook((void *) &fork, (void *) &f_fork, (void **) &p_fork); 109 | // helper->registerHook((void *) resl, (void *) &f_read, (void **) &p_read); 110 | LOGI("registerHook over"); 111 | LogHex::DumpHex(resl, 32); 112 | helper->hookAll(); 113 | LOGI("hook start"); 114 | fork(); 115 | LOGI("unhook start"); 116 | helper->unhook((void *) &fork); 117 | pid_t forkend = fork(); 118 | LOGI("test end %d", forkend); 119 | LogHex::DumpHex(resl, 32); 120 | LogHex::DumpHex(&p_fork, 32); 121 | 122 | //fork(); 123 | return env->NewStringUTF(hello.c_str()); 124 | } 125 | 126 | int main(int argc, char const *argv[]) { 127 | HookHelper *helper = HookHelper::getInstance(); 128 | LOGI("hook start"); 129 | auto libc = dlopen("system/lib/libc.so", RTLD_NOW); 130 | void *resl = dlsym(libc, "read"); 131 | LOGI("lic:%p", &fork); 132 | LOGI("ric:%p", &resl); 133 | LOGI("f_fork:%p", &f_fork); 134 | LOGI("p_fork:%p", &p_fork); 135 | helper->registerHook((void *) resl, (void *) &f_read, (void **) &p_read); 136 | helper->hookAll(); 137 | //A64HookFunction((void *)resl, (void *) &f_fork, (void **) &p_fork); 138 | fork(); 139 | LOGI("hook over"); 140 | return 0; 141 | } 142 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/instruction/ThumbInstruction.h: -------------------------------------------------------------------------------- 1 | //===------------------------------------------------------------*- C++ -*-===// 2 | // 3 | // Created by F8LEFT on 2017/6/19. 4 | // Copyright (c) 2017. All rights reserved. 5 | //===----------------------------------------------------------------------===// 6 | // instruction helper for thumb. Base on MSHook 7 | //===----------------------------------------------------------------------===// 8 | 9 | 10 | #ifndef FAINHOOK_THUMBINSTRUCTION_H 11 | #define FAINHOOK_THUMBINSTRUCTION_H 12 | 13 | #include "Instruction.h" 14 | #include "ArmInstruction.h" 15 | 16 | 17 | class ThumbInstruction : public Instruction { 18 | public: 19 | ~ThumbInstruction() {} 20 | 21 | bool createStub(HookInfo *info); 22 | 23 | bool createCallOriginalStub(HookInfo *info); 24 | 25 | private: 26 | 27 | #define T$Label(l, r) \ 28 | (((r) - (l)) * 2 - 4 + ((l) % 2 == 0 ? 0 : 2)) 29 | #define T$pop_$r0$ 0xbc01 // pop {r0} 30 | #define T$b(im) /* b im */ \ 31 | (0xde00 | (im & 0xff)) 32 | #define T$blx(rm) /* blx rm */ \ 33 | (0x4780 | (rm << 3)) 34 | #define T$bx(rm) /* bx rm */ \ 35 | (0x4700 | (rm << 3)) 36 | #define T$nop /* nop */ \ 37 | (0x46c0) 38 | #define T$add_rd_rm(rd, rm) /* add rd, rm */ \ 39 | (0x4400 | (((rd) & 0x8) >> 3 << 7) | (((rm) & 0x8) >> 3 << 6) | (((rm) & 0x7) << 3) | ((rd) & 0x7)) 40 | #define T$push_r(r) /* push r... */ \ 41 | (0xb400 | (((r) & (1 << A$lr)) >> A$lr << 8) | ((r) & 0xff)) 42 | #define T$pop_r(r) /* pop r... */ \ 43 | (0xbc00 | (((r) & (1 << A$pc)) >> A$pc << 8) | ((r) & 0xff)) 44 | #define T$mov_rd_rm(rd, rm) /* mov rd, rm */ \ 45 | (0x4600 | (((rd) & 0x8) >> 3 << 7) | (((rm) & 0x8) >> 3 << 6) | (((rm) & 0x7) << 3) | ((rd) & 0x7)) 46 | #define T$ldr_rd_$rn_im_4$(rd, rn, im) /* ldr rd, [rn, #im * 4] */ \ 47 | (0x6800 | (((im) & 0x1f) << 6) | ((rn) << 3) | (rd)) 48 | #define T$ldr_rd_$pc_im_4$(rd, im) /* ldr rd, [PC, #im * 4] */ \ 49 | (0x4800 | ((rd) << 8) | ((im) & 0xff)) 50 | #define T$cmp_rn_$im(rn, im) /* cmp rn, #im */ \ 51 | (0x2000 | ((rn) << 8) | ((im) & 0xff)) 52 | #define T$it$_cd(cd, ms) /* it, cd */ \ 53 | (0xbf00 | ((cd) << 4) | (ms)) 54 | #define T$cbz$_rn_$im(op, rn, im) /* cbz rn, #im */ \ 55 | (0xb100 | ((op) << 11) | (((im) & 0x40) >> 6 << 9) | (((im) & 0x3e) >> 1 << 3) | (rn)) 56 | #define T$b$_$im(cond, im) /* b #im */ \ 57 | (cond == A$al ? 0xe000 | (((im) >> 1) & 0x7ff) : 0xd000 | ((cond) << 8) | (((im) >> 1) & 0xff)) 58 | #define T1$ldr_rt_$rn_im$(rt, rn, im) /* ldr rt, [rn, #im] */ \ 59 | (0xf850 | ((im < 0 ? 0 : 1) << 7) | (rn)) 60 | 61 | static __inline int absss(int __n) { return (__n < 0) ? -__n : __n; } 62 | #define T2$ldr_rt_$rn_im$(rt, rn, im) /* ldr rt, [rn, #im] */ \ 63 | (((rt) << 12) | absss(im)) 64 | #define T1$mrs_rd_apsr(rd) /* mrs rd, apsr */ \ 65 | (0xf3ef) 66 | #define T2$mrs_rd_apsr(rd) /* mrs rd, apsr */ \ 67 | (0x8000 | ((rd) << 8)) 68 | #define T1$msr_apsr_nzcvqg_rn(rn) /* msr apsr, rn */ \ 69 | (0xf380 | (rn)) 70 | #define T2$msr_apsr_nzcvqg_rn(rn) /* msr apsr, rn */ \ 71 | (0x8c00) 72 | #define T$msr_apsr_nzcvqg_rn(rn) /* msr apsr, rn */ \ 73 | (T2$msr_apsr_nzcvqg_rn(rn) << 16 | T1$msr_apsr_nzcvqg_rn(rn)) 74 | #define A$ldr_rd_$rn_im$(rd, rn, im) /* ldr rd, [rn, #im] */ \ 75 | (0xe5100000 | ((im) < 0 ? 0 : 1 << 23) | ((rn) << 16) | ((rd) << 12) | abs(im)) 76 | 77 | static inline bool T$32bit$i(uint16_t ic) { 78 | return ((ic & 0xe000) == 0xe000 && (ic & 0x1800) != 0x0000); 79 | } 80 | 81 | static inline bool T$pcrel$cbz(uint16_t ic) { 82 | return (ic & 0xf500) == 0xb100; 83 | } 84 | 85 | static inline bool T$pcrel$b(uint16_t ic) { 86 | return (ic & 0xf000) == 0xd000 && (ic & 0x0e00) != 0x0e00; 87 | } 88 | 89 | static inline bool T2$pcrel$b(uint16_t *ic) { 90 | return (ic[0] & 0xf800) == 0xf000 && ((ic[1] & 0xd000) == 0x9000 || 91 | ((ic[1] & 0xd000) == 0x8000 && 92 | (ic[0] & 0x0380) != 0x0380)); 93 | } 94 | 95 | static inline bool T$pcrel$bl(uint16_t *ic) { 96 | return (ic[0] & 0xf800) == 0xf000 && 97 | ((ic[1] & 0xd000) == 0xd000 || (ic[1] & 0xd001) == 0xc000); 98 | } 99 | 100 | static inline bool T$pcrel$ldr(uint16_t ic) { 101 | return (ic & 0xf800) == 0x4800; 102 | } 103 | 104 | static inline bool T$pcrel$add(uint16_t ic) { 105 | return (ic & 0xff78) == 0x4478; 106 | } 107 | 108 | static inline bool T$pcrel$ldrw(uint16_t ic) { 109 | return (ic & 0xff7f) == 0xf85f; 110 | } 111 | 112 | static size_t MSGetInstructionWidthThumb(void *start) { 113 | uint16_t *thumb(reinterpret_cast(start)); 114 | return T$32bit$i(thumb[0]) ? 4 : 2; 115 | } 116 | 117 | static size_t MSGetInstructionWidthARM(void *start) { 118 | return 4; 119 | } 120 | 121 | static size_t MSGetInstructionWidth(void *start) { 122 | if ((reinterpret_cast(start) & 0x1) == 0) 123 | return MSGetInstructionWidthARM(start); 124 | else 125 | return MSGetInstructionWidthThumb( 126 | reinterpret_cast(reinterpret_cast(start) & ~0x1)); 127 | } 128 | }; 129 | 130 | 131 | #endif //FAINHOOK_THUMBINSTRUCTION_H 132 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/HookHelper.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @ name unpacker 3 | * @ author xiaobaiyey 4 | * @ email xiaobaiyey@outlook.com 5 | * @ time 2018/9/5 上午10:03 6 | * @ class describe 7 | */ 8 | 9 | #include "HookHelper.h" 10 | #include "instruction/Instruction.h" 11 | #include "Helper.h" 12 | 13 | #if defined(__arm__) 14 | 15 | #include "instruction/ArmInstruction.h" 16 | #include "instruction/ThumbInstruction.h" 17 | #include "Helper.h" 18 | 19 | #elif defined(__aarch64__) 20 | #include "instruction/Arm64Instruction.h" 21 | 22 | 23 | #elif defined(__i386__) || defined(__x86_64__) 24 | #include "instruction/IntelInstruction.h" 25 | #elif defined(__mips64__) /* mips64el-* toolchain defines __mips__ too */ 26 | #include "instruction/Mips64Instruction.h" 27 | #elif defined(__mips__) 28 | #include "instruction/MipsInstruction.h" 29 | #endif 30 | 31 | static HookHelper *mIns = nullptr; 32 | 33 | HookHelper *HookHelper::getInstance() { 34 | 35 | if (mIns == nullptr) { 36 | mIns = new HookHelper(); 37 | } 38 | return mIns; 39 | } 40 | 41 | HookHelper::HookHelper() { 42 | 43 | } 44 | 45 | HookHelper::~HookHelper() { 46 | 47 | } 48 | 49 | bool HookHelper::hook(void *originalFunAddr) { 50 | auto info = getHookInfo(originalFunAddr); 51 | if (info == nullptr) { 52 | return false; 53 | } 54 | if (info->getHookStatus() == HOOKED) { 55 | return true; 56 | } else if (info->getHookStatus() != REGISTERED) { 57 | return false; 58 | } 59 | return Hook(info); 60 | } 61 | 62 | bool HookHelper::unhook(void *originalFuncAddr) { 63 | auto info = getHookInfo(originalFuncAddr); 64 | if (info == nullptr) { 65 | return false; 66 | } 67 | if (info->getHookStatus() == REGISTERED) { 68 | return true; 69 | } else if (info->getHookStatus() != HOOKED) { 70 | return false; 71 | } 72 | return UnHook(info); 73 | } 74 | 75 | void HookHelper::hookAll() { 76 | for (auto it: hook_map) { 77 | if (it.second->getHookStatus() == REGISTERED) { 78 | Hook(it.second); 79 | } 80 | } 81 | } 82 | 83 | void HookHelper::unhookAll() { 84 | for (auto it: hook_map) { 85 | if (it.second->getHookStatus() == HOOKED) { 86 | UnHook(it.second); 87 | } 88 | } 89 | } 90 | 91 | bool HookHelper::isAlreadyHooked(void *originalFunAddr) { 92 | auto it = hook_map.find(originalFunAddr); 93 | if (it == hook_map.end()) { 94 | return false; 95 | } 96 | auto info = it->second; 97 | return info->getHookStatus() == HOOKED; 98 | } 99 | 100 | void *HookHelper::getCallOriginFuncAddr(void *originalFunAddr) { 101 | auto info = getHookInfo(originalFunAddr); 102 | if (info == nullptr) { 103 | return 0; 104 | } 105 | return (void *) info->getCallOriginalIns(); 106 | } 107 | 108 | void *HookHelper::getNewFunAddr(void *originalFunAddr) { 109 | auto info = getHookInfo(originalFunAddr); 110 | if (info == nullptr) { 111 | return 0; 112 | } 113 | return (void *) info->getHookAddr(); 114 | } 115 | 116 | int HookHelper::getHookedCount() { 117 | return hook_map.size(); 118 | } 119 | 120 | HookInfo *HookHelper::getHookInfo(void *origFunAddr) { 121 | auto it = hook_map.find(origFunAddr); 122 | if (it == hook_map.end()) { 123 | return nullptr; 124 | } 125 | return it->second; 126 | } 127 | 128 | bool HookHelper::Hook(HookInfo *info) { 129 | if (!Instruction::enableJumpStub(info)) { 130 | return false; 131 | } 132 | info->setHookStatus(HOOKED); 133 | return true; 134 | } 135 | 136 | bool HookHelper::UnHook(HookInfo *info) { 137 | if (!Instruction::disableJumpStub(info)) { 138 | return false; 139 | } 140 | info->setHookStatus(REGISTERED); 141 | return true; 142 | } 143 | 144 | void HookHelper::addHookInfo(HookInfo *info) { 145 | hook_map[(void *) info->getOriginalAddr()] = info; 146 | } 147 | 148 | bool HookHelper::delHookInfo(HookInfo *info) { 149 | auto it = hook_map.find((void *) info->getOriginalAddr()); 150 | if (it != hook_map.end()) { 151 | delete it->second; 152 | hook_map.erase(it); 153 | return true; 154 | } 155 | return false; 156 | } 157 | 158 | HOOK_STATUS HookHelper::registerHook(void *orginalFunAddr, void *newFunAddr, void **callOrigin) { 159 | if (!Helper::isFunctionAddr((void *) orginalFunAddr) 160 | || !Helper::isFunctionAddr((void *) newFunAddr)) { 161 | return FERROR_NOT_EXECUTABLE; 162 | } 163 | 164 | auto info = getHookInfo(orginalFunAddr); 165 | if (nullptr != info) { 166 | auto hookStatus = info->getHookStatus(); 167 | if (HOOKED == hookStatus) { 168 | return FERROR_ALREADY_HOOKED; 169 | } else if (REGISTERED == hookStatus) { 170 | delHookInfo(info); 171 | } 172 | } 173 | 174 | // check for FunctionType 175 | auto type = Instruction::getFunctionType(orginalFunAddr); 176 | if (ERRTYPE == type) { 177 | return FERROR_UNKNOWN; 178 | } 179 | 180 | info = new HookInfo((void *) orginalFunAddr, (void *) newFunAddr); 181 | info->setOriginalFunctionType(type); 182 | 183 | Instruction *instruction = nullptr; 184 | switch (type) { 185 | #if defined(__arm__) 186 | case ARM: 187 | instruction = new ArmInstruction(); 188 | break; 189 | case THUMB: 190 | instruction = new ThumbInstruction(); 191 | break; 192 | #elif defined(__aarch64__) 193 | case ARM64: 194 | instruction = new Arm64Instruction(); 195 | break; 196 | #elif defined(__i386__) || defined(__x86_64__) 197 | case X86: 198 | case X64: 199 | instruction = new IntelInstruction(); 200 | break; 201 | #elif defined(__mips64__) 202 | case MIPS64: 203 | instruction = new Mips64Instruction(); 204 | break; 205 | #elif defined(__mips__) 206 | case MIPS: 207 | instruction = new MipsInstruction(); 208 | break; 209 | #endif 210 | default: 211 | assert(false && "not support abi"); 212 | return FERROR_UNKNOWN; 213 | break; 214 | } 215 | 216 | if (!instruction->createStub(info) 217 | || !instruction->createBackStub(info) 218 | || (callOrigin != nullptr) ? 219 | !instruction->createCallOriginalStub(info) : false // want a callback 220 | ) { 221 | delete instruction; 222 | delete info; 223 | return FERROR_MEMORY; 224 | } 225 | 226 | addHookInfo(info); 227 | info->setHookStatus(REGISTERED); 228 | 229 | if (callOrigin != nullptr) { 230 | *callOrigin = (void *) info->getCallOriginalIns(); 231 | } 232 | 233 | delete instruction; 234 | return FERROR_SUCCESS; 235 | } 236 | -------------------------------------------------------------------------------- /app/src/main/cpp/jnihook/fake_dlfcn.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 avs333 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "fake_dlfcn.h" 27 | 28 | #define TAG_NAME "test2:fake_dlfcn" 29 | 30 | #define log_info(fmt, args...) 31 | #define log_err(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG_NAME, (const char *) fmt, ##args) 32 | 33 | //#ifdef LOG_DBG 34 | #define log_dbg log_info 35 | //#else 36 | //#define log_dbg(...) 37 | //#endif 38 | 39 | #ifdef __arm__ 40 | #define Elf_Ehdr Elf32_Ehdr 41 | #define Elf_Shdr Elf32_Shdr 42 | #define Elf_Sym Elf32_Sym 43 | #elif defined(__aarch64__) 44 | #define Elf_Ehdr Elf64_Ehdr 45 | #define Elf_Shdr Elf64_Shdr 46 | #define Elf_Sym Elf64_Sym 47 | #else 48 | #error "Arch unknown, please port me" 49 | #endif 50 | 51 | struct ctx { 52 | void *load_addr; 53 | void *dynstr; 54 | void *dynsym; 55 | int nsyms; 56 | off_t bias; 57 | }; 58 | 59 | extern "C" { 60 | int fake_dlclose(void *handle) { 61 | if (handle) { 62 | struct ctx *ctx = (struct ctx *) handle; 63 | if (ctx->dynsym) free(ctx->dynsym); /* we're saving dynsym and dynstr */ 64 | if (ctx->dynstr) free(ctx->dynstr); /* from library file just in case */ 65 | free(ctx); 66 | } 67 | return 0; 68 | } 69 | 70 | /* flags are ignored */ 71 | 72 | void *fake_dlopen(const char *libpath, int flags) { 73 | FILE *maps; 74 | char buff[256]; 75 | struct ctx *ctx = 0; 76 | off_t load_addr, size; 77 | int k, fd = -1, found = 0; 78 | char *shoff; 79 | Elf_Ehdr *elf = (Elf_Ehdr *) MAP_FAILED; 80 | 81 | #define fatal(fmt, args...) do { log_err(fmt,##args); goto err_exit; } while(0) 82 | //pid_t pid = getpid(); 83 | //log_err("i got pid: %d", pid); 84 | char mapsPath[128] = {'0'}; 85 | sprintf(mapsPath, "/proc/%d/maps", getpid()); 86 | maps = fopen(mapsPath, "r"); 87 | if (!maps) fatal("failed to open maps"); 88 | while (!found && fgets(buff, sizeof(buff), maps) != nullptr) { 89 | //log_err("getmaps: %s", buff); 90 | if (/*strstr(buff, "rwxp")!=nullptr && */strstr(buff, libpath) != nullptr) { 91 | found = 1; 92 | } 93 | 94 | } 95 | 96 | 97 | fclose(maps); 98 | 99 | if (!found) fatal("%s not found in my userspace", libpath); 100 | 101 | if (sscanf(buff, "%lx", &load_addr) != 1) 102 | fatal("failed to read load address for %s", libpath); 103 | 104 | log_info("%s loaded in Android at 0x%08lx", libpath, load_addr); 105 | 106 | /* Now, mmap the same library once again */ 107 | 108 | fd = open(libpath, O_RDONLY); 109 | if (fd < 0) fatal("failed to open %s", libpath); 110 | 111 | size = lseek(fd, 0, SEEK_END); 112 | if (size <= 0) fatal("lseek() failed for %s", libpath); 113 | 114 | elf = (Elf_Ehdr *) mmap(0, size, PROT_READ, MAP_SHARED, fd, 0); 115 | close(fd); 116 | fd = -1; 117 | 118 | if (elf == MAP_FAILED) fatal("mmap() failed for %s", libpath); 119 | 120 | ctx = (struct ctx *) calloc(1, sizeof(struct ctx)); 121 | if (!ctx) fatal("no memory for %s", libpath); 122 | 123 | ctx->load_addr = (void *) load_addr; 124 | shoff = ((char *) elf) + elf->e_shoff; 125 | 126 | for (k = 0; k < elf->e_shnum; k++, shoff += elf->e_shentsize) { 127 | 128 | Elf_Shdr *sh = (Elf_Shdr *) shoff; 129 | log_dbg("%s: k=%d shdr=%p type=%x", __func__, k, sh, sh->sh_type); 130 | 131 | switch (sh->sh_type) { 132 | 133 | case SHT_DYNSYM: 134 | if (ctx->dynsym) fatal("%s: duplicate DYNSYM sections", libpath); /* .dynsym */ 135 | ctx->dynsym = malloc(sh->sh_size); 136 | if (!ctx->dynsym) fatal("%s: no memory for .dynsym", libpath); 137 | memcpy(ctx->dynsym, ((char *) elf) + sh->sh_offset, sh->sh_size); 138 | ctx->nsyms = (sh->sh_size / sizeof(Elf_Sym)); 139 | break; 140 | 141 | case SHT_STRTAB: 142 | if (ctx->dynstr) break; /* .dynstr is guaranteed to be the first STRTAB */ 143 | ctx->dynstr = malloc(sh->sh_size); 144 | if (!ctx->dynstr) fatal("%s: no memory for .dynstr", libpath); 145 | memcpy(ctx->dynstr, ((char *) elf) + sh->sh_offset, sh->sh_size); 146 | break; 147 | 148 | case SHT_PROGBITS: 149 | if (!ctx->dynstr || !ctx->dynsym) break; 150 | /* won't even bother checking against the section name */ 151 | ctx->bias = (off_t) sh->sh_addr - (off_t) sh->sh_offset; 152 | k = elf->e_shnum; /* exit for */ 153 | break; 154 | } 155 | } 156 | 157 | munmap(elf, size); 158 | elf = 0; 159 | 160 | if (!ctx->dynstr || !ctx->dynsym) fatal("dynamic sections not found in %s", libpath); 161 | 162 | #undef fatal 163 | 164 | log_dbg("%s: ok, dynsym = %p, dynstr = %p", libpath, ctx->dynsym, ctx->dynstr); 165 | 166 | return ctx; 167 | 168 | err_exit: 169 | if (fd >= 0) close(fd); 170 | if (elf != MAP_FAILED) munmap(elf, size); 171 | fake_dlclose(ctx); 172 | return 0; 173 | } 174 | 175 | void *fake_dlsym(void *handle, const char *name) { 176 | int k; 177 | struct ctx *ctx = (struct ctx *) handle; 178 | Elf_Sym *sym = (Elf_Sym *) ctx->dynsym; 179 | char *strings = (char *) ctx->dynstr; 180 | 181 | for (k = 0; k < ctx->nsyms; k++, sym++) 182 | if (strcmp(strings + sym->st_name, name) == 0) { 183 | /* NB: sym->st_value is an offset into the section for relocatables, 184 | but a VMA for shared libs or exe files, so we have to subtract the bias */ 185 | void *ret = (char *) ctx->load_addr + sym->st_value - ctx->bias; 186 | log_info("%s found at %p", name, ret); 187 | return ret; 188 | } 189 | return 0; 190 | } 191 | } -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/instruction/IntelInstruction.cpp: -------------------------------------------------------------------------------- 1 | //===------------------------------------------------------------*- C++ -*-===// 2 | // 3 | // Created by F8LEFT on 2017/6/26. 4 | // Copyright (c) 2017. All rights reserved. 5 | //===----------------------------------------------------------------------===// 6 | // 7 | //===----------------------------------------------------------------------===// 8 | 9 | 10 | #include "IntelInstruction.h" 11 | #include "IntelDisasm.h" 12 | #include "../Helper.h" 13 | 14 | bool IntelInstruction::createStub(HookInfo *info) { 15 | 16 | uintptr_t source(reinterpret_cast(info->getOriginalAddr())); 17 | uintptr_t target(reinterpret_cast(info->getHookAddr())); 18 | 19 | auto required = MSSizeOfJump(target, source); 20 | auto current = new uint8_t[required]; 21 | auto stub = current; 22 | MSWriteJump(current, source, target); 23 | 24 | info->setJumpStubLen(required); 25 | info->setJumpStubBack(stub); 26 | 27 | return true; 28 | } 29 | 30 | bool IntelInstruction::createCallOriginalStub(HookInfo *info) { 31 | 32 | uintptr_t source(reinterpret_cast(info->getOriginalAddr())); 33 | uintptr_t target(reinterpret_cast(info->getHookAddr())); 34 | 35 | uint8_t *area(reinterpret_cast(source)); 36 | 37 | size_t required(MSSizeOfJump(target, source)); 38 | 39 | 40 | size_t used(0); 41 | while (used < required) { 42 | size_t width(hde64_getInsWidth(area + used)); 43 | if (width == 0) { 44 | return false; 45 | } 46 | 47 | used += width; 48 | } 49 | 50 | size_t blank(used - required); 51 | 52 | uint8_t backup[used]; 53 | memcpy(backup, area, used); 54 | 55 | 56 | if (backup[0] == 0xe9) { // call xxxxxxx 57 | info->setCallOriginalIns(reinterpret_cast(source + 5 + 58 | *reinterpret_cast(backup + 59 | 1))); 60 | return true; 61 | } 62 | 63 | if (!ia32 && backup[0] == 0xff && backup[1] == 0x25) { // jmp xxxxxxxx 64 | info->setCallOriginalIns(*reinterpret_cast(source + 6 + 65 | *reinterpret_cast( 66 | backup + 2))); 67 | return true; 68 | } 69 | 70 | size_t length(used + MSSizeOfJump(source + used)); 71 | 72 | for (size_t offset(0), width; offset != used; offset += width) { 73 | hde64s decode; 74 | hde64_disasm(backup + offset, &decode); 75 | width = decode.len; 76 | //_assert(width != 0 && offset + width <= used); 77 | 78 | #ifdef __LP64__ 79 | if ((decode.modrm & 0xc7) == 0x05) { 80 | if (decode.opcode == 0x8b) { 81 | void *destiny(area + offset + width + int32_t(decode.disp.disp32)); 82 | uint8_t reg(decode.rex_r << 3 | decode.modrm_reg); 83 | length -= decode.len; 84 | length += MSSizeOfPushPointer(destiny); 85 | length += MSSizeOfPop(reg); 86 | length += MSSizeOfMove64(); 87 | } else { 88 | continue; 89 | } 90 | } else 91 | #endif 92 | 93 | if (backup[offset] == 0xe8) { 94 | int32_t relative(*reinterpret_cast(backup + offset + 1)); 95 | void *destiny(area + offset + decode.len + relative); 96 | 97 | if (relative == 0) { 98 | length -= decode.len; 99 | length += MSSizeOfPushPointer(destiny); 100 | } else { 101 | length += MSSizeOfSkip(); 102 | length += MSSizeOfJump(destiny); 103 | } 104 | } else if (backup[offset] == 0xeb) { 105 | length -= decode.len; 106 | length += MSSizeOfJump( 107 | area + offset + decode.len + *reinterpret_cast(backup + offset + 1)); 108 | } else if (backup[offset] == 0xe9) { 109 | length -= decode.len; 110 | length += MSSizeOfJump( 111 | area + offset + decode.len + *reinterpret_cast(backup + offset + 1)); 112 | } else if ( 113 | backup[offset] == 0xe3 || 114 | (backup[offset] & 0xf0) == 0x70 115 | // XXX: opcode2 & 0xf0 is 0x80? 116 | ) { 117 | length += decode.len; 118 | length += MSSizeOfJump( 119 | area + offset + decode.len + *reinterpret_cast(backup + offset + 1)); 120 | } 121 | } 122 | 123 | uint8_t *buffer = (uint8_t *) Helper::createExecMemory(length); 124 | if (buffer == nullptr) { 125 | return false; 126 | } 127 | 128 | uint8_t *current(buffer); 129 | 130 | for (size_t offset(0), width; offset != used; offset += width) { 131 | hde64s decode; 132 | hde64_disasm(backup + offset, &decode); 133 | width = decode.len; 134 | //_assert(width != 0 && offset + width <= used); 135 | 136 | #ifdef __LP64__ 137 | if ((decode.modrm & 0xc7) == 0x05) { 138 | if (decode.opcode == 0x8b) { 139 | void *destiny(area + offset + width + int32_t(decode.disp.disp32)); 140 | uint8_t reg(decode.rex_r << 3 | decode.modrm_reg); 141 | MSPushPointer(current, destiny); 142 | MSWritePop(current, reg); 143 | MSWriteMove64(current, reg, reg); 144 | } else { 145 | goto copy; 146 | } 147 | } else 148 | #endif 149 | 150 | if (backup[offset] == 0xe8) { 151 | int32_t relative(*reinterpret_cast(backup + offset + 1)); 152 | if (relative == 0) 153 | MSPushPointer(current, area + offset + decode.len); 154 | else { 155 | MSWrite(current, 0xe8); 156 | MSWrite(current, MSSizeOfSkip()); 157 | void *destiny(area + offset + decode.len + relative); 158 | MSWriteSkip(current, MSSizeOfJump(destiny, current + MSSizeOfSkip())); 159 | MSWriteJump(current, destiny); 160 | } 161 | } else if (backup[offset] == 0xeb) 162 | MSWriteJump(current, area + offset + decode.len + 163 | *reinterpret_cast(backup + offset + 1)); 164 | else if (backup[offset] == 0xe9) 165 | MSWriteJump(current, area + offset + decode.len + 166 | *reinterpret_cast(backup + offset + 1)); 167 | else if ( 168 | backup[offset] == 0xe3 || 169 | (backup[offset] & 0xf0) == 0x70 170 | ) { 171 | MSWrite(current, backup[offset]); 172 | MSWrite(current, 2); 173 | MSWrite(current, 0xeb); 174 | void *destiny( 175 | area + offset + decode.len + *reinterpret_cast(backup + offset + 1)); 176 | MSWrite(current, MSSizeOfJump(destiny, current + 1)); 177 | MSWriteJump(current, destiny); 178 | } else 179 | #ifdef __LP64__ 180 | copy: 181 | #endif 182 | { 183 | MSWrite(current, backup + offset, width); 184 | } 185 | } 186 | 187 | MSWriteJump(current, area + used); 188 | info->setCallOriginalIns(buffer); 189 | 190 | return true; 191 | } 192 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/instruction/IntelInstruction.h: -------------------------------------------------------------------------------- 1 | //===------------------------------------------------------------*- C++ -*-===// 2 | // 3 | // Created by F8LEFT on 2017/6/26. 4 | // Copyright (c) 2017. All rights reserved. 5 | //===----------------------------------------------------------------------===// 6 | // IntellInstruction is base on MShook. 7 | //===----------------------------------------------------------------------===// 8 | 9 | 10 | #ifndef FAINHOOK_INTELINSTRUCTION_H 11 | #define FAINHOOK_INTELINSTRUCTION_H 12 | 13 | #include 14 | #include "Instruction.h" 15 | 16 | #define _finline \ 17 | inline __attribute__((__always_inline__)) 18 | #define _disused \ 19 | __attribute__((__unused__)) 20 | #define _extern \ 21 | extern "C" __attribute__((__visibility__("default"))) 22 | 23 | class IntelInstruction : public Instruction { 24 | public: 25 | ~IntelInstruction() {} 26 | 27 | bool createStub(HookInfo *info); 28 | 29 | bool createCallOriginalStub(HookInfo *info); 30 | 31 | private: 32 | 33 | template 34 | _disused static _finline void MSWrite(uint8_t *&buffer, Type_ value) { 35 | *reinterpret_cast(buffer) = value; 36 | buffer += sizeof(Type_); 37 | } 38 | 39 | _disused static _finline void MSWrite(uint8_t *&buffer, uint8_t *data, size_t size) { 40 | memcpy(buffer, data, size); 41 | buffer += size; 42 | } 43 | 44 | #ifdef __LP64__ 45 | static const bool ia32 = false; 46 | #else 47 | static const bool ia32 = true; 48 | #endif 49 | 50 | enum I$r { 51 | I$rax, I$rcx, I$rdx, I$rbx, 52 | I$rsp, I$rbp, I$rsi, I$rdi, 53 | I$r8, I$r9, I$r10, I$r11, 54 | I$r12, I$r13, I$r14, I$r15, 55 | }; 56 | 57 | _disused static bool MSIs32BitOffset(uintptr_t target, uintptr_t source) { 58 | intptr_t offset(target - source); 59 | return int32_t(offset) == offset; 60 | } 61 | 62 | _disused static size_t MSSizeOfSkip() { 63 | return 5; 64 | } 65 | 66 | _disused static size_t MSSizeOfPushPointer(uintptr_t target) { 67 | return uint64_t(target) >> 32 == 0 ? 5 : 13; 68 | } 69 | 70 | _disused static size_t MSSizeOfPushPointer(void *target) { 71 | return MSSizeOfPushPointer(reinterpret_cast(target)); 72 | } 73 | 74 | _disused static size_t MSSizeOfJump(bool blind, uintptr_t target, uintptr_t source = 0) { 75 | if (ia32 || (!blind && MSIs32BitOffset(target, source + 5))) 76 | return MSSizeOfSkip(); 77 | else 78 | return MSSizeOfPushPointer(target) + 1; 79 | } 80 | 81 | _disused static size_t MSSizeOfJump(uintptr_t target, uintptr_t source) { 82 | return MSSizeOfJump(false, target, source); 83 | } 84 | 85 | _disused static size_t MSSizeOfJump(uintptr_t target) { 86 | return MSSizeOfJump(true, target); 87 | } 88 | 89 | _disused static size_t MSSizeOfJump(void *target, void *source) { 90 | return MSSizeOfJump(reinterpret_cast(target), 91 | reinterpret_cast(source)); 92 | } 93 | 94 | _disused static size_t MSSizeOfJump(void *target) { 95 | return MSSizeOfJump(reinterpret_cast(target)); 96 | } 97 | 98 | _disused static void MSWriteSkip(uint8_t *¤t, size_t size) { 99 | MSWrite(current, 0xe9); 100 | MSWrite(current, size); 101 | } 102 | 103 | _disused static void MSPushPointer(uint8_t *¤t, uintptr_t target) { 104 | MSWrite(current, 0x68); 105 | MSWrite(current, target); 106 | 107 | if (uint32_t high = uint64_t(target) >> 32) { 108 | MSWrite(current, 0xc7); 109 | MSWrite(current, 0x44); 110 | MSWrite(current, 0x24); 111 | MSWrite(current, 0x04); 112 | MSWrite(current, high); 113 | } 114 | } 115 | 116 | _disused static void MSPushPointer(uint8_t *¤t, void *target) { 117 | return MSPushPointer(current, reinterpret_cast(target)); 118 | } 119 | 120 | _disused static void MSWriteCall(uint8_t *¤t, I$r target) { 121 | if (target >> 3 != 0) 122 | MSWrite(current, 0x40 | (target & 0x08) >> 3); 123 | MSWrite(current, 0xff); 124 | MSWrite(current, 0xd0 | (target & 0x07)); 125 | } 126 | 127 | _disused static void MSWriteCall(uint8_t *¤t, uintptr_t target) { 128 | uintptr_t source(reinterpret_cast(current)); 129 | 130 | if (ia32 || MSIs32BitOffset(target, source + 5)) { 131 | MSWrite(current, 0xe8); 132 | MSWrite(current, target - (source + 5)); 133 | } else { 134 | MSPushPointer(current, target); 135 | 136 | MSWrite(current, 0x83); 137 | MSWrite(current, 0xc4); 138 | MSWrite(current, 0x08); 139 | 140 | MSWrite(current, 0x67); 141 | MSWrite(current, 0xff); 142 | MSWrite(current, 0x54); 143 | MSWrite(current, 0x24); 144 | MSWrite(current, 0xf8); 145 | } 146 | } 147 | 148 | template 149 | _disused static void MSWriteCall(uint8_t *¤t, Type_ *target) { 150 | return MSWriteCall(current, reinterpret_cast(target)); 151 | } 152 | 153 | _disused static void MSWriteJump(uint8_t *¤t, uintptr_t source, uintptr_t target) { 154 | 155 | if (ia32 || MSIs32BitOffset(target, source + 5)) 156 | MSWriteSkip(current, target - (source + 5)); 157 | else { 158 | MSPushPointer(current, target); 159 | MSWrite(current, 0xc3); 160 | } 161 | } 162 | 163 | _disused static void MSWriteJump(uint8_t *¤t, uintptr_t target) { 164 | uintptr_t source(reinterpret_cast(current)); 165 | 166 | if (ia32 || MSIs32BitOffset(target, source + 5)) 167 | MSWriteSkip(current, target - (source + 5)); 168 | else { 169 | MSPushPointer(current, target); 170 | MSWrite(current, 0xc3); 171 | } 172 | } 173 | 174 | _disused static void MSWriteJump(uint8_t *¤t, void *target) { 175 | return MSWriteJump(current, reinterpret_cast(target)); 176 | } 177 | 178 | _disused static void MSWriteJump(uint8_t *¤t, I$r target) { 179 | if (target >> 3 != 0) 180 | MSWrite(current, 0x40 | (target & 0x08) >> 3); 181 | MSWrite(current, 0xff); 182 | MSWrite(current, 0xe0 | (target & 0x07)); 183 | } 184 | 185 | _disused static void MSWritePop(uint8_t *¤t, uint8_t target) { 186 | if (target >> 3 != 0) 187 | MSWrite(current, 0x40 | (target & 0x08) >> 3); 188 | MSWrite(current, 0x58 | (target & 0x07)); 189 | } 190 | 191 | _disused static size_t MSSizeOfPop(uint8_t target) { 192 | return target >> 3 != 0 ? 2 : 1; 193 | } 194 | 195 | _disused static void MSWritePush(uint8_t *¤t, I$r target) { 196 | if (target >> 3 != 0) 197 | MSWrite(current, 0x40 | (target & 0x08) >> 3); 198 | MSWrite(current, 0x50 | (target & 0x07)); 199 | } 200 | 201 | _disused static void MSWriteAdd(uint8_t *¤t, I$r target, uint8_t source) { 202 | MSWrite(current, 0x83); 203 | MSWrite(current, 0xc4 | (target & 0x07)); 204 | MSWrite(current, source); 205 | } 206 | 207 | _disused static void MSWriteSet64(uint8_t *¤t, I$r target, uintptr_t source) { 208 | MSWrite(current, 0x48 | (target & 0x08) >> 3 << 2); 209 | MSWrite(current, 0xb8 | (target & 0x7)); 210 | MSWrite(current, source); 211 | } 212 | 213 | template 214 | _disused static void MSWriteSet64(uint8_t *¤t, I$r target, Type_ *source) { 215 | return MSWriteSet64(current, target, reinterpret_cast(source)); 216 | } 217 | 218 | _disused static void MSWriteMove64(uint8_t *¤t, uint8_t source, uint8_t target) { 219 | MSWrite(current, 0x48 | (target & 0x08) >> 3 << 2 | (source & 0x08) >> 3); 220 | MSWrite(current, 0x8b); 221 | MSWrite(current, (target & 0x07) << 3 | (source & 0x07)); 222 | } 223 | 224 | _disused static size_t MSSizeOfMove64() { 225 | return 3; 226 | } 227 | }; 228 | 229 | 230 | #endif //FAINHOOK_INTELINSTRUCTION_H 231 | -------------------------------------------------------------------------------- /app/src/main/cpp/jnihook/JniHook.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @ name unpacker 3 | * @ author xiaobaiyey 4 | * @ email xiaobaiyey@outlook.com 5 | * @ time 2018/10/25 1:44 PM 6 | * @ class 模块需要art 和 dalvik 两个cpp 用于获取到方法名称 7 | * 8 | */ 9 | 10 | #ifndef UNPACKER_JNIHOOK_H 11 | #define UNPACKER_JNIHOOK_H 12 | 13 | #include 14 | #include "JNIInterface.h" 15 | 16 | class JniHook { 17 | public: 18 | static JniHook *getInstance(JNIEnv *env, JNIInterface *jniInterface); 19 | 20 | void hookFindClass(); 21 | 22 | void hookFromReflectedMethod(); 23 | 24 | void hookFromReflectedField(); 25 | 26 | void hookToReflectedMethod(); 27 | 28 | void hookGetSuperclass(); 29 | 30 | void hookIsAssignableFrom(); 31 | 32 | void hookToReflectedField(); 33 | 34 | void hookThrow(); 35 | 36 | void hookThrowNew(); 37 | 38 | void hookExceptionOccurred(); 39 | 40 | void hookExceptionDescribe(); 41 | 42 | void hookExceptionClear(); 43 | 44 | void hookFatalError(); 45 | 46 | void hookPushLocalFrame(); 47 | 48 | void hookPopLocalFrame(); 49 | 50 | void hookNewGlobalRef(); 51 | 52 | void hookDeleteGlobalRef(); 53 | 54 | void hookDeleteLocalRef(); 55 | 56 | void hookIsSameObject(); 57 | 58 | void hookNewLocalRef(); 59 | 60 | void hookEnsureLocalCapacity(); 61 | 62 | void hookAllocObject(); 63 | 64 | void hookNewObject(); 65 | 66 | void hookNewObjectV(); 67 | 68 | void hookNewObjectA(); 69 | 70 | void hookGetObjectClass(); 71 | 72 | void hookIsInstanceOf(); 73 | 74 | void hookGetMethodID(); 75 | 76 | void hookCallObjectMethod(); 77 | 78 | void hookCallObjectMethodV(); 79 | 80 | void hookCallObjectMethodA(); 81 | 82 | void hookCallBooleanMethod(); 83 | 84 | void hookCallBooleanMethodV(); 85 | 86 | void hookCallBooleanMethodA(); 87 | 88 | void hookCallByteMethod(); 89 | 90 | void hookCallByteMethodV(); 91 | 92 | void hookCallByteMethodA(); 93 | 94 | void hookCallCharMethod(); 95 | 96 | void hookCallCharMethodV(); 97 | 98 | void hookCallCharMethodA(); 99 | 100 | void hookCallShortMethod(); 101 | 102 | void hookCallShortMethodV(); 103 | 104 | void hookCallShortMethodA(); 105 | 106 | void hookCallIntMethod(); 107 | 108 | void hookCallIntMethodV(); 109 | 110 | void hookCallIntMethodA(); 111 | 112 | void hookCallLongMethod(); 113 | 114 | void hookCallLongMethodV(); 115 | 116 | void hookCallLongMethodA(); 117 | 118 | void hookCallFloatMethod(); 119 | 120 | void hookCallFloatMethodV(); 121 | 122 | void hookCallFloatMethodA(); 123 | 124 | void hookCallDoubleMethod(); 125 | 126 | void hookCallDoubleMethodV(); 127 | 128 | void hookCallDoubleMethodA(); 129 | 130 | void hookCallVoidMethod(); 131 | 132 | void hookCallVoidMethodV(); 133 | 134 | void hookCallVoidMethodA(); 135 | 136 | void hookCallNonvirtualObjectMethod(); 137 | 138 | void hookCallNonvirtualObjectMethodV(); 139 | 140 | void hookCallNonvirtualObjectMethodA(); 141 | 142 | void hookCallNonvirtualBooleanMethod(); 143 | 144 | void hookCallNonvirtualBooleanMethodV(); 145 | 146 | void hookCallNonvirtualBooleanMethodA(); 147 | 148 | void hookCallNonvirtualByteMethod(); 149 | 150 | void hookCallNonvirtualByteMethodV(); 151 | 152 | void hookCallNonvirtualByteMethodA(); 153 | 154 | void hookCallNonvirtualCharMethod(); 155 | 156 | void hookCallNonvirtualCharMethodV(); 157 | 158 | void hookCallNonvirtualCharMethodA(); 159 | 160 | void hookCallNonvirtualShortMethod(); 161 | 162 | void hookCallNonvirtualShortMethodV(); 163 | 164 | void hookCallNonvirtualShortMethodA(); 165 | 166 | void hookCallNonvirtualIntMethod(); 167 | 168 | void hookCallNonvirtualIntMethodV(); 169 | 170 | void hookCallNonvirtualIntMethodA(); 171 | 172 | void hookCallNonvirtualLongMethod(); 173 | 174 | void hookCallNonvirtualLongMethodV(); 175 | 176 | void hookCallNonvirtualLongMethodA(); 177 | 178 | void hookCallNonvirtualFloatMethod(); 179 | 180 | void hookCallNonvirtualFloatMethodV(); 181 | 182 | void hookCallNonvirtualFloatMethodA(); 183 | 184 | void hookCallNonvirtualDoubleMethod(); 185 | 186 | void hookCallNonvirtualDoubleMethodV(); 187 | 188 | void hookCallNonvirtualDoubleMethodA(); 189 | 190 | void hookCallNonvirtualVoidMethod(); 191 | 192 | void hookCallNonvirtualVoidMethodV(); 193 | 194 | void hookCallNonvirtualVoidMethodA(); 195 | 196 | void hookGetFieldID(); 197 | 198 | void hookGetObjectField(); 199 | 200 | void hookGetBooleanField(); 201 | 202 | void hookGetByteField(); 203 | 204 | void hookGetCharField(); 205 | 206 | void hookGetShortField(); 207 | 208 | void hookGetIntField(); 209 | 210 | void hookGetLongField(); 211 | 212 | void hookGetFloatField(); 213 | 214 | void hookGetDoubleField(); 215 | 216 | void hookSetObjectField(); 217 | 218 | void hookSetBooleanField(); 219 | 220 | void hookSetByteField(); 221 | 222 | void hookSetCharField(); 223 | 224 | void hookSetShortField(); 225 | 226 | void hookSetIntField(); 227 | 228 | void hookSetLongField(); 229 | 230 | void hookSetFloatField(); 231 | 232 | void hookSetDoubleField(); 233 | 234 | void hookGetStaticMethodID(); 235 | 236 | void hookCallStaticObjectMethod(); 237 | 238 | void hookCallStaticObjectMethodV(); 239 | 240 | void hookCallStaticObjectMethodA(); 241 | 242 | void hookCallStaticBooleanMethod(); 243 | 244 | void hookCallStaticBooleanMethodV(); 245 | 246 | void hookCallStaticBooleanMethodA(); 247 | 248 | void hookCallStaticByteMethod(); 249 | 250 | void hookCallStaticByteMethodV(); 251 | 252 | void hookCallStaticByteMethodA(); 253 | 254 | void hookCallStaticCharMethod(); 255 | 256 | void hookCallStaticCharMethodV(); 257 | 258 | void hookCallStaticCharMethodA(); 259 | 260 | void hookCallStaticShortMethod(); 261 | 262 | void hookCallStaticShortMethodV(); 263 | 264 | void hookCallStaticShortMethodA(); 265 | 266 | void hookCallStaticIntMethod(); 267 | 268 | void hookCallStaticIntMethodV(); 269 | 270 | void hookCallStaticIntMethodA(); 271 | 272 | void hookCallStaticLongMethod(); 273 | 274 | void hookCallStaticLongMethodV(); 275 | 276 | void hookCallStaticLongMethodA(); 277 | 278 | void hookCallStaticFloatMethod(); 279 | 280 | void hookCallStaticFloatMethodV(); 281 | 282 | void hookCallStaticFloatMethodA(); 283 | 284 | void hookCallStaticDoubleMethod(); 285 | 286 | void hookCallStaticDoubleMethodV(); 287 | 288 | void hookCallStaticDoubleMethodA(); 289 | 290 | void hookCallStaticVoidMethod(); 291 | 292 | void hookCallStaticVoidMethodV(); 293 | 294 | void hookCallStaticVoidMethodA(); 295 | 296 | void hookGetStaticFieldID(); 297 | 298 | void hookGetStaticObjectField(); 299 | 300 | void hookGetStaticBooleanField(); 301 | 302 | void hookGetStaticByteField(); 303 | 304 | void hookGetStaticCharField(); 305 | 306 | void hookGetStaticShortField(); 307 | 308 | void hookGetStaticIntField(); 309 | 310 | void hookGetStaticLongField(); 311 | 312 | void hookGetStaticFloatField(); 313 | 314 | void hookGetStaticDoubleField(); 315 | 316 | void hookSetStaticObjectField(); 317 | 318 | void hookSetStaticBooleanField(); 319 | 320 | void hookSetStaticByteField(); 321 | 322 | void hookSetStaticCharField(); 323 | 324 | void hookSetStaticShortField(); 325 | 326 | void hookSetStaticIntField(); 327 | 328 | void hookSetStaticLongField(); 329 | 330 | void hookSetStaticFloatField(); 331 | 332 | void hookSetStaticDoubleField(); 333 | 334 | void hookNewString(); 335 | 336 | void hookGetStringLength(); 337 | 338 | void hookGetStringChars(); 339 | 340 | void hookReleaseStringChars(); 341 | 342 | void hookNewStringUTF(); 343 | 344 | void hookGetStringUTFLength(); 345 | 346 | void hookGetStringUTFChars(); 347 | 348 | void hookReleaseStringUTFChars(); 349 | 350 | void hookGetArrayLength(); 351 | 352 | void hookNewObjectArray(); 353 | 354 | void hookGetObjectArrayElement(); 355 | 356 | void hookSetObjectArrayElement(); 357 | 358 | void hookNewBooleanArray(); 359 | 360 | void hookNewByteArray(); 361 | 362 | void hookNewCharArray(); 363 | 364 | void hookNewShortArray(); 365 | 366 | void hookNewIntArray(); 367 | 368 | void hookNewLongArray(); 369 | 370 | void hookNewFloatArray(); 371 | 372 | void hookNewDoubleArray(); 373 | 374 | void hookGetBooleanArrayElements(); 375 | 376 | void hookGetByteArrayElements(); 377 | 378 | void hookGetCharArrayElements(); 379 | 380 | void hookGetShortArrayElements(); 381 | 382 | void hookGetIntArrayElements(); 383 | 384 | void hookGetLongArrayElements(); 385 | 386 | void hookGetFloatArrayElements(); 387 | 388 | void hookGetDoubleArrayElements(); 389 | 390 | void hookReleaseBooleanArrayElements(); 391 | 392 | void hookReleaseByteArrayElements(); 393 | 394 | void hookReleaseCharArrayElements(); 395 | 396 | void hookReleaseShortArrayElements(); 397 | 398 | void hookReleaseIntArrayElements(); 399 | 400 | void hookReleaseLongArrayElements(); 401 | 402 | void hookReleaseFloatArrayElements(); 403 | 404 | void hookReleaseDoubleArrayElements(); 405 | 406 | void hookGetBooleanArrayRegion(); 407 | 408 | void hookGetByteArrayRegion(); 409 | 410 | void hookGetCharArrayRegion(); 411 | 412 | void hookGetShortArrayRegion(); 413 | 414 | 415 | void hookGetLongArrayRegion(); 416 | 417 | void hookGetFloatArrayRegion(); 418 | 419 | void hookGetDoubleArrayRegion(); 420 | 421 | void hookSetBooleanArrayRegion(); 422 | 423 | void hookSetByteArrayRegion(); 424 | 425 | void hookSetCharArrayRegion(); 426 | 427 | void hookSetShortArrayRegion(); 428 | 429 | void hookSetIntArrayRegion(); 430 | 431 | void hookSetLongArrayRegion(); 432 | 433 | void hookSetFloatArrayRegion(); 434 | 435 | void hookSetDoubleArrayRegion(); 436 | 437 | void hookRegisterNatives(); 438 | 439 | void hookUnregisterNatives(); 440 | 441 | void hookMonitorEnter(); 442 | 443 | void hookMonitorExit(); 444 | 445 | void hookGetJavaVM(); 446 | 447 | void hookGetStringRegion(); 448 | 449 | void hookGetStringUTFRegion(); 450 | 451 | void hookGetPrimitiveArrayCritical(); 452 | 453 | void hookReleasePrimitiveArrayCritical(); 454 | 455 | void hookGetStringCritical(); 456 | 457 | void hookReleaseStringCritical(); 458 | 459 | void hookNewWeakGlobalRef(); 460 | 461 | void hookDeleteWeakGlobalRef(); 462 | 463 | void hookExceptionCheck(); 464 | 465 | void hookNewDirectByteBuffer(); 466 | 467 | void hookGetDirectBufferAddress(); 468 | 469 | void hookGetDirectBufferCapacity(); 470 | 471 | void hookGetObjectRefType(); 472 | 473 | 474 | private: 475 | JniHook(JNIEnv *env); 476 | 477 | JniHook(); 478 | 479 | /*系统版本*/ 480 | int sdk_version; 481 | 482 | 483 | private: 484 | JNIEnv *m_env; 485 | }; 486 | 487 | 488 | #endif //UNPACKER_JNIHOOK_H 489 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/instruction/ThumbInstruction.cpp: -------------------------------------------------------------------------------- 1 | //===------------------------------------------------------------*- C++ -*-===// 2 | // 3 | // Created by F8LEFT on 2017/6/19. 4 | // Copyright (c) 2017. All rights reserved. 5 | //===----------------------------------------------------------------------===// 6 | // 7 | //===----------------------------------------------------------------------===// 8 | 9 | 10 | #include 11 | #include "ThumbInstruction.h" 12 | #include "../Helper.h" 13 | 14 | 15 | bool ThumbInstruction::createStub(HookInfo *info) { 16 | auto stubSize = 0; 17 | uint8_t *stub = nullptr; 18 | 19 | uint32_t addr = (uint32_t) info->getOriginalAddr(); 20 | auto clearBit0 = addr & 0xFFFFFFFE; 21 | 22 | if (clearBit0 % 4 != 0) { // need to align 4, just patch with nop 23 | stub = new uint8_t[10]; 24 | ((uint16_t *) stub)[stubSize++] = 0xBF00; //NOP 25 | } else { 26 | stub = new uint8_t[8]; 27 | } 28 | ((uint16_t *) stub)[stubSize++] = 0xF8DF; 29 | ((uint16_t *) stub)[stubSize++] = 0xF000; // LDR.W PC, [PC] 30 | ((uint16_t *) stub)[stubSize++] = (uint32_t) info->getHookAddr() & 0xFFFF; 31 | ((uint16_t *) stub)[stubSize++] = (uint32_t) info->getHookAddr() >> 16; 32 | 33 | info->setJumpStubLen(stubSize * 2); 34 | info->setJumpStubBack(stub); 35 | return true; 36 | } 37 | 38 | bool ThumbInstruction::createCallOriginalStub(HookInfo *info) { 39 | uint16_t *area(reinterpret_cast(getOriginalAddr(info))); 40 | 41 | 42 | uint16_t *trail(reinterpret_cast( 43 | reinterpret_cast(area) + info->getJumpStubLen())); 44 | 45 | if (T$pcrel$ldrw(area[0]) && 46 | area[1] == 0xF000 47 | ) { 48 | uint32_t *arm(reinterpret_cast(area)); 49 | info->setCallOriginalIns(reinterpret_cast(arm[1])); 50 | return true; 51 | } 52 | 53 | size_t required((trail - area) * sizeof(uint16_t)); 54 | 55 | size_t used(0); 56 | while (used < required) 57 | used += MSGetInstructionWidthThumb(reinterpret_cast(area) + used); 58 | used = (used + sizeof(uint16_t) - 1) / sizeof(uint16_t) * sizeof(uint16_t); 59 | 60 | size_t blank((used - required) / sizeof(uint16_t)); 61 | 62 | uint16_t backup[used / sizeof(uint16_t)]; 63 | memcpy(backup, area, used); 64 | 65 | 66 | size_t length(used); 67 | for (unsigned offset(0); offset != used / sizeof(uint16_t); ++offset) 68 | if (T$pcrel$ldr(backup[offset])) 69 | length += 3 * sizeof(uint16_t); 70 | else if (T$pcrel$b(backup[offset])) 71 | length += 6 * sizeof(uint16_t); 72 | else if (T2$pcrel$b(backup + offset)) { 73 | length += 5 * sizeof(uint16_t); 74 | ++offset; 75 | } else if (T$pcrel$bl(backup + offset)) { 76 | length += 5 * sizeof(uint16_t); 77 | ++offset; 78 | } else if (T$pcrel$cbz(backup[offset])) { 79 | length += 16 * sizeof(uint16_t); 80 | } else if (T$pcrel$ldrw(backup[offset])) { 81 | length += 4 * sizeof(uint16_t); 82 | ++offset; 83 | } else if (T$pcrel$add(backup[offset])) 84 | length += 6 * sizeof(uint16_t); 85 | else if (T$32bit$i(backup[offset])) 86 | ++offset; 87 | 88 | unsigned pad((length & 0x2) == 0 ? 0 : 1); 89 | length += (pad + 2) * sizeof(uint16_t) + 2 * sizeof(uint32_t); 90 | 91 | uint16_t *buffer = (uint16_t *) Helper::createExecMemory(length); 92 | if (buffer == nullptr) { 93 | return false; 94 | } 95 | 96 | size_t start(pad), end(length / sizeof(uint16_t)); 97 | uint32_t *trailer(reinterpret_cast(buffer + end)); 98 | for (unsigned offset(0); offset != used / sizeof(uint16_t); ++offset) { 99 | if (T$pcrel$ldr(backup[offset])) { 100 | union { 101 | uint16_t value; 102 | 103 | struct { 104 | uint16_t immediate : 8; 105 | uint16_t rd : 3; 106 | uint16_t : 5; 107 | }; 108 | } bits = {backup[offset + 0]}; 109 | 110 | buffer[start + 0] = T$ldr_rd_$pc_im_4$(bits.rd, T$Label(start + 0, end - 2) / 4); 111 | buffer[start + 1] = T$ldr_rd_$rn_im_4$(bits.rd, bits.rd, 0); 112 | 113 | // XXX: this code "works", but is "wrong": the mechanism is more complex than this 114 | *--trailer = 115 | ((reinterpret_cast(area + offset) + 4) & ~0x2) + bits.immediate * 4; 116 | 117 | start += 2; 118 | end -= 2; 119 | } else if (T$pcrel$b(backup[offset])) { 120 | union { 121 | uint16_t value; 122 | 123 | struct { 124 | uint16_t imm8 : 8; 125 | uint16_t cond : 4; 126 | uint16_t /*1101*/ : 4; 127 | }; 128 | } bits = {backup[offset + 0]}; 129 | 130 | intptr_t jump(bits.imm8 << 1); 131 | jump |= 1; 132 | jump <<= 23; 133 | jump >>= 23; 134 | 135 | buffer[start + 0] = T$b$_$im(bits.cond, (end - 6 - (start + 0)) * 2 - 4); 136 | 137 | *--trailer = reinterpret_cast(area + offset) + 4 + jump; 138 | *--trailer = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); 139 | *--trailer = T$nop << 16 | T$bx(A$pc); 140 | 141 | start += 1; 142 | end -= 6; 143 | } else if (T2$pcrel$b(backup + offset)) { 144 | union { 145 | uint16_t value; 146 | 147 | struct { 148 | uint16_t imm6 : 6; 149 | uint16_t cond : 4; 150 | uint16_t s : 1; 151 | uint16_t : 5; 152 | }; 153 | } bits = {backup[offset + 0]}; 154 | 155 | union { 156 | uint16_t value; 157 | 158 | struct { 159 | uint16_t imm11 : 11; 160 | uint16_t j2 : 1; 161 | uint16_t a : 1; 162 | uint16_t j1 : 1; 163 | uint16_t : 2; 164 | }; 165 | } exts = {backup[offset + 1]}; 166 | 167 | intptr_t jump(1); 168 | jump |= exts.imm11 << 1; 169 | jump |= bits.imm6 << 12; 170 | 171 | if (exts.a) { 172 | jump |= bits.s << 24; 173 | jump |= (~(bits.s ^ exts.j1) & 0x1) << 23; 174 | jump |= (~(bits.s ^ exts.j2) & 0x1) << 22; 175 | jump |= bits.cond << 18; 176 | jump <<= 7; 177 | jump >>= 7; 178 | } else { 179 | jump |= bits.s << 20; 180 | jump |= exts.j2 << 19; 181 | jump |= exts.j1 << 18; 182 | jump <<= 11; 183 | jump >>= 11; 184 | } 185 | 186 | buffer[start + 0] = T$b$_$im(exts.a ? A$al : bits.cond, 187 | (end - 6 - (start + 0)) * 2 - 4); 188 | 189 | *--trailer = reinterpret_cast(area + offset) + 4 + jump; 190 | *--trailer = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); 191 | *--trailer = T$nop << 16 | T$bx(A$pc); 192 | 193 | ++offset; 194 | start += 1; 195 | end -= 6; 196 | } else if (T$pcrel$bl(backup + offset)) { 197 | union { 198 | uint16_t value; 199 | 200 | struct { 201 | uint16_t immediate : 10; 202 | uint16_t s : 1; 203 | uint16_t : 5; 204 | }; 205 | } bits = {backup[offset + 0]}; 206 | 207 | union { 208 | uint16_t value; 209 | 210 | struct { 211 | uint16_t immediate : 11; 212 | uint16_t j2 : 1; 213 | uint16_t x : 1; 214 | uint16_t j1 : 1; 215 | uint16_t : 2; 216 | }; 217 | } exts = {backup[offset + 1]}; 218 | 219 | int32_t jump(0); 220 | jump |= bits.s << 24; 221 | jump |= (~(bits.s ^ exts.j1) & 0x1) << 23; 222 | jump |= (~(bits.s ^ exts.j2) & 0x1) << 22; 223 | jump |= bits.immediate << 12; 224 | jump |= exts.immediate << 1; 225 | jump |= exts.x; 226 | jump <<= 7; 227 | jump >>= 7; 228 | 229 | buffer[start + 0] = T$push_r(1 << A$r7); 230 | buffer[start + 1] = T$ldr_rd_$pc_im_4$(A$r7, ((end - 2 - (start + 1)) * 2 - 4 + 2) / 4); 231 | buffer[start + 2] = T$mov_rd_rm(A$lr, A$r7); 232 | buffer[start + 3] = T$pop_r(1 << A$r7); 233 | buffer[start + 4] = T$blx(A$lr); 234 | 235 | *--trailer = reinterpret_cast(area + offset) + 4 + jump; 236 | 237 | ++offset; 238 | start += 5; 239 | end -= 2; 240 | } else if (T$pcrel$cbz(backup[offset])) { 241 | union { 242 | uint16_t value; 243 | 244 | struct { 245 | uint16_t rn : 3; 246 | uint16_t immediate : 5; 247 | uint16_t : 1; 248 | uint16_t i : 1; 249 | uint16_t : 1; 250 | uint16_t op : 1; 251 | uint16_t : 4; 252 | }; 253 | } bits = {backup[offset + 0]}; 254 | 255 | intptr_t jump(1); 256 | jump |= bits.i << 6; 257 | jump |= bits.immediate << 1; 258 | 259 | //jump <<= 24; 260 | //jump >>= 24; 261 | 262 | unsigned rn(bits.rn); 263 | unsigned rt(rn == A$r7 ? A$r6 : A$r7); 264 | 265 | buffer[start + 0] = T$push_r(1 << rt); 266 | buffer[start + 1] = T1$mrs_rd_apsr(rt); 267 | buffer[start + 2] = T2$mrs_rd_apsr(rt); 268 | buffer[start + 3] = T$cbz$_rn_$im(bits.op, rn, (end - 10 - (start + 3)) * 2 - 4); 269 | buffer[start + 4] = T1$msr_apsr_nzcvqg_rn(rt); 270 | buffer[start + 5] = T2$msr_apsr_nzcvqg_rn(rt); 271 | buffer[start + 6] = T$pop_r(1 << rt); 272 | 273 | *--trailer = reinterpret_cast(area + offset) + 4 + jump; 274 | *--trailer = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); 275 | *--trailer = T$nop << 16 | T$bx(A$pc); 276 | *--trailer = T$nop << 16 | T$pop_r(1 << rt); 277 | *--trailer = T$msr_apsr_nzcvqg_rn(rt); 278 | 279 | #if 0 280 | if ((start & 0x1) == 0) 281 | buffer[start++] = T$nop; 282 | buffer[start++] = T$bx(A$pc); 283 | buffer[start++] = T$nop; 284 | 285 | uint32_t *arm(reinterpret_cast(buffer + start)); 286 | arm[0] = A$add(A$lr, A$pc, 1); 287 | arm[1] = A$ldr_rd_$rn_im$(A$pc, A$pc, (trailer - arm) * sizeof(uint32_t) - 8); 288 | #endif 289 | 290 | start += 7; 291 | end -= 10; 292 | } else if (T$pcrel$ldrw(backup[offset])) { 293 | union { 294 | uint16_t value; 295 | 296 | struct { 297 | uint16_t : 7; 298 | uint16_t u : 1; 299 | uint16_t : 8; 300 | }; 301 | } bits = {backup[offset + 0]}; 302 | 303 | union { 304 | uint16_t value; 305 | 306 | struct { 307 | uint16_t immediate : 12; 308 | uint16_t rt : 4; 309 | }; 310 | } exts = {backup[offset + 1]}; 311 | 312 | buffer[start + 0] = T1$ldr_rt_$rn_im$(exts.rt, A$pc, T$Label(start + 0, end - 2)); 313 | buffer[start + 1] = T2$ldr_rt_$rn_im$(exts.rt, A$pc, T$Label(start + 0, end - 2)); 314 | 315 | buffer[start + 2] = T1$ldr_rt_$rn_im$(exts.rt, exts.rt, 0); 316 | buffer[start + 3] = T2$ldr_rt_$rn_im$(exts.rt, exts.rt, 0); 317 | 318 | // XXX: this code "works", but is "wrong": the mechanism is more complex than this 319 | *--trailer = ((reinterpret_cast(area + offset) + 4) & ~0x2) + 320 | (bits.u == 0 ? -exts.immediate : exts.immediate); 321 | 322 | ++offset; 323 | start += 4; 324 | end -= 2; 325 | } else if (T$pcrel$add(backup[offset])) { 326 | union { 327 | uint16_t value; 328 | 329 | struct { 330 | uint16_t rd : 3; 331 | uint16_t rm : 3; 332 | uint16_t h2 : 1; 333 | uint16_t h1 : 1; 334 | uint16_t : 8; 335 | }; 336 | } bits = {backup[offset + 0]}; 337 | 338 | if (bits.h1) { 339 | return false; 340 | } 341 | 342 | unsigned rt(bits.rd == A$r7 ? A$r6 : A$r7); 343 | 344 | buffer[start + 0] = T$push_r(1 << rt); 345 | buffer[start + 1] = T$mov_rd_rm(rt, (bits.h1 << 3) | bits.rd); 346 | buffer[start + 2] = T$ldr_rd_$pc_im_4$(bits.rd, T$Label(start + 2, end - 2) / 4); 347 | buffer[start + 3] = T$add_rd_rm((bits.h1 << 3) | bits.rd, rt); 348 | buffer[start + 4] = T$pop_r(1 << rt); 349 | *--trailer = reinterpret_cast(area + offset) + 4; 350 | 351 | start += 5; 352 | end -= 2; 353 | } else if (T$32bit$i(backup[offset])) { 354 | buffer[start++] = backup[offset]; 355 | buffer[start++] = backup[++offset]; 356 | } else { 357 | buffer[start++] = backup[offset]; 358 | } 359 | } 360 | 361 | buffer[start++] = T$bx(A$pc); 362 | buffer[start++] = T$nop; 363 | 364 | uint32_t *transfer = reinterpret_cast(buffer + start); 365 | transfer[0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); 366 | transfer[1] = reinterpret_cast(area + used / sizeof(uint16_t)) + 1; 367 | 368 | info->setCallOriginalIns(reinterpret_cast(buffer + pad) + 1); 369 | 370 | return true; 371 | } 372 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/instruction/IntelDisasm.cpp: -------------------------------------------------------------------------------- 1 | //===------------------------------------------------------------*- C++ -*-===// 2 | // 3 | // Created by F8LEFT on 2017/6/23. 4 | // Copyright (c) 2017. All rights reserved. 5 | //===----------------------------------------------------------------------===// 6 | // 7 | //===----------------------------------------------------------------------===// 8 | 9 | 10 | #include 11 | #include "IntelDisasm.h" 12 | 13 | 14 | unsigned char hde64_table[] = { 15 | 0xa5, 0xaa, 0xa5, 0xb8, 0xa5, 0xaa, 0xa5, 0xaa, 0xa5, 0xb8, 0xa5, 0xb8, 0xa5, 0xb8, 0xa5, 16 | 0xb8, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xac, 0xc0, 0xcc, 0xc0, 0xa1, 0xa1, 17 | 0xa1, 0xa1, 0xb1, 0xa5, 0xa5, 0xa6, 0xc0, 0xc0, 0xd7, 0xda, 0xe0, 0xc0, 0xe4, 0xc0, 0xea, 18 | 0xea, 0xe0, 0xe0, 0x98, 0xc8, 0xee, 0xf1, 0xa5, 0xd3, 0xa5, 0xa5, 0xa1, 0xea, 0x9e, 0xc0, 19 | 0xc0, 0xc2, 0xc0, 0xe6, 0x03, 0x7f, 0x11, 0x7f, 0x01, 0x7f, 0x01, 0x3f, 0x01, 0x01, 0xab, 20 | 0x8b, 0x90, 0x64, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x92, 0x5b, 0x5b, 0x76, 0x90, 0x92, 0x92, 21 | 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x6a, 0x73, 0x90, 22 | 0x5b, 0x52, 0x52, 0x52, 0x52, 0x5b, 0x5b, 0x5b, 0x5b, 0x77, 0x7c, 0x77, 0x85, 0x5b, 0x5b, 23 | 0x70, 0x5b, 0x7a, 0xaf, 0x76, 0x76, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 24 | 0x5b, 0x5b, 0x86, 0x01, 0x03, 0x01, 0x04, 0x03, 0xd5, 0x03, 0xd5, 0x03, 0xcc, 0x01, 0xbc, 25 | 0x03, 0xf0, 0x03, 0x03, 0x04, 0x00, 0x50, 0x50, 0x50, 0x50, 0xff, 0x20, 0x20, 0x20, 0x20, 26 | 0x01, 0x01, 0x01, 0x01, 0xc4, 0x02, 0x10, 0xff, 0xff, 0xff, 0x01, 0x00, 0x03, 0x11, 0xff, 27 | 0x03, 0xc4, 0xc6, 0xc8, 0x02, 0x10, 0x00, 0xff, 0xcc, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 28 | 0x00, 0x01, 0x01, 0x03, 0x01, 0xff, 0xff, 0xc0, 0xc2, 0x10, 0x11, 0x02, 0x03, 0x01, 0x01, 29 | 0x01, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x10, 30 | 0x10, 0x10, 0x10, 0x02, 0x10, 0x00, 0x00, 0xc6, 0xc8, 0x02, 0x02, 0x02, 0x02, 0x06, 0x00, 31 | 0x04, 0x00, 0x02, 0xff, 0x00, 0xc0, 0xc2, 0x01, 0x01, 0x03, 0x03, 0x03, 0xca, 0x40, 0x00, 32 | 0x0a, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00, 33 | 0x00, 0x00, 0xff, 0xbf, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0xff, 0x00, 34 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 35 | 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 36 | 0xff, 0x40, 0x40, 0x40, 0x40, 0x41, 0x49, 0x40, 0x40, 0x40, 0x40, 0x4c, 0x42, 0x40, 0x40, 37 | 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4f, 0x44, 0x53, 0x40, 0x40, 0x40, 0x44, 0x57, 0x43, 38 | 0x5c, 0x40, 0x60, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 39 | 0x40, 0x40, 0x64, 0x66, 0x6e, 0x6b, 0x40, 0x40, 0x6a, 0x46, 0x40, 0x40, 0x44, 0x46, 0x40, 40 | 0x40, 0x5b, 0x44, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x01, 0x06, 41 | 0x06, 0x02, 0x06, 0x06, 0x00, 0x06, 0x00, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x07, 0x07, 42 | 0x06, 0x02, 0x0d, 0x06, 0x06, 0x06, 0x0e, 0x05, 0x05, 0x02, 0x02, 0x00, 0x00, 0x04, 0x04, 43 | 0x04, 0x04, 0x05, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x08, 0x00, 0x10, 44 | 0x00, 0x18, 0x00, 0x20, 0x00, 0x28, 0x00, 0x30, 0x00, 0x80, 0x01, 0x82, 0x01, 0x86, 0x00, 45 | 0xf6, 0xcf, 0xfe, 0x3f, 0xab, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xba, 0xf8, 0xbb, 46 | 0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc7, 0xbf, 0x62, 0xff, 0x00, 0x8d, 0xff, 0x00, 0xc4, 0xff, 47 | 0x00, 0xc5, 0xff, 0x00, 0xff, 0xff, 0xeb, 0x01, 0xff, 0x0e, 0x12, 0x08, 0x00, 0x13, 0x09, 48 | 0x00, 0x16, 0x08, 0x00, 0x17, 0x09, 0x00, 0x2b, 0x09, 0x00, 0xae, 0xff, 0x07, 0xb2, 0xff, 49 | 0x00, 0xb4, 0xff, 0x00, 0xb5, 0xff, 0x00, 0xc3, 0x01, 0x00, 0xc7, 0xff, 0xbf, 0xe7, 0x08, 50 | 0x00, 0xf0, 0x02, 0x00 51 | }; 52 | 53 | /* 54 | * Hacker Disassembler Engine 64 C 55 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 56 | * All rights reserved. 57 | * 58 | */ 59 | unsigned int hde64_disasm(const void *code, hde64s *hs) { 60 | uint8_t x, c, *p = (uint8_t *) code, cflags, opcode, pref = 0; 61 | uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0; 62 | uint8_t op64 = 0; 63 | 64 | memset(hs, 0, sizeof(hde64s)); 65 | 66 | for (x = 16; x; x--) 67 | switch (c = *p++) { 68 | case 0xf3: 69 | hs->p_rep = c; 70 | pref |= PRE_F3; 71 | break; 72 | case 0xf2: 73 | hs->p_rep = c; 74 | pref |= PRE_F2; 75 | break; 76 | case 0xf0: 77 | hs->p_lock = c; 78 | pref |= PRE_LOCK; 79 | break; 80 | case 0x26: 81 | case 0x2e: 82 | case 0x36: 83 | case 0x3e: 84 | case 0x64: 85 | case 0x65: 86 | hs->p_seg = c; 87 | pref |= PRE_SEG; 88 | break; 89 | case 0x66: 90 | hs->p_66 = c; 91 | pref |= PRE_66; 92 | break; 93 | case 0x67: 94 | hs->p_67 = c; 95 | pref |= PRE_67; 96 | break; 97 | default: 98 | goto pref_done; 99 | } 100 | pref_done: 101 | 102 | hs->flags = (uint32_t) pref << 23; 103 | 104 | if (!pref) 105 | pref |= PRE_NONE; 106 | 107 | if ((c & 0xf0) == 0x40) { 108 | hs->flags |= F_PREFIX_REX; 109 | if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8) 110 | op64++; 111 | hs->rex_r = (c & 7) >> 2; 112 | hs->rex_x = (c & 3) >> 1; 113 | hs->rex_b = c & 1; 114 | if (((c = *p++) & 0xf0) == 0x40) { 115 | opcode = c; 116 | goto error_opcode; 117 | } 118 | } 119 | 120 | if ((hs->opcode = c) == 0x0f) { 121 | hs->opcode2 = c = *p++; 122 | ht += DELTA_OPCODES; 123 | } else if (c >= 0xa0 && c <= 0xa3) { 124 | op64++; 125 | if (pref & PRE_67) 126 | pref |= PRE_66; 127 | else 128 | pref &= ~PRE_66; 129 | } 130 | 131 | opcode = c; 132 | cflags = ht[ht[opcode / 4] + (opcode % 4)]; 133 | 134 | if (cflags == C_ERROR) { 135 | error_opcode: 136 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 137 | cflags = 0; 138 | if ((opcode & -3) == 0x24) 139 | cflags++; 140 | } 141 | 142 | x = 0; 143 | if (cflags & C_GROUP) { 144 | uint16_t t; 145 | t = *(uint16_t *) (ht + (cflags & 0x7f)); 146 | cflags = (uint8_t) t; 147 | x = (uint8_t) (t >> 8); 148 | } 149 | 150 | if (hs->opcode2) { 151 | ht = hde64_table + DELTA_PREFIXES; 152 | if (ht[ht[opcode / 4] + (opcode % 4)] & pref) 153 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 154 | } 155 | 156 | if (cflags & C_MODRM) { 157 | hs->flags |= F_MODRM; 158 | hs->modrm = c = *p++; 159 | hs->modrm_mod = m_mod = c >> 6; 160 | hs->modrm_rm = m_rm = c & 7; 161 | hs->modrm_reg = m_reg = (c & 0x3f) >> 3; 162 | 163 | if (x && ((x << m_reg) & 0x80)) 164 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 165 | 166 | if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { 167 | uint8_t t = opcode - 0xd9; 168 | if (m_mod == 3) { 169 | ht = hde64_table + DELTA_FPU_MODRM + t * 8; 170 | t = ht[m_reg] << m_rm; 171 | } else { 172 | ht = hde64_table + DELTA_FPU_REG; 173 | t = ht[t] << m_reg; 174 | } 175 | if (t & 0x80) 176 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 177 | } 178 | 179 | if (pref & PRE_LOCK) { 180 | if (m_mod == 3) { 181 | hs->flags |= F_ERROR | F_ERROR_LOCK; 182 | } else { 183 | uint8_t *table_end, op = opcode; 184 | if (hs->opcode2) { 185 | ht = hde64_table + DELTA_OP2_LOCK_OK; 186 | table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; 187 | } else { 188 | ht = hde64_table + DELTA_OP_LOCK_OK; 189 | table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; 190 | op &= -2; 191 | } 192 | for (; ht != table_end; ht++) 193 | if (*ht++ == op) { 194 | if (!((*ht << m_reg) & 0x80)) 195 | goto no_lock_error; 196 | else 197 | break; 198 | } 199 | hs->flags |= F_ERROR | F_ERROR_LOCK; 200 | no_lock_error:; 201 | } 202 | } 203 | 204 | if (hs->opcode2) { 205 | switch (opcode) { 206 | case 0x20: 207 | case 0x22: 208 | m_mod = 3; 209 | if (m_reg > 4 || m_reg == 1) 210 | goto error_operand; 211 | else 212 | goto no_error_operand; 213 | case 0x21: 214 | case 0x23: 215 | m_mod = 3; 216 | if (m_reg == 4 || m_reg == 5) 217 | goto error_operand; 218 | else 219 | goto no_error_operand; 220 | } 221 | } else { 222 | switch (opcode) { 223 | case 0x8c: 224 | if (m_reg > 5) 225 | goto error_operand; 226 | else 227 | goto no_error_operand; 228 | case 0x8e: 229 | if (m_reg == 1 || m_reg > 5) 230 | goto error_operand; 231 | else 232 | goto no_error_operand; 233 | } 234 | } 235 | 236 | if (m_mod == 3) { 237 | uint8_t *table_end; 238 | if (hs->opcode2) { 239 | ht = hde64_table + DELTA_OP2_ONLY_MEM; 240 | table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM; 241 | } else { 242 | ht = hde64_table + DELTA_OP_ONLY_MEM; 243 | table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; 244 | } 245 | for (; ht != table_end; ht += 2) 246 | if (*ht++ == opcode) { 247 | if (*ht++ & pref && !((*ht << m_reg) & 0x80)) 248 | goto error_operand; 249 | else 250 | break; 251 | } 252 | goto no_error_operand; 253 | } else if (hs->opcode2) { 254 | switch (opcode) { 255 | case 0x50: 256 | case 0xd7: 257 | case 0xf7: 258 | if (pref & (PRE_NONE | PRE_66)) 259 | goto error_operand; 260 | break; 261 | case 0xd6: 262 | if (pref & (PRE_F2 | PRE_F3)) 263 | goto error_operand; 264 | break; 265 | case 0xc5: 266 | goto error_operand; 267 | } 268 | goto no_error_operand; 269 | } else 270 | goto no_error_operand; 271 | 272 | error_operand: 273 | hs->flags |= F_ERROR | F_ERROR_OPERAND; 274 | no_error_operand: 275 | 276 | c = *p++; 277 | if (m_reg <= 1) { 278 | if (opcode == 0xf6) 279 | cflags |= C_IMM8; 280 | else if (opcode == 0xf7) 281 | cflags |= C_IMM_P66; 282 | } 283 | 284 | switch (m_mod) { 285 | case 0: 286 | if (pref & PRE_67) { 287 | if (m_rm == 6) 288 | disp_size = 2; 289 | } else if (m_rm == 5) 290 | disp_size = 4; 291 | break; 292 | case 1: 293 | disp_size = 1; 294 | break; 295 | case 2: 296 | disp_size = 2; 297 | if (!(pref & PRE_67)) 298 | disp_size <<= 1; 299 | } 300 | 301 | if (m_mod != 3 && m_rm == 4) { 302 | hs->flags |= F_SIB; 303 | p++; 304 | hs->sib = c; 305 | hs->sib_scale = c >> 6; 306 | hs->sib_index = (c & 0x3f) >> 3; 307 | if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) 308 | disp_size = 4; 309 | } 310 | 311 | p--; 312 | switch (disp_size) { 313 | case 1: 314 | hs->flags |= F_DISP8; 315 | hs->disp.disp8 = *p; 316 | break; 317 | case 2: 318 | hs->flags |= F_DISP16; 319 | hs->disp.disp16 = *(uint16_t *) p; 320 | break; 321 | case 4: 322 | hs->flags |= F_DISP32; 323 | hs->disp.disp32 = *(uint32_t *) p; 324 | } 325 | p += disp_size; 326 | } else if (pref & PRE_LOCK) 327 | hs->flags |= F_ERROR | F_ERROR_LOCK; 328 | 329 | if (cflags & C_IMM_P66) { 330 | if (cflags & C_REL32) { 331 | if (pref & PRE_66) { 332 | hs->flags |= F_IMM16 | F_RELATIVE; 333 | hs->imm.imm16 = *(uint16_t *) p; 334 | p += 2; 335 | goto disasm_done; 336 | } 337 | goto rel32_ok; 338 | } 339 | if (op64) { 340 | hs->flags |= F_IMM64; 341 | hs->imm.imm64 = *(uint64_t *) p; 342 | p += 8; 343 | } else if (!(pref & PRE_66)) { 344 | hs->flags |= F_IMM32; 345 | hs->imm.imm32 = *(uint32_t *) p; 346 | p += 4; 347 | } else 348 | goto imm16_ok; 349 | } 350 | 351 | 352 | if (cflags & C_IMM16) { 353 | imm16_ok: 354 | hs->flags |= F_IMM16; 355 | hs->imm.imm16 = *(uint16_t *) p; 356 | p += 2; 357 | } 358 | if (cflags & C_IMM8) { 359 | hs->flags |= F_IMM8; 360 | hs->imm.imm8 = *p++; 361 | } 362 | 363 | if (cflags & C_REL32) { 364 | rel32_ok: 365 | hs->flags |= F_IMM32 | F_RELATIVE; 366 | hs->imm.imm32 = *(uint32_t *) p; 367 | p += 4; 368 | } else if (cflags & C_REL8) { 369 | hs->flags |= F_IMM8 | F_RELATIVE; 370 | hs->imm.imm8 = *p++; 371 | } 372 | 373 | disasm_done: 374 | 375 | if ((hs->len = (uint8_t) (p - (uint8_t *) code)) > 15) { 376 | hs->flags |= F_ERROR | F_ERROR_LENGTH; 377 | hs->len = 15; 378 | } 379 | 380 | return (unsigned int) hs->len; 381 | } 382 | 383 | size_t hde64_getInsWidth(void *start) { 384 | hde64s decode; 385 | return hde64_disasm(start, &decode); 386 | } 387 | 388 | 389 | -------------------------------------------------------------------------------- /app/src/main/cpp/jnihook/JNIInterface.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @ name unpacker 3 | * @ author xiaobaiyey 4 | * @ email xiaobaiyey@outlook.com 5 | * @ time 2018/10/26 11:29 AM 6 | * @ class describe 7 | */ 8 | 9 | #ifndef UNPACKER_JNIINTERFACE_H 10 | #define UNPACKER_JNIINTERFACE_H 11 | 12 | #include 13 | #include 14 | 15 | class JNIInterface { 16 | public: 17 | virtual void FindClass(JNIEnv *, const char *) {}; 18 | 19 | virtual void FromReflectedMethod(JNIEnv *, jobject) {}; 20 | 21 | virtual void FromReflectedField(JNIEnv *, jobject) {}; 22 | 23 | virtual void ToReflectedMethod(JNIEnv *, jclass, jmethodID, jboolean) {}; 24 | 25 | virtual void GetSuperclass(JNIEnv *, jclass) {}; 26 | 27 | virtual void IsAssignableFrom(JNIEnv *, jclass, jclass) {}; 28 | 29 | virtual void ToReflectedField(JNIEnv *, jclass, jfieldID, jboolean) {}; 30 | 31 | virtual void Throw(JNIEnv *, jthrowable) {}; 32 | 33 | virtual void ThrowNew(JNIEnv *, jclass, const char *) {}; 34 | 35 | virtual void ExceptionOccurred(JNIEnv *) {}; 36 | 37 | virtual void ExceptionDescribe(JNIEnv *) {}; 38 | 39 | virtual void ExceptionClear(JNIEnv *) {}; 40 | 41 | virtual void FatalError(JNIEnv *, const char *) {}; 42 | 43 | virtual void PushLocalFrame(JNIEnv *, jint) {}; 44 | 45 | virtual void PopLocalFrame(JNIEnv *, jobject) {}; 46 | 47 | virtual void NewGlobalRef(JNIEnv *, jobject) {}; 48 | 49 | virtual void DeleteGlobalRef(JNIEnv *, jobject) {}; 50 | 51 | virtual void DeleteLocalRef(JNIEnv *, jobject) {}; 52 | 53 | virtual void IsSameObject(JNIEnv *, jobject, jobject) {}; 54 | 55 | virtual void NewLocalRef(JNIEnv *, jobject) {}; 56 | 57 | virtual void EnsureLocalCapacity(JNIEnv *, jint) {}; 58 | 59 | virtual void AllocObject(JNIEnv *, jclass) {}; 60 | 61 | virtual void NewObject(JNIEnv *, jclass, jmethodID, ...) {}; 62 | 63 | virtual void NewObjectV(JNIEnv *, jclass, jmethodID, va_list) {}; 64 | 65 | virtual void NewObjectA(JNIEnv *, jclass, jmethodID, jvalue *) {}; 66 | 67 | virtual void GetObjectClass(JNIEnv *, jobject) {}; 68 | 69 | virtual void IsInstanceOf(JNIEnv *, jobject, jclass) {}; 70 | 71 | virtual void GetMethodID(JNIEnv *, jclass, const char *, const char *) {}; 72 | 73 | virtual void CallObjectMethod(JNIEnv *, jobject, jmethodID, ...) {}; 74 | 75 | virtual void CallObjectMethodV(JNIEnv *, jobject, jmethodID, va_list) {}; 76 | 77 | virtual void CallObjectMethodA(JNIEnv *, jobject, jmethodID, jvalue *) {}; 78 | 79 | virtual void CallBooleanMethod(JNIEnv *, jobject, jmethodID, ...) {}; 80 | 81 | virtual void CallBooleanMethodV(JNIEnv *, jobject, jmethodID, va_list) {}; 82 | 83 | virtual void CallBooleanMethodA(JNIEnv *, jobject, jmethodID, jvalue *) {}; 84 | 85 | virtual void CallByteMethod(JNIEnv *, jobject, jmethodID, ...) {}; 86 | 87 | virtual void CallByteMethodV(JNIEnv *, jobject, jmethodID, va_list) {}; 88 | 89 | virtual void CallByteMethodA(JNIEnv *, jobject, jmethodID, jvalue *) {}; 90 | 91 | virtual void CallCharMethod(JNIEnv *, jobject, jmethodID, ...) {}; 92 | 93 | virtual void CallCharMethodV(JNIEnv *, jobject, jmethodID, va_list) {}; 94 | 95 | virtual void CallCharMethodA(JNIEnv *, jobject, jmethodID, jvalue *) {}; 96 | 97 | virtual void CallShortMethod(JNIEnv *, jobject, jmethodID, ...) {}; 98 | 99 | virtual void CallShortMethodV(JNIEnv *, jobject, jmethodID, va_list) {}; 100 | 101 | virtual void CallShortMethodA(JNIEnv *, jobject, jmethodID, jvalue *) {}; 102 | 103 | virtual void CallIntMethod(JNIEnv *, jobject, jmethodID, ...) {}; 104 | 105 | virtual void CallIntMethodV(JNIEnv *, jobject, jmethodID, va_list) {}; 106 | 107 | virtual void CallIntMethodA(JNIEnv *, jobject, jmethodID, jvalue *) {}; 108 | 109 | virtual void CallLongMethod(JNIEnv *, jobject, jmethodID, ...) {}; 110 | 111 | virtual void CallLongMethodV(JNIEnv *, jobject, jmethodID, va_list) {}; 112 | 113 | virtual void CallLongMethodA(JNIEnv *, jobject, jmethodID, jvalue *) {}; 114 | 115 | virtual void CallFloatMethod(JNIEnv *, jobject, jmethodID, ...) {}; 116 | 117 | virtual void CallFloatMethodV(JNIEnv *, jobject, jmethodID, va_list) {}; 118 | 119 | virtual void CallFloatMethodA(JNIEnv *, jobject, jmethodID, jvalue *) {}; 120 | 121 | virtual void CallDoubleMethod(JNIEnv *, jobject, jmethodID, ...) {}; 122 | 123 | virtual void CallDoubleMethodV(JNIEnv *, jobject, jmethodID, va_list) {}; 124 | 125 | virtual void CallDoubleMethodA(JNIEnv *, jobject, jmethodID, jvalue *) {}; 126 | 127 | virtual void CallVoidMethod(JNIEnv *, jobject, jmethodID, ...) {}; 128 | 129 | virtual void CallVoidMethodV(JNIEnv *, jobject, jmethodID, va_list) {}; 130 | 131 | virtual void CallVoidMethodA(JNIEnv *, jobject, jmethodID, jvalue *) {}; 132 | 133 | virtual void CallNonvirtualObjectMethod(JNIEnv *, jobject, jclass, jmethodID, ...) {}; 134 | 135 | virtual void CallNonvirtualObjectMethodV(JNIEnv *, jobject, jclass, jmethodID, va_list) {}; 136 | 137 | virtual void CallNonvirtualObjectMethodA(JNIEnv *, jobject, jclass, jmethodID, jvalue *) {}; 138 | 139 | virtual void CallNonvirtualBooleanMethod(JNIEnv *, jobject, jclass, jmethodID, ...) {}; 140 | 141 | virtual void CallNonvirtualBooleanMethodV(JNIEnv *, jobject, jclass, jmethodID, va_list) {}; 142 | 143 | virtual void CallNonvirtualBooleanMethodA(JNIEnv *, jobject, jclass, jmethodID, jvalue *) {}; 144 | 145 | virtual void CallNonvirtualByteMethod(JNIEnv *, jobject, jclass, jmethodID, ...) {}; 146 | 147 | virtual void CallNonvirtualByteMethodV(JNIEnv *, jobject, jclass, jmethodID, va_list) {}; 148 | 149 | virtual void CallNonvirtualByteMethodA(JNIEnv *, jobject, jclass, jmethodID, jvalue *) {}; 150 | 151 | virtual void CallNonvirtualCharMethod(JNIEnv *, jobject, jclass, jmethodID, ...) {}; 152 | 153 | virtual void CallNonvirtualCharMethodV(JNIEnv *, jobject, jclass, jmethodID, va_list) {}; 154 | 155 | virtual void CallNonvirtualCharMethodA(JNIEnv *, jobject, jclass, jmethodID, jvalue *) {}; 156 | 157 | virtual void CallNonvirtualShortMethod(JNIEnv *, jobject, jclass, jmethodID, ...) {}; 158 | 159 | virtual void CallNonvirtualShortMethodV(JNIEnv *, jobject, jclass, jmethodID, va_list) {}; 160 | 161 | virtual void CallNonvirtualShortMethodA(JNIEnv *, jobject, jclass, jmethodID, jvalue *) {}; 162 | 163 | virtual void CallNonvirtualIntMethod(JNIEnv *, jobject, jclass, jmethodID, ...) {}; 164 | 165 | virtual void CallNonvirtualIntMethodV(JNIEnv *, jobject, jclass, jmethodID, va_list) {}; 166 | 167 | virtual void CallNonvirtualIntMethodA(JNIEnv *, jobject, jclass, jmethodID, jvalue *) {}; 168 | 169 | virtual void CallNonvirtualLongMethod(JNIEnv *, jobject, jclass, jmethodID, ...) {}; 170 | 171 | virtual void CallNonvirtualLongMethodV(JNIEnv *, jobject, jclass, jmethodID, va_list) {}; 172 | 173 | virtual void CallNonvirtualLongMethodA(JNIEnv *, jobject, jclass, jmethodID, jvalue *) {}; 174 | 175 | virtual void CallNonvirtualFloatMethod(JNIEnv *, jobject, jclass, jmethodID, ...) {}; 176 | 177 | virtual void CallNonvirtualFloatMethodV(JNIEnv *, jobject, jclass, jmethodID, va_list) {}; 178 | 179 | virtual void CallNonvirtualFloatMethodA(JNIEnv *, jobject, jclass, jmethodID, jvalue *) {}; 180 | 181 | virtual void CallNonvirtualDoubleMethod(JNIEnv *, jobject, jclass, jmethodID, ...) {}; 182 | 183 | virtual void CallNonvirtualDoubleMethodV(JNIEnv *, jobject, jclass, jmethodID, va_list) {}; 184 | 185 | virtual void CallNonvirtualDoubleMethodA(JNIEnv *, jobject, jclass, jmethodID, jvalue *) {}; 186 | 187 | virtual void CallNonvirtualVoidMethod(JNIEnv *, jobject, jclass, jmethodID, ...) {}; 188 | 189 | virtual void CallNonvirtualVoidMethodV(JNIEnv *, jobject, jclass, jmethodID, va_list) {}; 190 | 191 | virtual void CallNonvirtualVoidMethodA(JNIEnv *, jobject, jclass, jmethodID, jvalue *) {}; 192 | 193 | virtual void GetFieldID(JNIEnv *, jclass, const char *, const char *) {}; 194 | 195 | virtual void GetObjectField(JNIEnv *, jobject, jfieldID) {}; 196 | 197 | virtual void GetBooleanField(JNIEnv *, jobject, jfieldID) {}; 198 | 199 | virtual void GetByteField(JNIEnv *, jobject, jfieldID) {}; 200 | 201 | virtual void GetCharField(JNIEnv *, jobject, jfieldID) {}; 202 | 203 | virtual void GetShortField(JNIEnv *, jobject, jfieldID) {}; 204 | 205 | virtual void GetIntField(JNIEnv *, jobject, jfieldID) {}; 206 | 207 | virtual void GetLongField(JNIEnv *, jobject, jfieldID) {}; 208 | 209 | virtual void GetFloatField(JNIEnv *, jobject, jfieldID) {}; 210 | 211 | virtual void GetDoubleField(JNIEnv *, jobject, jfieldID) {}; 212 | 213 | virtual void SetObjectField(JNIEnv *, jobject, jfieldID, jobject) {}; 214 | 215 | virtual void SetBooleanField(JNIEnv *, jobject, jfieldID, jboolean) {}; 216 | 217 | virtual void SetByteField(JNIEnv *, jobject, jfieldID, jbyte) {}; 218 | 219 | virtual void SetCharField(JNIEnv *, jobject, jfieldID, jchar) {}; 220 | 221 | virtual void SetShortField(JNIEnv *, jobject, jfieldID, jshort) {}; 222 | 223 | virtual void SetIntField(JNIEnv *, jobject, jfieldID, jint) {}; 224 | 225 | virtual void SetLongField(JNIEnv *, jobject, jfieldID, jlong) {}; 226 | 227 | virtual void SetFloatField(JNIEnv *, jobject, jfieldID, jfloat) {}; 228 | 229 | virtual void SetDoubleField(JNIEnv *, jobject, jfieldID, jdouble) {}; 230 | 231 | virtual void GetStaticMethodID(JNIEnv *, jclass, const char *, const char *) {}; 232 | 233 | virtual void CallStaticObjectMethod(JNIEnv *, jclass, jmethodID, ...) {}; 234 | 235 | virtual void CallStaticObjectMethodV(JNIEnv *, jclass, jmethodID, va_list) {}; 236 | 237 | virtual void CallStaticObjectMethodA(JNIEnv *, jclass, jmethodID, jvalue *) {}; 238 | 239 | virtual void CallStaticBooleanMethod(JNIEnv *, jclass, jmethodID, ...) {}; 240 | 241 | virtual void CallStaticBooleanMethodV(JNIEnv *, jclass, jmethodID, va_list) {}; 242 | 243 | virtual void CallStaticBooleanMethodA(JNIEnv *, jclass, jmethodID, jvalue *) {}; 244 | 245 | virtual void CallStaticByteMethod(JNIEnv *, jclass, jmethodID, ...) {}; 246 | 247 | virtual void CallStaticByteMethodV(JNIEnv *, jclass, jmethodID, va_list) {}; 248 | 249 | virtual void CallStaticByteMethodA(JNIEnv *, jclass, jmethodID, jvalue *) {}; 250 | 251 | virtual void CallStaticCharMethod(JNIEnv *, jclass, jmethodID, ...) {}; 252 | 253 | virtual void CallStaticCharMethodV(JNIEnv *, jclass, jmethodID, va_list) {}; 254 | 255 | virtual void CallStaticCharMethodA(JNIEnv *, jclass, jmethodID, jvalue *) {}; 256 | 257 | virtual void CallStaticShortMethod(JNIEnv *, jclass, jmethodID, ...) {}; 258 | 259 | virtual void CallStaticShortMethodV(JNIEnv *, jclass, jmethodID, va_list) {}; 260 | 261 | virtual void CallStaticShortMethodA(JNIEnv *, jclass, jmethodID, jvalue *) {}; 262 | 263 | virtual void CallStaticIntMethod(JNIEnv *, jclass, jmethodID, ...) {}; 264 | 265 | virtual void CallStaticIntMethodV(JNIEnv *, jclass, jmethodID, va_list) {}; 266 | 267 | virtual void CallStaticIntMethodA(JNIEnv *, jclass, jmethodID, jvalue *) {}; 268 | 269 | virtual void CallStaticLongMethod(JNIEnv *, jclass, jmethodID, ...) {}; 270 | 271 | virtual void CallStaticLongMethodV(JNIEnv *, jclass, jmethodID, va_list) {}; 272 | 273 | virtual void CallStaticLongMethodA(JNIEnv *, jclass, jmethodID, jvalue *) {}; 274 | 275 | virtual void CallStaticFloatMethod(JNIEnv *, jclass, jmethodID, ...) {}; 276 | 277 | virtual void CallStaticFloatMethodV(JNIEnv *, jclass, jmethodID, va_list) {}; 278 | 279 | virtual void CallStaticFloatMethodA(JNIEnv *, jclass, jmethodID, jvalue *) {}; 280 | 281 | virtual void CallStaticDoubleMethod(JNIEnv *, jclass, jmethodID, ...) {}; 282 | 283 | virtual void CallStaticDoubleMethodV(JNIEnv *, jclass, jmethodID, va_list) {}; 284 | 285 | virtual void CallStaticDoubleMethodA(JNIEnv *, jclass, jmethodID, jvalue *) {}; 286 | 287 | virtual void CallStaticVoidMethod(JNIEnv *, jclass, jmethodID, ...) {}; 288 | 289 | virtual void CallStaticVoidMethodV(JNIEnv *, jclass, jmethodID, va_list) {}; 290 | 291 | virtual void CallStaticVoidMethodA(JNIEnv *, jclass, jmethodID, jvalue *) {}; 292 | 293 | virtual void GetStaticFieldID(JNIEnv *, jclass, const char *, const char *) {}; 294 | 295 | virtual void GetStaticObjectField(JNIEnv *, jclass, jfieldID) {}; 296 | 297 | virtual void GetStaticBooleanField(JNIEnv *, jclass, jfieldID) {}; 298 | 299 | virtual void GetStaticByteField(JNIEnv *, jclass, jfieldID) {}; 300 | 301 | virtual void GetStaticCharField(JNIEnv *, jclass, jfieldID) {}; 302 | 303 | virtual void GetStaticShortField(JNIEnv *, jclass, jfieldID) {}; 304 | 305 | virtual void GetStaticIntField(JNIEnv *, jclass, jfieldID) {}; 306 | 307 | virtual void GetStaticLongField(JNIEnv *, jclass, jfieldID) {}; 308 | 309 | virtual void GetStaticFloatField(JNIEnv *, jclass, jfieldID) {}; 310 | 311 | virtual void GetStaticDoubleField(JNIEnv *, jclass, jfieldID) {}; 312 | 313 | virtual void SetStaticObjectField(JNIEnv *, jclass, jfieldID, jobject) {}; 314 | 315 | virtual void SetStaticBooleanField(JNIEnv *, jclass, jfieldID, jboolean) {}; 316 | 317 | virtual void SetStaticByteField(JNIEnv *, jclass, jfieldID, jbyte) {}; 318 | 319 | virtual void SetStaticCharField(JNIEnv *, jclass, jfieldID, jchar) {}; 320 | 321 | virtual void SetStaticShortField(JNIEnv *, jclass, jfieldID, jshort) {}; 322 | 323 | virtual void SetStaticIntField(JNIEnv *, jclass, jfieldID, jint) {}; 324 | 325 | virtual void SetStaticLongField(JNIEnv *, jclass, jfieldID, jlong) {}; 326 | 327 | virtual void SetStaticFloatField(JNIEnv *, jclass, jfieldID, jfloat) {}; 328 | 329 | virtual void SetStaticDoubleField(JNIEnv *, jclass, jfieldID, jdouble) {}; 330 | 331 | virtual void NewString(JNIEnv *, const jchar *, jsize) {}; 332 | 333 | virtual void GetStringLength(JNIEnv *, jstring) {}; 334 | 335 | virtual void GetStringChars(JNIEnv *, jstring, jboolean *) {}; 336 | 337 | virtual void ReleaseStringChars(JNIEnv *, jstring, const char *) {}; 338 | 339 | virtual void NewStringUTF(JNIEnv *, const char *) {}; 340 | 341 | virtual void GetStringUTFLength(JNIEnv *, jstring) {}; 342 | 343 | virtual void GetStringUTFChars(JNIEnv *, jstring, jboolean *) {}; 344 | 345 | virtual void ReleaseStringUTFChars(JNIEnv *, jstring, const char *) {}; 346 | 347 | virtual void GetArrayLength(JNIEnv *, jarray) {}; 348 | 349 | virtual void NewObjectArray(JNIEnv *, jsize, jclass, jobject) {}; 350 | 351 | virtual void GetObjectArrayElement(JNIEnv *, jobjectArray, jsize) {}; 352 | 353 | virtual void SetObjectArrayElement(JNIEnv *, jobjectArray, jsize, jobject) {}; 354 | 355 | virtual void NewBooleanArray(JNIEnv *, jsize) {}; 356 | 357 | virtual void NewByteArray(JNIEnv *, jsize) {}; 358 | 359 | virtual void NewCharArray(JNIEnv *, jsize) {}; 360 | 361 | virtual void NewShortArray(JNIEnv *, jsize) {}; 362 | 363 | virtual void NewIntArray(JNIEnv *, jsize) {}; 364 | 365 | virtual void NewLongArray(JNIEnv *, jsize) {}; 366 | 367 | virtual void NewFloatArray(JNIEnv *, jsize) {}; 368 | 369 | virtual void NewDoubleArray(JNIEnv *, jsize) {}; 370 | 371 | virtual void GetBooleanArrayElements(JNIEnv *, jbooleanArray, jboolean *) {}; 372 | 373 | virtual void GetByteArrayElements(JNIEnv *, jbyteArray, jboolean *) {}; 374 | 375 | virtual void GetCharArrayElements(JNIEnv *, jcharArray, jboolean *) {}; 376 | 377 | virtual void GetShortArrayElements(JNIEnv *, jshortArray, jboolean *) {}; 378 | 379 | virtual void GetIntArrayElements(JNIEnv *, jintArray, jboolean *) {}; 380 | 381 | virtual void GetLongArrayElements(JNIEnv *, jlongArray, jboolean *) {}; 382 | 383 | virtual void GetFloatArrayElements(JNIEnv *, jfloatArray, jboolean *) {}; 384 | 385 | virtual void GetDoubleArrayElements(JNIEnv *, jdoubleArray, jboolean *) {}; 386 | 387 | virtual void ReleaseBooleanArrayElements(JNIEnv *, jbooleanArray, jboolean *, jint) {}; 388 | 389 | virtual void ReleaseByteArrayElements(JNIEnv *, jbyteArray, jbyte *, jint) {}; 390 | 391 | virtual void ReleaseCharArrayElements(JNIEnv *, jcharArray, jchar *, jint) {}; 392 | 393 | virtual void ReleaseShortArrayElements(JNIEnv *, jshortArray, jshort *, jint) {}; 394 | 395 | virtual void ReleaseIntArrayElements(JNIEnv *, jintArray, jint *, jint) {}; 396 | 397 | virtual void ReleaseLongArrayElements(JNIEnv *, jlongArray, jlong *, jint) {}; 398 | 399 | virtual void ReleaseFloatArrayElements(JNIEnv *, jfloatArray, jfloat *, jint) {}; 400 | 401 | virtual void ReleaseDoubleArrayElements(JNIEnv *, jdoubleArray, jdouble *, jint) {}; 402 | 403 | virtual void GetBooleanArrayRegion(JNIEnv *, jbooleanArray, jsize, jsize, jboolean *) {}; 404 | 405 | virtual void GetByteArrayRegion(JNIEnv *, jbyteArray, jsize, jsize, jbyte *) {}; 406 | 407 | virtual void GetCharArrayRegion(JNIEnv *, jcharArray, jsize, jsize, jchar *) {}; 408 | 409 | virtual void GetShortArrayRegion(JNIEnv *, jshortArray, jsize, jsize, jshort *) {}; 410 | 411 | virtual void GetIntArrayRegion(JNIEnv *, jintArray, jsize, jsize, jint *) {}; 412 | 413 | virtual void GetLongArrayRegion(JNIEnv *, jlongArray, jsize, jsize, jlong *) {}; 414 | 415 | virtual void GetFloatArrayRegion(JNIEnv *, jfloatArray, jsize, jsize, jfloat *) {}; 416 | 417 | virtual void GetDoubleArrayRegion(JNIEnv *, jdoubleArray, jsize, jsize, jdouble *) {}; 418 | 419 | virtual void SetBooleanArrayRegion(JNIEnv *, jbooleanArray, jsize, jsize, const jboolean *) {}; 420 | 421 | virtual void SetByteArrayRegion(JNIEnv *, jbyteArray, jsize, jsize, const jbyte *) {}; 422 | 423 | virtual void SetCharArrayRegion(JNIEnv *, jcharArray, jsize, jsize, const jchar *) {}; 424 | 425 | virtual void SetShortArrayRegion(JNIEnv *, jshortArray, jsize, jsize, const jshort *) {}; 426 | 427 | virtual void SetIntArrayRegion(JNIEnv *, jintArray, jsize, jsize, const jint *) {}; 428 | 429 | virtual void SetLongArrayRegion(JNIEnv *, jlongArray, jsize, jsize, const jlong *) {}; 430 | 431 | virtual void SetFloatArrayRegion(JNIEnv *, jfloatArray, jsize, jsize, const jfloat *) {}; 432 | 433 | virtual void SetDoubleArrayRegion(JNIEnv *, jdoubleArray, jsize, jsize, const jdouble *) {}; 434 | 435 | virtual void RegisterNatives(JNIEnv *, jclass, const JNINativeMethod *, jint) {}; 436 | 437 | virtual void UnregisterNatives(JNIEnv *, jclass) {}; 438 | 439 | virtual void MonitorEnter(JNIEnv *, jobject) {}; 440 | 441 | virtual void MonitorExit(JNIEnv *, jobject) {}; 442 | 443 | virtual void GetJavaVM(JNIEnv *, JavaVM **) {}; 444 | 445 | virtual void GetStringRegion(JNIEnv *, jstring, jsize, jsize, jchar *) {}; 446 | 447 | virtual void GetStringUTFRegion(JNIEnv *, jstring, jsize, jsize, char *) {}; 448 | 449 | virtual void GetPrimitiveArrayCritical(JNIEnv *, jarray, jboolean *) {}; 450 | 451 | virtual void ReleasePrimitiveArrayCritical(JNIEnv *, jarray, void *, jint) {}; 452 | 453 | virtual void GetStringCritical(JNIEnv *, jstring, jboolean *) {}; 454 | 455 | virtual void ReleaseStringCritical(JNIEnv *, jstring, const jchar *) {}; 456 | 457 | virtual void NewWeakGlobalRef(JNIEnv *, jobject) {}; 458 | 459 | virtual void DeleteWeakGlobalRef(JNIEnv *, jweak) {}; 460 | 461 | virtual void ExceptionCheck(JNIEnv *) {}; 462 | 463 | virtual void NewDirectByteBuffer(JNIEnv *, void *, jlong) {}; 464 | 465 | virtual void GetDirectBufferAddress(JNIEnv *, jobject) {}; 466 | 467 | virtual void GetDirectBufferCapacity(JNIEnv *, jobject) {}; 468 | 469 | virtual ~JNIInterface() {}; 470 | }; 471 | 472 | 473 | #endif //UNPACKER_JNIINTERFACE_H 474 | -------------------------------------------------------------------------------- /app/src/main/cpp/Hook/instruction/Arm64Instruction.cpp: -------------------------------------------------------------------------------- 1 | //===------------------------------------------------------------*- C++ -*-===// 2 | // 3 | // Created by F8LEFT on 2017/6/19. 4 | // Copyright (c) 2017. All rights reserved. 5 | //===----------------------------------------------------------------------===// 6 | // 7 | //===----------------------------------------------------------------------===// 8 | 9 | 10 | #include "Arm64Instruction.h" 11 | #include "../Helper.h" 12 | #include "../LogHex.h" 13 | #include 14 | 15 | 16 | #define A64_MAX_INSTRUCTIONS 5 17 | #define A64_MAX_REFERENCES (A64_MAX_INSTRUCTIONS * 2) 18 | #define A64_NOP 0xd503201fu 19 | #define A64_JNIEXPORT __attribute__((visibility("default"))) 20 | #define A64_LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "A64_HOOK", __VA_ARGS__)) 21 | #ifndef NDEBUG 22 | # define A64_LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "A64_HOOK", __VA_ARGS__)) 23 | #else 24 | # define A64_LOGI(...) ((void)0) 25 | #endif // NDEBUG 26 | 27 | #include 28 | 29 | typedef uint32_t *__restrict *__restrict instruction; 30 | typedef struct { 31 | struct fix_info { 32 | uint32_t *bp; 33 | uint32_t ls; // left-shift counts 34 | uint32_t ad; // & operand 35 | }; 36 | struct insns_info { 37 | union { 38 | uint64_t insu; 39 | int64_t ins; 40 | void *insp; 41 | }; 42 | fix_info fmap[A64_MAX_REFERENCES]; 43 | }; 44 | int64_t basep; 45 | int64_t endp; 46 | insns_info dat[A64_MAX_INSTRUCTIONS]; 47 | 48 | public: 49 | inline bool is_in_fixing_range(const int64_t absolute_addr) { 50 | return absolute_addr >= this->basep && absolute_addr < this->endp; 51 | } 52 | 53 | inline intptr_t get_ref_ins_index(const int64_t absolute_addr) { 54 | return static_cast((absolute_addr - this->basep) / sizeof(uint32_t)); 55 | } 56 | 57 | inline intptr_t get_and_set_current_index(uint32_t *__restrict inp, uint32_t *__restrict outp) { 58 | intptr_t current_idx = this->get_ref_ins_index(reinterpret_cast(inp)); 59 | this->dat[current_idx].insp = outp; 60 | return current_idx; 61 | } 62 | 63 | inline void reset_current_ins(const intptr_t idx, uint32_t *__restrict outp) { 64 | this->dat[idx].insp = outp; 65 | } 66 | 67 | void 68 | insert_fix_map(const intptr_t idx, uint32_t *bp, uint32_t ls = 0u, uint32_t ad = 0xffffffffu) { 69 | for (auto &f : this->dat[idx].fmap) { 70 | if (f.bp == NULL) { 71 | f.bp = bp; 72 | f.ls = ls; 73 | f.ad = ad; 74 | return; 75 | } //if 76 | } 77 | // What? GGing.. 78 | } 79 | 80 | void process_fix_map(const intptr_t idx) { 81 | for (auto &f : this->dat[idx].fmap) { 82 | if (f.bp == NULL) break; 83 | *(f.bp) = *(f.bp) | 84 | (((int32_t(this->dat[idx].ins - reinterpret_cast(f.bp)) >> 2) 85 | << f.ls) & f.ad); 86 | f.bp = NULL; 87 | } 88 | } 89 | } context; 90 | 91 | //------------------------------------------------------------------------- 92 | 93 | static bool __fix_branch_imm(instruction inpp, instruction outpp, context *ctxp) { 94 | static constexpr uint32_t mbits = 6u; 95 | static constexpr uint32_t mask = 0xfc000000u; // 0b11111100000000000000000000000000 96 | static constexpr uint32_t rmask = 0x03ffffffu; // 0b00000011111111111111111111111111 97 | static constexpr uint32_t op_b = 0x14000000u; // "b" ADDR_PCREL26 98 | static constexpr uint32_t op_bl = 0x94000000u; // "bl" ADDR_PCREL26 99 | 100 | const uint32_t ins = *(*inpp); 101 | const uint32_t opc = ins & mask; 102 | switch (opc) { 103 | case op_b: 104 | case op_bl: { 105 | intptr_t current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); 106 | int64_t absolute_addr = reinterpret_cast(*inpp) + 107 | (static_cast(ins << mbits) 108 | >> (mbits - 2u)); // sign-extended 109 | int64_t new_pc_offset = 110 | static_cast(absolute_addr - reinterpret_cast(*outpp)) 111 | >> 2; // shifted 112 | bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr); 113 | // whether the branch should be converted to absolute jump 114 | if (!special_fix_type && llabs(new_pc_offset) >= (rmask >> 1)) { 115 | bool b_aligned = (reinterpret_cast(*outpp + 2) & 7u) == 0u; 116 | if (opc == op_b) { 117 | if (b_aligned != true) { 118 | (*outpp)[0] = A64_NOP; 119 | ctxp->reset_current_ins(current_idx, ++(*outpp)); 120 | } //if 121 | (*outpp)[0] = 0x58000051u; // LDR X17, #0x8 122 | (*outpp)[1] = 0xd61f0220u; // BR X17 123 | memcpy(*outpp + 2, &absolute_addr, sizeof(absolute_addr)); 124 | *outpp += 4; 125 | } else { 126 | if (b_aligned == true) { 127 | (*outpp)[0] = A64_NOP; 128 | ctxp->reset_current_ins(current_idx, ++(*outpp)); 129 | } //if 130 | (*outpp)[0] = 0x58000071u; // LDR X17, #12 131 | (*outpp)[1] = 0x1000009eu; // ADR X30, #16 132 | (*outpp)[2] = 0xd61f0220u; // BR X17 133 | memcpy(*outpp + 3, &absolute_addr, sizeof(absolute_addr)); 134 | *outpp += 5; 135 | } //if 136 | } else { 137 | if (special_fix_type) { 138 | intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr); 139 | if (ref_idx <= current_idx) { 140 | new_pc_offset = static_cast(ctxp->dat[ref_idx].ins - 141 | reinterpret_cast(*outpp)) 142 | >> 2; 143 | } else { 144 | ctxp->insert_fix_map(ref_idx, *outpp, 0u, rmask); 145 | new_pc_offset = 0; 146 | } //if 147 | } //if 148 | 149 | (*outpp)[0] = opc | (new_pc_offset & ~mask); 150 | ++(*outpp); 151 | } //if 152 | 153 | ++(*inpp); 154 | return ctxp->process_fix_map(current_idx), true; 155 | } 156 | } 157 | return false; 158 | } 159 | 160 | //------------------------------------------------------------------------- 161 | 162 | static bool __fix_cond_comp_test_branch(instruction inpp, instruction outpp, context *ctxp) { 163 | static constexpr uint32_t lsb = 5u; 164 | static constexpr uint32_t lmask01 = 0xff00001fu; // 0b11111111000000000000000000011111 165 | static constexpr uint32_t mask0 = 0xff000010u; // 0b11111111000000000000000000010000 166 | static constexpr uint32_t op_bc = 0x54000000u; // "b.c" ADDR_PCREL19 167 | static constexpr uint32_t mask1 = 0x7f000000u; // 0b01111111000000000000000000000000 168 | static constexpr uint32_t op_cbz = 0x34000000u; // "cbz" Rt, ADDR_PCREL19 169 | static constexpr uint32_t op_cbnz = 0x35000000u; // "cbnz" Rt, ADDR_PCREL19 170 | static constexpr uint32_t lmask2 = 0xfff8001fu; // 0b11111111111110000000000000011111 171 | static constexpr uint32_t mask2 = 0x7f000000u; // 0b01111111000000000000000000000000 172 | static constexpr uint32_t op_tbz = 0x36000000u; // 0b00110110000000000000000000000000 "tbz" Rt, BIT_NUM, ADDR_PCREL14 173 | static constexpr uint32_t op_tbnz = 0x37000000u; // 0b00110111000000000000000000000000 "tbnz" Rt, BIT_NUM, ADDR_PCREL14 174 | 175 | const uint32_t ins = *(*inpp); 176 | uint32_t lmask = lmask01; 177 | if ((ins & mask0) != op_bc) { 178 | uint32_t opc = ins & mask1; 179 | if (opc != op_cbz && opc != op_cbnz) { 180 | opc = ins & mask2; 181 | if (opc != op_tbz && opc != op_tbnz) { 182 | return false; 183 | } //if 184 | lmask = lmask2; 185 | } //if 186 | } //if 187 | 188 | intptr_t current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); 189 | int64_t absolute_addr = reinterpret_cast(*inpp) + ((ins & ~lmask) >> (lsb - 2u)); 190 | int64_t new_pc_offset = 191 | static_cast(absolute_addr - reinterpret_cast(*outpp)) >> 2; // shifted 192 | bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr); 193 | if (!special_fix_type && llabs(new_pc_offset) >= (~lmask >> (lsb + 1))) { 194 | if ((reinterpret_cast(*outpp + 4) & 7u) != 0u) { 195 | (*outpp)[0] = A64_NOP; 196 | ctxp->reset_current_ins(current_idx, ++(*outpp)); 197 | } //if 198 | (*outpp)[0] = (((8u >> 2u) << lsb) & ~lmask) | (ins & lmask); // B.C #0x8 199 | (*outpp)[1] = 0x14000005u; // B #0x14 200 | (*outpp)[2] = 0x58000051u; // LDR X17, #0x8 201 | (*outpp)[3] = 0xd61f0220u; // BR X17 202 | memcpy(*outpp + 4, &absolute_addr, sizeof(absolute_addr)); 203 | *outpp += 6; 204 | } else { 205 | if (special_fix_type) { 206 | intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr); 207 | if (ref_idx <= current_idx) { 208 | new_pc_offset = static_cast(ctxp->dat[ref_idx].ins - 209 | reinterpret_cast(*outpp)) >> 2; 210 | } else { 211 | ctxp->insert_fix_map(ref_idx, *outpp, lsb, ~lmask); 212 | new_pc_offset = 0; 213 | } //if 214 | } //if 215 | 216 | (*outpp)[0] = (static_cast(new_pc_offset << lsb) & ~lmask) | (ins & lmask); 217 | ++(*outpp); 218 | } //if 219 | 220 | ++(*inpp); 221 | return ctxp->process_fix_map(current_idx), true; 222 | } 223 | 224 | //------------------------------------------------------------------------- 225 | 226 | static bool __fix_loadlit(instruction inpp, instruction outpp, context *ctxp) { 227 | const uint32_t ins = *(*inpp); 228 | 229 | // memory prefetch("prfm"), just skip it 230 | // http://infocenter.arm.com/help/topic/com.arm.doc.100069_0608_00_en/pge1427897420050.html 231 | if ((ins & 0xff000000u) == 0xd8000000u) { 232 | ctxp->process_fix_map(ctxp->get_and_set_current_index(*inpp, *outpp)); 233 | ++(*inpp); 234 | return true; 235 | } //if 236 | 237 | static constexpr uint32_t msb = 8u; 238 | static constexpr uint32_t lsb = 5u; 239 | static constexpr uint32_t mask_30 = 0x40000000u; // 0b01000000000000000000000000000000 240 | static constexpr uint32_t mask_31 = 0x80000000u; // 0b10000000000000000000000000000000 241 | static constexpr uint32_t lmask = 0xff00001fu; // 0b11111111000000000000000000011111 242 | static constexpr uint32_t mask_ldr = 0xbf000000u; // 0b10111111000000000000000000000000 243 | static constexpr uint32_t op_ldr = 0x18000000u; // 0b00011000000000000000000000000000 "LDR Wt/Xt, label" | ADDR_PCREL19 244 | static constexpr uint32_t mask_ldrv = 0x3f000000u; // 0b00111111000000000000000000000000 245 | static constexpr uint32_t op_ldrv = 0x1c000000u; // 0b00011100000000000000000000000000 "LDR St/Dt/Qt, label" | ADDR_PCREL19 246 | static constexpr uint32_t mask_ldrsw = 0xff000000u; // 0b11111111000000000000000000000000 247 | static constexpr uint32_t op_ldrsw = 0x98000000u; // "LDRSW Xt, label" | ADDR_PCREL19 | load register signed word 248 | // LDR S0, #0 | 0b00011100000000000000000000000000 | 32-bit 249 | // LDR D0, #0 | 0b01011100000000000000000000000000 | 64-bit 250 | // LDR Q0, #0 | 0b10011100000000000000000000000000 | 128-bit 251 | // INVALID | 0b11011100000000000000000000000000 | may be 256-bit 252 | 253 | uint32_t mask = mask_ldr; 254 | uintptr_t faligned = (ins & mask_30) ? 7u : 3u; 255 | if ((ins & mask_ldr) != op_ldr) { 256 | mask = mask_ldrv; 257 | if (faligned != 7u) 258 | faligned = (ins & mask_31) ? 15u : 3u; 259 | if ((ins & mask_ldrv) != op_ldrv) { 260 | if ((ins & mask_ldrsw) != op_ldrsw) { 261 | return false; 262 | } //if 263 | mask = mask_ldrsw; 264 | faligned = 7u; 265 | } //if 266 | } //if 267 | 268 | intptr_t current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); 269 | int64_t absolute_addr = reinterpret_cast(*inpp) + 270 | ((static_cast(ins << msb) >> (msb + lsb - 2u)) & ~3u); 271 | int64_t new_pc_offset = 272 | static_cast(absolute_addr - reinterpret_cast(*outpp)) >> 2; // shifted 273 | bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr); 274 | // special_fix_type may encounter issue when there are mixed data and code 275 | if (special_fix_type || (llabs(new_pc_offset) + (faligned + 1u - 4u) / 4u) >= 276 | (~lmask >> (lsb + 1))) { // inaccurate, but it works 277 | while ((reinterpret_cast(*outpp + 2) & faligned) != 0u) { 278 | *(*outpp)++ = A64_NOP; 279 | } 280 | ctxp->reset_current_ins(current_idx, *outpp); 281 | 282 | // Note that if memory at absolute_addr is writeable (non-const), we will fail to fetch it. 283 | // And what's worse, we may unexpectedly overwrite something if special_fix_type is true... 284 | uint32_t ns = static_cast((faligned + 1) / sizeof(uint32_t)); 285 | (*outpp)[0] = (((8u >> 2u) << lsb) & ~mask) | (ins & lmask); // LDR #0x8 286 | (*outpp)[1] = 0x14000001u + ns; // B #0xc 287 | memcpy(*outpp + 2, reinterpret_cast(absolute_addr), faligned + 1); 288 | *outpp += 2 + ns; 289 | } else { 290 | faligned >>= 2; // new_pc_offset is shifted and 4-byte aligned 291 | while ((new_pc_offset & faligned) != 0) { 292 | *(*outpp)++ = A64_NOP; 293 | new_pc_offset = 294 | static_cast(absolute_addr - reinterpret_cast(*outpp)) >> 2; 295 | } 296 | ctxp->reset_current_ins(current_idx, *outpp); 297 | 298 | (*outpp)[0] = (static_cast(new_pc_offset << lsb) & ~mask) | (ins & lmask); 299 | ++(*outpp); 300 | } //if 301 | 302 | ++(*inpp); 303 | return ctxp->process_fix_map(current_idx), true; 304 | } 305 | 306 | //------------------------------------------------------------------------- 307 | 308 | static bool __fix_pcreladdr(instruction inpp, instruction outpp, context *ctxp) { 309 | // Load a PC-relative address into a register 310 | // http://infocenter.arm.com/help/topic/com.arm.doc.100069_0608_00_en/pge1427897645644.html 311 | static constexpr uint32_t msb = 8u; 312 | static constexpr uint32_t lsb = 5u; 313 | static constexpr uint32_t mask = 0x9f000000u; // 0b10011111000000000000000000000000 314 | static constexpr uint32_t rmask = 0x0000001fu; // 0b00000000000000000000000000011111 315 | static constexpr uint32_t lmask = 0xff00001fu; // 0b11111111000000000000000000011111 316 | static constexpr uint32_t fmask = 0x00ffffffu; // 0b00000000111111111111111111111111 317 | static constexpr uint32_t max_val = 0x001fffffu; // 0b00000000000111111111111111111111 318 | static constexpr uint32_t op_adr = 0x10000000u; // "adr" Rd, ADDR_PCREL21 319 | static constexpr uint32_t op_adrp = 0x90000000u; // "adrp" Rd, ADDR_ADRP 320 | 321 | const uint32_t ins = *(*inpp); 322 | intptr_t current_idx; 323 | switch (ins & mask) { 324 | case op_adr: { 325 | current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); 326 | int64_t lsb_bytes = static_cast(ins << 1u) >> 30u; 327 | int64_t absolute_addr = reinterpret_cast(*inpp) + 328 | (((static_cast(ins << msb) >> (msb + lsb - 2u)) & 329 | ~3u) | lsb_bytes); 330 | int64_t new_pc_offset = static_cast(absolute_addr - 331 | reinterpret_cast(*outpp)); 332 | bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr); 333 | if (!special_fix_type && llabs(new_pc_offset) >= (max_val >> 1)) { 334 | if ((reinterpret_cast(*outpp + 2) & 7u) != 0u) { 335 | (*outpp)[0] = A64_NOP; 336 | ctxp->reset_current_ins(current_idx, ++(*outpp)); 337 | } //if 338 | 339 | (*outpp)[0] = 340 | 0x58000000u | (((8u >> 2u) << lsb) & ~mask) | (ins & rmask); // LDR #0x8 341 | (*outpp)[1] = 0x14000003u; // B #0xc 342 | memcpy(*outpp + 2, &absolute_addr, sizeof(absolute_addr)); 343 | *outpp += 4; 344 | } else { 345 | if (special_fix_type) { 346 | intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr & ~3ull); 347 | if (ref_idx <= current_idx) { 348 | new_pc_offset = static_cast(ctxp->dat[ref_idx].ins - 349 | reinterpret_cast(*outpp)); 350 | } else { 351 | ctxp->insert_fix_map(ref_idx, *outpp, lsb, fmask); 352 | new_pc_offset = 0; 353 | } //if 354 | } //if 355 | 356 | // the lsb_bytes will never be changed, so we can use lmask to keep it 357 | (*outpp)[0] = (static_cast(new_pc_offset << (lsb - 2u)) & fmask) | 358 | (ins & lmask); 359 | ++(*outpp); 360 | } //if 361 | } 362 | break; 363 | case op_adrp: { 364 | current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); 365 | int32_t lsb_bytes = static_cast(ins << 1u) >> 30u; 366 | int64_t absolute_addr = (reinterpret_cast(*inpp) & ~0xfffll) + 367 | ((((static_cast(ins << msb) >> (msb + lsb - 2u)) & 368 | ~3u) | lsb_bytes) << 12); 369 | A64_LOGI("ins = 0x%.8X, pc = %p, abs_addr = %p", 370 | ins, *inpp, reinterpret_cast(absolute_addr)); 371 | if (ctxp->is_in_fixing_range(absolute_addr)) { 372 | intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr/* & ~3ull*/); 373 | if (ref_idx > current_idx) { 374 | // the bottom 12 bits of absolute_addr are masked out, 375 | // so ref_idx must be less than or equal to current_idx! 376 | A64_LOGE("ref_idx must be less than or equal to current_idx!"); 377 | } //if 378 | 379 | // *absolute_addr may be changed due to relocation fixing 380 | A64_LOGI("What is the correct way to fix this?"); 381 | *(*outpp)++ = ins; // 0x90000000u; 382 | } else { 383 | if ((reinterpret_cast(*outpp + 2) & 7u) != 0u) { 384 | (*outpp)[0] = A64_NOP; 385 | ctxp->reset_current_ins(current_idx, ++(*outpp)); 386 | } //if 387 | 388 | (*outpp)[0] = 389 | 0x58000000u | (((8u >> 2u) << lsb) & ~mask) | (ins & rmask); // LDR #0x8 390 | (*outpp)[1] = 0x14000003u; // B #0xc 391 | memcpy(*outpp + 2, &absolute_addr, sizeof(absolute_addr)); // potential overflow? 392 | *outpp += 4; 393 | } //if 394 | } 395 | break; 396 | default: 397 | return false; 398 | } 399 | 400 | ctxp->process_fix_map(current_idx); 401 | ++(*inpp); 402 | return true; 403 | } 404 | 405 | //------------------------------------------------------------------------- 406 | 407 | #define __attribute __attribute__ 408 | #define aligned(x) __aligned__(x) 409 | #define __intval(p) reinterpret_cast(p) 410 | #define __uintval(p) reinterpret_cast(p) 411 | #define __ptr(p) reinterpret_cast(p) 412 | #define __page_size 4096 413 | #define __page_align(n) __align_up(static_cast(n), __page_size) 414 | #define __ptr_align(x) __ptr(__align_down(reinterpret_cast(x), __page_size)) 415 | #define __align_up(x, n) (((x) + ((n) - 1)) & ~((n) - 1)) 416 | #define __align_down(x, n) ((x) & -(n)) 417 | #define __countof(x) static_cast(sizeof(x) / sizeof((x)[0])) // must be signed 418 | #define __atomic_increase(p) __sync_add_and_fetch(p, 1) 419 | #define __sync_cmpswap(p, v, n) __sync_bool_compare_and_swap(p, v, n) 420 | #define __predict_true(exp) __builtin_expect((exp) != 0, 1) 421 | #define __flush_cache(c, n) __builtin___clear_cache(reinterpret_cast(c), reinterpret_cast(c) + n) 422 | #define __make_rwx(p, n) ::mprotect(__ptr_align(p), \ 423 | __page_align(__uintval(p) + n) != __page_align(__uintval(p)) ? __page_align(n) + __page_size : __page_align(n), \ 424 | PROT_READ | PROT_WRITE | PROT_EXEC) 425 | 426 | static void __fix_instructions(uint32_t *__restrict inp, int32_t count, uint32_t *__restrict outp) { 427 | context ctx; 428 | ctx.basep = reinterpret_cast(inp); 429 | ctx.endp = reinterpret_cast(inp + count); 430 | memset(ctx.dat, 0, sizeof(ctx.dat)); 431 | static_assert(sizeof(ctx.dat) / sizeof(ctx.dat[0]) == A64_MAX_INSTRUCTIONS, 432 | "please use A64_MAX_INSTRUCTIONS!"); 433 | #ifndef NDEBUG 434 | if (count > A64_MAX_INSTRUCTIONS) { 435 | A64_LOGE("too many fixing instructions!"); 436 | } //if 437 | #endif // NDEBUG 438 | 439 | uint32_t *const outp_base = outp; 440 | 441 | while (--count >= 0) { 442 | if (__fix_branch_imm(&inp, &outp, &ctx)) continue; 443 | if (__fix_cond_comp_test_branch(&inp, &outp, &ctx)) continue; 444 | if (__fix_loadlit(&inp, &outp, &ctx)) continue; 445 | if (__fix_pcreladdr(&inp, &outp, &ctx)) continue; 446 | 447 | // without PC-relative offset 448 | ctx.process_fix_map(ctx.get_and_set_current_index(inp, outp)); 449 | *(outp++) = *(inp++); 450 | } 451 | 452 | static constexpr uint_fast64_t mask = 0x03ffffffu; // 0b00000011111111111111111111111111 453 | auto callback = reinterpret_cast(inp); 454 | auto pc_offset = static_cast(callback - reinterpret_cast(outp)) >> 2; 455 | if (llabs(pc_offset) >= (mask >> 1)) { 456 | if ((reinterpret_cast(outp + 2) & 7u) != 0u) { 457 | outp[0] = A64_NOP; 458 | ++outp; 459 | } //if 460 | outp[0] = 0x58000051u; // LDR X17, #0x8 461 | outp[1] = 0xd61f0220u; // BR X17 462 | *reinterpret_cast(outp + 2) = callback; 463 | outp += 4; 464 | } else { 465 | outp[0] = 0x14000000u | (pc_offset & mask); // "B" ADDR_PCREL26 466 | ++outp; 467 | } //if 468 | 469 | const uintptr_t total = (outp - outp_base) * sizeof(uint32_t); 470 | __flush_cache(outp_base, total); // necessary 471 | } 472 | 473 | //------------------------------------------------------------------------- 474 | 475 | //------------------------------------------------------------------------- 476 | 477 | static __attribute((aligned(__page_size))) uint32_t __insns_pool[A64_MAX_BACKUPS][ 478 | A64_MAX_INSTRUCTIONS * 10]; 479 | 480 | //------------------------------------------------------------------------- 481 | 482 | class A64HookInit { 483 | public: 484 | A64HookInit() { 485 | __make_rwx(__insns_pool, sizeof(__insns_pool)); 486 | A64_LOGI("insns pool initialized."); 487 | } 488 | }; 489 | 490 | static A64HookInit __init; 491 | 492 | //------------------------------------------------------------------------- 493 | 494 | static uint32_t *FastAllocateTrampoline() { 495 | static_assert((A64_MAX_INSTRUCTIONS * 10 * sizeof(uint32_t)) % 8 == 0, "8-byte align"); 496 | static volatile int32_t __index = -1; 497 | 498 | int32_t i = __atomic_increase(&__index); 499 | if (__predict_true(i >= 0 && i < __countof(__insns_pool))) { 500 | return __insns_pool[i]; 501 | } //if 502 | 503 | A64_LOGE("failed to allocate trampoline!"); 504 | return NULL; 505 | } 506 | 507 | //------------------------------------------------------------------------- 508 | 509 | void *A64HookFunctionV(void *const symbol, void *const replace, 510 | void *const rwx, const uintptr_t rwx_size, HookInfo *hookInfo) { 511 | static constexpr uint_fast64_t mask = 0x03ffffffu; // 0b00000011111111111111111111111111 512 | 513 | uint32_t *trampoline = static_cast(rwx), *original = static_cast(symbol); 514 | 515 | static_assert(A64_MAX_INSTRUCTIONS >= 5, "please fix A64_MAX_INSTRUCTIONS!"); 516 | auto pc_offset = static_cast(__intval(replace) - __intval(symbol)) >> 2; 517 | if (llabs(pc_offset) >= (mask >> 1)) { 518 | int32_t count = (reinterpret_cast(original + 2) & 7u) != 0u ? 5 : 4; 519 | hookInfo->setJumpStubLen(count * sizeof(int32_t)); 520 | if (trampoline) { 521 | if (rwx_size < count * 10u) { 522 | LOGW("rwx size is too small to hold %u bytes backup instructions!", count * 10u); 523 | return NULL; 524 | } //if 525 | __fix_instructions(original, count, trampoline); 526 | hookInfo->setCallOriginalIns((uint8_t *) trampoline); 527 | } //if 528 | uint32_t *temp = new uint32_t[5]; 529 | memset(temp, 0, 5 * sizeof(uint32_t)); 530 | 531 | if (count == 5) { 532 | temp[0] = A64_NOP; 533 | ++temp; 534 | } //if 535 | temp[0] = 0x58000051u; // LDR X17, #0x8 536 | temp[1] = 0xd61f0220u; // BR X17 537 | *reinterpret_cast(temp + 2) = __intval(replace); 538 | //__flush_cache(symbol, 5 * sizeof(uint32_t)); 539 | hookInfo->setJumpStubBack((uint8_t *) temp); 540 | A64_LOGI("inline hook %p->%p successfully! %zu bytes overwritten", 541 | symbol, replace, 5 * sizeof(uint32_t)); 542 | 543 | } else { 544 | hookInfo->setJumpStubLen(1 * sizeof(int32_t)); 545 | if (trampoline) { 546 | if (rwx_size < 1u * 10u) { 547 | /*LOGW("rwx size is too small to hold %u bytes backup instructions!", 1u * 10u);*/ 548 | return NULL; 549 | } //if 550 | __fix_instructions(original, 1, trampoline); 551 | hookInfo->setCallOriginalIns((uint8_t *) trampoline); 552 | } //if 553 | uint32_t *temp = new uint32_t[1]; 554 | memset(temp, 0, 1 * sizeof(uint32_t)); 555 | 556 | __sync_cmpswap(temp, *temp, 557 | 0x14000000u | (pc_offset & mask)); // "B" ADDR_PCREL26 558 | hookInfo->setJumpStubBack((uint8_t *) temp); 559 | A64_LOGI("inline hook %p->%p successfully! %zu bytes overwritten", 560 | symbol, replace, 1 * sizeof(uint32_t)); 561 | 562 | } //if 563 | 564 | return trampoline; 565 | } 566 | 567 | //------------------------------------------------------------------------- 568 | 569 | void A64HookFunction(void *const symbol, void *const replace, HookInfo *hookInfo) { 570 | void *trampoline = NULL; 571 | trampoline = FastAllocateTrampoline(); 572 | if (trampoline == NULL) return; 573 | trampoline = A64HookFunctionV(symbol, replace, trampoline, A64_MAX_INSTRUCTIONS * 10u, 574 | hookInfo); 575 | if (trampoline != nullptr) { 576 | hookInfo->setCallOriginalIns((uint8_t *) trampoline); 577 | } else { 578 | LOGE("hook symbol:%p fail", symbol); 579 | } 580 | } 581 | 582 | 583 | bool Arm64Instruction::createStub(HookInfo *info) { 584 | 585 | void *replace = info->getHookAddr(); 586 | void *symbol = info->getOriginalAddr(); 587 | LOGI("createStub replace:%p symbol:%p", replace, symbol); 588 | A64HookFunction(symbol, replace, info); 589 | return true; 590 | } 591 | 592 | 593 | bool Arm64Instruction::createCallOriginalStub(HookInfo *info) { 594 | void *replace = info->getHookAddr(); 595 | void *symbol = info->getOriginalAddr(); 596 | return true; 597 | } 598 | 599 | bool Arm64Instruction::repairCallOriginIns(HookInfo *info, 600 | uint8_t *repair, 601 | uint32_t &repairLen) { 602 | 603 | /* int32_t count = info->getJumpStubLen(); 604 | void *symbol = info->getOriginalAddr(); 605 | uint32_t *original = static_cast(symbol); 606 | repairLen = count;*/ 607 | return true; 608 | } --------------------------------------------------------------------------------