├── .gitignore ├── .gitmodules ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── xposed_init │ ├── cpp │ ├── CMakeLists.txt │ ├── QBDI.h │ ├── QBDI │ │ ├── Bitmask.h │ │ ├── Callback.h │ │ ├── Config.h │ │ ├── Errors.h │ │ ├── InstAnalysis.h │ │ ├── Logs.h │ │ ├── Memory.h │ │ ├── Memory.hpp │ │ ├── Options.h │ │ ├── Platform.h │ │ ├── Range.h │ │ ├── State.h │ │ ├── VM.h │ │ ├── VM_C.h │ │ └── Version.h │ ├── demo │ │ ├── il2cpp-class.h │ │ ├── il2cpp-tabledefs.h │ │ ├── il2cpp_dumper.cpp │ │ ├── il2cpp_dumper.h │ │ ├── modmenu.cpp │ │ ├── modmenu_native.cpp │ │ ├── modmenu_native.h │ │ ├── qbdihook.cpp │ │ ├── qbdihook.h │ │ ├── ytbssl.cpp │ │ └── ytbssl.h │ ├── dobby │ │ └── dobby.h │ ├── elfio │ │ ├── elf_types.hpp │ │ ├── elfio.hpp │ │ ├── elfio_array.hpp │ │ ├── elfio_dump.hpp │ │ ├── elfio_dynamic.hpp │ │ ├── elfio_header.hpp │ │ ├── elfio_modinfo.hpp │ │ ├── elfio_note.hpp │ │ ├── elfio_relocation.hpp │ │ ├── elfio_section.hpp │ │ ├── elfio_segment.hpp │ │ ├── elfio_strings.hpp │ │ ├── elfio_symbols.hpp │ │ ├── elfio_utils.hpp │ │ ├── elfio_version.hpp │ │ └── elfio_versym.hpp │ ├── libs │ │ └── arm64-v8a │ │ │ ├── libQBDI.a │ │ │ └── libdobby.a │ ├── linker_hook.cpp │ ├── linker_hook.h │ ├── nhook.cpp │ ├── nhook.h │ ├── utils.cpp │ ├── utils.h │ ├── vm.cpp │ └── vm.h │ ├── java │ └── cn │ │ └── mrack │ │ └── xposed │ │ └── nhook │ │ ├── HookUtils.java │ │ ├── MainHook.java │ │ ├── NHook.java │ │ ├── SettingsActivity.java │ │ └── menu │ │ ├── Config.java │ │ ├── Menu.java │ │ ├── PBoolean.java │ │ ├── PInteger.java │ │ ├── PString.java │ │ ├── PValue.java │ │ └── SurfaceImGUI.java │ └── res │ ├── drawable │ ├── ic_launcher_background.xml │ └── ic_launcher_foreground.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-mdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-xhdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-xxhdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── mipmap-xxxhdpi │ ├── ic_launcher.webp │ └── ic_launcher_round.webp │ ├── values │ ├── colors.xml │ └── strings.xml │ └── xml │ └── settings.xml ├── build.gradle ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | /app/src/main/java/cn/mrack/so/ 17 | /.idea 18 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "app/src/main/cpp/imgui"] 2 | path = app/src/main/cpp/imgui 3 | url = https://github.com/Mrack/imgui.git 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XposedNHook 2 | 3 | Xposed免root注入so方案, 支持android各个版本 4 | 5 | ## demo: 6 | #### qbdi trace 7 | ![image](https://github.com/Mrack/XposedNHook/assets/15072171/87d14b94-736f-4511-bcc2-de14d331f6c4) 8 | 9 | #### android mod menu 10 | [Android-Mod-Menu](https://github.com/LGLTeam/Android-Mod-Menu/) 11 | 12 | #### android mod menu (ImGui) 13 | ![7853106f157ca453cab47600a85de357](https://github.com/Mrack/XposedNHook/assets/15072171/18cb056e-78a6-4430-a0a5-b11e42a9fbfd) 14 | ![91ebff12cf653f23fac0342b1be2adba](https://github.com/Mrack/XposedNHook/assets/15072171/b1c012df-5bfc-4749-8070-3ea3d05c5eb4) 15 | 16 | #### il2cppdumper 17 | ![image](https://github.com/Mrack/XposedNHook/assets/15072171/9092c99f-6b59-481e-892c-0ec6b1a2aae7) 18 | 19 | 20 | #### youtube ssl pinning 21 | ... 22 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.androidApplication) 3 | } 4 | 5 | android { 6 | namespace 'cn.mrack.xposed.nhook' 7 | compileSdk 34 8 | 9 | defaultConfig { 10 | applicationId "cn.mrack.xposed.nhook" 11 | minSdk 24 12 | targetSdk 34 13 | versionCode 1 14 | versionName "1.0" 15 | 16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 17 | 18 | ndk { 19 | abiFilters 'arm64-v8a' 20 | } 21 | 22 | } 23 | 24 | buildTypes { 25 | release { 26 | minifyEnabled true 27 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 28 | } 29 | } 30 | compileOptions { 31 | sourceCompatibility JavaVersion.VERSION_1_8 32 | targetCompatibility JavaVersion.VERSION_1_8 33 | } 34 | externalNativeBuild { 35 | cmake { 36 | path file('src/main/cpp/CMakeLists.txt') 37 | version '3.22.1' 38 | } 39 | } 40 | 41 | 42 | buildFeatures { 43 | buildConfig = true 44 | } 45 | 46 | project.tasks.whenTaskAdded { task -> 47 | if (task.name == 'stripDebugDebugSymbols') { 48 | task.finalizedBy dealAfterMergeDebugNativeLibs 49 | } 50 | if (task.name == 'stripReleaseDebugSymbols') { 51 | task.finalizedBy dealAfterMergeReleaseNativeLibs 52 | } 53 | } 54 | 55 | 56 | task dealAfterMergeReleaseNativeLibs() { 57 | doLast { 58 | var arch = ["arm64", "v7a"] 59 | var version = "release" 60 | generate(version, arch) 61 | } 62 | } 63 | 64 | task dealAfterMergeDebugNativeLibs() { 65 | doLast { 66 | var arch = ["arm64", "v7a"] 67 | var version = "debug" 68 | generate(version, arch) 69 | } 70 | } 71 | 72 | } 73 | 74 | 75 | dependencies { 76 | compileOnly 'de.robv.android.xposed:api:82' 77 | } 78 | 79 | 80 | def generate(version, archs) { 81 | def MERGED_NATIVE_LIBS_PATH = "$buildDir/intermediates/stripped_native_libs" 82 | var fileList = fileTree("$MERGED_NATIVE_LIBS_PATH/$version").matching { 83 | include '**/lib*.so' 84 | }.collect() 85 | var length = 32000 86 | for (final def data in fileList) { 87 | for (arch in archs) { 88 | if (data.path.contains("$arch")) { 89 | byte[] fileBytes = data.bytes 90 | if (fileBytes == "placeholder".bytes) { 91 | continue 92 | } 93 | data.bytes = "placeholder".bytes 94 | delete file("src/main/java/cn/mrack/so/$arch") 95 | file("src/main/java/cn/mrack/so/$arch").mkdirs() 96 | int i = fileBytes.length / length 97 | String totalText = ""; 98 | for (int j = 0; j < i; j++) { 99 | byte[] temp = new byte[length]; 100 | System.arraycopy(fileBytes, j * length, temp, 0, length); 101 | // hex 102 | file("src/main/java/cn/mrack/so/$arch/SoData${j}.java").text = "package cn.mrack.so.$arch;\n" + 103 | "public class SoData$j {\n" + 104 | " protected static String data${j} = \"" + temp.collect { String.format("%02X", it) }.join("") + "\";\n" + 105 | "}"; 106 | totalText += "SoData${j}.data${j} + "; 107 | } 108 | byte[] temp = new byte[fileBytes.length - i * length]; 109 | System.arraycopy(fileBytes, i * length, temp, 0, fileBytes.length - i * length); 110 | file("src/main/java/cn/mrack/so/$arch/SoData${i}.java").text = "package cn.mrack.so.$arch;\n" + 111 | "public class SoData${i} {\n" + 112 | " protected static String data${i} = \"" + temp.collect { String.format("%02X", it) }.join("") + "\";\n" + 113 | "}"; 114 | totalText += "SoData${i}.data${i}"; 115 | 116 | file("src/main/java/cn/mrack/so/$arch/SoData.java").text = "package cn.mrack.so.$arch;\n" + 117 | "public class SoData {\n" + 118 | " public static byte[] data = hexToBytes(" + totalText + ");\n" + 119 | " public static String md5 = \"${fileBytes.md5().toLowerCase()}\";\n" + 120 | " public static byte[] hexToBytes(String hex) {\n" + 121 | " byte[] bytes = new byte[hex.length() / 2];\n" + 122 | " for (int i = 0; i < hex.length(); i += 2) {\n" + 123 | " bytes[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16));\n" + 124 | " }\n" + 125 | " return bytes;\n" + 126 | " }\n" + 127 | "}"; 128 | 129 | } 130 | } 131 | 132 | } 133 | } -------------------------------------------------------------------------------- /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 | 23 | -keep class cn.mrack.xposed.nhook.NHook 24 | -keepclasseswithmembers class cn.mrack.so.*.SoData 25 | -keepclasseswithmembers class cn.mrack.xposed.nhook.MainHook 26 | -keep class cn.mrack.xposed.nhook.SettingsActivity { 27 | isModuleActive(); 28 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 14 | 17 | 20 | 21 | 24 | 25 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/assets/xposed_init: -------------------------------------------------------------------------------- 1 | cn.mrack.xposed.nhook.MainHook -------------------------------------------------------------------------------- /app/src/main/cpp/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 | # For more examples on how to use CMake, see https://github.com/android/ndk-samples. 4 | 5 | # Sets the minimum CMake version required for this project. 6 | cmake_minimum_required(VERSION 3.22.1) 7 | 8 | # Declares the project name. The project name can be accessed via ${ PROJECT_NAME}, 9 | # Since this is the top level CMakeLists.txt, the project name is also accessible 10 | # with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level 11 | # build script scope). 12 | project("nhook") 13 | 14 | set(CMAKE_CXX_STANDARD 20) 15 | 16 | 17 | set(LINKER_FLAGS "-ffixed-x18 -Wl,--hash-style=both") 18 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=format -fdata-sections -ffunction-sections -fvisibility=hidden -Wl,--exclude-libs,ALL") 19 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti -fvisibility=hidden -Wl,--exclude-libs,ALL") 20 | 21 | include_directories(.) 22 | 23 | find_library(egl EGL) 24 | find_library(GLESV2_LIB GLESv2) 25 | find_library(android android) 26 | add_library(local_dobby STATIC IMPORTED) 27 | add_library(local_qbdi STATIC IMPORTED) 28 | 29 | set_target_properties(local_dobby PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/libs/${ANDROID_ABI}/libdobby.a) 30 | set_target_properties(local_qbdi PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/libs/${ANDROID_ABI}/libQBDI.a) 31 | 32 | include_directories(imgui) 33 | 34 | add_library(${CMAKE_PROJECT_NAME} SHARED 35 | # List C/C++ source files with relative paths to this CMakeLists.txt. 36 | nhook.cpp 37 | linker_hook.cpp 38 | vm.cpp 39 | utils.cpp 40 | 41 | #demo 42 | demo/qbdihook.cpp 43 | demo/modmenu.cpp 44 | demo/ytbssl.cpp 45 | demo/modmenu_native.cpp 46 | demo/il2cpp_dumper.cpp 47 | ) 48 | 49 | 50 | 51 | include_directories(./imgui) 52 | 53 | add_library(imgui STATIC 54 | imgui/imgui.cpp 55 | imgui/imgui_draw.cpp 56 | imgui/imgui_tables.cpp 57 | imgui/imgui_widgets.cpp 58 | imgui/backends/imgui_impl_android.cpp 59 | imgui/backends/imgui_impl_opengl3.cpp) 60 | 61 | # Specifies libraries CMake should link to your target library. You 62 | # can link libraries from various origins, such as libraries defined in this 63 | # build script, prebuilt third-party libraries, or Android system libraries. 64 | target_link_libraries(${CMAKE_PROJECT_NAME} 65 | # List libraries link to the target library 66 | android 67 | local_dobby 68 | local_qbdi 69 | EGL 70 | GLESv3 71 | imgui 72 | log) -------------------------------------------------------------------------------- /app/src/main/cpp/QBDI.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of QBDI. 3 | * 4 | * Copyright 2017 - 2023 Quarkslab 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | #ifndef QBDI_H_ 19 | #define QBDI_H_ 20 | 21 | #ifdef __cplusplus 22 | #include "QBDI/Memory.hpp" 23 | #include "QBDI/VM.h" 24 | #else 25 | #include "QBDI/Memory.h" 26 | #include "QBDI/VM_C.h" 27 | #endif 28 | 29 | #include "QBDI/Logs.h" 30 | #include "QBDI/Version.h" 31 | 32 | #endif // QBDI_H_ 33 | -------------------------------------------------------------------------------- /app/src/main/cpp/QBDI/Bitmask.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of QBDI. 3 | * 4 | * Copyright 2017 - 2023 Quarkslab 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | #ifndef QBDI_BITMASK_H_ 19 | #define QBDI_BITMASK_H_ 20 | 21 | #ifdef __cplusplus 22 | #include 23 | 24 | namespace QBDI { 25 | 26 | template 27 | struct EnableBitMaskOperators { 28 | static const bool enable = false; 29 | }; 30 | 31 | template 32 | typename std::enable_if::enable, Enum>::type 33 | operator|(Enum lhs, Enum rhs) { 34 | using underlying = typename std::underlying_type::type; 35 | return static_cast(static_cast(lhs) | 36 | static_cast(rhs)); 37 | } 38 | 39 | template 40 | typename std::enable_if::enable, Enum>::type & 41 | operator|=(Enum &lhs, Enum rhs) { 42 | using underlying = typename std::underlying_type::type; 43 | lhs = static_cast(static_cast(lhs) | 44 | static_cast(rhs)); 45 | return lhs; 46 | } 47 | 48 | #define _QBDI_ENABLE_BITMASK_OPERATORS(x) \ 49 | template <> \ 50 | struct EnableBitMaskOperators { \ 51 | static const bool enable = true; \ 52 | }; 53 | 54 | } // namespace QBDI 55 | #else 56 | #define _QBDI_ENABLE_BITMASK_OPERATORS(x) 57 | #endif 58 | 59 | #endif // QBDI_BITMASK_H_ 60 | -------------------------------------------------------------------------------- /app/src/main/cpp/QBDI/Config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of QBDI. 3 | * 4 | * Copyright 2017 - 2023 Quarkslab 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | #ifndef QBDI_CONFIG_H_ 19 | #define QBDI_CONFIG_H_ 20 | 21 | /* #undef QBDI_ARCH_ARM */ 22 | #define QBDI_ARCH_AARCH64 1 23 | /* #undef QBDI_ARCH_X86 */ 24 | /* #undef QBDI_ARCH_X86_64 */ 25 | 26 | /* #undef QBDI_PLATFORM_WINDOWS */ 27 | /* #undef QBDI_PLATFORM_LINUX */ 28 | #define QBDI_PLATFORM_ANDROID 1 29 | /* #undef QBDI_PLATFORM_OSX */ 30 | /* #undef QBDI_PLATFORM_IOS */ 31 | 32 | /* #undef QBDI_NOT_AVX_SUPPORT */ 33 | 34 | /* #undef QBDI_BITS_32 */ 35 | #define QBDI_BITS_64 1 36 | 37 | /* #undef QBDI_LOG_DEBUG */ 38 | 39 | /* #undef QBDI_EXPORT_SYM */ 40 | 41 | #ifdef __cplusplus 42 | namespace QBDI { 43 | 44 | static constexpr bool is_android = 1; 45 | static constexpr bool is_linux = 0; 46 | static constexpr bool is_osx = 0; 47 | static constexpr bool is_ios = 0; 48 | static constexpr bool is_windows = 0; 49 | 50 | 51 | static constexpr bool is_arm = 0; 52 | static constexpr bool is_aarch64 = 1; 53 | static constexpr bool is_x86 = 0; 54 | static constexpr bool is_x86_64 = 0; 55 | 56 | static constexpr bool it_bits_32 = 0; 57 | static constexpr bool is_bits_64 = 1; 58 | 59 | static constexpr bool has_debug_log = 0; 60 | } 61 | #endif // __cplusplus 62 | 63 | #endif // QBDI_CONFIG_H_ 64 | -------------------------------------------------------------------------------- /app/src/main/cpp/QBDI/Errors.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of QBDI. 3 | * 4 | * Copyright 2017 - 2023 Quarkslab 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | #ifndef QBDI_ERRORS_H_ 19 | #define QBDI_ERRORS_H_ 20 | 21 | #include "QBDI/Platform.h" 22 | 23 | #ifdef __cplusplus 24 | namespace QBDI { 25 | #endif 26 | 27 | /*! QBDI Error values 28 | */ 29 | typedef enum { 30 | _QBDI_EI(INVALID_EVENTID) = 0xffffffff, /*!< Mark a returned event id as 31 | * invalid 32 | */ 33 | } VMError; 34 | 35 | #ifdef __cplusplus 36 | } 37 | #endif 38 | 39 | #endif // QBDI_ERRORS_H_ 40 | -------------------------------------------------------------------------------- /app/src/main/cpp/QBDI/InstAnalysis.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of QBDI. 3 | * 4 | * Copyright 2017 - 2023 Quarkslab 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | #ifndef QBDI_INSTANALYSIS_H_ 19 | #define QBDI_INSTANALYSIS_H_ 20 | 21 | #include 22 | 23 | #include "QBDI/Bitmask.h" 24 | #include "QBDI/Platform.h" 25 | #include "QBDI/State.h" 26 | 27 | #ifdef __cplusplus 28 | namespace QBDI { 29 | #endif 30 | 31 | /*! Access type (R/W/RW) of a register operand 32 | */ 33 | typedef enum { 34 | _QBDI_EI(REGISTER_UNUSED) = 0, /*!< Unused register */ 35 | _QBDI_EI(REGISTER_READ) = 1, /*!< Register read access */ 36 | _QBDI_EI(REGISTER_WRITE) = 1 << 1, /*!< Register write access */ 37 | _QBDI_EI(REGISTER_READ_WRITE) = 3, /*!< Register read/write access */ 38 | } RegisterAccessType; 39 | 40 | _QBDI_ENABLE_BITMASK_OPERATORS(RegisterAccessType) 41 | 42 | /*! Instruction Condition 43 | */ 44 | typedef enum { 45 | _QBDI_EI(CONDITION_NONE) = 0x0, /*!< The instruction is unconditionnal */ 46 | // ConditionType ^ 0x1 reverse the condition, except for CONDITION_NONE 47 | _QBDI_EI(CONDITION_ALWAYS) = 0x2, /*!< The instruction is always true */ 48 | _QBDI_EI(CONDITION_NEVER) = 0x3, /*!< The instruction is always false 49 | */ 50 | _QBDI_EI(CONDITION_EQUALS) = 0x4, /*!< Equals ('==') */ 51 | _QBDI_EI(CONDITION_NOT_EQUALS) = 0x5, /*!< Not Equals ('!=') */ 52 | _QBDI_EI(CONDITION_ABOVE) = 0x6, /*!< Above ('>' unsigned) */ 53 | _QBDI_EI(CONDITION_BELOW_EQUALS) = 0x7, /*!< Below or Equals ('<=' unsigned) 54 | */ 55 | _QBDI_EI(CONDITION_ABOVE_EQUALS) = 0x8, /*!< Above or Equals ('>=' unsigned) 56 | */ 57 | _QBDI_EI(CONDITION_BELOW) = 0x9, /*!< Below ('<' unsigned) */ 58 | _QBDI_EI(CONDITION_GREAT) = 0xa, /*!< Great ('>' signed) */ 59 | _QBDI_EI(CONDITION_LESS_EQUALS) = 0xb, /*!< Less or Equals ('<=' signed) */ 60 | _QBDI_EI(CONDITION_GREAT_EQUALS) = 0xc, /*!< Great or Equals ('>=' signed) */ 61 | _QBDI_EI(CONDITION_LESS) = 0xd, /*!< Less ('<' signed) */ 62 | _QBDI_EI(CONDITION_EVEN) = 0xe, /*!< Even */ 63 | _QBDI_EI(CONDITION_ODD) = 0xf, /*!< Odd */ 64 | _QBDI_EI(CONDITION_OVERFLOW) = 0x10, /*!< Overflow */ 65 | _QBDI_EI(CONDITION_NOT_OVERFLOW) = 0x11, /*!< Not Overflow */ 66 | _QBDI_EI(CONDITION_SIGN) = 0x12, /*!< Sign */ 67 | _QBDI_EI(CONDITION_NOT_SIGN) = 0x13, /*!< Not Sign */ 68 | } ConditionType; 69 | 70 | /*! Operand type 71 | */ 72 | typedef enum { 73 | _QBDI_EI(OPERAND_INVALID) = 0, /*!< Invalid operand */ 74 | _QBDI_EI(OPERAND_IMM), /*!< Immediate operand */ 75 | _QBDI_EI(OPERAND_GPR), /*!< Register operand */ 76 | _QBDI_EI(OPERAND_PRED), /*!< Predicate operand */ 77 | _QBDI_EI(OPERAND_FPR), /*!< Float register operand */ 78 | _QBDI_EI(OPERAND_SEG), /*!< Segment or unsupported register operand */ 79 | } OperandType; 80 | 81 | typedef enum { 82 | _QBDI_EI(OPERANDFLAG_NONE) = 0, /*!< No flag */ 83 | _QBDI_EI(OPERANDFLAG_ADDR) = 1 << 0, /*!< The operand is used to 84 | * compute an address 85 | */ 86 | _QBDI_EI(OPERANDFLAG_PCREL) = 1 << 1, /*!< The value of the 87 | * operand is PC relative 88 | */ 89 | _QBDI_EI(OPERANDFLAG_UNDEFINED_EFFECT) = 1 << 2, /*!< The operand role isn't 90 | * fully defined 91 | */ 92 | _QBDI_EI(OPERANDFLAG_IMPLICIT) = 1 << 3, /*!< The operand is implicit 93 | */ 94 | } OperandFlag; 95 | 96 | _QBDI_ENABLE_BITMASK_OPERATORS(OperandFlag) 97 | 98 | /*! Structure containing analysis results of an operand provided by the VM. 99 | */ 100 | typedef struct { 101 | // Common fields 102 | OperandType type; /*!< Operand type */ 103 | OperandFlag flag; /*!< Operand flag */ 104 | sword value; /*!< Operand value (if immediate), or register Id */ 105 | uint8_t size; /*!< Operand size (in bytes) */ 106 | // Register specific fields 107 | uint8_t regOff; /*!< Sub-register offset in register (in bits) */ 108 | int16_t regCtxIdx; /*!< Register index in VM state (< 0 if not know) */ 109 | const char *regName; /*!< Register name */ 110 | RegisterAccessType regAccess; /*!< Register access type (r, w, rw) */ 111 | } OperandAnalysis; 112 | 113 | /*! Instruction analysis type 114 | */ 115 | typedef enum { 116 | _QBDI_EI(ANALYSIS_INSTRUCTION) = 1, /*!< Instruction analysis (address, 117 | * mnemonic, ...) 118 | */ 119 | _QBDI_EI(ANALYSIS_DISASSEMBLY) = 1 << 1, /*!< Instruction disassembly */ 120 | _QBDI_EI(ANALYSIS_OPERANDS) = 1 << 2, /*!< Instruction operands analysis */ 121 | _QBDI_EI(ANALYSIS_SYMBOL) = 1 << 3, /*!< Instruction symbol */ 122 | } AnalysisType; 123 | 124 | _QBDI_ENABLE_BITMASK_OPERATORS(AnalysisType) 125 | 126 | /*! Structure containing analysis results of an instruction provided by the VM. 127 | */ 128 | typedef struct { 129 | // ANALYSIS_INSTRUCTION 130 | const char *mnemonic; /*!< LLVM mnemonic 131 | * (warning: NULL if !ANALYSIS_INSTRUCTION) 132 | */ 133 | rword address; /*!< Instruction address */ 134 | uint32_t instSize; /*!< Instruction size (in bytes) */ 135 | CPUMode cpuMode; /*!< Instruction CPU mode */ 136 | bool affectControlFlow; /*!< true if instruction affects control flow */ 137 | bool isBranch; /*!< true if instruction acts like a 'jump' */ 138 | bool isCall; /*!< true if instruction acts like a 'call' */ 139 | bool isReturn; /*!< true if instruction acts like a 'return' */ 140 | bool isCompare; /*!< true if instruction is a comparison */ 141 | bool isPredicable; /*!< true if instruction contains a predicate 142 | * (~is conditional) 143 | */ 144 | bool isMoveImm; /*!< true if this instruction is a move immediate 145 | * (including conditional moves) instruction. 146 | */ 147 | bool mayLoad; /*!< true if QBDI detects a load for this instruction */ 148 | bool mayStore; /*!< true if QBDI detects a store for this instruction */ 149 | uint32_t loadSize; /*!< size of the expected read access, 150 | * may be 0 with mayLoad if the size isn't 151 | * determined 152 | */ 153 | uint32_t storeSize; /*!< size of the expected write access, 154 | * may be 0 with mayStore if the size isn't 155 | * determined 156 | */ 157 | ConditionType condition; /*!< Condition associated with the instruction */ 158 | bool mayLoad_LLVM; // mayLoad of 0.7.1 159 | bool mayStore_LLVM; // mayStore of 0.7.1 160 | // ANALYSIS_DISASSEMBLY 161 | char *disassembly; /*!< Instruction disassembly 162 | * (warning: NULL if !ANALYSIS_DISASSEMBLY) */ 163 | // ANALYSIS_OPERANDS 164 | RegisterAccessType flagsAccess; /*!< Flag access type (noaccess, r, w, rw) 165 | * (warning: REGISTER_UNUSED if 166 | * !ANALYSIS_OPERANDS) 167 | */ 168 | uint8_t numOperands; /*!< Number of operands used by the 169 | * instruction 170 | */ 171 | OperandAnalysis *operands; /*!< Structure containing analysis results 172 | * of an operand provided by the VM. 173 | * (warning: NULL if !ANALYSIS_OPERANDS) */ 174 | // ANALYSIS_SYMBOL 175 | const char *symbol; /*!< Instruction symbol 176 | * (warning: NULL if !ANALYSIS_SYMBOL or not found) 177 | */ 178 | uint32_t symbolOffset; /*!< Instruction symbol offset */ 179 | const char *module; /*!< Instruction module name 180 | * (warning: NULL if !ANALYSIS_SYMBOL or not found) 181 | */ 182 | // INTERNAL 183 | uint32_t analysisType; /*!< INTERNAL: Instruction analysis type 184 | * (this should NOT be used) 185 | */ 186 | } InstAnalysis; 187 | 188 | #ifdef __cplusplus 189 | } 190 | #endif 191 | 192 | #endif // QBDI_INSTANALYSIS_H_ 193 | -------------------------------------------------------------------------------- /app/src/main/cpp/QBDI/Logs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of QBDI. 3 | * 4 | * Copyright 2017 - 2023 Quarkslab 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | #ifndef QBDI_LOGS_H_ 19 | #define QBDI_LOGS_H_ 20 | 21 | #include 22 | #include "QBDI/Platform.h" 23 | 24 | #ifdef __cplusplus 25 | #include 26 | #endif 27 | 28 | #ifdef __cplusplus 29 | namespace QBDI { 30 | extern "C" { 31 | #endif 32 | 33 | /*! Each log has a priority (or level) which can be used to control verbosity. 34 | * In production builds, only Warning and Error logs are kept. 35 | */ 36 | typedef enum { 37 | _QBDI_EI(DEBUG) = 0, /*!< Debug logs */ 38 | _QBDI_EI(INFO), /*!< Info logs (default) */ 39 | _QBDI_EI(WARNING), /*!< Warning logs */ 40 | _QBDI_EI(ERROR), /*!< Error logs */ 41 | _QBDI_EI(DISABLE) = 0xff, /*!< Disable logs message */ 42 | } LogPriority; 43 | 44 | /*! Redirect logs to a file. 45 | * 46 | * @param[in] filename the path of the file to append the log 47 | * @param[in] truncate Set to true to clear the file before append the log 48 | */ 49 | QBDI_EXPORT void qbdi_setLogFile(const char *filename, bool truncate); 50 | 51 | /*! Write log to the console (stderr) 52 | */ 53 | QBDI_EXPORT void qbdi_setLogConsole(); 54 | 55 | /*! Write log to the default location (stderr for linux, android_logger for 56 | * android) 57 | */ 58 | QBDI_EXPORT void qbdi_setLogDefault(); 59 | 60 | /*! Enable logs matching priority. 61 | * 62 | * @param[in] priority Filter logs with greater or equal priority. 63 | */ 64 | QBDI_EXPORT void qbdi_setLogPriority(LogPriority priority); 65 | 66 | #ifdef __cplusplus 67 | 68 | /* 69 | * C API C++ bindings 70 | */ 71 | 72 | /*! Redirect logs to a file. 73 | * 74 | * @param[in] filename the path of the file to append the log 75 | * @param[in] truncate Set to true to clear the file before append the log 76 | */ 77 | QBDI_EXPORT void setLogFile(const std::string &filename, bool truncate = false); 78 | 79 | /*! Enable logs matching priority. 80 | * 81 | * @param[in] priority Filter logs with greater or equal priority. 82 | */ 83 | inline void setLogPriority(LogPriority priority = LogPriority::INFO) { 84 | return qbdi_setLogPriority(priority); 85 | } 86 | 87 | /*! Write log to the console (stderr) 88 | */ 89 | inline void setLogConsole() { return qbdi_setLogConsole(); } 90 | 91 | /*! Write log to the default location (stderr for linux, android_logger for 92 | * android) 93 | */ 94 | inline void setLogDefault() { return qbdi_setLogDefault(); } 95 | 96 | } // "C" 97 | 98 | } // QBDI:: 99 | #endif 100 | 101 | #endif // QBDI_LOGS_H_ 102 | -------------------------------------------------------------------------------- /app/src/main/cpp/QBDI/Memory.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of QBDI. 3 | * 4 | * Copyright 2017 - 2023 Quarkslab 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | #ifndef QBDI_MEMORY_H_ 19 | #define QBDI_MEMORY_H_ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "QBDI/Platform.h" 26 | #include "QBDI/State.h" 27 | 28 | #ifdef __cplusplus 29 | namespace QBDI { 30 | extern "C" { 31 | #endif 32 | 33 | /*! Memory access rights. 34 | */ 35 | typedef enum { 36 | QBDI_PF_NONE = 0, /*!< No access */ 37 | QBDI_PF_READ = 1, /*!< Read access */ 38 | QBDI_PF_WRITE = 2, /*!< Write access */ 39 | QBDI_PF_EXEC = 4 /*!< Execution access */ 40 | } qbdi_Permission; 41 | 42 | /*! Map of a memory area (region). 43 | */ 44 | typedef struct { 45 | rword start; /*!< Range start value. */ 46 | rword end; /*!< Range end value (always excluded). */ 47 | qbdi_Permission permission; /*!< Region access rights 48 | * (PF_READ, PF_WRITE, PF_EXEC). 49 | */ 50 | char *name; /*!< Region name or path (useful when a region 51 | * is mapping a module). 52 | */ 53 | } qbdi_MemoryMap; 54 | 55 | /*! Get a list of all the memory maps (regions) of a process. 56 | * 57 | * @param[in] pid The identifier of the process. 58 | * @param[in] full_path Return the full path of the module in name field 59 | * @param[out] size Will be set to the number of strings in the returned array. 60 | * 61 | * @return An array of MemoryMap object. 62 | */ 63 | QBDI_EXPORT qbdi_MemoryMap *qbdi_getRemoteProcessMaps(rword pid, bool full_path, 64 | size_t *size); 65 | 66 | /*! Get a list of all the memory maps (regions) of the current process. 67 | * 68 | * @param[in] full_path Return the full path of the module in name field 69 | * @param[out] size Will be set to the number of strings in the returned array. 70 | * 71 | * @return An array of MemoryMap object. 72 | */ 73 | QBDI_EXPORT qbdi_MemoryMap *qbdi_getCurrentProcessMaps(bool full_path, 74 | size_t *size); 75 | 76 | /*! Free an array of memory maps objects. 77 | * 78 | * @param[in] arr An array of MemoryMap object. 79 | * @param[in] size Number of elements in the array. 80 | */ 81 | QBDI_EXPORT void qbdi_freeMemoryMapArray(qbdi_MemoryMap *arr, size_t size); 82 | 83 | /*! Get a list of all the module names loaded in the process memory. 84 | * If no modules are found, size is set to 0 and this function returns NULL. 85 | * 86 | * @param[out] size Will be set to the number of strings in the returned 87 | * array. 88 | * 89 | * @return An array of C strings, each one containing the name of a loaded 90 | * module. This array needs to be free'd by the caller by repetively 91 | * calling free() on each of its element then finally on the array 92 | * itself. 93 | */ 94 | QBDI_EXPORT char **qbdi_getModuleNames(size_t *size); 95 | 96 | /*! Allocate a block of memory of a specified sized with an aligned base 97 | * address. 98 | * 99 | * @param[in] size Allocation size in bytes. 100 | * @param[in] align Base address alignement in bytes. 101 | * 102 | * @return Pointer to the allocated memory or NULL in case an error was 103 | * encountered. 104 | * 105 | */ 106 | QBDI_EXPORT void *qbdi_alignedAlloc(size_t size, size_t align); 107 | 108 | /*! Free a block of aligned memory allocated with alignedAlloc. 109 | * 110 | * @param[in] ptr Pointer to the allocated memory. 111 | * 112 | */ 113 | QBDI_EXPORT void qbdi_alignedFree(void *ptr); 114 | 115 | /*! Allocate a new stack and setup the GPRState accordingly. 116 | * The allocated stack needs to be freed with alignedFree(). 117 | * 118 | * @param[in] ctx GPRState which will be setup to use the new stack. 119 | * @param[in] stackSize Size of the stack to be allocated. 120 | * @param[out] stack The newly allocated stack pointer will be returned 121 | * in the variable pointed by stack. 122 | * 123 | * @return True if stack allocation was successfull. 124 | */ 125 | QBDI_EXPORT bool qbdi_allocateVirtualStack(GPRState *ctx, uint32_t stackSize, 126 | uint8_t **stack); 127 | 128 | /*! Simulate a call by modifying the stack and registers accordingly. 129 | * 130 | * @param[in] ctx GPRState where the simulated call will be setup. 131 | * The state needs to point to a valid stack for 132 | * example setup with allocateVirtualStack(). 133 | * @param[in] returnAddress Return address of the call to simulate. 134 | * @param[in] argNum The number of arguments in the variadic list. 135 | * @param[in] ... A variadic list of arguments. 136 | */ 137 | QBDI_EXPORT void qbdi_simulateCall(GPRState *ctx, rword returnAddress, 138 | uint32_t argNum, ...); 139 | 140 | /*! Simulate a call by modifying the stack and registers accordingly 141 | * (stdarg version). 142 | * 143 | * @param[in] ctx GPRState where the simulated call will be setup. 144 | * The state needs to point to a valid stack 145 | * for example setup with allocateVirtualStack(). 146 | * @param[in] returnAddress Return address of the call to simulate. 147 | * @param[in] argNum The number of arguments in the va_list object. 148 | * @param[in] ap An stdarg va_list object. 149 | */ 150 | QBDI_EXPORT void qbdi_simulateCallV(GPRState *ctx, rword returnAddress, 151 | uint32_t argNum, va_list ap); 152 | 153 | /*! Simulate a call by modifying the stack and registers accordingly 154 | * (C array version). 155 | * 156 | * @param[in] ctx GPRState where the simulated call will be setup. 157 | * The state needs to point to a valid stack for 158 | * example setup with allocateVirtualStack(). 159 | * @param[in] returnAddress Return address of the call to simulate. 160 | * @param[in] argNum The number of arguments in the array args. 161 | * @param[in] args An array or arguments. 162 | */ 163 | QBDI_EXPORT void qbdi_simulateCallA(GPRState *ctx, rword returnAddress, 164 | uint32_t argNum, const rword *args); 165 | 166 | #ifdef __cplusplus 167 | } 168 | } 169 | #endif 170 | 171 | #endif // QBDI_MEMORY_H_ 172 | -------------------------------------------------------------------------------- /app/src/main/cpp/QBDI/Memory.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of QBDI. 3 | * 4 | * Copyright 2017 - 2023 Quarkslab 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | #ifndef QBDI_MEMORY_HPP_ 19 | #define QBDI_MEMORY_HPP_ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "QBDI/Bitmask.h" 28 | #include "QBDI/Platform.h" 29 | #include "QBDI/Range.h" 30 | #include "QBDI/State.h" 31 | 32 | namespace QBDI { 33 | 34 | /*! Memory access rights. 35 | */ 36 | typedef enum { 37 | PF_NONE = 0, /*!< No access */ 38 | PF_READ = 1, /*!< Read access */ 39 | PF_WRITE = 2, /*!< Write access */ 40 | PF_EXEC = 4 /*!< Execution access */ 41 | } Permission; 42 | 43 | _QBDI_ENABLE_BITMASK_OPERATORS(Permission) 44 | 45 | /*! Map of a memory area (region). 46 | */ 47 | struct MemoryMap { 48 | 49 | Range range; /*!< A range of memory (region), delimited between 50 | * a start and an (excluded) end address. 51 | */ 52 | Permission permission; /*!< Region access rights 53 | * (PF_READ, PF_WRITE, PF_EXEC). 54 | */ 55 | std::string name; /*!< Region name or path (useful when a region 56 | * is mapping a module). 57 | */ 58 | 59 | /* Construct a new (empty) MemoryMap. 60 | */ 61 | MemoryMap() : range(0, 0), permission(QBDI::PF_NONE){}; 62 | 63 | /*! Construct a new MemoryMap (given some properties). 64 | * 65 | * @param[in] start Range start value. 66 | * @param[in] end Range end value (always excluded). 67 | * @param[in] permission Region access rights (PF_READ, PF_WRITE, PF_EXEC). 68 | * @param[in] name Region name (useful when a region is mapping 69 | * a module). 70 | */ 71 | MemoryMap(rword start, rword end, Permission permission, std::string name) 72 | : range(start, end), permission(permission), name(name) {} 73 | 74 | /*! Construct a new MemoryMap (given some properties). 75 | * 76 | * @param[in] range A range of memory (region), delimited between 77 | * a start and an (excluded) end address. 78 | * @param[in] permission Region access rights (PF_READ, PF_WRITE, PF_EXEC). 79 | * @param[in] name Region name (useful when a region is mapping 80 | * a module). 81 | */ 82 | MemoryMap(Range range, Permission permission, std::string name) 83 | : range(range), permission(permission), name(name) {} 84 | }; 85 | 86 | /*! Get a list of all the memory maps (regions) of a process. 87 | * 88 | * @param[in] pid The identifier of the process. 89 | * @param[in] full_path Return the full path of the module in name field 90 | * 91 | * @return A vector of MemoryMap object. 92 | */ 93 | QBDI_EXPORT std::vector getRemoteProcessMaps(QBDI::rword pid, 94 | bool full_path = false); 95 | 96 | /*! Get a list of all the memory maps (regions) of the current process. 97 | * 98 | * @param[in] full_path Return the full path of the module in name field 99 | * @return A vector of MemoryMap object. 100 | */ 101 | QBDI_EXPORT std::vector 102 | getCurrentProcessMaps(bool full_path = false); 103 | 104 | /*! Get a list of all the module names loaded in the process memory. 105 | * 106 | * @return A vector of string of module names. 107 | */ 108 | QBDI_EXPORT std::vector getModuleNames(); 109 | 110 | /*! Allocate a block of memory of a specified sized with an aligned base 111 | * address. 112 | * 113 | * @param[in] size Allocation size in bytes. 114 | * @param[in] align Base address alignement in bytes. 115 | * 116 | * @return Pointer to the allocated memory or NULL in case an error was 117 | * encountered. 118 | * 119 | */ 120 | QBDI_EXPORT void *alignedAlloc(size_t size, size_t align); 121 | 122 | /*! Free a block of aligned memory allocated with alignedAlloc. 123 | * 124 | * @param[in] ptr Pointer to the allocated memory. 125 | * 126 | */ 127 | QBDI_EXPORT void alignedFree(void *ptr); 128 | 129 | /*! Allocate a new stack and setup the GPRState accordingly. 130 | * The allocated stack needs to be freed with alignedFree(). 131 | * 132 | * @param[in] ctx GPRState which will be setup to use the new stack. 133 | * @param[in] stackSize Size of the stack to be allocated. 134 | * @param[out] stack The newly allocated stack pointer will be returned in 135 | * the variable pointed by stack. 136 | * 137 | * @return True if stack allocation was successfull. 138 | */ 139 | QBDI_EXPORT bool allocateVirtualStack(GPRState *ctx, uint32_t stackSize, 140 | uint8_t **stack); 141 | 142 | /*! Simulate a call by modifying the stack and registers accordingly 143 | * (std::vector version). 144 | * 145 | * @param[in] ctx GPRState where the simulated call will be setup. 146 | * The state needs to point to a valid stack for 147 | * example setup with allocateVirtualStack(). 148 | * @param[in] returnAddress Return address of the call to simulate. 149 | * @param[in] args A list of arguments. 150 | */ 151 | QBDI_EXPORT void simulateCall(GPRState *ctx, rword returnAddress, 152 | const std::vector &args = {}); 153 | 154 | /*! Simulate a call by modifying the stack and registers accordingly 155 | * (stdarg version). 156 | * 157 | * @param[in] ctx GPRState where the simulated call will be setup. 158 | * The state needs to point to a valid stack for 159 | * example setup with allocateVirtualStack(). 160 | * @param[in] returnAddress Return address of the call to simulate. 161 | * @param[in] argNum The number of arguments in the va_list object. 162 | * @param[in] ap An stdarg va_list object. 163 | */ 164 | QBDI_EXPORT void simulateCallV(GPRState *ctx, rword returnAddress, 165 | uint32_t argNum, va_list ap); 166 | 167 | /*! Simulate a call by modifying the stack and registers accordingly 168 | * (C array version). 169 | * 170 | * @param[in] ctx GPRState where the simulated call will be setup. 171 | * The state needs to point to a valid stack for 172 | * example setup with allocateVirtualStack(). 173 | * @param[in] returnAddress Return address of the call to simulate. 174 | * @param[in] argNum The number of arguments in the array args. 175 | * @param[in] args An array or arguments. 176 | */ 177 | QBDI_EXPORT void simulateCallA(GPRState *ctx, rword returnAddress, 178 | uint32_t argNum, const rword *args); 179 | 180 | } // namespace QBDI 181 | 182 | #endif // QBDI_MEMORY_HPP_ 183 | -------------------------------------------------------------------------------- /app/src/main/cpp/QBDI/Options.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of QBDI. 3 | * 4 | * Copyright 2017 - 2023 Quarkslab 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | #ifndef QBDI_OPTION_AARCH64_H_ 19 | #define QBDI_OPTION_AARCH64_H_ 20 | 21 | #include 22 | 23 | #include "QBDI/Bitmask.h" 24 | #include "QBDI/Platform.h" 25 | 26 | #ifdef __cplusplus 27 | namespace QBDI { 28 | #endif 29 | 30 | typedef enum { 31 | _QBDI_EI(NO_OPT) = 0, /*!< Default value */ 32 | // general options between 0 and 23 33 | _QBDI_EI(OPT_DISABLE_FPR) = 1 << 0, /*!< Disable all operation on FPU 34 | * (SSE, AVX, SIMD). May break 35 | * the execution if the target 36 | * use the FPU 37 | */ 38 | _QBDI_EI(OPT_DISABLE_OPTIONAL_FPR) = 1 << 1, /*!< Disable context switch 39 | * optimisation when the target 40 | * execblock doesn't used FPR 41 | */ 42 | // architecture specific option between 24 and 31 43 | _QBDI_EI(OPT_DISABLE_LOCAL_MONITOR) = 44 | 1 << 24, /*!< Disable the local monitor for instruction like stxr */ 45 | _QBDI_EI(OPT_BYPASS_PAUTH) = 1 << 25, /*!< Disable pointeur authentication */ 46 | _QBDI_EI(OPT_ENABLE_BTI) = 1 << 26, /*!< Enable BTI on instrumented code*/ 47 | } Options; 48 | 49 | _QBDI_ENABLE_BITMASK_OPERATORS(Options) 50 | 51 | #ifdef __cplusplus 52 | } 53 | #endif 54 | 55 | #endif /* QBDI_OPTION_AARCH64_H_ */ 56 | -------------------------------------------------------------------------------- /app/src/main/cpp/QBDI/Platform.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of QBDI. 3 | * 4 | * Copyright 2017 - 2023 Quarkslab 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | #ifndef QBDI_PLATFORM_H_ 19 | #define QBDI_PLATFORM_H_ 20 | 21 | #include "QBDI/Config.h" 22 | 23 | #ifdef QBDI_PLATFORM_WINDOWS 24 | #define QBDI_ALIGNED(n) __declspec(align(n)) 25 | #define QBDI_NOINLINE __declspec(noinline) 26 | #define QBDI_NOSTACKPROTECTOR 27 | #define _QBDI_FORCE_USE 28 | #define _QBDI_UNREACHABLE() __assume(0) 29 | #define QBDI_DISABLE_ASAN __declspec(no_sanitize_address) 30 | #define QBDI_FORCE_EXPORT __declspec(dllexport) 31 | #else 32 | #define QBDI_ALIGNED(n) __attribute__((aligned(n))) 33 | #define QBDI_NOINLINE __attribute__((noinline)) 34 | #define QBDI_NOSTACKPROTECTOR __attribute__((no_stack_protector)) 35 | #define _QBDI_FORCE_USE __attribute__((__used__)) 36 | #define _QBDI_UNREACHABLE() __builtin_unreachable() 37 | #define QBDI_DISABLE_ASAN __attribute__((no_sanitize_address)) 38 | #define QBDI_FORCE_EXPORT __attribute__((visibility("default"))) 39 | #endif 40 | 41 | #ifdef QBDI_EXPORT_SYM 42 | #define QBDI_EXPORT QBDI_FORCE_EXPORT 43 | #else 44 | #define QBDI_EXPORT 45 | #endif 46 | 47 | #if defined(__has_feature) 48 | #if __has_feature(address_sanitizer) 49 | #define _QBDI_ASAN_ENABLED_ 50 | #endif 51 | #endif 52 | 53 | #ifdef __cplusplus 54 | #define _QBDI_EI(X) X 55 | #else 56 | #define _QBDI_EI(X) QBDI_##X 57 | #endif 58 | 59 | #endif // QBDI_PLATFORM_H_ 60 | -------------------------------------------------------------------------------- /app/src/main/cpp/QBDI/State.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of QBDI. 3 | * 4 | * Copyright 2017 - 2023 Quarkslab 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | #ifndef QBDI_STATE_AARCH64_H_ 19 | #define QBDI_STATE_AARCH64_H_ 20 | 21 | #ifdef __cplusplus 22 | #include 23 | #endif 24 | #include 25 | #include 26 | #include "QBDI/Platform.h" 27 | 28 | // ============================================================================ 29 | // AARCH64 Context 30 | // ============================================================================ 31 | 32 | #define PRIRWORD PRIx64 33 | 34 | #define QBDI_NUM_FPR 32 35 | 36 | #ifdef __cplusplus 37 | namespace QBDI { 38 | #endif // __cplusplus 39 | 40 | /*! ARM CPU modes. 41 | */ 42 | typedef enum { AARCH64 = 0, DEFAULT = 0, COUNT } CPUMode; 43 | 44 | typedef uint64_t rword; 45 | typedef int64_t sword; 46 | 47 | // SPHINX_AARCH64_FPRSTATE_BEGIN 48 | /*! ARM Floating Point Register context. 49 | */ 50 | typedef struct QBDI_ALIGNED(8) { 51 | __uint128_t v0; 52 | __uint128_t v1; 53 | __uint128_t v2; 54 | __uint128_t v3; 55 | 56 | __uint128_t v4; 57 | __uint128_t v5; 58 | __uint128_t v6; 59 | __uint128_t v7; 60 | 61 | __uint128_t v8; 62 | __uint128_t v9; 63 | __uint128_t v10; 64 | __uint128_t v11; 65 | 66 | __uint128_t v12; 67 | __uint128_t v13; 68 | __uint128_t v14; 69 | __uint128_t v15; 70 | 71 | __uint128_t v16; 72 | __uint128_t v17; 73 | __uint128_t v18; 74 | __uint128_t v19; 75 | 76 | __uint128_t v20; 77 | __uint128_t v21; 78 | __uint128_t v22; 79 | __uint128_t v23; 80 | 81 | __uint128_t v24; 82 | __uint128_t v25; 83 | __uint128_t v26; 84 | __uint128_t v27; 85 | 86 | __uint128_t v28; 87 | __uint128_t v29; 88 | __uint128_t v30; 89 | __uint128_t v31; 90 | 91 | rword fpcr; 92 | rword fpsr; 93 | } FPRState; 94 | // SPHINX_AARCH64_FPRSTATE_END 95 | 96 | // SPHINX_AARCH64_GPRSTATE_BEGIN 97 | /*! ARM General Purpose Register context. 98 | */ 99 | typedef struct QBDI_ALIGNED(8) { 100 | rword x0; 101 | rword x1; 102 | rword x2; 103 | rword x3; 104 | rword x4; 105 | rword x5; 106 | rword x6; 107 | rword x7; 108 | rword x8; 109 | rword x9; 110 | rword x10; 111 | rword x11; 112 | rword x12; 113 | rword x13; 114 | rword x14; 115 | rword x15; 116 | rword x16; 117 | rword x17; 118 | rword x18; 119 | rword x19; 120 | rword x20; 121 | rword x21; 122 | rword x22; 123 | rword x23; 124 | rword x24; 125 | rword x25; 126 | rword x26; 127 | rword x27; 128 | rword x28; 129 | rword x29; // FP (x29) 130 | rword lr; // LR (x30) 131 | 132 | rword sp; 133 | rword nzcv; 134 | rword pc; 135 | // ? rword daif; ? 136 | 137 | /* Internal CPU state 138 | * Local monitor state for exclusive load/store instruction 139 | */ 140 | struct { 141 | rword addr; 142 | rword enable; /* 0=>disable, 1=>exclusive state, use a rword to not break 143 | align */ 144 | } localMonitor; 145 | 146 | } GPRState; 147 | // SPHINX_AARCH64_GPRSTATE_END 148 | 149 | static const char *const GPR_NAMES[] = { 150 | "X0", "X1", "X2", "X3", "X4", "X5", "X6", "X7", "X8", "X9", 151 | "X10", "X11", "X12", "X13", "X14", "X15", "X16", "X17", "X18", "X19", 152 | "X20", "X21", "X22", "X23", "X24", "X25", "X26", "X27", "X28", 153 | "X29", // FP 154 | "LR", 155 | 156 | "SP", "NZCV", "PC", 157 | }; 158 | 159 | static const unsigned int NUM_GPR = 32; 160 | static const unsigned int AVAILABLE_GPR = 28; 161 | static const unsigned int REG_RETURN = 0; 162 | static const unsigned int REG_BP = 29; 163 | static const unsigned int REG_LR = 30; 164 | static const unsigned int REG_SP = 31; 165 | static const unsigned int REG_PC = 33; 166 | static const unsigned int REG_FLAG = 32; 167 | 168 | #ifdef __cplusplus 169 | #define QBDI_GPR_GET(state, i) (reinterpret_cast(state)[i]) 170 | #define QBDI_GPR_SET(state, i, v) \ 171 | (reinterpret_cast(state)[i] = v) 172 | #else 173 | #define QBDI_GPR_GET(state, i) (((rword *)state)[i]) 174 | #define QBDI_GPR_SET(state, i, v) (((rword *)state)[i] = v) 175 | #endif 176 | 177 | #ifdef __cplusplus 178 | } // namespace QBDI 179 | #endif // __cplusplus 180 | 181 | #endif // QBDI_STATE_AARCH64_H_ 182 | -------------------------------------------------------------------------------- /app/src/main/cpp/QBDI/Version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of QBDI. 3 | * 4 | * Copyright 2017 - 2023 Quarkslab 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | #ifndef QBDI_VERSION_H_ 19 | #define QBDI_VERSION_H_ 20 | 21 | #include 22 | #include "QBDI/Platform.h" 23 | 24 | #ifdef __cplusplus 25 | namespace QBDI { 26 | extern "C" { 27 | #endif 28 | 29 | #define QBDI_VERSION ((0 << 16 ) | \ 30 | (10 << 8 ) | \ 31 | (0 << 0 )) 32 | #define QBDI_VERSION_STRING "0.10.0" 33 | 34 | #define QBDI_VERSION_MAJOR 0 35 | #define QBDI_VERSION_MINOR 10 36 | #define QBDI_VERSION_PATCH 0 37 | #define QBDI_VERSION_DEV 0 38 | 39 | #define QBDI_ARCHITECTURE_STRING "AARCH64" 40 | #define QBDI_PLATFORM_STRING "android" 41 | 42 | /*! Return QBDI version. 43 | * 44 | * @param[out] version QBDI version encoded as an unsigned integer (0xMMmmpp). 45 | * @return QBDI version as a string (major.minor.patch). 46 | */ 47 | QBDI_EXPORT const char* qbdi_getVersion(uint32_t* version); 48 | 49 | #ifdef __cplusplus 50 | /*! Return QBDI version. 51 | * 52 | * @param[out] version QBDI version encoded as an unsigned integer (0xMMmmpp). 53 | * @return QBDI version as a string (major.minor.patch). 54 | */ 55 | inline const char* getVersion(uint32_t* version) { 56 | return qbdi_getVersion(version); 57 | } 58 | 59 | } // "C" 60 | } // QBDI:: 61 | #endif 62 | 63 | #endif // QBDI_VERSION_H_ 64 | -------------------------------------------------------------------------------- /app/src/main/cpp/demo/il2cpp-class.h: -------------------------------------------------------------------------------- 1 | #ifndef IL2CPP_CLASS 2 | #define IL2CPP_CLASS 3 | 4 | typedef uint16_t Il2CppChar; 5 | typedef uintptr_t il2cpp_array_size_t; 6 | typedef int32_t TypeDefinitionIndex; 7 | typedef int32_t GenericParameterIndex; 8 | typedef char Il2CppNativeChar; 9 | 10 | typedef struct Il2CppMemoryCallbacks Il2CppMemoryCallbacks; 11 | typedef struct Il2CppImage Il2CppImage; 12 | typedef struct Il2CppClass Il2CppClass; 13 | typedef struct Il2CppArrayBounds Il2CppArrayBounds; 14 | typedef struct Il2CppAssembly Il2CppAssembly; 15 | typedef struct Il2CppArrayType Il2CppArrayType; 16 | typedef struct Il2CppGenericClass Il2CppGenericClass; 17 | typedef struct Il2CppReflectionType Il2CppReflectionType; 18 | typedef struct MonitorData MonitorData; 19 | typedef Il2CppClass Il2CppVTable; 20 | typedef struct EventInfo EventInfo; 21 | typedef struct FieldInfo FieldInfo; 22 | typedef struct PropertyInfo PropertyInfo; 23 | typedef struct Il2CppDomain Il2CppDomain; 24 | typedef struct Il2CppException Il2CppException; 25 | typedef struct Il2CppObject Il2CppObject; 26 | typedef struct Il2CppReflectionMethod Il2CppReflectionMethod; 27 | typedef struct Il2CppString Il2CppString; 28 | typedef struct Il2CppThread Il2CppThread; 29 | typedef struct Il2CppStackFrameInfo Il2CppStackFrameInfo; 30 | typedef struct Il2CppManagedMemorySnapshot Il2CppManagedMemorySnapshot; 31 | typedef struct Il2CppDebuggerTransport Il2CppDebuggerTransport; 32 | typedef struct Il2CppMethodDebugInfo Il2CppMethodDebugInfo; 33 | typedef struct Il2CppCustomAttrInfo Il2CppCustomAttrInfo; 34 | typedef const struct ___Il2CppMetadataTypeHandle *Il2CppMetadataTypeHandle; 35 | typedef const struct ___Il2CppMetadataGenericParameterHandle *Il2CppMetadataGenericParameterHandle; 36 | 37 | typedef void (*Il2CppMethodPointer)(); 38 | 39 | typedef void (*il2cpp_register_object_callback)(Il2CppObject **arr, int size, void *userdata); 40 | 41 | typedef void *(*il2cpp_liveness_reallocate_callback)(void *ptr, size_t size, void *userdata); 42 | 43 | typedef void (*Il2CppFrameWalkFunc)(const Il2CppStackFrameInfo *info, void *user_data); 44 | 45 | typedef size_t(*Il2CppBacktraceFunc)(Il2CppMethodPointer *buffer, size_t maxSize); 46 | 47 | typedef const Il2CppNativeChar *(*Il2CppSetFindPlugInCallback)(const Il2CppNativeChar *); 48 | 49 | typedef void (*Il2CppLogCallback)(const char *); 50 | 51 | typedef enum { 52 | IL2CPP_UNHANDLED_POLICY_LEGACY, 53 | IL2CPP_UNHANDLED_POLICY_CURRENT 54 | } Il2CppRuntimeUnhandledExceptionPolicy; 55 | 56 | typedef enum { 57 | IL2CPP_GC_MODE_DISABLED = 0, 58 | IL2CPP_GC_MODE_ENABLED = 1, 59 | IL2CPP_GC_MODE_MANUAL = 2 60 | } Il2CppGCMode; 61 | 62 | typedef enum Il2CppStat { 63 | IL2CPP_STAT_NEW_OBJECT_COUNT, 64 | IL2CPP_STAT_INITIALIZED_CLASS_COUNT, 65 | IL2CPP_STAT_METHOD_COUNT, 66 | IL2CPP_STAT_CLASS_STATIC_DATA_SIZE, 67 | IL2CPP_STAT_GENERIC_INSTANCE_COUNT, 68 | IL2CPP_STAT_GENERIC_CLASS_COUNT, 69 | IL2CPP_STAT_INFLATED_METHOD_COUNT, 70 | IL2CPP_STAT_INFLATED_TYPE_COUNT, 71 | } Il2CppStat; 72 | 73 | typedef enum Il2CppTypeEnum { 74 | IL2CPP_TYPE_END = 0x00, 75 | IL2CPP_TYPE_VOID = 0x01, 76 | IL2CPP_TYPE_BOOLEAN = 0x02, 77 | IL2CPP_TYPE_CHAR = 0x03, 78 | IL2CPP_TYPE_I1 = 0x04, 79 | IL2CPP_TYPE_U1 = 0x05, 80 | IL2CPP_TYPE_I2 = 0x06, 81 | IL2CPP_TYPE_U2 = 0x07, 82 | IL2CPP_TYPE_I4 = 0x08, 83 | IL2CPP_TYPE_U4 = 0x09, 84 | IL2CPP_TYPE_I8 = 0x0a, 85 | IL2CPP_TYPE_U8 = 0x0b, 86 | IL2CPP_TYPE_R4 = 0x0c, 87 | IL2CPP_TYPE_R8 = 0x0d, 88 | IL2CPP_TYPE_STRING = 0x0e, 89 | IL2CPP_TYPE_PTR = 0x0f, 90 | IL2CPP_TYPE_BYREF = 0x10, 91 | IL2CPP_TYPE_VALUETYPE = 0x11, 92 | IL2CPP_TYPE_CLASS = 0x12, 93 | IL2CPP_TYPE_VAR = 0x13, 94 | IL2CPP_TYPE_ARRAY = 0x14, 95 | IL2CPP_TYPE_GENERICINST = 0x15, 96 | IL2CPP_TYPE_TYPEDBYREF = 0x16, 97 | IL2CPP_TYPE_I = 0x18, 98 | IL2CPP_TYPE_U = 0x19, 99 | IL2CPP_TYPE_FNPTR = 0x1b, 100 | IL2CPP_TYPE_OBJECT = 0x1c, 101 | IL2CPP_TYPE_SZARRAY = 0x1d, 102 | IL2CPP_TYPE_MVAR = 0x1e, 103 | IL2CPP_TYPE_CMOD_REQD = 0x1f, 104 | IL2CPP_TYPE_CMOD_OPT = 0x20, 105 | IL2CPP_TYPE_INTERNAL = 0x21, 106 | IL2CPP_TYPE_MODIFIER = 0x40, 107 | IL2CPP_TYPE_SENTINEL = 0x41, 108 | IL2CPP_TYPE_PINNED = 0x45, 109 | IL2CPP_TYPE_ENUM = 0x55, 110 | IL2CPP_TYPE_IL2CPP_TYPE_INDEX = 0xff 111 | } Il2CppTypeEnum; 112 | 113 | typedef struct Il2CppType { 114 | union { 115 | void *dummy; 116 | TypeDefinitionIndex klassIndex; 117 | const Il2CppType *type; 118 | Il2CppArrayType *array; 119 | GenericParameterIndex genericParameterIndex; 120 | Il2CppGenericClass *generic_class; 121 | } data; 122 | unsigned int attrs: 16; 123 | Il2CppTypeEnum type: 8; 124 | unsigned int num_mods: 6; 125 | unsigned int byref: 1; 126 | unsigned int pinned: 1; 127 | } Il2CppType; 128 | 129 | typedef struct MethodInfo { 130 | Il2CppMethodPointer methodPointer; 131 | } MethodInfo; 132 | 133 | typedef struct Il2CppObject { 134 | union { 135 | Il2CppClass *klass; 136 | Il2CppVTable *vtable; 137 | }; 138 | MonitorData *monitor; 139 | } Il2CppObject; 140 | 141 | typedef struct Il2CppArray { 142 | Il2CppObject obj; 143 | Il2CppArrayBounds *bounds; 144 | il2cpp_array_size_t max_length; 145 | void *vector[32]; 146 | } Il2CppArray; 147 | 148 | #endif 149 | -------------------------------------------------------------------------------- /app/src/main/cpp/demo/il2cpp-tabledefs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | * Field Attributes (21.1.5). 5 | */ 6 | 7 | #define FIELD_ATTRIBUTE_FIELD_ACCESS_MASK 0x0007 8 | #define FIELD_ATTRIBUTE_COMPILER_CONTROLLED 0x0000 9 | #define FIELD_ATTRIBUTE_PRIVATE 0x0001 10 | #define FIELD_ATTRIBUTE_FAM_AND_ASSEM 0x0002 11 | #define FIELD_ATTRIBUTE_ASSEMBLY 0x0003 12 | #define FIELD_ATTRIBUTE_FAMILY 0x0004 13 | #define FIELD_ATTRIBUTE_FAM_OR_ASSEM 0x0005 14 | #define FIELD_ATTRIBUTE_PUBLIC 0x0006 15 | 16 | #define FIELD_ATTRIBUTE_STATIC 0x0010 17 | #define FIELD_ATTRIBUTE_INIT_ONLY 0x0020 18 | #define FIELD_ATTRIBUTE_LITERAL 0x0040 19 | #define FIELD_ATTRIBUTE_NOT_SERIALIZED 0x0080 20 | #define FIELD_ATTRIBUTE_SPECIAL_NAME 0x0200 21 | #define FIELD_ATTRIBUTE_PINVOKE_IMPL 0x2000 22 | 23 | /* For runtime use only */ 24 | #define FIELD_ATTRIBUTE_RESERVED_MASK 0x9500 25 | #define FIELD_ATTRIBUTE_RT_SPECIAL_NAME 0x0400 26 | #define FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL 0x1000 27 | #define FIELD_ATTRIBUTE_HAS_DEFAULT 0x8000 28 | #define FIELD_ATTRIBUTE_HAS_FIELD_RVA 0x0100 29 | 30 | /* 31 | * Method Attributes (22.1.9) 32 | */ 33 | 34 | #define METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK 0x0003 35 | #define METHOD_IMPL_ATTRIBUTE_IL 0x0000 36 | #define METHOD_IMPL_ATTRIBUTE_NATIVE 0x0001 37 | #define METHOD_IMPL_ATTRIBUTE_OPTIL 0x0002 38 | #define METHOD_IMPL_ATTRIBUTE_RUNTIME 0x0003 39 | 40 | #define METHOD_IMPL_ATTRIBUTE_MANAGED_MASK 0x0004 41 | #define METHOD_IMPL_ATTRIBUTE_UNMANAGED 0x0004 42 | #define METHOD_IMPL_ATTRIBUTE_MANAGED 0x0000 43 | 44 | #define METHOD_IMPL_ATTRIBUTE_FORWARD_REF 0x0010 45 | #define METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG 0x0080 46 | #define METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL 0x1000 47 | #define METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED 0x0020 48 | #define METHOD_IMPL_ATTRIBUTE_NOINLINING 0x0008 49 | #define METHOD_IMPL_ATTRIBUTE_MAX_METHOD_IMPL_VAL 0xffff 50 | 51 | #define METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK 0x0007 52 | #define METHOD_ATTRIBUTE_COMPILER_CONTROLLED 0x0000 53 | #define METHOD_ATTRIBUTE_PRIVATE 0x0001 54 | #define METHOD_ATTRIBUTE_FAM_AND_ASSEM 0x0002 55 | #define METHOD_ATTRIBUTE_ASSEM 0x0003 56 | #define METHOD_ATTRIBUTE_FAMILY 0x0004 57 | #define METHOD_ATTRIBUTE_FAM_OR_ASSEM 0x0005 58 | #define METHOD_ATTRIBUTE_PUBLIC 0x0006 59 | 60 | #define METHOD_ATTRIBUTE_STATIC 0x0010 61 | #define METHOD_ATTRIBUTE_FINAL 0x0020 62 | #define METHOD_ATTRIBUTE_VIRTUAL 0x0040 63 | #define METHOD_ATTRIBUTE_HIDE_BY_SIG 0x0080 64 | 65 | #define METHOD_ATTRIBUTE_VTABLE_LAYOUT_MASK 0x0100 66 | #define METHOD_ATTRIBUTE_REUSE_SLOT 0x0000 67 | #define METHOD_ATTRIBUTE_NEW_SLOT 0x0100 68 | 69 | #define METHOD_ATTRIBUTE_STRICT 0x0200 70 | #define METHOD_ATTRIBUTE_ABSTRACT 0x0400 71 | #define METHOD_ATTRIBUTE_SPECIAL_NAME 0x0800 72 | 73 | #define METHOD_ATTRIBUTE_PINVOKE_IMPL 0x2000 74 | #define METHOD_ATTRIBUTE_UNMANAGED_EXPORT 0x0008 75 | 76 | /* 77 | * For runtime use only 78 | */ 79 | #define METHOD_ATTRIBUTE_RESERVED_MASK 0xd000 80 | #define METHOD_ATTRIBUTE_RT_SPECIAL_NAME 0x1000 81 | #define METHOD_ATTRIBUTE_HAS_SECURITY 0x4000 82 | #define METHOD_ATTRIBUTE_REQUIRE_SEC_OBJECT 0x8000 83 | 84 | /* 85 | * Type Attributes (21.1.13). 86 | */ 87 | #define TYPE_ATTRIBUTE_VISIBILITY_MASK 0x00000007 88 | #define TYPE_ATTRIBUTE_NOT_PUBLIC 0x00000000 89 | #define TYPE_ATTRIBUTE_PUBLIC 0x00000001 90 | #define TYPE_ATTRIBUTE_NESTED_PUBLIC 0x00000002 91 | #define TYPE_ATTRIBUTE_NESTED_PRIVATE 0x00000003 92 | #define TYPE_ATTRIBUTE_NESTED_FAMILY 0x00000004 93 | #define TYPE_ATTRIBUTE_NESTED_ASSEMBLY 0x00000005 94 | #define TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM 0x00000006 95 | #define TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM 0x00000007 96 | 97 | #define TYPE_ATTRIBUTE_LAYOUT_MASK 0x00000018 98 | #define TYPE_ATTRIBUTE_AUTO_LAYOUT 0x00000000 99 | #define TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT 0x00000008 100 | #define TYPE_ATTRIBUTE_EXPLICIT_LAYOUT 0x00000010 101 | 102 | #define TYPE_ATTRIBUTE_CLASS_SEMANTIC_MASK 0x00000020 103 | #define TYPE_ATTRIBUTE_CLASS 0x00000000 104 | #define TYPE_ATTRIBUTE_INTERFACE 0x00000020 105 | 106 | #define TYPE_ATTRIBUTE_ABSTRACT 0x00000080 107 | #define TYPE_ATTRIBUTE_SEALED 0x00000100 108 | #define TYPE_ATTRIBUTE_SPECIAL_NAME 0x00000400 109 | 110 | #define TYPE_ATTRIBUTE_IMPORT 0x00001000 111 | #define TYPE_ATTRIBUTE_SERIALIZABLE 0x00002000 112 | 113 | #define TYPE_ATTRIBUTE_STRING_FORMAT_MASK 0x00030000 114 | #define TYPE_ATTRIBUTE_ANSI_CLASS 0x00000000 115 | #define TYPE_ATTRIBUTE_UNICODE_CLASS 0x00010000 116 | #define TYPE_ATTRIBUTE_AUTO_CLASS 0x00020000 117 | 118 | #define TYPE_ATTRIBUTE_BEFORE_FIELD_INIT 0x00100000 119 | #define TYPE_ATTRIBUTE_FORWARDER 0x00200000 120 | 121 | #define TYPE_ATTRIBUTE_RESERVED_MASK 0x00040800 122 | #define TYPE_ATTRIBUTE_RT_SPECIAL_NAME 0x00000800 123 | #define TYPE_ATTRIBUTE_HAS_SECURITY 0x00040000 124 | 125 | /* 126 | * Flags for Params (22.1.12) 127 | */ 128 | #define PARAM_ATTRIBUTE_IN 0x0001 129 | #define PARAM_ATTRIBUTE_OUT 0x0002 130 | #define PARAM_ATTRIBUTE_OPTIONAL 0x0010 131 | #define PARAM_ATTRIBUTE_RESERVED_MASK 0xf000 132 | #define PARAM_ATTRIBUTE_HAS_DEFAULT 0x1000 133 | #define PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL 0x2000 134 | #define PARAM_ATTRIBUTE_UNUSED 0xcfe0 135 | 136 | // Flags for Generic Parameters (II.23.1.7) 137 | #define IL2CPP_GENERIC_PARAMETER_ATTRIBUTE_NON_VARIANT 0x00 138 | #define IL2CPP_GENERIC_PARAMETER_ATTRIBUTE_COVARIANT 0x01 139 | #define IL2CPP_GENERIC_PARAMETER_ATTRIBUTE_CONTRAVARIANT 0x02 140 | #define IL2CPP_GENERIC_PARAMETER_ATTRIBUTE_VARIANCE_MASK 0x03 141 | #define IL2CPP_GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT 0x04 142 | #define IL2CPP_GENERIC_PARAMETER_ATTRIBUTE_NOT_NULLABLE_VALUE_TYPE_CONSTRAINT 0x08 143 | #define IL2CPP_GENERIC_PARAMETER_ATTRIBUTE_DEFAULT_CONSTRUCTOR_CONSTRAINT 0x10 144 | #define IL2CPP_GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINT_MASK 0x1C 145 | 146 | /** 147 | * 21.5 AssemblyRefs 148 | */ 149 | #define ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG 0x00000001 150 | #define ASSEMBLYREF_RETARGETABLE_FLAG 0x00000100 151 | #define ASSEMBLYREF_ENABLEJITCOMPILE_TRACKING_FLAG 0x00008000 152 | #define ASSEMBLYREF_DISABLEJITCOMPILE_OPTIMIZER_FLAG 0x00004000 153 | -------------------------------------------------------------------------------- /app/src/main/cpp/demo/il2cpp_dumper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mrack on 2024/4/30. 3 | // 4 | 5 | #ifndef XPOSEDNHOOK_IL2CPP_DUMPER_H 6 | #define XPOSEDNHOOK_IL2CPP_DUMPER_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "il2cpp-tabledefs.h" 14 | #include "il2cpp-class.h" 15 | 16 | bool dump(int, const char *); 17 | 18 | void dumpIL2cpp(const char *); 19 | 20 | void *get_il2cpp_handle(); 21 | 22 | 23 | class Il2CppApi { 24 | public: 25 | static std::map il2cpp_functions; 26 | 27 | static void *get(const std::string &name) { 28 | if (il2cpp_functions.find(name) == il2cpp_functions.end()) { 29 | void *address = dlsym(il2cpp_handle, name.c_str()); 30 | if (address == nullptr) { 31 | return nullptr; 32 | } 33 | il2cpp_functions[name] = address; 34 | } 35 | assert(il2cpp_functions[name] != nullptr); 36 | return il2cpp_functions[name]; 37 | } 38 | 39 | static void *il2cpp_handle; 40 | static size_t il2cpp_base; 41 | }; 42 | 43 | #define IL2CPP_API(functionName, returnType, paramType, param) \ 44 | typedef returnType (*functionName##_t) paramType; \ 45 | static functionName##_t functionName##_ptr; \ 46 | static returnType functionName paramType { \ 47 | functionName##_ptr = (functionName##_t)Il2CppApi::get(#functionName); \ 48 | return functionName##_ptr param; \ 49 | } 50 | 51 | #endif //XPOSEDNHOOK_IL2CPP_DUMPER_H 52 | -------------------------------------------------------------------------------- /app/src/main/cpp/demo/modmenu.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mrack on 2024/4/23. 3 | // 4 | #include 5 | #include 6 | #include 7 | 8 | extern "C" JNIEXPORT jstring JNICALL 9 | Java_cn_mrack_xposed_nhook_NHook_test111(JNIEnv *env, jclass thiz, jint value) { 10 | char buf[128]; 11 | sprintf(buf, "value: %d", value); 12 | // write code here 13 | return env->NewStringUTF(buf); 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/cpp/demo/modmenu_native.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mrack on 2024/4/28. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "modmenu_native.h" 10 | #include "thread" 11 | #include "linker_hook.h" 12 | #include "utils.h" 13 | #include "imgui.h" 14 | #include 15 | #include "backends/imgui_impl_android.h" 16 | #include "backends/imgui_impl_opengl3.h" 17 | 18 | static int g_GlHeight, g_GlWidth; 19 | static bool g_IsSetup = false; 20 | static bool g_Orientation = false; 21 | static std::string g_IniFileName = ""; 22 | 23 | static EGLDisplay g_EglDisplay = EGL_NO_DISPLAY; 24 | static EGLSurface g_EglSurface = EGL_NO_SURFACE; 25 | static EGLContext g_EglContext = EGL_NO_CONTEXT; 26 | 27 | 28 | char *get_input_path() { 29 | char *input; 30 | #if defined(__aarch64__) 31 | input = "/system/lib64/libinput.so"; 32 | #else 33 | input = "/system/lib/libinput.so"; 34 | #endif 35 | return input; 36 | } 37 | 38 | 39 | char *get_EGL_path() { 40 | char *input; 41 | #if defined(__aarch64__) 42 | input = "/system/lib64/libEGL.so"; 43 | #else 44 | input = "/system/lib/libEGL.so"; 45 | #endif 46 | return input; 47 | } 48 | 49 | 50 | void ImGui_ImplAndroid_NewFrame(int width, int height) 51 | { 52 | ImGuiIO& io = ImGui::GetIO(); 53 | 54 | // Setup display size (every frame to accommodate for window resizing) 55 | int32_t window_width = (int32_t)width; 56 | int32_t window_height = (int32_t)height; 57 | int display_width = window_width; 58 | int display_height = window_height; 59 | 60 | io.DisplaySize = ImVec2((float)window_width, (float)window_height); 61 | if (window_width > 0 && window_height > 0) 62 | io.DisplayFramebufferScale = ImVec2((float)display_width / window_width, (float)display_height / window_height); 63 | 64 | } 65 | 66 | static bool cb = false; 67 | 68 | void draw() { 69 | ImGuiIO &io = ImGui::GetIO(); 70 | if (g_EglDisplay == EGL_NO_DISPLAY) { 71 | return; 72 | } 73 | ImGui_ImplOpenGL3_NewFrame(); 74 | ImGui_ImplAndroid_NewFrame(g_GlWidth, g_GlHeight); 75 | ImGui::NewFrame(); 76 | 77 | static float colorPickerValue = 0.1f; 78 | static float seekBarValue = 0.5f; 79 | static bool checkBoxValue = false; 80 | 81 | ImGui::SetNextWindowPos(ImVec2(0, 0)); 82 | ImGui::SetNextWindowSize(ImVec2(g_GlWidth, g_GlHeight)); 83 | 84 | ImGui::Begin("Demo", nullptr, 85 | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse); 86 | ImGui::Text("Hello, world!"); 87 | 88 | if (ImGui::Button("Button")) { 89 | // Code to execute when the button is clicked 90 | } 91 | ImGui::SliderFloat("SeekBar", &seekBarValue, 0.0f, 1.0f); 92 | 93 | ImGui::Checkbox("CheckBox", &checkBoxValue); 94 | 95 | ImGui::ColorPicker4("ColorPicker", &colorPickerValue); 96 | 97 | ImGui::End(); 98 | 99 | ImGui::Render(); 100 | glViewport(0, 0, (int) io.DisplaySize.x, (int) io.DisplaySize.y); 101 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 102 | ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); 103 | eglSwapBuffers(g_EglDisplay, g_EglSurface); 104 | } 105 | 106 | 107 | install_hook_name(initializeMotionEvent, void, void *thiz, void *event, void *msg) { 108 | orig_initializeMotionEvent(thiz, event, msg); 109 | if (g_IsSetup) { 110 | ImGui_ImplAndroid_HandleInputEvent((AInputEvent *) thiz); 111 | } 112 | } 113 | 114 | // 115 | //void SetupImGui() { 116 | // if (g_IsSetup) return; 117 | // auto ctx = ImGui::CreateContext(); 118 | // if (!ctx) { 119 | // LOGI(("Failed to create context")); 120 | // return; 121 | // } 122 | // 123 | // ImGuiIO &io = ImGui::GetIO(); 124 | // io.DisplaySize = ImVec2((float) g_GlWidth * 3, (float) g_GlHeight * 3); 125 | // io.ConfigWindowsMoveFromTitleBarOnly = true; 126 | // io.IniFilename = nullptr; 127 | // 128 | // // Setup Platform/Renderer backends 129 | // ImGui_ImplAndroid_Init(nullptr); 130 | // ImGui_ImplOpenGL3_Init("#version 300 es"); 131 | // ImGui::StyleColorsLight(); 132 | // ImFontConfig font_cfg; 133 | // font_cfg.SizePixels = 30.0f; 134 | // io.Fonts->AddFontDefault(&font_cfg); 135 | // 136 | // ImGui::GetStyle().ScaleAllSizes(5); 137 | // 138 | // g_IsSetup = true; 139 | // LOGI("setup done."); 140 | //} 141 | 142 | 143 | //void menu_inject() { 144 | // input_inject(); 145 | // void *peglSwapBuffers = ((void *) get_address_from_module( 146 | // get_EGL_path(), "eglSwapBuffers")); 147 | // 148 | // if (peglSwapBuffers != nullptr) { 149 | // DobbyInstrument(peglSwapBuffers, [](void *address, DobbyRegisterContext *ctx) { 150 | // Window::instance()->getViewPort(); 151 | // g_GlWidth = Window::instance()->getWidth(); 152 | // g_GlHeight = Window::instance()->getHeight(); 153 | // SetupImGui(); 154 | // if (g_IsSetup) { 155 | // draw(); 156 | // } 157 | // }); 158 | // } 159 | //} 160 | // 161 | //void test_modmenu_native() { 162 | // std::thread t(menu_inject); 163 | // t.detach(); 164 | //} 165 | 166 | 167 | void input_inject() { 168 | void *pinitializeMotionEvent = ((void *) get_address_from_module( 169 | get_input_path(), 170 | "initializeMotionEvent")); 171 | if (pinitializeMotionEvent != nullptr) { 172 | install_hook_initializeMotionEvent(pinitializeMotionEvent); 173 | } 174 | } 175 | 176 | void init(ANativeWindow *window) { 177 | if (g_IsSetup) 178 | return; 179 | input_inject(); 180 | ANativeWindow_acquire(window); 181 | 182 | { 183 | g_EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); 184 | if (g_EglDisplay == EGL_NO_DISPLAY) 185 | LOGD("%s", "eglGetDisplay(EGL_DEFAULT_DISPLAY) returned EGL_NO_DISPLAY"); 186 | 187 | if (eglInitialize(g_EglDisplay, 0, 0) != EGL_TRUE) 188 | LOGD("%s", "eglInitialize() returned with an error"); 189 | 190 | const EGLint egl_attributes[] = {EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, 191 | EGL_DEPTH_SIZE, 24, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 192 | EGL_NONE}; 193 | EGLint num_configs = 0; 194 | if (eglChooseConfig(g_EglDisplay, egl_attributes, nullptr, 0, &num_configs) != EGL_TRUE) 195 | LOGD("%s", "eglChooseConfig() returned with an error"); 196 | if (num_configs == 0) 197 | LOGD("%s", "eglChooseConfig() returned 0 matching config"); 198 | 199 | // Get the first matching config 200 | EGLConfig egl_config; 201 | eglChooseConfig(g_EglDisplay, egl_attributes, &egl_config, 1, &num_configs); 202 | EGLint egl_format; 203 | eglGetConfigAttrib(g_EglDisplay, egl_config, EGL_NATIVE_VISUAL_ID, &egl_format); 204 | ANativeWindow_setBuffersGeometry(window, 0, 0, egl_format); 205 | 206 | const EGLint egl_context_attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE}; 207 | g_EglContext = eglCreateContext(g_EglDisplay, egl_config, EGL_NO_CONTEXT, 208 | egl_context_attributes); 209 | 210 | if (g_EglContext == EGL_NO_CONTEXT) 211 | LOGD("%s", "eglCreateContext() returned EGL_NO_CONTEXT"); 212 | 213 | g_EglSurface = eglCreateWindowSurface(g_EglDisplay, egl_config, window, nullptr); 214 | eglMakeCurrent(g_EglDisplay, g_EglSurface, g_EglSurface, g_EglContext); 215 | } 216 | 217 | // Setup Dear ImGui context 218 | IMGUI_CHECKVERSION(); 219 | ImGui::CreateContext(); 220 | ImGuiIO &io = ImGui::GetIO(); 221 | 222 | 223 | // Setup Dear ImGui style 224 | ImGui::StyleColorsDark(); 225 | //ImGui::StyleColorsLight(); 226 | 227 | // Setup Platform/Renderer backends 228 | ImGui_ImplAndroid_Init(window); 229 | ImGui_ImplOpenGL3_Init("#version 300 es"); 230 | ImFontConfig font_cfg; 231 | font_cfg.SizePixels = 42.0f; 232 | io.Fonts->AddFontDefault(&font_cfg); 233 | ImGui::GetStyle().ScaleAllSizes(5.0f); 234 | 235 | g_IsSetup = true; 236 | } 237 | 238 | const int FRAME_PER_SECOND = 30; 239 | std::atomic g_Rendering(false); 240 | 241 | 242 | extern "C" 243 | JNIEXPORT void JNICALL 244 | Java_cn_mrack_xposed_nhook_menu_SurfaceImGUI_initImGUI(JNIEnv *env, jclass clazz, jobject surface) { 245 | g_Rendering = true; 246 | g_IsSetup = false; 247 | ANativeWindow *w = ANativeWindow_fromSurface(env, (jobject) surface); 248 | g_GlWidth = ANativeWindow_getWidth(w); 249 | g_GlHeight = ANativeWindow_getHeight(w); 250 | init(w); 251 | while (g_Rendering) { 252 | draw(); 253 | usleep(1000 / FRAME_PER_SECOND); 254 | } 255 | ANativeWindow_release(w); 256 | ImGui_ImplAndroid_Shutdown(); 257 | ImGui_ImplOpenGL3_Shutdown(); 258 | ImGui::DestroyContext(); 259 | } 260 | 261 | 262 | extern "C" 263 | JNIEXPORT void JNICALL 264 | Java_cn_mrack_xposed_nhook_menu_SurfaceImGUI_setOrientationImGUI(JNIEnv *env, jclass clazz, 265 | jint orientation) { 266 | // TODO 267 | } 268 | 269 | extern "C" 270 | JNIEXPORT void JNICALL 271 | Java_cn_mrack_xposed_nhook_menu_SurfaceImGUI_destroyImGUI(JNIEnv *env, jclass clazz) { 272 | g_Rendering = false; 273 | } -------------------------------------------------------------------------------- /app/src/main/cpp/demo/modmenu_native.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mrack on 2024/4/28. 3 | // 4 | 5 | #ifndef XPOSEDNHOOK_MODMENU_NATIVE_H 6 | #define XPOSEDNHOOK_MODMENU_NATIVE_H 7 | 8 | #include "imgui.h" 9 | #include 10 | 11 | void test_modmenu_native(); 12 | 13 | void input_inject(); 14 | 15 | void render(); 16 | 17 | class Window { 18 | private: 19 | int ViewPort[4]; 20 | 21 | public: 22 | static Window *instance() { 23 | static Window *instance = NULL; 24 | if (instance == NULL) instance = new Window; 25 | return instance; 26 | } 27 | 28 | bool getViewPort() { 29 | glGetIntegerv(GL_VIEWPORT, this->ViewPort); 30 | if (this->ViewPort[2] && this->ViewPort[3]) return true; 31 | return false; 32 | } 33 | 34 | float getX() { 35 | return (float) this->ViewPort[0]; 36 | } 37 | 38 | float getY() { 39 | return (float) this->ViewPort[1]; 40 | } 41 | 42 | float getW() { 43 | return (float) this->ViewPort[2]; 44 | } 45 | 46 | float getH() { 47 | return (float) this->ViewPort[3]; 48 | } 49 | 50 | float getWidth() { 51 | return (this->getW() + (this->getX() * 2.0f)); 52 | } 53 | 54 | float getHeight() { 55 | return (this->getH() + (this->getY() * 2.0f)); 56 | } 57 | 58 | ImVec2 getSize() { 59 | return ImVec2(this->getWidth(), this->getHeight()); 60 | } 61 | 62 | ImVec2 getCenter() { 63 | return ImVec2(this->getWidth() / 2.0f, this->getHeight() / 2.0f); 64 | } 65 | 66 | ImVec2 getScale() { 67 | return ImVec2(this->getWidth() * 0.00052083333f, this->getHeight() * 0.00092592592f); 68 | } 69 | 70 | bool isRotation() { 71 | if (this->getWidth() < this->getHeight()) return true; 72 | return false; 73 | } 74 | }; 75 | 76 | #endif //XPOSEDNHOOK_MODMENU_NATIVE_H 77 | -------------------------------------------------------------------------------- /app/src/main/cpp/demo/qbdihook.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mrack on 2024/4/20. 3 | // 4 | 5 | #include "qbdihook.h" 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include "vm.h" 12 | #include "utils.h" 13 | 14 | void vm_handle_add(void *address, DobbyRegisterContext *ctx) { 15 | 16 | LOGT("vm address %p ", address); 17 | DobbyDestroy(address); 18 | auto vm_ = new vm(); 19 | auto qvm = vm_->init(address); 20 | auto state = qvm.getGPRState(); 21 | syn_regs(ctx, state); 22 | uint8_t *fakestack; 23 | QBDI::allocateVirtualStack(state, 0x800000, &fakestack); 24 | qvm.call(nullptr, (uint64_t) address); 25 | QBDI::alignedFree(fakestack); 26 | 27 | // write to file 28 | std::ofstream out; 29 | std::string data = get_data_path(gContext); 30 | out.open(data + "/trace_log.txt", std::ios::out); 31 | out << vm_->logbuf.str(); 32 | out.close(); 33 | } 34 | 35 | 36 | void test_QBDI() { 37 | DobbyInstrument((void *) (Java_cn_mrack_xposed_nhook_NHook_sign1), vm_handle_add); 38 | } 39 | 40 | 41 | unsigned char s[256]; 42 | unsigned char t[256]; 43 | 44 | 45 | void swap(unsigned char *p1, unsigned char *p2) { 46 | unsigned char t = *p1; 47 | *p1 = *p2; 48 | *p2 = t; 49 | } 50 | 51 | void rc4_init(unsigned char *key, int key_len) { 52 | int i, j = 0; 53 | 54 | //Initial values of both vectors 55 | for (i = 0; i < 256; i++) { 56 | s[i] = i; 57 | t[i] = key[i % key_len]; 58 | } 59 | //Initial permutation 60 | for (i = 0; i < 256; i++) { 61 | j = (j + s[i] + t[i]) % 256; 62 | swap(&s[i], &s[j]); 63 | } 64 | } 65 | 66 | void rc4(unsigned char *key, int key_len, char *buff, int len) { 67 | int i = 0; 68 | unsigned long t1, t2; 69 | unsigned char val; 70 | unsigned char out; 71 | t1 = 0; 72 | t2 = 0; 73 | rc4_init(key, key_len); 74 | 75 | //process one byte at a time 76 | for (i = 0; i < len; i++) { 77 | t1 = (t1 + 1) % 256; 78 | t2 = (t2 + s[t1]) % 256; 79 | swap(&s[t1], &s[t2]); 80 | val = (s[t1] + s[t2]) % 256; 81 | out = *buff ^ val; 82 | *buff = out; 83 | buff++; 84 | } 85 | } 86 | 87 | extern "C" JNIEXPORT jstring JNICALL 88 | Java_cn_mrack_xposed_nhook_NHook_sign1(JNIEnv *env, jclass thiz, jstring sign) { 89 | const char *sign_ = env->GetStringUTFChars(sign, 0); 90 | char *res_chars = new char[strlen(sign_)]; 91 | strcpy(res_chars, sign_); 92 | auto *key = (u_char *) "\x01\x02\x03\x04\x05"; 93 | rc4(key, sizeof(key), res_chars, strlen(sign_)); 94 | char *hex = new char[strlen(sign_) * 2 + 1]; 95 | for (int i = 0; i < strlen(sign_); i++) { 96 | sprintf(hex + i * 2, "%02x", res_chars[i]); 97 | } 98 | env->ReleaseStringUTFChars(sign, sign_); 99 | return env->NewStringUTF(hex); 100 | } 101 | 102 | -------------------------------------------------------------------------------- /app/src/main/cpp/demo/qbdihook.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mrack on 2024/4/28. 3 | // 4 | 5 | #ifndef XPOSEDNHOOK_QBDIHOOK_H 6 | #define XPOSEDNHOOK_QBDIHOOK_H 7 | 8 | #include "jni.h" 9 | #include "dobby/dobby.h" 10 | 11 | void test_QBDI(); 12 | 13 | extern "C" JNIEXPORT jstring JNICALL 14 | Java_cn_mrack_xposed_nhook_NHook_sign1(JNIEnv *env, jclass thiz, jstring sign); 15 | void vm_handle_add(void *address, DobbyRegisterContext *ctx); 16 | #endif //XPOSEDNHOOK_QBDIHOOK_H 17 | -------------------------------------------------------------------------------- /app/src/main/cpp/demo/ytbssl.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mrack on 2024/4/28. 3 | // 4 | 5 | #include "ytbssl.h" 6 | #include "utils.h" 7 | #include "linker_hook.h" 8 | 9 | int (*SSL_callback)(void *ctx, void *out_alert); 10 | 11 | int hook_SSL_callback(void *ctx, void *out_alert) { 12 | int res = SSL_callback(ctx, out_alert); 13 | return 0; 14 | } 15 | 16 | void (*SSL_CTX_set_custom_verify)(void *ctx, int mode, void *callback); 17 | 18 | void hook_SSL_CTX_set_custom_verify(void *ctx, int mode, void *callback) { 19 | LOGD("SSL_CTX_set_custom_verify callback %p", callback); 20 | SSL_CTX_set_custom_verify(ctx, mode, callback); 21 | DobbyHook(callback, (void *) hook_SSL_callback, 22 | (void **) &SSL_callback); 23 | } 24 | 25 | void test_youtube() { 26 | hook_module_load(); 27 | } 28 | 29 | void module_load(const char *file_path) { 30 | std::string path = file_path; 31 | if (path.find("libcronet") == std::string::npos) { 32 | return; 33 | } 34 | const char *file_name = strrchr(file_path, '/'); 35 | const std::pair &info = find_info_from_maps(file_name + 1); 36 | u_char *base = (u_char *) info.first; 37 | size_t size = info.second; 38 | int offset = search_hex((u_char *) base, size, 39 | "????01B9????00F9C0035FD6"); 40 | if (offset > 0) { 41 | void *p_SSL_CTX_set_custom_verify = (void *) (offset + info.first); 42 | LOGD("SSL_CTX_set_custom_verify: %p", p_SSL_CTX_set_custom_verify); 43 | DobbyHook(p_SSL_CTX_set_custom_verify, (void *) hook_SSL_CTX_set_custom_verify, 44 | (void **) &SSL_CTX_set_custom_verify); 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/cpp/demo/ytbssl.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mrack on 2024/4/28. 3 | // 4 | 5 | #ifndef XPOSEDNHOOK_YTBSSL_H 6 | #define XPOSEDNHOOK_YTBSSL_H 7 | 8 | void test_youtube(); 9 | 10 | void hook_SSL_CTX_set_custom_verify(void *ctx, int mode, void *callback); 11 | 12 | #endif //XPOSEDNHOOK_YTBSSL_H 13 | -------------------------------------------------------------------------------- /app/src/main/cpp/dobby/dobby.h: -------------------------------------------------------------------------------- 1 | #ifndef dobby_h 2 | #define dobby_h 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | 11 | typedef uintptr_t addr_t; 12 | typedef uint32_t addr32_t; 13 | typedef uint64_t addr64_t; 14 | 15 | typedef void *dobby_dummy_func_t; 16 | typedef void *asm_func_t; 17 | 18 | #if defined(__arm__) 19 | typedef struct { 20 | uint32_t dummy_0; 21 | uint32_t dummy_1; 22 | 23 | uint32_t dummy_2; 24 | uint32_t sp; 25 | 26 | union { 27 | uint32_t r[13]; 28 | struct { 29 | uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12; 30 | } regs; 31 | } general; 32 | 33 | uint32_t lr; 34 | } DobbyRegisterContext; 35 | #elif defined(__arm64__) || defined(__aarch64__) 36 | #define ARM64_TMP_REG_NDX_0 17 37 | 38 | typedef union _FPReg { 39 | __int128_t q; 40 | struct { 41 | double d1; 42 | double d2; 43 | } d; 44 | struct { 45 | float f1; 46 | float f2; 47 | float f3; 48 | float f4; 49 | } f; 50 | } FPReg; 51 | 52 | // register context 53 | typedef struct { 54 | uint64_t dmmpy_0; // dummy placeholder 55 | uint64_t sp; 56 | 57 | uint64_t dmmpy_1; // dummy placeholder 58 | union { 59 | uint64_t x[29]; 60 | struct { 61 | uint64_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, 62 | x23, x24, x25, x26, x27, x28; 63 | } regs; 64 | } general; 65 | 66 | uint64_t fp; 67 | uint64_t lr; 68 | 69 | union { 70 | FPReg q[32]; 71 | struct { 72 | FPReg q0, q1, q2, q3, q4, q5, q6, q7; 73 | // [!!! READ ME !!!] 74 | // for Arm64, can't access q8 - q31, unless you enable full floating-point register pack 75 | FPReg q8, q9, q10, q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, q21, q22, q23, q24, q25, q26, q27, q28, q29, 76 | q30, q31; 77 | } regs; 78 | } floating; 79 | } DobbyRegisterContext; 80 | #elif defined(_M_IX86) || defined(__i386__) 81 | typedef struct _RegisterContext { 82 | uint32_t dummy_0; 83 | uint32_t esp; 84 | 85 | uint32_t dummy_1; 86 | uint32_t flags; 87 | 88 | union { 89 | struct { 90 | uint32_t eax, ebx, ecx, edx, ebp, esp, edi, esi; 91 | } regs; 92 | } general; 93 | 94 | } DobbyRegisterContext; 95 | #elif defined(_M_X64) || defined(__x86_64__) 96 | typedef struct { 97 | uint64_t dummy_0; 98 | uint64_t rsp; 99 | 100 | union { 101 | struct { 102 | uint64_t rax, rbx, rcx, rdx, rbp, rsp, rdi, rsi, r8, r9, r10, r11, r12, r13, r14, r15; 103 | } regs; 104 | } general; 105 | 106 | uint64_t dummy_1; 107 | uint64_t flags; 108 | } DobbyRegisterContext; 109 | #endif 110 | 111 | #define install_hook_name(name, fn_ret_t, fn_args_t...) \ 112 | static fn_ret_t fake_##name(fn_args_t); \ 113 | static fn_ret_t (*orig_##name)(fn_args_t); \ 114 | /* __attribute__((constructor)) */ static void install_hook_##name(void *sym_addr) { \ 115 | DobbyHook(sym_addr, (dobby_dummy_func_t)fake_##name, (dobby_dummy_func_t *)&orig_##name); \ 116 | return; \ 117 | } \ 118 | fn_ret_t fake_##name(fn_args_t) 119 | 120 | // memory code patch 121 | int DobbyCodePatch(void *address, uint8_t *buffer, uint32_t buffer_size); 122 | 123 | // function inline hook 124 | int DobbyHook(void *address, dobby_dummy_func_t replace_func, dobby_dummy_func_t *origin_func); 125 | 126 | // dynamic binary instruction instrument 127 | // for Arm64, can't access q8 - q31, unless enable full floating-point register pack 128 | typedef void (*dobby_instrument_callback_t)(void *address, DobbyRegisterContext *ctx); 129 | int DobbyInstrument(void *address, dobby_instrument_callback_t pre_handler); 130 | 131 | // destroy and restore code patch 132 | int DobbyDestroy(void *address); 133 | 134 | const char *DobbyGetVersion(); 135 | 136 | // symbol resolver 137 | void *DobbySymbolResolver(const char *image_name, const char *symbol_name); 138 | 139 | // import table replace 140 | int DobbyImportTableReplace(char *image_name, char *symbol_name, dobby_dummy_func_t fake_func, 141 | dobby_dummy_func_t *orig_func); 142 | 143 | // for arm, Arm64, try use b xxx instead of ldr absolute indirect branch 144 | // for x86, x64, always use absolute indirect jump 145 | void dobby_enable_near_branch_trampoline(); 146 | void dobby_disable_near_branch_trampoline(); 147 | 148 | #ifdef __cplusplus 149 | } 150 | #endif 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /app/src/main/cpp/elfio/elfio_array.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2001-present by Serge Lamikhov-Center 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifndef ELFIO_ARRAY_HPP 24 | #define ELFIO_ARRAY_HPP 25 | 26 | #include 27 | 28 | namespace ELFIO { 29 | 30 | //------------------------------------------------------------------------------ 31 | template class array_section_accessor_template 32 | { 33 | public: 34 | //------------------------------------------------------------------------------ 35 | explicit array_section_accessor_template( const elfio& elf_file, 36 | S* section ) 37 | : elf_file( elf_file ), array_section( section ) 38 | { 39 | } 40 | 41 | //------------------------------------------------------------------------------ 42 | Elf_Xword get_entries_num() const 43 | { 44 | Elf_Xword entry_size = sizeof( T ); 45 | return array_section->get_size() / entry_size; 46 | } 47 | 48 | //------------------------------------------------------------------------------ 49 | bool get_entry( Elf_Xword index, Elf64_Addr& address ) const 50 | { 51 | if ( index >= get_entries_num() ) { // Is index valid 52 | return false; 53 | } 54 | 55 | const endianess_convertor& convertor = elf_file.get_convertor(); 56 | 57 | const T temp = *reinterpret_cast( array_section->get_data() + 58 | index * sizeof( T ) ); 59 | address = convertor( temp ); 60 | 61 | return true; 62 | } 63 | 64 | //------------------------------------------------------------------------------ 65 | void add_entry( Elf64_Addr address ) 66 | { 67 | const endianess_convertor& convertor = elf_file.get_convertor(); 68 | 69 | T temp = convertor( (T)address ); 70 | array_section->append_data( reinterpret_cast( &temp ), 71 | sizeof( temp ) ); 72 | } 73 | 74 | private: 75 | //------------------------------------------------------------------------------ 76 | const elfio& elf_file; 77 | S* array_section; 78 | }; 79 | 80 | template 81 | using array_section_accessor = array_section_accessor_template; 82 | template 83 | using const_array_section_accessor = 84 | array_section_accessor_template; 85 | 86 | } // namespace ELFIO 87 | 88 | #endif // ELFIO_ARRAY_HPP 89 | -------------------------------------------------------------------------------- /app/src/main/cpp/elfio/elfio_dynamic.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2001-present by Serge Lamikhov-Center 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifndef ELFIO_DYNAMIC_HPP 24 | #define ELFIO_DYNAMIC_HPP 25 | 26 | #include 27 | 28 | namespace ELFIO { 29 | 30 | //------------------------------------------------------------------------------ 31 | template class dynamic_section_accessor_template 32 | { 33 | public: 34 | //------------------------------------------------------------------------------ 35 | explicit dynamic_section_accessor_template( const elfio& elf_file, 36 | S* section ) 37 | : elf_file( elf_file ), dynamic_section( section ), entries_num( 0 ) 38 | { 39 | } 40 | 41 | //------------------------------------------------------------------------------ 42 | Elf_Xword get_entries_num() const 43 | { 44 | size_t needed_entry_size = -1; 45 | if ( elf_file.get_class() == ELFCLASS32 ) { 46 | needed_entry_size = sizeof( Elf32_Dyn ); 47 | } 48 | else { 49 | needed_entry_size = sizeof( Elf64_Dyn ); 50 | } 51 | 52 | if ( ( 0 == entries_num ) && 53 | ( 0 != dynamic_section->get_entry_size() && 54 | dynamic_section->get_entry_size() >= needed_entry_size ) ) { 55 | entries_num = 56 | dynamic_section->get_size() / dynamic_section->get_entry_size(); 57 | Elf_Xword i; 58 | Elf_Xword tag = DT_NULL; 59 | Elf_Xword value = 0; 60 | std::string str; 61 | for ( i = 0; i < entries_num; i++ ) { 62 | get_entry( i, tag, value, str ); 63 | if ( tag == DT_NULL ) 64 | break; 65 | } 66 | entries_num = std::min( entries_num, i + 1 ); 67 | } 68 | 69 | return entries_num; 70 | } 71 | 72 | //------------------------------------------------------------------------------ 73 | bool get_entry( Elf_Xword index, 74 | Elf_Xword& tag, 75 | Elf_Xword& value, 76 | std::string& str ) const 77 | { 78 | if ( index >= get_entries_num() ) { // Is index valid 79 | return false; 80 | } 81 | 82 | if ( elf_file.get_class() == ELFCLASS32 ) { 83 | generic_get_entry_dyn( index, tag, value ); 84 | } 85 | else { 86 | generic_get_entry_dyn( index, tag, value ); 87 | } 88 | 89 | // If the tag has a string table reference - prepare the string 90 | if ( tag == DT_NEEDED || tag == DT_SONAME || tag == DT_RPATH || 91 | tag == DT_RUNPATH ) { 92 | string_section_accessor strsec( 93 | elf_file.sections[get_string_table_index()] ); 94 | const char* result = strsec.get_string( (Elf_Word)value ); 95 | if ( nullptr == result ) { 96 | str.clear(); 97 | return false; 98 | } 99 | str = result; 100 | } 101 | else { 102 | str.clear(); 103 | } 104 | 105 | return true; 106 | } 107 | 108 | //------------------------------------------------------------------------------ 109 | void add_entry( Elf_Xword tag, Elf_Xword value ) 110 | { 111 | if ( elf_file.get_class() == ELFCLASS32 ) { 112 | generic_add_entry_dyn( tag, value ); 113 | } 114 | else { 115 | generic_add_entry_dyn( tag, value ); 116 | } 117 | } 118 | 119 | //------------------------------------------------------------------------------ 120 | void add_entry( Elf_Xword tag, const std::string& str ) 121 | { 122 | string_section_accessor strsec( 123 | elf_file.sections[get_string_table_index()] ); 124 | Elf_Xword value = strsec.add_string( str ); 125 | add_entry( tag, value ); 126 | } 127 | 128 | //------------------------------------------------------------------------------ 129 | private: 130 | //------------------------------------------------------------------------------ 131 | Elf_Half get_string_table_index() const 132 | { 133 | return (Elf_Half)dynamic_section->get_link(); 134 | } 135 | 136 | //------------------------------------------------------------------------------ 137 | template 138 | void generic_get_entry_dyn( Elf_Xword index, 139 | Elf_Xword& tag, 140 | Elf_Xword& value ) const 141 | { 142 | const endianess_convertor& convertor = elf_file.get_convertor(); 143 | 144 | // Check unusual case when dynamic section has no data 145 | if ( dynamic_section->get_data() == nullptr || 146 | ( index + 1 ) * dynamic_section->get_entry_size() > 147 | dynamic_section->get_size() || 148 | dynamic_section->get_entry_size() < sizeof( T ) ) { 149 | tag = DT_NULL; 150 | value = 0; 151 | return; 152 | } 153 | 154 | const T* pEntry = reinterpret_cast( 155 | dynamic_section->get_data() + 156 | index * dynamic_section->get_entry_size() ); 157 | tag = convertor( pEntry->d_tag ); 158 | switch ( tag ) { 159 | case DT_NULL: 160 | case DT_SYMBOLIC: 161 | case DT_TEXTREL: 162 | case DT_BIND_NOW: 163 | value = 0; 164 | break; 165 | case DT_NEEDED: 166 | case DT_PLTRELSZ: 167 | case DT_RELASZ: 168 | case DT_RELAENT: 169 | case DT_STRSZ: 170 | case DT_SYMENT: 171 | case DT_SONAME: 172 | case DT_RPATH: 173 | case DT_RELSZ: 174 | case DT_RELENT: 175 | case DT_PLTREL: 176 | case DT_INIT_ARRAYSZ: 177 | case DT_FINI_ARRAYSZ: 178 | case DT_RUNPATH: 179 | case DT_FLAGS: 180 | case DT_PREINIT_ARRAYSZ: 181 | value = convertor( pEntry->d_un.d_val ); 182 | break; 183 | case DT_PLTGOT: 184 | case DT_HASH: 185 | case DT_STRTAB: 186 | case DT_SYMTAB: 187 | case DT_RELA: 188 | case DT_INIT: 189 | case DT_FINI: 190 | case DT_REL: 191 | case DT_DEBUG: 192 | case DT_JMPREL: 193 | case DT_INIT_ARRAY: 194 | case DT_FINI_ARRAY: 195 | case DT_PREINIT_ARRAY: 196 | default: 197 | value = convertor( pEntry->d_un.d_ptr ); 198 | break; 199 | } 200 | } 201 | 202 | //------------------------------------------------------------------------------ 203 | template 204 | void generic_add_entry_dyn( Elf_Xword tag, Elf_Xword value ) 205 | { 206 | const endianess_convertor& convertor = elf_file.get_convertor(); 207 | 208 | T entry; 209 | 210 | switch ( tag ) { 211 | case DT_NULL: 212 | case DT_SYMBOLIC: 213 | case DT_TEXTREL: 214 | case DT_BIND_NOW: 215 | entry.d_un.d_val = convertor( decltype( entry.d_un.d_val )( 0 ) ); 216 | break; 217 | case DT_NEEDED: 218 | case DT_PLTRELSZ: 219 | case DT_RELASZ: 220 | case DT_RELAENT: 221 | case DT_STRSZ: 222 | case DT_SYMENT: 223 | case DT_SONAME: 224 | case DT_RPATH: 225 | case DT_RELSZ: 226 | case DT_RELENT: 227 | case DT_PLTREL: 228 | case DT_INIT_ARRAYSZ: 229 | case DT_FINI_ARRAYSZ: 230 | case DT_RUNPATH: 231 | case DT_FLAGS: 232 | case DT_PREINIT_ARRAYSZ: 233 | entry.d_un.d_val = 234 | convertor( decltype( entry.d_un.d_val )( value ) ); 235 | break; 236 | case DT_PLTGOT: 237 | case DT_HASH: 238 | case DT_STRTAB: 239 | case DT_SYMTAB: 240 | case DT_RELA: 241 | case DT_INIT: 242 | case DT_FINI: 243 | case DT_REL: 244 | case DT_DEBUG: 245 | case DT_JMPREL: 246 | case DT_INIT_ARRAY: 247 | case DT_FINI_ARRAY: 248 | case DT_PREINIT_ARRAY: 249 | default: 250 | entry.d_un.d_ptr = 251 | convertor( decltype( entry.d_un.d_val )( value ) ); 252 | break; 253 | } 254 | 255 | entry.d_tag = convertor( decltype( entry.d_tag )( tag ) ); 256 | 257 | dynamic_section->append_data( reinterpret_cast( &entry ), 258 | sizeof( entry ) ); 259 | } 260 | 261 | //------------------------------------------------------------------------------ 262 | private: 263 | const elfio& elf_file; 264 | S* dynamic_section; 265 | mutable Elf_Xword entries_num; 266 | }; 267 | 268 | using dynamic_section_accessor = dynamic_section_accessor_template
; 269 | using const_dynamic_section_accessor = 270 | dynamic_section_accessor_template; 271 | 272 | } // namespace ELFIO 273 | 274 | #endif // ELFIO_DYNAMIC_HPP 275 | -------------------------------------------------------------------------------- /app/src/main/cpp/elfio/elfio_header.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2001-present by Serge Lamikhov-Center 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifndef ELF_HEADER_HPP 24 | #define ELF_HEADER_HPP 25 | 26 | #include 27 | 28 | namespace ELFIO { 29 | 30 | class elf_header 31 | { 32 | public: 33 | virtual ~elf_header() = default; 34 | 35 | virtual bool load( std::istream& stream ) = 0; 36 | virtual bool save( std::ostream& stream ) const = 0; 37 | 38 | // ELF header functions 39 | ELFIO_GET_ACCESS_DECL( unsigned char, class ); 40 | ELFIO_GET_ACCESS_DECL( unsigned char, elf_version ); 41 | ELFIO_GET_ACCESS_DECL( unsigned char, encoding ); 42 | ELFIO_GET_ACCESS_DECL( Elf_Half, header_size ); 43 | ELFIO_GET_ACCESS_DECL( Elf_Half, section_entry_size ); 44 | ELFIO_GET_ACCESS_DECL( Elf_Half, segment_entry_size ); 45 | 46 | ELFIO_GET_SET_ACCESS_DECL( Elf_Word, version ); 47 | ELFIO_GET_SET_ACCESS_DECL( unsigned char, os_abi ); 48 | ELFIO_GET_SET_ACCESS_DECL( unsigned char, abi_version ); 49 | ELFIO_GET_SET_ACCESS_DECL( Elf_Half, type ); 50 | ELFIO_GET_SET_ACCESS_DECL( Elf_Half, machine ); 51 | ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); 52 | ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, entry ); 53 | ELFIO_GET_SET_ACCESS_DECL( Elf_Half, sections_num ); 54 | ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, sections_offset ); 55 | ELFIO_GET_SET_ACCESS_DECL( Elf_Half, segments_num ); 56 | ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, segments_offset ); 57 | ELFIO_GET_SET_ACCESS_DECL( Elf_Half, section_name_str_index ); 58 | }; 59 | 60 | template struct elf_header_impl_types; 61 | template <> struct elf_header_impl_types 62 | { 63 | using Phdr_type = Elf32_Phdr; 64 | using Shdr_type = Elf32_Shdr; 65 | static const unsigned char file_class = ELFCLASS32; 66 | }; 67 | template <> struct elf_header_impl_types 68 | { 69 | using Phdr_type = Elf64_Phdr; 70 | using Shdr_type = Elf64_Shdr; 71 | static const unsigned char file_class = ELFCLASS64; 72 | }; 73 | 74 | template class elf_header_impl : public elf_header 75 | { 76 | public: 77 | //------------------------------------------------------------------------------ 78 | elf_header_impl( endianess_convertor* convertor, 79 | unsigned char encoding, 80 | const address_translator* translator ) 81 | : convertor( convertor ), translator( translator ) 82 | { 83 | header.e_ident[EI_MAG0] = ELFMAG0; 84 | header.e_ident[EI_MAG1] = ELFMAG1; 85 | header.e_ident[EI_MAG2] = ELFMAG2; 86 | header.e_ident[EI_MAG3] = ELFMAG3; 87 | header.e_ident[EI_CLASS] = elf_header_impl_types::file_class; 88 | header.e_ident[EI_DATA] = encoding; 89 | header.e_ident[EI_VERSION] = EV_CURRENT; 90 | header.e_version = ( *convertor )( (Elf_Word)EV_CURRENT ); 91 | header.e_ehsize = ( sizeof( header ) ); 92 | header.e_ehsize = ( *convertor )( header.e_ehsize ); 93 | header.e_shstrndx = ( *convertor )( (Elf_Half)1 ); 94 | header.e_phentsize = 95 | sizeof( typename elf_header_impl_types::Phdr_type ); 96 | header.e_shentsize = 97 | sizeof( typename elf_header_impl_types::Shdr_type ); 98 | header.e_phentsize = ( *convertor )( header.e_phentsize ); 99 | header.e_shentsize = ( *convertor )( header.e_shentsize ); 100 | } 101 | 102 | //------------------------------------------------------------------------------ 103 | bool load( std::istream& stream ) override 104 | { 105 | stream.seekg( ( *translator )[0] ); 106 | stream.read( reinterpret_cast( &header ), sizeof( header ) ); 107 | 108 | return ( stream.gcount() == sizeof( header ) ); 109 | } 110 | 111 | //------------------------------------------------------------------------------ 112 | bool save( std::ostream& stream ) const override 113 | { 114 | stream.seekp( ( *translator )[0] ); 115 | stream.write( reinterpret_cast( &header ), 116 | sizeof( header ) ); 117 | 118 | return stream.good(); 119 | } 120 | 121 | //------------------------------------------------------------------------------ 122 | // ELF header functions 123 | ELFIO_GET_ACCESS( unsigned char, class, header.e_ident[EI_CLASS] ); 124 | ELFIO_GET_ACCESS( unsigned char, elf_version, header.e_ident[EI_VERSION] ); 125 | ELFIO_GET_ACCESS( unsigned char, encoding, header.e_ident[EI_DATA] ); 126 | ELFIO_GET_ACCESS( Elf_Half, header_size, header.e_ehsize ); 127 | ELFIO_GET_ACCESS( Elf_Half, section_entry_size, header.e_shentsize ); 128 | ELFIO_GET_ACCESS( Elf_Half, segment_entry_size, header.e_phentsize ); 129 | 130 | ELFIO_GET_SET_ACCESS( Elf_Word, version, header.e_version ); 131 | ELFIO_GET_SET_ACCESS( unsigned char, os_abi, header.e_ident[EI_OSABI] ); 132 | ELFIO_GET_SET_ACCESS( unsigned char, 133 | abi_version, 134 | header.e_ident[EI_ABIVERSION] ); 135 | ELFIO_GET_SET_ACCESS( Elf_Half, type, header.e_type ); 136 | ELFIO_GET_SET_ACCESS( Elf_Half, machine, header.e_machine ); 137 | ELFIO_GET_SET_ACCESS( Elf_Word, flags, header.e_flags ); 138 | ELFIO_GET_SET_ACCESS( Elf_Half, section_name_str_index, header.e_shstrndx ); 139 | ELFIO_GET_SET_ACCESS( Elf64_Addr, entry, header.e_entry ); 140 | ELFIO_GET_SET_ACCESS( Elf_Half, sections_num, header.e_shnum ); 141 | ELFIO_GET_SET_ACCESS( Elf64_Off, sections_offset, header.e_shoff ); 142 | ELFIO_GET_SET_ACCESS( Elf_Half, segments_num, header.e_phnum ); 143 | ELFIO_GET_SET_ACCESS( Elf64_Off, segments_offset, header.e_phoff ); 144 | 145 | private: 146 | T header = {}; 147 | endianess_convertor* convertor = nullptr; 148 | const address_translator* translator = nullptr; 149 | }; 150 | 151 | } // namespace ELFIO 152 | 153 | #endif // ELF_HEADER_HPP 154 | -------------------------------------------------------------------------------- /app/src/main/cpp/elfio/elfio_modinfo.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2001-present by Serge Lamikhov-Center 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifndef ELFIO_MODINFO_HPP 24 | #define ELFIO_MODINFO_HPP 25 | 26 | #include 27 | #include 28 | 29 | namespace ELFIO { 30 | 31 | //------------------------------------------------------------------------------ 32 | template class modinfo_section_accessor_template 33 | { 34 | public: 35 | //------------------------------------------------------------------------------ 36 | explicit modinfo_section_accessor_template( S* section ) 37 | : modinfo_section( section ) 38 | { 39 | process_section(); 40 | } 41 | 42 | //------------------------------------------------------------------------------ 43 | Elf_Word get_attribute_num() const { return (Elf_Word)content.size(); } 44 | 45 | //------------------------------------------------------------------------------ 46 | bool 47 | get_attribute( Elf_Word no, std::string& field, std::string& value ) const 48 | { 49 | if ( no < content.size() ) { 50 | field = content[no].first; 51 | value = content[no].second; 52 | return true; 53 | } 54 | 55 | return false; 56 | } 57 | 58 | //------------------------------------------------------------------------------ 59 | bool get_attribute( const std::string_view& field_name, 60 | std::string& value ) const 61 | { 62 | for ( const auto [first, second] : content ) { 63 | if ( field_name == first ) { 64 | value = second; 65 | return true; 66 | } 67 | } 68 | 69 | return false; 70 | } 71 | 72 | //------------------------------------------------------------------------------ 73 | Elf_Word add_attribute( const std::string& field, const std::string& value ) 74 | { 75 | Elf_Word current_position = 0; 76 | 77 | if ( modinfo_section ) { 78 | // Strings are addeded to the end of the current section data 79 | current_position = (Elf_Word)modinfo_section->get_size(); 80 | 81 | std::string attribute = field + "=" + value; 82 | 83 | modinfo_section->append_data( attribute + '\0' ); 84 | content.emplace_back( field, value ); 85 | } 86 | 87 | return current_position; 88 | } 89 | 90 | //------------------------------------------------------------------------------ 91 | private: 92 | void process_section() 93 | { 94 | const char* pdata = modinfo_section->get_data(); 95 | if ( pdata ) { 96 | ELFIO::Elf_Xword i = 0; 97 | while ( i < modinfo_section->get_size() ) { 98 | while ( i < modinfo_section->get_size() && !pdata[i] ) 99 | i++; 100 | if ( i < modinfo_section->get_size() ) { 101 | std::string info = pdata + i; 102 | size_t loc = info.find( '=' ); 103 | content.emplace_back( info.substr( 0, loc ), 104 | info.substr( loc + 1 ) ); 105 | 106 | i += info.length(); 107 | } 108 | } 109 | } 110 | } 111 | 112 | //------------------------------------------------------------------------------ 113 | private: 114 | S* modinfo_section; 115 | std::vector> content; 116 | }; 117 | 118 | using modinfo_section_accessor = modinfo_section_accessor_template
; 119 | using const_modinfo_section_accessor = 120 | modinfo_section_accessor_template; 121 | 122 | } // namespace ELFIO 123 | 124 | #endif // ELFIO_MODINFO_HPP 125 | -------------------------------------------------------------------------------- /app/src/main/cpp/elfio/elfio_note.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2001-present by Serge Lamikhov-Center 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifndef ELFIO_NOTE_HPP 24 | #define ELFIO_NOTE_HPP 25 | 26 | namespace ELFIO { 27 | 28 | //------------------------------------------------------------------------------ 29 | // There are discrepancies in documentations. SCO documentation 30 | // (http://www.sco.com/developers/gabi/latest/ch5.pheader.html#note_section) 31 | // requires 8 byte entries alignment for 64-bit ELF file, 32 | // but Oracle's definition uses the same structure 33 | // for 32-bit and 64-bit formats. 34 | // (https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-18048.html) 35 | // 36 | // It looks like EM_X86_64 Linux implementation is similar to Oracle's 37 | // definition. Therefore, the same alignment works for both formats 38 | //------------------------------------------------------------------------------ 39 | 40 | //------------------------------------------------------------------------------ 41 | template 42 | class note_section_accessor_template 43 | { 44 | public: 45 | //------------------------------------------------------------------------------ 46 | explicit note_section_accessor_template( const elfio& elf_file, S* section ) 47 | : elf_file( elf_file ), notes( section ) 48 | { 49 | process_section(); 50 | } 51 | 52 | //------------------------------------------------------------------------------ 53 | Elf_Word get_notes_num() const 54 | { 55 | return (Elf_Word)note_start_positions.size(); 56 | } 57 | 58 | //------------------------------------------------------------------------------ 59 | bool get_note( Elf_Word index, 60 | Elf_Word& type, 61 | std::string& name, 62 | char*& desc, 63 | Elf_Word& descSize ) const 64 | { 65 | if ( index >= ( notes->*F_get_size )() ) { 66 | return false; 67 | } 68 | 69 | const char* pData = notes->get_data() + note_start_positions[index]; 70 | int align = sizeof( Elf_Word ); 71 | 72 | const endianess_convertor& convertor = elf_file.get_convertor(); 73 | type = convertor( *(const Elf_Word*)( pData + 2 * (size_t)align ) ); 74 | Elf_Word namesz = convertor( *(const Elf_Word*)( pData ) ); 75 | descSize = convertor( *(const Elf_Word*)( pData + sizeof( namesz ) ) ); 76 | 77 | Elf_Xword max_name_size = 78 | ( notes->*F_get_size )() - note_start_positions[index]; 79 | if ( namesz < 1 || namesz > max_name_size || 80 | (Elf_Xword)namesz + descSize > max_name_size ) { 81 | return false; 82 | } 83 | name.assign( pData + 3 * (size_t)align, namesz - 1 ); 84 | if ( 0 == descSize ) { 85 | desc = nullptr; 86 | } 87 | else { 88 | desc = const_cast( pData + 3 * (size_t)align + 89 | ( ( namesz + align - 1 ) / align ) * 90 | (size_t)align ); 91 | } 92 | 93 | return true; 94 | } 95 | 96 | //------------------------------------------------------------------------------ 97 | void add_note( Elf_Word type, 98 | const std::string& name, 99 | const char* desc, 100 | Elf_Word descSize ) 101 | { 102 | const endianess_convertor& convertor = elf_file.get_convertor(); 103 | 104 | int align = sizeof( Elf_Word ); 105 | Elf_Word nameLen = (Elf_Word)name.size() + 1; 106 | Elf_Word nameLenConv = convertor( nameLen ); 107 | std::string buffer( reinterpret_cast( &nameLenConv ), align ); 108 | Elf_Word descSizeConv = convertor( descSize ); 109 | 110 | buffer.append( reinterpret_cast( &descSizeConv ), align ); 111 | type = convertor( type ); 112 | buffer.append( reinterpret_cast( &type ), align ); 113 | buffer.append( name ); 114 | buffer.append( 1, '\x00' ); 115 | const char pad[] = { '\0', '\0', '\0', '\0' }; 116 | if ( nameLen % align != 0 ) { 117 | buffer.append( pad, (size_t)align - nameLen % align ); 118 | } 119 | if ( desc != nullptr && descSize != 0 ) { 120 | buffer.append( desc, descSize ); 121 | if ( descSize % align != 0 ) { 122 | buffer.append( pad, (size_t)align - descSize % align ); 123 | } 124 | } 125 | 126 | note_start_positions.emplace_back( ( notes->*F_get_size )() ); 127 | notes->append_data( buffer ); 128 | } 129 | 130 | private: 131 | //------------------------------------------------------------------------------ 132 | void process_section() 133 | { 134 | const endianess_convertor& convertor = elf_file.get_convertor(); 135 | const char* data = notes->get_data(); 136 | Elf_Xword size = ( notes->*F_get_size )(); 137 | Elf_Xword current = 0; 138 | 139 | note_start_positions.clear(); 140 | 141 | // Is it empty? 142 | if ( nullptr == data || 0 == size ) { 143 | return; 144 | } 145 | 146 | Elf_Word align = sizeof( Elf_Word ); 147 | while ( current + (Elf_Xword)3 * align <= size ) { 148 | Elf_Word namesz = convertor( *(const Elf_Word*)( data + current ) ); 149 | Elf_Word descsz = convertor( 150 | *(const Elf_Word*)( data + current + sizeof( namesz ) ) ); 151 | Elf_Word advance = 152 | (Elf_Xword)3 * sizeof( Elf_Word ) + 153 | ( ( namesz + align - 1 ) / align ) * (Elf_Xword)align + 154 | ( ( descsz + align - 1 ) / align ) * (Elf_Xword)align; 155 | if ( namesz < size && descsz < size && current + advance <= size ) { 156 | note_start_positions.emplace_back( current ); 157 | } 158 | else { 159 | break; 160 | } 161 | 162 | current += advance; 163 | } 164 | } 165 | 166 | //------------------------------------------------------------------------------ 167 | private: 168 | const elfio& elf_file; 169 | S* notes; 170 | std::vector note_start_positions; 171 | }; 172 | 173 | using note_section_accessor = 174 | note_section_accessor_template; 175 | using const_note_section_accessor = 176 | note_section_accessor_template; 177 | using note_segment_accessor = 178 | note_section_accessor_template; 179 | using const_note_segment_accessor = 180 | note_section_accessor_template; 181 | 182 | } // namespace ELFIO 183 | 184 | #endif // ELFIO_NOTE_HPP 185 | -------------------------------------------------------------------------------- /app/src/main/cpp/elfio/elfio_segment.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2001-present by Serge Lamikhov-Center 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifndef ELFIO_SEGMENT_HPP 24 | #define ELFIO_SEGMENT_HPP 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace ELFIO { 32 | 33 | class segment 34 | { 35 | friend class elfio; 36 | 37 | public: 38 | virtual ~segment() = default; 39 | 40 | ELFIO_GET_ACCESS_DECL( Elf_Half, index ); 41 | ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type ); 42 | ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); 43 | ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, align ); 44 | ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, virtual_address ); 45 | ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, physical_address ); 46 | ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, file_size ); 47 | ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, memory_size ); 48 | ELFIO_GET_ACCESS_DECL( Elf64_Off, offset ); 49 | 50 | virtual const char* get_data() const = 0; 51 | 52 | virtual Elf_Half add_section( section* psec, Elf_Xword addr_align ) = 0; 53 | virtual Elf_Half add_section_index( Elf_Half index, 54 | Elf_Xword addr_align ) = 0; 55 | virtual Elf_Half get_sections_num() const = 0; 56 | virtual Elf_Half get_section_index_at( Elf_Half num ) const = 0; 57 | virtual bool is_offset_initialized() const = 0; 58 | 59 | protected: 60 | ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); 61 | ELFIO_SET_ACCESS_DECL( Elf_Half, index ); 62 | 63 | virtual const std::vector& get_sections() const = 0; 64 | 65 | virtual bool load( std::istream& stream, 66 | std::streampos header_offset, 67 | bool is_lazy ) = 0; 68 | virtual void save( std::ostream& stream, 69 | std::streampos header_offset, 70 | std::streampos data_offset ) = 0; 71 | }; 72 | 73 | //------------------------------------------------------------------------------ 74 | template class segment_impl : public segment 75 | { 76 | public: 77 | //------------------------------------------------------------------------------ 78 | segment_impl( const endianess_convertor* convertor, 79 | const address_translator* translator ) 80 | : convertor( convertor ), translator( translator ) 81 | { 82 | } 83 | 84 | //------------------------------------------------------------------------------ 85 | // Section info functions 86 | ELFIO_GET_SET_ACCESS( Elf_Word, type, ph.p_type ); 87 | ELFIO_GET_SET_ACCESS( Elf_Word, flags, ph.p_flags ); 88 | ELFIO_GET_SET_ACCESS( Elf_Xword, align, ph.p_align ); 89 | ELFIO_GET_SET_ACCESS( Elf64_Addr, virtual_address, ph.p_vaddr ); 90 | ELFIO_GET_SET_ACCESS( Elf64_Addr, physical_address, ph.p_paddr ); 91 | ELFIO_GET_SET_ACCESS( Elf_Xword, file_size, ph.p_filesz ); 92 | ELFIO_GET_SET_ACCESS( Elf_Xword, memory_size, ph.p_memsz ); 93 | ELFIO_GET_ACCESS( Elf64_Off, offset, ph.p_offset ); 94 | 95 | //------------------------------------------------------------------------------ 96 | Elf_Half get_index() const override { return index; } 97 | 98 | //------------------------------------------------------------------------------ 99 | const char* get_data() const override 100 | { 101 | if ( is_lazy ) { 102 | load_data(); 103 | } 104 | return data.get(); 105 | } 106 | 107 | //------------------------------------------------------------------------------ 108 | Elf_Half add_section_index( Elf_Half sec_index, 109 | Elf_Xword addr_align ) override 110 | { 111 | sections.emplace_back( sec_index ); 112 | if ( addr_align > get_align() ) { 113 | set_align( addr_align ); 114 | } 115 | 116 | return (Elf_Half)sections.size(); 117 | } 118 | 119 | //------------------------------------------------------------------------------ 120 | Elf_Half add_section( section* psec, Elf_Xword addr_align ) override 121 | { 122 | return add_section_index( psec->get_index(), addr_align ); 123 | } 124 | 125 | //------------------------------------------------------------------------------ 126 | Elf_Half get_sections_num() const override 127 | { 128 | return (Elf_Half)sections.size(); 129 | } 130 | 131 | //------------------------------------------------------------------------------ 132 | Elf_Half get_section_index_at( Elf_Half num ) const override 133 | { 134 | if ( num < sections.size() ) { 135 | return sections[num]; 136 | } 137 | 138 | return Elf_Half( -1 ); 139 | } 140 | 141 | //------------------------------------------------------------------------------ 142 | protected: 143 | //------------------------------------------------------------------------------ 144 | 145 | //------------------------------------------------------------------------------ 146 | void set_offset( const Elf64_Off& value ) override 147 | { 148 | ph.p_offset = decltype( ph.p_offset )( value ); 149 | ph.p_offset = ( *convertor )( ph.p_offset ); 150 | is_offset_set = true; 151 | } 152 | 153 | //------------------------------------------------------------------------------ 154 | bool is_offset_initialized() const override { return is_offset_set; } 155 | 156 | //------------------------------------------------------------------------------ 157 | const std::vector& get_sections() const override 158 | { 159 | return sections; 160 | } 161 | 162 | //------------------------------------------------------------------------------ 163 | void set_index( const Elf_Half& value ) override { index = value; } 164 | 165 | //------------------------------------------------------------------------------ 166 | bool load( std::istream& stream, 167 | std::streampos header_offset, 168 | bool is_lazy_ ) override 169 | { 170 | pstream = &stream; 171 | is_lazy = is_lazy_; 172 | 173 | if ( translator->empty() ) { 174 | stream.seekg( 0, std::istream::end ); 175 | set_stream_size( size_t( stream.tellg() ) ); 176 | } 177 | else { 178 | set_stream_size( std::numeric_limits::max() ); 179 | } 180 | 181 | stream.seekg( ( *translator )[header_offset] ); 182 | stream.read( reinterpret_cast( &ph ), sizeof( ph ) ); 183 | is_offset_set = true; 184 | 185 | if ( !is_lazy ) { 186 | return load_data(); 187 | } 188 | 189 | return true; 190 | } 191 | 192 | //------------------------------------------------------------------------------ 193 | bool load_data() const 194 | { 195 | is_lazy = false; 196 | if ( PT_NULL == get_type() || 0 == get_file_size() ) { 197 | return true; 198 | } 199 | 200 | pstream->seekg( ( *translator )[( *convertor )( ph.p_offset )] ); 201 | Elf_Xword size = get_file_size(); 202 | 203 | if ( size > get_stream_size() ) { 204 | data = nullptr; 205 | } 206 | else { 207 | data.reset( new ( std::nothrow ) char[(size_t)size + 1] ); 208 | 209 | if ( nullptr != data.get() && pstream->read( data.get(), size ) ) { 210 | data.get()[size] = 0; 211 | } 212 | else { 213 | data = nullptr; 214 | return false; 215 | } 216 | } 217 | 218 | return true; 219 | } 220 | 221 | //------------------------------------------------------------------------------ 222 | void save( std::ostream& stream, 223 | std::streampos header_offset, 224 | std::streampos data_offset ) override 225 | { 226 | ph.p_offset = decltype( ph.p_offset )( data_offset ); 227 | ph.p_offset = ( *convertor )( ph.p_offset ); 228 | adjust_stream_size( stream, header_offset ); 229 | stream.write( reinterpret_cast( &ph ), sizeof( ph ) ); 230 | } 231 | 232 | //------------------------------------------------------------------------------ 233 | size_t get_stream_size() const { return stream_size; } 234 | 235 | //------------------------------------------------------------------------------ 236 | void set_stream_size( size_t value ) { stream_size = value; } 237 | 238 | //------------------------------------------------------------------------------ 239 | private: 240 | mutable std::istream* pstream = nullptr; 241 | T ph = {}; 242 | Elf_Half index = 0; 243 | mutable std::unique_ptr data; 244 | std::vector sections; 245 | const endianess_convertor* convertor = nullptr; 246 | const address_translator* translator = nullptr; 247 | size_t stream_size = 0; 248 | bool is_offset_set = false; 249 | mutable bool is_lazy = false; 250 | }; 251 | 252 | } // namespace ELFIO 253 | 254 | #endif // ELFIO_SEGMENT_HPP 255 | -------------------------------------------------------------------------------- /app/src/main/cpp/elfio/elfio_strings.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2001-present by Serge Lamikhov-Center 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifndef ELFIO_STRINGS_HPP 24 | #define ELFIO_STRINGS_HPP 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | namespace ELFIO { 31 | 32 | //------------------------------------------------------------------------------ 33 | template class string_section_accessor_template 34 | { 35 | public: 36 | //------------------------------------------------------------------------------ 37 | explicit string_section_accessor_template( S* section ) 38 | : string_section( section ) 39 | { 40 | } 41 | 42 | //------------------------------------------------------------------------------ 43 | const char* get_string( Elf_Word index ) const 44 | { 45 | if ( string_section ) { 46 | const char* data = string_section->get_data(); 47 | if ( index < string_section->get_size() && nullptr != data ) { 48 | size_t string_length = 49 | strnlen( data + index, string_section->get_size() - index ); 50 | if ( string_length < ( string_section->get_size() - index ) ) 51 | return data + index; 52 | } 53 | } 54 | 55 | return nullptr; 56 | } 57 | 58 | //------------------------------------------------------------------------------ 59 | Elf_Word add_string( const char* str ) 60 | { 61 | Elf_Word current_position = 0; 62 | 63 | if ( string_section ) { 64 | // Strings are addeded to the end of the current section data 65 | current_position = 66 | static_cast( string_section->get_size() ); 67 | 68 | if ( current_position == 0 ) { 69 | char empty_string = '\0'; 70 | string_section->append_data( &empty_string, 1 ); 71 | current_position++; 72 | } 73 | string_section->append_data( 74 | str, static_cast( std::strlen( str ) + 1 ) ); 75 | } 76 | 77 | return current_position; 78 | } 79 | 80 | //------------------------------------------------------------------------------ 81 | Elf_Word add_string( const std::string& str ) 82 | { 83 | return add_string( str.c_str() ); 84 | } 85 | 86 | //------------------------------------------------------------------------------ 87 | private: 88 | S* string_section; 89 | }; 90 | 91 | using string_section_accessor = string_section_accessor_template
; 92 | using const_string_section_accessor = 93 | string_section_accessor_template; 94 | 95 | } // namespace ELFIO 96 | 97 | #endif // ELFIO_STRINGS_HPP 98 | -------------------------------------------------------------------------------- /app/src/main/cpp/elfio/elfio_version.hpp: -------------------------------------------------------------------------------- 1 | #define ELFIO_VERSION "3.12" 2 | -------------------------------------------------------------------------------- /app/src/main/cpp/elfio/elfio_versym.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2001-present by Serge Lamikhov-Center 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifndef ELFIO_VERSYM_HPP 24 | #define ELFIO_VERSYM_HPP 25 | 26 | namespace ELFIO { 27 | 28 | //------------------------------------------------------------------------------ 29 | template class versym_section_accessor_template 30 | { 31 | public: 32 | //------------------------------------------------------------------------------ 33 | explicit versym_section_accessor_template( S* section ) 34 | : versym_section( section ) 35 | { 36 | if ( section != nullptr ) { 37 | entries_num = decltype( entries_num )( section->get_size() / 38 | sizeof( Elf_Half ) ); 39 | } 40 | } 41 | 42 | //------------------------------------------------------------------------------ 43 | Elf_Word get_entries_num() const 44 | { 45 | if ( versym_section ) { 46 | return entries_num; 47 | } 48 | return 0; 49 | } 50 | 51 | //------------------------------------------------------------------------------ 52 | bool get_entry( Elf_Word no, Elf_Half& value ) const 53 | { 54 | if ( versym_section && ( no < get_entries_num() ) ) { 55 | value = ( (Elf_Half*)versym_section->get_data() )[no]; 56 | return true; 57 | } 58 | 59 | return false; 60 | } 61 | 62 | //------------------------------------------------------------------------------ 63 | bool modify_entry( Elf_Word no, Elf_Half value ) 64 | { 65 | if ( versym_section && ( no < get_entries_num() ) ) { 66 | ( (Elf_Half*)versym_section->get_data() )[no] = value; 67 | return true; 68 | } 69 | 70 | return false; 71 | } 72 | 73 | //------------------------------------------------------------------------------ 74 | bool add_entry( Elf_Half value ) 75 | { 76 | if ( !versym_section ) { 77 | return false; 78 | } 79 | 80 | versym_section->append_data( (const char*)&value, sizeof( Elf_Half ) ); 81 | ++entries_num; 82 | 83 | return true; 84 | } 85 | 86 | //------------------------------------------------------------------------------ 87 | private: 88 | S* versym_section = nullptr; 89 | Elf_Word entries_num = 0; 90 | }; 91 | 92 | using versym_section_accessor = versym_section_accessor_template
; 93 | using const_versym_section_accessor = 94 | versym_section_accessor_template; 95 | 96 | //------------------------------------------------------------------------------ 97 | template class versym_r_section_accessor_template 98 | { 99 | public: 100 | //------------------------------------------------------------------------------ 101 | versym_r_section_accessor_template( const elfio& elf_file, 102 | S* versym_r_section ) 103 | : elf_file( elf_file ), versym_r_section( versym_r_section ), 104 | entries_num( 0 ) 105 | { 106 | // Find .dynamic section 107 | const section* dynamic_section = elf_file.sections[".dynamic"]; 108 | 109 | if ( dynamic_section == nullptr ) { 110 | return; 111 | } 112 | 113 | const_dynamic_section_accessor dynamic_section_acc( elf_file, 114 | dynamic_section ); 115 | Elf_Xword dyn_sec_num = dynamic_section_acc.get_entries_num(); 116 | for ( Elf_Xword i = 0; i < dyn_sec_num; ++i ) { 117 | Elf_Xword tag; 118 | Elf_Xword value; 119 | std::string str; 120 | 121 | if ( dynamic_section_acc.get_entry( i, tag, value, str ) && 122 | tag == DT_VERNEEDNUM ) { 123 | entries_num = (Elf_Word)value; 124 | break; 125 | } 126 | } 127 | } 128 | 129 | //------------------------------------------------------------------------------ 130 | Elf_Word get_entries_num() const { return entries_num; } 131 | 132 | //------------------------------------------------------------------------------ 133 | bool get_entry( Elf_Word no, 134 | Elf_Half& version, 135 | std::string& file_name, 136 | Elf_Word& hash, 137 | Elf_Half& flags, 138 | Elf_Half& other, 139 | std::string& dep_name ) const 140 | { 141 | if ( versym_r_section == nullptr || ( no >= get_entries_num() ) ) { 142 | return false; 143 | } 144 | 145 | const_string_section_accessor string_section_acc( 146 | elf_file.sections[versym_r_section->get_link()] ); 147 | 148 | Elfxx_Verneed* verneed = (Elfxx_Verneed*)versym_r_section->get_data(); 149 | Elfxx_Vernaux* veraux = 150 | (Elfxx_Vernaux*)( (char*)verneed + verneed->vn_aux ); 151 | for ( Elf_Word i = 0; i < no; ++i ) { 152 | verneed = (Elfxx_Verneed*)( (char*)verneed + verneed->vn_next ); 153 | veraux = (Elfxx_Vernaux*)( (char*)verneed + verneed->vn_aux ); 154 | } 155 | 156 | version = verneed->vn_version; 157 | file_name = string_section_acc.get_string( verneed->vn_file ); 158 | hash = veraux->vna_hash; 159 | flags = veraux->vna_flags; 160 | other = veraux->vna_other; 161 | dep_name = string_section_acc.get_string( veraux->vna_name ); 162 | 163 | return true; 164 | } 165 | 166 | //------------------------------------------------------------------------------ 167 | private: 168 | const elfio& elf_file; 169 | S* versym_r_section = nullptr; 170 | Elf_Word entries_num = 0; 171 | }; 172 | 173 | using versym_r_section_accessor = versym_r_section_accessor_template
; 174 | using const_versym_r_section_accessor = 175 | versym_r_section_accessor_template; 176 | 177 | } // namespace ELFIO 178 | 179 | #endif // ELFIO_VERSYM_HPP 180 | -------------------------------------------------------------------------------- /app/src/main/cpp/libs/arm64-v8a/libQBDI.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mrack/XposedNHook/a250ffcd543b7dad77d43b44af0ac80c873f77f0/app/src/main/cpp/libs/arm64-v8a/libQBDI.a -------------------------------------------------------------------------------- /app/src/main/cpp/libs/arm64-v8a/libdobby.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mrack/XposedNHook/a250ffcd543b7dad77d43b44af0ac80c873f77f0/app/src/main/cpp/libs/arm64-v8a/libdobby.a -------------------------------------------------------------------------------- /app/src/main/cpp/linker_hook.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mrack on 2024/4/19. 3 | // 4 | 5 | #include "linker_hook.h" 6 | #include "elfio/elfio.hpp" 7 | #include "nhook.h" 8 | 9 | 10 | install_hook_name(android_dlopen_ext, void *, const char *filename, int flags, 11 | const void *extinfo) { 12 | void *ret = orig_android_dlopen_ext(filename, flags, extinfo); 13 | module_load(filename); 14 | return ret; 15 | } 16 | 17 | void hook_module_load() { 18 | void *address = get_address_from_module(get_linker_path(), "android_dlopen_ext"); 19 | if (address != nullptr) { 20 | install_hook_android_dlopen_ext(address); 21 | } else { 22 | LOGD("hook_module_load: android_dlopen_ext not found"); 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/cpp/linker_hook.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mrack on 2024/4/19. 3 | // 4 | 5 | #ifndef XPOSEDNHOOK_LINKER_HOOK_H 6 | #define XPOSEDNHOOK_LINKER_HOOK_H 7 | 8 | #include "utils.h" 9 | #include "dobby/dobby.h" 10 | #include 11 | 12 | void hook_module_load(); 13 | 14 | #endif //XPOSEDNHOOK_LINKER_HOOK_H 15 | -------------------------------------------------------------------------------- /app/src/main/cpp/nhook.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mrack on 2024/4/19. 3 | // 4 | 5 | #include "nhook.h" 6 | 7 | #include "demo/qbdihook.h" 8 | #include "demo/ytbssl.h" 9 | #include "demo/modmenu_native.h" 10 | #include "linker_hook.h" 11 | #include 12 | #include 13 | #include "demo/il2cpp_dumper.h" 14 | 15 | extern "C" 16 | { 17 | 18 | JNIEXPORT void JNICALL 19 | Java_cn_mrack_xposed_nhook_NHook_initNativeHook(JNIEnv *env, jclass thiz, jobject context) { 20 | LOGD("initNativeHook"); 21 | gContext = env->NewGlobalRef(context); 22 | LOGD("test_QBDI"); 23 | test_QBDI(); 24 | LOGD("test_youtube"); 25 | test_youtube(); 26 | LOGD("dump_il2cpp"); 27 | dumpIL2cpp(get_data_path(gContext)); 28 | } 29 | 30 | 31 | JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { 32 | LOGD("JNI_OnLoad"); 33 | JNIEnv *env; 34 | if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { 35 | return -1; 36 | } 37 | gVm = vm; 38 | return JNI_VERSION_1_6; 39 | } 40 | } -------------------------------------------------------------------------------- /app/src/main/cpp/nhook.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mrack on 2024/4/19. 3 | // 4 | 5 | #ifndef NHOOK_H 6 | #define NHOOK_H 7 | 8 | #include 9 | #include 10 | 11 | void module_load(const char *filename); 12 | 13 | #endif -------------------------------------------------------------------------------- /app/src/main/cpp/utils.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mrack on 2024/4/19. 3 | // 4 | #include "utils.h" 5 | #include "elfio/elfio.hpp" 6 | 7 | JavaVM *gVm = nullptr; 8 | jobject gContext = nullptr; 9 | 10 | class JavaEnv { 11 | public: 12 | JavaEnv() { 13 | if (gVm != nullptr) { 14 | int state = gVm->GetEnv((void **) &env, JNI_VERSION_1_6); 15 | if (state == JNI_EDETACHED) { 16 | if (JNI_OK == gVm->AttachCurrentThread(&env, NULL)) { 17 | attach = true; 18 | } else { 19 | env = nullptr; 20 | } 21 | } else if (state == JNI_EVERSION) { 22 | env = nullptr; 23 | } 24 | } 25 | 26 | } 27 | 28 | ~JavaEnv() { 29 | if (gVm != nullptr && attach) { 30 | gVm->DetachCurrentThread(); 31 | } 32 | } 33 | 34 | JNIEnv *operator->() const { 35 | return env; 36 | } 37 | 38 | bool isNull() const { 39 | return env == nullptr; 40 | } 41 | 42 | JNIEnv *env; 43 | bool attach = false; 44 | }; 45 | 46 | const char *get_data_path(jobject context) { 47 | JavaEnv env; 48 | if (env.isNull()) { 49 | return nullptr; 50 | } 51 | jclass context_class = env->GetObjectClass(context); 52 | jmethodID getFilesDir = env->GetMethodID(context_class, "getDataDir", "()Ljava/io/File;"); 53 | jobject file = env->CallObjectMethod(context, getFilesDir); 54 | jclass file_class = env->GetObjectClass(file); 55 | jmethodID getPath = env->GetMethodID(file_class, "getPath", "()Ljava/lang/String;"); 56 | jstring path = (jstring) env->CallObjectMethod(file, getPath); 57 | const char *data = env->GetStringUTFChars(path, 0); 58 | return data; 59 | } 60 | 61 | int get_sdk_level() { 62 | if (SDK_INT > 0) { 63 | return SDK_INT; 64 | } 65 | char sdk[128] = {0}; 66 | __system_property_get("ro.build.version.sdk", sdk); 67 | SDK_INT = atoi(sdk); 68 | return SDK_INT; 69 | } 70 | 71 | 72 | char *get_linker_path() { 73 | char *linker; 74 | #if defined(__aarch64__) 75 | if (get_sdk_level() >= ANDROID_R) { 76 | linker = (char *) "/apex/com.android.runtime/bin/linker64"; 77 | } else if (get_sdk_level() >= ANDROID_Q) { 78 | linker = (char *) "/apex/com.android.runtime/bin/linker64"; 79 | } else { 80 | linker = (char *) "/system/bin/linker64"; 81 | } 82 | #else 83 | if (get_sdk_level() >= ANDROID_R) { 84 | linker = (char *) "/apex/com.android.runtime/bin/linker"; 85 | } else if (get_sdk_level() >= ANDROID_Q) { 86 | linker = (char *) "/apex/com.android.runtime/bin/linker"; 87 | } else { 88 | linker = (char *) "/system/bin/linker"; 89 | } 90 | #endif 91 | return linker; 92 | } 93 | 94 | const char* find_path_from_maps(const char *soname) { 95 | FILE *fp = fopen("/proc/self/maps", "r"); 96 | if (fp == NULL) { 97 | return nullptr; 98 | } 99 | // get path from maps 100 | char line[1024]; 101 | while (fgets(line, sizeof(line), fp)) { 102 | if (strstr(line, soname)) { 103 | char *start = strchr(line, '/'); 104 | char *path = strdup(start); 105 | fclose(fp); 106 | return path; 107 | } 108 | } 109 | fclose(fp); 110 | return nullptr; 111 | } 112 | 113 | std::pair find_info_from_maps(const char *soname) { 114 | FILE *fp = fopen("/proc/self/maps", "r"); 115 | if (fp == NULL) { 116 | return std::make_pair(0, 0); 117 | } 118 | char line[1024]; 119 | while (fgets(line, sizeof(line), fp)) { 120 | if (strstr(line, soname)) { 121 | char *start = strtok(line, "-"); 122 | char *end = strtok(NULL, " "); 123 | fclose(fp); 124 | return std::make_pair((size_t) strtoul(start, NULL, 16), 125 | strtoul(end, NULL, 16) - strtoul(start, NULL, 16)); 126 | } 127 | } 128 | fclose(fp); 129 | return std::make_pair(0, 0); 130 | } 131 | 132 | uint64_t get_arg(DobbyRegisterContext *ctx, int index) { 133 | #if defined(_M_X64) || defined(__x86_64__) 134 | assert(index < 6); 135 | if (index == 0) 136 | return ctx->general.regs.rdi; 137 | if (index == 1) 138 | return ctx->general.regs.rsi; 139 | if (index == 2) 140 | return ctx->general.regs.rdx; 141 | if (index == 3) 142 | return ctx->general.regs.rcx; 143 | if (index == 4) 144 | return ctx->general.regs.r8; 145 | if (index == 5) 146 | return ctx->general.regs.r9; 147 | #elif defined(__arm64__) || defined(__aarch64__) 148 | assert(index < 8); 149 | return ctx->general.x[index]; 150 | #else 151 | #error "Not support this architecture" 152 | #endif 153 | return -1; 154 | } 155 | 156 | u_char *hex2char(const char *hex) { 157 | size_t len = strlen(hex); 158 | u_char *result = (u_char *) malloc(len / 2); 159 | for (size_t i = 0; i < len; i += 2) { 160 | if (hex[i] == '?' || hex[i + 1] == '?') { 161 | result[i / 2] = 0xcc; 162 | continue; 163 | } 164 | sscanf(hex + i, "%2hhx", &result[i / 2]); 165 | } 166 | return result; 167 | } 168 | 169 | int search_hex(u_char *haystack, size_t haystackLen, const char *needle) { 170 | size_t needleLen = strlen(needle) / 2; 171 | u_char *needleChar = hex2char(needle); 172 | int result = boyer_moore_search(haystack, haystackLen, needleChar, needleLen); 173 | free(needleChar); 174 | return result; 175 | } 176 | 177 | int boyer_moore_search(u_char *haystack, size_t haystackLen, u_char *needle, size_t needleLen) { 178 | size_t skipTable[256]; 179 | for (size_t i = 0; i < 256; i++) { 180 | skipTable[i] = needleLen; 181 | } 182 | for (size_t i = 0; i < needleLen - 1; i++) { 183 | skipTable[(size_t) needle[i]] = needleLen - 1 - i; 184 | } 185 | size_t i = 0; 186 | while (i <= haystackLen - needleLen) { 187 | int j = needleLen - 1; 188 | while (j >= 0 && (haystack[i + j] == needle[j] || needle[j] == 0xcc)) { 189 | j--; 190 | } 191 | if (j < 0) { 192 | return i; 193 | } else { 194 | i += skipTable[(size_t) haystack[i + needleLen - 1]]; 195 | } 196 | } 197 | return -1; 198 | } 199 | 200 | 201 | 202 | void *get_address_from_module(const char *module_path, const char *symbol_name) { 203 | ELFIO::elfio elffile; 204 | std::string name; 205 | ELFIO::Elf64_Addr value; 206 | ELFIO::Elf_Xword size; 207 | unsigned char bind; 208 | unsigned char type; 209 | ELFIO::Elf_Half section_index; 210 | unsigned char other; 211 | const char *file_name = strrchr(module_path, '/'); 212 | elffile.load(module_path); 213 | size_t module_base = find_info_from_maps(file_name).first; 214 | ELFIO::section *s = elffile.sections[".dynsym"]; 215 | if (s != nullptr) { 216 | ELFIO::symbol_section_accessor symbol_accessor(elffile, s); 217 | for (int i = 0; i < symbol_accessor.get_symbols_num(); ++i) { 218 | symbol_accessor.get_symbol(i, name, value, size, bind, type, section_index, other); 219 | if (name.find(symbol_name) != std::string::npos && type == ELFIO::STT_FUNC) { 220 | return (void *) (value + module_base); 221 | } 222 | } 223 | } 224 | 225 | s = elffile.sections[".symtab"]; 226 | if (s != nullptr) { 227 | ELFIO::symbol_section_accessor symbol_accessor(elffile, s); 228 | for (int i = 0; i < symbol_accessor.get_symbols_num(); ++i) { 229 | symbol_accessor.get_symbol(i, name, value, size, bind, type, section_index, other); 230 | if (name.find(symbol_name) != std::string::npos) { 231 | return (void *) (value + module_base); 232 | } 233 | } 234 | } 235 | return nullptr; 236 | } -------------------------------------------------------------------------------- /app/src/main/cpp/utils.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mrack on 2024/4/19. 3 | // 4 | 5 | #ifndef XPOSEDNHOOK_UTILS_H 6 | #define XPOSEDNHOOK_UTILS_H 7 | 8 | #include 9 | #include "dobby/dobby.h" 10 | #include 11 | #include 12 | #include 13 | 14 | #ifdef NDEBUG 15 | #define LOGD(...) 16 | #define LOGE(...) 17 | #define LOGI(...) 18 | #define LOGW(...) 19 | #else 20 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "MainHook", __VA_ARGS__) 21 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "MainHook", __VA_ARGS__) 22 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "MainHook", __VA_ARGS__) 23 | #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, "MainHook", __VA_ARGS__) 24 | #endif 25 | #define ANDROID_O 26 26 | #define ANDROID_O2 27 27 | #define ANDROID_P 28 28 | #define ANDROID_Q 29 29 | #define ANDROID_R 30 30 | #define ANDROID_S 31 31 | static int SDK_INT = -1; 32 | 33 | 34 | extern JavaVM *gVm; 35 | 36 | extern jobject gContext; 37 | 38 | const char *get_data_path(jobject context); 39 | 40 | int get_sdk_level(); 41 | 42 | char *get_linker_path(); 43 | 44 | std::pair find_info_from_maps(const char *soname); 45 | 46 | const char *find_path_from_maps(const char *soname); 47 | 48 | int boyer_moore_search(u_char *haystack, size_t haystackLen, u_char *needle, size_t needleLen); 49 | 50 | int search_hex(u_char *haystack, size_t haystackLen, const char *needle); 51 | 52 | uint64_t get_arg(DobbyRegisterContext *ctx, int index); 53 | 54 | void *get_address_from_module(const char *module_path, const char *symbol_name); 55 | 56 | #endif //XPOSEDNHOOK_UTILS_H 57 | -------------------------------------------------------------------------------- /app/src/main/cpp/vm.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "vm.h" 3 | #include "assert.h" 4 | 5 | using namespace std; 6 | using namespace QBDI; 7 | 8 | 9 | QBDI::VMAction 10 | showPostInstruction(QBDI::VM *vm, QBDI::GPRState *gprState, QBDI::FPRState *fprState, 11 | void *data) { 12 | 13 | auto thiz = (class vm *) data; 14 | const QBDI::InstAnalysis *instAnalysis = vm->getInstAnalysis(QBDI::ANALYSIS_INSTRUCTION 15 | | QBDI::ANALYSIS_SYMBOL 16 | | QBDI::ANALYSIS_DISASSEMBLY 17 | | QBDI::ANALYSIS_OPERANDS 18 | ); 19 | 20 | std::stringstream output; 21 | for (int i = 0; i < instAnalysis->numOperands; ++i) { 22 | auto op = instAnalysis->operands[i]; 23 | if (op.regAccess == REGISTER_WRITE || op.regAccess == REGISTER_READ_WRITE) { 24 | if (op.regCtxIdx != -1) { 25 | if (op.type == OPERAND_GPR) { 26 | output << op.regName << "=" << std::hex << QBDI_GPR_GET(gprState, op.regCtxIdx) 27 | << " "; 28 | output.flush(); 29 | } 30 | } 31 | } 32 | } 33 | if (!output.str().empty()) { 34 | thiz->logbuf << "\tw[" << output.str() << "]" << std::endl; 35 | } else { 36 | thiz->logbuf << std::endl; 37 | } 38 | return QBDI::VMAction::CONTINUE; 39 | } 40 | 41 | QBDI::VMAction 42 | showPreInstruction(QBDI::VM *vm, QBDI::GPRState *gprState, QBDI::FPRState *fprState, 43 | void *data) { 44 | auto thiz = (class vm *) data; 45 | const QBDI::InstAnalysis *instAnalysis = vm->getInstAnalysis(QBDI::ANALYSIS_INSTRUCTION 46 | | QBDI::ANALYSIS_SYMBOL 47 | | QBDI::ANALYSIS_DISASSEMBLY 48 | | QBDI::ANALYSIS_OPERANDS 49 | ); 50 | 51 | 52 | if (instAnalysis->symbol != nullptr) { 53 | thiz->logbuf << instAnalysis->symbol << "[0x" << std::hex << instAnalysis->symbolOffset 54 | << "]:0x" << instAnalysis->address 55 | << ": " << instAnalysis->disassembly; 56 | } else { 57 | thiz->logbuf << "0x" << std::hex << instAnalysis->address 58 | << ": " << instAnalysis->disassembly; 59 | } 60 | 61 | stringstream output; 62 | for (int i = 0; i < instAnalysis->numOperands; ++i) { 63 | auto op = instAnalysis->operands[i]; 64 | if (op.regAccess == QBDI::REGISTER_READ || op.regAccess == REGISTER_READ_WRITE) { 65 | if (op.regCtxIdx != -1) { 66 | if (op.type == OPERAND_GPR) { 67 | output << op.regName << "=" << std::hex << QBDI_GPR_GET(gprState, op.regCtxIdx) 68 | << " "; 69 | output.flush(); 70 | } 71 | } 72 | } 73 | } 74 | 75 | 76 | if (!output.str().empty()) { 77 | thiz->logbuf << "\tr[" << output.str() << "]"; 78 | } 79 | return QBDI::VMAction::CONTINUE; 80 | } 81 | 82 | 83 | QBDI::VMAction 84 | showMemoryAccess(QBDI::VM *vm, QBDI::GPRState *gprState, QBDI::FPRState *fprState, 85 | void *data) { 86 | auto thiz = (class vm *) data; 87 | if (vm->getInstMemoryAccess().empty()) { 88 | thiz->logbuf << std::endl; 89 | } 90 | for (const auto &acc: vm->getInstMemoryAccess()) { 91 | if (acc.type == MEMORY_READ) { 92 | thiz->logbuf << " mem[r]:" << std::hex << acc.accessAddress << " size:" << acc.size 93 | << " value:" << acc.value; 94 | } else if (acc.type == MEMORY_WRITE) { 95 | thiz->logbuf << " mem[w]:" << std::hex << acc.accessAddress << " size:" << acc.size 96 | << " value:" << acc.value; 97 | } else { 98 | thiz->logbuf << " mem[rw]:" << std::hex << acc.accessAddress << " size:" << acc.size 99 | << " value:" << acc.value; 100 | } 101 | } 102 | thiz->logbuf << std::endl << std::endl; 103 | return QBDI::VMAction::CONTINUE; 104 | } 105 | 106 | QBDI::VM vm::init(void *address) { 107 | uint32_t cid; 108 | QBDI::GPRState *state; 109 | QBDI::VM qvm{}; 110 | state = qvm.getGPRState(); 111 | qvm.setOptions(QBDI::OPT_DISABLE_LOCAL_MONITOR | QBDI::OPT_BYPASS_PAUTH | QBDI::OPT_ENABLE_BTI); 112 | assert(state != nullptr); 113 | qvm.recordMemoryAccess(QBDI::MEMORY_READ_WRITE); 114 | cid = qvm.addCodeCB(QBDI::PREINST, showPreInstruction, this); 115 | assert(cid != QBDI::INVALID_EVENTID); 116 | cid = qvm.addCodeCB(QBDI::POSTINST, showPostInstruction, this); 117 | assert(cid != QBDI::INVALID_EVENTID); 118 | cid = qvm.addMemAccessCB(MEMORY_READ_WRITE, showMemoryAccess, this); 119 | assert(cid != QBDI::INVALID_EVENTID); 120 | bool ret = qvm.addInstrumentedModuleFromAddr(reinterpret_cast(address)); 121 | assert(ret == true); 122 | return qvm; 123 | } 124 | 125 | void syn_regs(DobbyRegisterContext *ctx, QBDI::GPRState *state) { 126 | for (int i = 0; i < 29; i++) { 127 | QBDI_GPR_SET(state, i, ctx->general.x[i]); 128 | } 129 | state->lr = ctx->lr; 130 | state->x29 = ctx->fp; 131 | state->sp = ctx->sp; 132 | } -------------------------------------------------------------------------------- /app/src/main/cpp/vm.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Mrack on 2024/4/19. 3 | // 4 | 5 | #ifndef XPOSEDNHOOK_VM_H 6 | #define XPOSEDNHOOK_VM_H 7 | 8 | #include "QBDI.h" 9 | #include 10 | #include "nhook.h" 11 | #include "dobby/dobby.h" 12 | #include 13 | 14 | 15 | void syn_regs(DobbyRegisterContext *ctx, QBDI::GPRState *state); 16 | 17 | #define LOGT(...) __android_log_print(ANDROID_LOG_DEBUG, "TRACER", __VA_ARGS__) 18 | 19 | class vm { 20 | 21 | public: 22 | QBDI::VM init(void *address); 23 | 24 | std::stringstream logbuf; 25 | private: 26 | }; 27 | 28 | 29 | #endif //XPOSEDNHOOK_VM_H 30 | -------------------------------------------------------------------------------- /app/src/main/java/cn/mrack/xposed/nhook/HookUtils.java: -------------------------------------------------------------------------------- 1 | package cn.mrack.xposed.nhook; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Activity; 5 | import android.app.Application; 6 | import android.content.Context; 7 | import android.os.Bundle; 8 | import android.util.Log; 9 | 10 | import java.io.ByteArrayOutputStream; 11 | import java.io.File; 12 | import java.io.FileInputStream; 13 | import java.io.FileOutputStream; 14 | import java.security.MessageDigest; 15 | 16 | import cn.mrack.so.arm64.SoData; 17 | import de.robv.android.xposed.XC_MethodHook; 18 | import de.robv.android.xposed.XposedHelpers; 19 | 20 | public class HookUtils { 21 | 22 | interface InitCallback { 23 | void onHook(Context context); 24 | } 25 | 26 | public static void attachApplication(InitCallback callback) { 27 | // hook application attach 28 | XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() { 29 | @Override 30 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 31 | // get the context 32 | Context context = (Context) param.args[0]; 33 | callback.onHook(context); 34 | } 35 | }); 36 | } 37 | 38 | public static void attachActivity(InitCallback callback) { 39 | XposedHelpers.findAndHookMethod(Activity.class, "onCreate", Bundle.class, new XC_MethodHook() { 40 | @Override 41 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 42 | Activity activity = (Activity) param.thisObject; 43 | callback.onHook(activity); 44 | } 45 | }); 46 | } 47 | 48 | public static void nativeHookInit(Context context) { 49 | if (loadSo(context)) { 50 | Log.d(TAG, "nativeHookInit: load so success"); 51 | } else { 52 | Log.e(TAG, "nativeHookInit: load so failed"); 53 | } 54 | NHook.initNativeHook(context); 55 | } 56 | 57 | 58 | private static final String TAG = "HookUtils"; 59 | 60 | 61 | private static boolean verifyMd5(File file, String md5) { 62 | if (!file.exists()) { 63 | return false; 64 | } 65 | try { 66 | FileInputStream fileInputStream = new FileInputStream(file); 67 | byte[] buffer = new byte[1024]; 68 | int bytesRead; 69 | ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 70 | while ((bytesRead = fileInputStream.read(buffer)) != -1) { 71 | byteArrayOutputStream.write(buffer, 0, bytesRead); 72 | } 73 | fileInputStream.close(); 74 | byte[] bytes = byteArrayOutputStream.toByteArray(); 75 | byteArrayOutputStream.close(); 76 | MessageDigest md = MessageDigest.getInstance("MD5"); 77 | byte[] fileMd5 = md.digest(bytes); 78 | StringBuilder sb = new StringBuilder(); 79 | for (byte b : fileMd5) { 80 | sb.append(Integer.toHexString((b & 0xFF) | 0x100).substring(1, 3)); 81 | } 82 | if (!sb.toString().equals(md5)) { 83 | return false; 84 | } 85 | return true; 86 | } catch (Exception e) { 87 | return false; 88 | } 89 | } 90 | 91 | @SuppressLint("UnsafeDynamicallyLoadedCode") 92 | private static boolean loadSo(Context context) { 93 | try { 94 | File file = context.getFileStreamPath("libnhook.so"); 95 | String md5 = SoData.md5; 96 | byte[] data = SoData.data; 97 | if (!verifyMd5(file, md5)) { 98 | FileOutputStream fileOutputStream = new FileOutputStream(file); 99 | fileOutputStream.write(data); 100 | fileOutputStream.close(); 101 | } 102 | System.load(file.getAbsolutePath()); 103 | return true; 104 | } catch (Exception e) { 105 | Log.e(TAG, "loadSo: ", e); 106 | return false; 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /app/src/main/java/cn/mrack/xposed/nhook/MainHook.java: -------------------------------------------------------------------------------- 1 | package cn.mrack.xposed.nhook; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.Context; 5 | import android.content.SharedPreferences; 6 | import android.util.Log; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import cn.mrack.xposed.nhook.menu.Menu; 10 | import cn.mrack.xposed.nhook.menu.PBoolean; 11 | import cn.mrack.xposed.nhook.menu.PInteger; 12 | import cn.mrack.xposed.nhook.menu.PString; 13 | import cn.mrack.xposed.nhook.menu.SurfaceImGUI; 14 | import de.robv.android.xposed.IXposedHookLoadPackage; 15 | import de.robv.android.xposed.XC_MethodReplacement; 16 | import de.robv.android.xposed.XposedHelpers; 17 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 18 | 19 | public class MainHook implements IXposedHookLoadPackage { 20 | private static final String TAG = "MainHook"; 21 | 22 | public static final boolean USE_NATIVE_MENU = true; 23 | 24 | private static final List packageList = new ArrayList() {{ 25 | add("com.google.android.youtube"); 26 | add("com.block.juggle"); 27 | add("com.tencent.tmgp.sgame"); 28 | add("com.colossi.survival.samurai"); 29 | }}; 30 | 31 | @Override 32 | public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) { 33 | if (lpparam.packageName.equals(BuildConfig.APPLICATION_ID)) { 34 | XposedHelpers.findAndHookMethod(BuildConfig.APPLICATION_ID + ".SettingsActivity", 35 | lpparam.classLoader, "isModuleActive", XC_MethodReplacement.returnConstant(Boolean.TRUE)); 36 | } else if (packageList.contains(lpparam.packageName)) { 37 | Log.d(TAG, "handleLoadPackage: " + lpparam.packageName + " loaded"); 38 | HookUtils.attachApplication(HookUtils::nativeHookInit); 39 | HookUtils.attachActivity(activity -> { 40 | if (USE_NATIVE_MENU){ 41 | createNativeMenu(activity); 42 | } else { 43 | createMenu(activity); 44 | } 45 | NHook.sign1("test sign trace"); 46 | }); 47 | } 48 | } 49 | 50 | private static void createNativeMenu(Context activity) { 51 | Menu menu = new Menu(activity); 52 | menu.attach(); 53 | menu.Surface(new SurfaceImGUI(activity)); 54 | } 55 | 56 | private static void createMenu(Context activity) { 57 | SharedPreferences sp = activity.getSharedPreferences("menu", Context.MODE_PRIVATE); 58 | Menu menu = new Menu(activity); 59 | menu.attach(); 60 | menu.Category("Value Change"); 61 | menu.Category("Value Change"); 62 | PBoolean value1 = PBoolean.of(sp, "test1", false); 63 | value1.setOnValueChangedListener((v, v1) -> { 64 | Log.d(TAG, "Switch: " + NHook.test111(v1 ? 1 : 0)); 65 | }); 66 | menu.Switch("Switch 1", value1); 67 | PInteger value = PInteger.of(sp, "test2", 0); 68 | value.setOnValueChangedListener((v, v1) -> { 69 | Log.d(TAG, "SeekBar: " + NHook.test111(v1)); 70 | }); 71 | menu.SeekBar("SeekBar 1", value, 0, 100, 5); 72 | 73 | menu.Category("Category 1"); 74 | menu.InputNum("InputNum 1", PInteger.of(0)); 75 | menu.InputText("InputText 1", PString.of("Hello World")); 76 | menu.Button("Button 1", PBoolean.of(sp, "test3", false)); 77 | menu.CheckBox("CheckBox 1", PBoolean.of(false)); 78 | menu.Switch("Switch 1", PBoolean.of(false)); 79 | menu.ButtonOnOff("Button 2", PBoolean.of(false)); 80 | menu.SeekBar("SeekBar 1", PInteger.of(0), 0, 100, 5); 81 | menu.CheckBox("CheckBox 2", PBoolean.of(false)); 82 | menu.ButtonLink("External Link ↗", "https://baidu.com"); 83 | menu.SeekBar("SeekBar 2", PInteger.of(0), -50, 100, 5); 84 | menu.SeekBar("SeekBar 3", PInteger.of(0), 0, 5); 85 | menu.RadioButton("Radio Button 1", new String[]{"Option 1", "Option 2", "Option 3"}, PInteger.of(0)); 86 | 87 | menu.startCollapse("Collapse 1"); 88 | 89 | menu.ButtonAction("Button 3", () -> { 90 | AlertDialog.Builder builder = new AlertDialog.Builder(activity); 91 | builder.setTitle("Alert"); 92 | builder.setMessage("This is an alert"); 93 | builder.setPositiveButton("OK", null); 94 | builder.show(); 95 | }); 96 | 97 | menu.ButtonLink("External Link ↗", "https://baidu.com"); 98 | menu.SeekBar("SeekBar 2", PInteger.of(0), -50, 100, 5); 99 | menu.SeekBar("SeekBar 3", PInteger.of(0), 0, 5); 100 | menu.Switch("Switch 1", PBoolean.of(false)); 101 | 102 | menu.endCollapse(); 103 | 104 | menu.TextView("This is a TextView not fully html supported. bold italic underline strikethrough color size face link"); 105 | 106 | menu.SeekBar("SeekBar 2", PInteger.of(0), -50, 100, 5); 107 | 108 | menu.WebTextView("" + "This is WebView, with REAL HTML support!" + "
Support CSS
" + "This is scrollable text" + ""); 109 | 110 | menu.SeekBar("SeekBar 3", PInteger.of(0), 0, 5); 111 | menu.RadioButton("Radio Button 1", new String[]{"Option 1", "Option 2", "Option 3"}, PInteger.of(0)); 112 | } 113 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/mrack/xposed/nhook/NHook.java: -------------------------------------------------------------------------------- 1 | package cn.mrack.xposed.nhook; 2 | 3 | import android.content.Context; 4 | 5 | public class NHook { 6 | public static native void initNativeHook(Context context); 7 | 8 | public static native String sign1(String data); 9 | 10 | public static native String test111(int value); 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/cn/mrack/xposed/nhook/SettingsActivity.java: -------------------------------------------------------------------------------- 1 | package cn.mrack.xposed.nhook; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.preference.Preference; 6 | import android.preference.PreferenceFragment; 7 | import android.util.Log; 8 | 9 | public class SettingsActivity extends Activity { 10 | 11 | public static class SettingsFragment extends PreferenceFragment { 12 | @Override 13 | public void onCreate(Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | addPreferencesFromResource(R.xml.settings); 16 | Preference moduleStatus = findPreference("module_status"); 17 | boolean active = isModuleActive(); 18 | Log.d("MainHook", "onCreate: " + active); 19 | moduleStatus.setEnabled(active); 20 | moduleStatus.setTitle(active ? "模块状态: [已激活]" : "模块状态: [未激活]"); 21 | } 22 | } 23 | 24 | private static final String TAG = "SettingsActivity"; 25 | @Override 26 | public void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit(); 29 | } 30 | 31 | public static boolean isModuleActive() { 32 | return false; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/cn/mrack/xposed/nhook/menu/Config.java: -------------------------------------------------------------------------------- 1 | 2 | package cn.mrack.xposed.nhook.menu; 3 | 4 | import android.graphics.Color; 5 | import android.text.Html; 6 | 7 | /** 8 | * Menu configuration 9 | */ 10 | public class Config { 11 | protected final int RADIO_BUTTON_COLOR = Color.parseColor("#FFFFFF"); 12 | protected final int COLLAPSE_BG_COLOR = Color.parseColor("#222D38"); 13 | protected final int NUMBER_TEXT_COLOR = Color.parseColor("#41c300"); 14 | protected final int SEEKBAR_NUMBER_NEG_COLOR = Color.parseColor("#FF0000"); 15 | protected final int SEEKBAR_NUMBER_POS_COLOR = Color.parseColor("#00FF00"); 16 | protected final int SEEKBAR_PROGRESS_COLOR = Color.parseColor("#80CBC4"); 17 | protected final int SEEKBAR_COLOR = Color.parseColor("#80CBC4"); 18 | protected final int CHECKBOX_COLOR = Color.parseColor("#80CBC4"); 19 | protected final String MENU_TITLE = Html.fromHtml("Moded By (your name)").toString(); 20 | protected final boolean MENU_TITLE_ENABLE = false; 21 | protected final String MENU_SUBTITLE = "https://site.com lorem ipsum dolor sit amet consectetur adipiscing elit"; 22 | protected final boolean MENU_SUBTITLE_ENABLE = false; 23 | protected final int MENU_WIDTH = 290; 24 | protected final int MENU_HEIGHT = 210; 25 | protected final int MENU_BG_COLOR = Color.parseColor("#EE1C2A35"); 26 | protected final int MENU_FEATURE_BG_COLOR = Color.parseColor("#DD141C22"); 27 | protected final int TEXT_COLOR_PRIMARY = Color.parseColor("#82CAFD"); 28 | protected final int TEXT_COLOR_SECONDARY = Color.parseColor("#FFFFFF"); 29 | protected final float MENU_COLLAPSED_ALPHA = 0.9f; 30 | protected final int MENU_BUTTON_BG_COLOR = Color.parseColor("#1C262D"); 31 | protected final int MENU_CATEGORY_BG_COLOR = Color.parseColor("#2F3D4C"); 32 | protected final String MENU_HIDE_BUTTON_TEXT = Html.fromHtml("△").toString(); 33 | protected final String MENU_CLOSE_BUTTON_TEXT = Html.fromHtml("✕").toString(); 34 | protected final int BTN_ON_BG_COLOR = Color.parseColor("#1b5e20"); 35 | protected final int BTN_OFF_BG_COLOR = Color.parseColor("#7f0000"); 36 | protected final int MENU_LAUNCHER_ICON_SIZE = 42; 37 | protected final String MENU_LAUNCHER_ICON = "iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAADNNJREFUeF7tnV1oXMcVgM/M/VnJWksrZeW1ZceWLSUFUUip+0tf8lAoFAqFQKCUQAvFD23zFCdxmj7ch7b5f3Kbh1BooZRCIFAoFAp5yEvpb0oDxdBEtmVHli2vIkvyytLuvTPTzl2vvPrZ3bl7586MdEevmjnnzDnfzp2fMzMIDuLfTOCPw22/URv2BrzIIw3sUt9zfEIc5gEmBLl7NdtxWIRCoA3HIbgREsen0Wbohn5xLazCkQZcChoHzV1o3zfo8cAt37w36ER0MIRCwWGNAQZuJu1CEDGC/E0P6nXi4o2lY4c24L0g2s8+zMRRWTukUjk/BEUYqhP3kIuRn7W+bvJdyhrMie5BDdYXF19f12lLP7r3DQA86HQQHQbHKTKGcD+NzboOQowCITW8we7uFxjMBmAm8CciGI5oNEIpcbIOoEz5GDvExe7qggtrJo8djASA/9qJj0fAc4oyg6JNVkhqToOumtgrGAXA+ExQJPVwFDM6qC1YGSqmCG84Be9O9VJQy1BNItFGAMB/8WGxMHZQA78zIhwEr1ZfNqFH0ArA9PTThZX64EMHpqtP9NsDgJDUSoWNT2ZnL9aTVpVVXhsAE48G5UZUH5PVkP0sx3cLywsfBks62qAcgPGZ7xede8PlSPP8XYeze60nkENrS9VLbyodHygFoDJ1/ghhXsk055tkj4PClcXLr99WZZMSACYng4EVdLfiIr+gqmH7WU/EGvUSO7w4NxdsZt2OzAEYPfP8iAO4knVDDqJ8AnTxzpVXVrNsW6YAHJ1+YTyiMJplAw66bBfDnVuzL1WzamdWAKDyw88dy+30Tna0QlJb+vjVmwDAZIvOAIC3nbGpDybysqgjOyCd5PHFo+XL3v8hkLv9LBeAs+e80vL4hIuoHexlQEbEcH1lrLoA778VyhIvD4CZwK+s144Tx/NkGWfl7PaAQ8Jwcah4Q9YOoxwAzp7zKkvDJ2zw1SAbQ1Bem5fRE0gAIHBLp8PjtttXE/yWlvhzcPWxeYAnSRrNaQFAY1MvnrADvjQh6L9uc2D40/k0s4NUAJQffm7CTvX6D6CUms0p4kK/svoGwC7y9Oty+fXSLBb1BYBd3pUfxLQS+102TgwA39ip4frJtAbb+vI9UKSF60k3kBIDUDr9zCm7qyc/eDIk8l3ElatvXEsiKxEAdj8/iWv1lE2aTyAMAM/kYZsjE3qaZbUm8QAaWF0QzSwSBuDo5IVJm8aVJAz6yvLjarfmXp4TsUAIAJvAKeJKs8qIJpr2BCBO3abFU2Y1z1oj4oESrl3rlXLeEwC72ifiakPLCKwSdgUgPqM35B1X3TyKcBkx+AwAOwGMDaXSj9A6AJpnCP6NGU2de08pGcPYKQOgYQQszntggOoAbI1SsoSxs5zKXsmVnfXwRrcTSF0BGJt68WG1Gz14mCH4ITD2dcl+aIpD6I+Iwc8B6Foi+RgVGYFPA6BHAGiPtHa8AsA+Qg78ByhTmuO/V5vubxh93Km9HQHgBzXZZl3htI8Hn10EBlOJgpO0MILLiKGnRSFgDL4IAF9IquZ++b8jBH/rs660amigsNDpQGpHAFT/+hnCP8rsl7/TlXFPQH/WzcMM2AgA/iowlu5HgNACAH0XAco0vbtbW7r1AnsCoPrb3/zms99LQ15AEEPom53GBBjBOGPoGzTt+OO+HRihdYTYHyiDzNK7ezW501hgTwBUj/wZ/6UBC3o1Qu7/UYCAvrtTJv/lY8BPyAp+Sz6HgAJ9R1tP0GFGsBuAmcAvb9Yn5Tq7uzQG6DsA8D2VOgHglwjYr3cDgJ5I3e13HHGhBQTsHcXt3FK3NFCY25lMugsAHat+jMEPAKFvKXUMY79DCH7RrjPlgE/UfG0Dw71WB3cBcGT6x1OqL2QyAoB4qse+KxrFNOWQg36lY4rIL666PfuTy+22bwNA9eCvZYgJADCGvgTAPp8msOJ10T8QYn8VLy+v5M7B4DYAxiefPcqwOyxPnZgkMwDAT/Ve5BFrT+9SeAUh+pve5eSXQDRaq869dqsleTsAUxemdVzCqBsAvryLkPNt+e7uLJEx8lsdy8b8Msvq5ZdndwGgq/vnhugGAAAeZQy+phIAhOBPAPChSp0tXe2fga0eQGe6l34A0OcYY19WGQyE0F8A2D9V6twCoO0ami0AdGb86AYAAXyFMvisymBgBP9iAH9WqbOlK6KssXI/Y6gJAL9y/Xr9jA5jTPgE5A0A7vOlk4Ur/Kr7GIDyp547DKFzLK8AAOTrExDH2SM3l/776t0YAJ3ffxN6gLwNArnPW+njMQCqt3539jS6xwB5mga2fN/aIo4BGD/z7CNZPbMi8lnRDUCzF8rHQtCD+X/Eqlde+wiBht0/03qAJgD5WApu9z3fHUQmnPgxoQeAHGwG7fzh8RNEaOTkhVHPReMiXXVWZYwAoLkimSb/T9Q92raDdxoYRqyKdM8A4u7XJoSIwiO1HJ8J8Bs9tV/zYlPCpMZVXFhIavySJ8W5/7vts0mh4jGTWZJPBZHOPYD2xti0cJmhFZPFTxGjyiMXznR6S1dMjKxS9mCILE+KyonfSi6feeFR0QrZl7NHw7L38XYNhgHQNM4eDlWHgZEAqGu+1WQByDkDRgKg+xOgW79KJg0DQPcgULd+laFv6rLTwC2fmzkNzRKJeBpoF4KaLjZtISrLwLdkxwtBdim4Ne00534CFcG/P93esJtB8W6kOfcTqAp+rIdvBtntYLO2o1UCEG8H24QQI46mqYz7lq44IcSmhOUXgDglzCaF5heAOCmU9wd5Tws3JSdR5XcAQSst3B4MMeF4usrYt3Zc+ZNzH9ujYWbcT6AcgG1Hw/J+ODSPn4Bth0Pzfjw8jwBsOx7O+5/S5IVJFyNfeV9kQBecNwDan5SxV8QYAKDqH137y2IPAND0OES8E6f5plDd+pUD0PaIhL0mzgAAVQLQ8Zq4eEEopxdF5qkH6HpRpK67AnUHQLd+lT1A16tiuSF5vCw6LwD0vCyaA5DH6+LzAoDQdfE6dgd13w+gW7+qT4DQgxHcGNV3BuhOydKtXwkAwk/G8HsDFa8J6L4fQLd+FQAkejSKG6Q6W1h3WrZu/VlCkPjZuHhNIHcPRx7cgyF9PRypoxcA0H00S7d++f1A30/HclNUjwVazdd9OFO3fpkYpHo8WseMQGbjcy8r7fPx3IHT008XVmjxVO6duQ8dUMK1a7OzF+vdTO/6fHyroo7VwX3ob6NM3mvVby8DhQDgFU05RWyUlw01pj3jp5eJwgCYcIKoV2Ps/5se4Cd+qpferIn4QxiAeFYwdf4IYV5JRLAto8cD7eleIhYkAoALLJ1+5pSL/IKIcFtGrQci1qivXH3jWhKtiQGYnAwGarh+MokSW1aNB4q0cH1uLthMoi0xAFz46JnnRxzAlSSKbNlsPUCALt658spqUi19ARDPCqZfGI8ojCZVaMvL94CL4c6t2Zeq/UjuGwCuTHXeQD8NPPB1BFb7uvkgFQB8xjE29eIJzOjggXe0gQ28v9EzH19z1OdfWgAA4G2ndPqDEy6idmbQZxD6qRYxXF+56t0ACKJ+6rfqSAAAAM6e8ypLwyeI43lpjLF1xTzgkDBcLK/Nw/tvhWI1OpeSAwCXPxP4lfXacQtB2pB0rx8Hf6h4Ay4FDRma5AHArTl7zistj0/Yz4GM0OyWEXf7Y9UFGb98uZ+AbbYG7thUeMwODOVC0BzwPbYA8CSRKVluD/DAMn4D6THwnKJMY3MrqznVu5lmtN/Jd1kBEOuzi0XpkU2zyCOiPVMAuAF22VgkDHuX6Xd5N4nGzAHgxvANpBV0t2J3EcVCw3f1SuzwYtKNHTHp20spAaCl0uYT9A5R0v383hK7l1AKADeFZxY594bLkaYLqdI6LKv6PI2LHFpbEs3kkWWHcgBahttE0wchFE3glBX0djnaAOBGxCnn9cGHcjtdDEmtVNj4pFfqdhaBb8nUCsDW2KByfigsFsbysnjEF3W8Wn15cfH19SyDKyLbCABahvIDqaQejh5UEHjgnYJ3p3opEMrYFQlg2jJGAdDeIxAfjxyYT0NIak6Drprwi98JjJEAbBk5E/gTEQxHNBqhlDhpaVdZn1/I5GJ3dcGFNVk7d1nYbzYAbS3mJ5XpIDoMjlNkDOEsnJFWJr+EEQip4Q1218Rf+17t2zcAtBvPYYAiDCHiHtK9nhBR1ig40T2owfp+Cbox08C0v7i4/uOBW755b9CJ6GAIhYLDGgMM3EzA5s+sEORvelCvExdvLB07tAHvpUvJkuKDFEIycVQKe+RUnQn8cbjtN2rD3oAXeaSBXep7jk+IwzzAhCB3L0XxW7oh0IbjENwIiePTaDN0Q7+4FlbhSMPkb3m/jvsfyER0DjwqKGYAAAAASUVORK5CYII="; 38 | 39 | } 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/java/cn/mrack/xposed/nhook/menu/PBoolean.java: -------------------------------------------------------------------------------- 1 | package cn.mrack.xposed.nhook.menu; 2 | 3 | 4 | import android.content.SharedPreferences; 5 | 6 | /** 7 | * Wrapper class for primitive boolean, to be used as a parameter for Menu 8 | */ 9 | public class PBoolean extends PValue { 10 | public PBoolean(SharedPreferences sp, String key, Boolean value) { 11 | super(sp, key, value); 12 | } 13 | 14 | public PBoolean(Boolean value) { 15 | super(value); 16 | } 17 | 18 | public static PBoolean of(SharedPreferences sp, String key, Boolean value) { 19 | return new PBoolean(sp, key, value); 20 | } 21 | 22 | public static PBoolean of(Boolean value) { 23 | return new PBoolean(value); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/cn/mrack/xposed/nhook/menu/PInteger.java: -------------------------------------------------------------------------------- 1 | package cn.mrack.xposed.nhook.menu; 2 | 3 | 4 | import android.content.SharedPreferences; 5 | 6 | /** 7 | * Wrapper class for primitive int, to be used as a parameter for Menu 8 | */ 9 | public class PInteger extends PValue { 10 | public PInteger(SharedPreferences sp, String key, Integer value) { 11 | super(sp, key, value); 12 | } 13 | 14 | public PInteger(Integer value) { 15 | super(value); 16 | } 17 | 18 | public static PInteger of(SharedPreferences sp, String key, Integer value) { 19 | return new PInteger(sp, key, value); 20 | } 21 | 22 | public static PInteger of(Integer value) { 23 | return new PInteger(value); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/cn/mrack/xposed/nhook/menu/PString.java: -------------------------------------------------------------------------------- 1 | package cn.mrack.xposed.nhook.menu; 2 | 3 | import android.content.SharedPreferences; 4 | 5 | /** 6 | * Wrapper class for primitive String, to be used as a parameter for Menu 7 | */ 8 | public class PString extends PValue { 9 | public PString(SharedPreferences sp, String key, String value) { 10 | super(sp, key, value); 11 | } 12 | 13 | public PString(String value) { 14 | super(value); 15 | } 16 | 17 | public static PString of(SharedPreferences sp, String key, String value) { 18 | return new PString(sp, key, value); 19 | } 20 | 21 | public static PString of(String value) { 22 | return new PString(value); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/cn/mrack/xposed/nhook/menu/PValue.java: -------------------------------------------------------------------------------- 1 | package cn.mrack.xposed.nhook.menu; 2 | 3 | import android.content.SharedPreferences; 4 | 5 | public class PValue { 6 | public interface onValueChangedListener { 7 | void onValueChanged(T v, T v1); 8 | } 9 | 10 | private T value; 11 | private SharedPreferences sp; 12 | private String key; 13 | 14 | public PValue(SharedPreferences sp, String key, T value) { 15 | this.sp = sp; 16 | if (value instanceof Boolean) { 17 | this.value = (T) Boolean.valueOf(sp.getBoolean(key, (Boolean) value)); 18 | } else if (value instanceof Integer) { 19 | this.value = (T) Integer.valueOf(sp.getInt(key, (Integer) value)); 20 | } else if (value instanceof String) { 21 | this.value = (T) sp.getString(key, (String) value); 22 | } else { 23 | this.value = value; 24 | } 25 | this.key = key; 26 | } 27 | 28 | public PValue(T value) { 29 | this.value = value; 30 | } 31 | 32 | public T get() { 33 | return value; 34 | } 35 | 36 | public void set(T value) { 37 | T oldValue = this.value; 38 | this.value = value; 39 | if (listener != null) { 40 | listener.onValueChanged(oldValue, value); 41 | } 42 | if (sp != null){ 43 | if (value instanceof Boolean) { 44 | sp.edit().putBoolean(key, (Boolean) value).apply(); 45 | } else if (value instanceof Integer) { 46 | sp.edit().putInt(key, (Integer) value).apply(); 47 | } else if (value instanceof String) { 48 | sp.edit().putString(key, (String) value).apply(); 49 | } 50 | } 51 | } 52 | 53 | private onValueChangedListener listener; 54 | 55 | public void setOnValueChangedListener(onValueChangedListener listener) { 56 | this.listener = listener; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/cn/mrack/xposed/nhook/menu/SurfaceImGUI.java: -------------------------------------------------------------------------------- 1 | package cn.mrack.xposed.nhook.menu; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.Path; 8 | import android.graphics.PixelFormat; 9 | import android.os.RemoteException; 10 | import android.util.AttributeSet; 11 | import android.util.Log; 12 | import android.view.Surface; 13 | import android.view.SurfaceHolder; 14 | import android.view.SurfaceView; 15 | import android.view.WindowManager; 16 | 17 | public class SurfaceImGUI extends SurfaceView implements SurfaceHolder.Callback { 18 | 19 | private static final String TAG = "SurfaceImGUI"; 20 | public static native void initImGUI(Surface surface); 21 | 22 | public static native void destroyImGUI(); 23 | 24 | public static native void setOrientationImGUI(int orientation); 25 | 26 | public final WindowManager wms; 27 | 28 | @Override 29 | protected void onDetachedFromWindow() { 30 | super.onDetachedFromWindow(); 31 | Log.d(TAG, "onDetachedFromWindow: "); 32 | } 33 | 34 | @Override 35 | protected void onAttachedToWindow() { 36 | super.onAttachedToWindow(); 37 | Log.d(TAG, "onAttachedToWindow: "); 38 | } 39 | 40 | public SurfaceImGUI(Context context) { 41 | super(context); 42 | setZOrderOnTop(true); 43 | SurfaceHolder holder = getHolder(); 44 | holder.setFormat(PixelFormat.TRANSPARENT); 45 | getHolder().addCallback(this); 46 | wms = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 47 | } 48 | 49 | @Override 50 | public void surfaceCreated(SurfaceHolder surfaceHolder) { 51 | new Thread( () ->{ 52 | initImGUI(surfaceHolder.getSurface()); 53 | }).start(); 54 | } 55 | 56 | @Override 57 | public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { 58 | setOrientationImGUI(wms.getDefaultDisplay().getRotation()); 59 | } 60 | 61 | @Override 62 | public void surfaceDestroyed(SurfaceHolder surfaceHolder) { 63 | destroyImGUI(); 64 | } 65 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mrack/XposedNHook/a250ffcd543b7dad77d43b44af0ac80c873f77f0/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mrack/XposedNHook/a250ffcd543b7dad77d43b44af0ac80c873f77f0/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mrack/XposedNHook/a250ffcd543b7dad77d43b44af0ac80c873f77f0/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mrack/XposedNHook/a250ffcd543b7dad77d43b44af0ac80c873f77f0/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mrack/XposedNHook/a250ffcd543b7dad77d43b44af0ac80c873f77f0/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mrack/XposedNHook/a250ffcd543b7dad77d43b44af0ac80c873f77f0/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mrack/XposedNHook/a250ffcd543b7dad77d43b44af0ac80c873f77f0/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mrack/XposedNHook/a250ffcd543b7dad77d43b44af0ac80c873f77f0/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mrack/XposedNHook/a250ffcd543b7dad77d43b44af0ac80c873f77f0/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mrack/XposedNHook/a250ffcd543b7dad77d43b44af0ac80c873f77f0/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | XposedNHook 3 | -------------------------------------------------------------------------------- /app/src/main/res/xml/settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | plugins { 3 | alias(libs.plugins.androidApplication) apply false 4 | } -------------------------------------------------------------------------------- /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=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. For more details, visit 12 | # https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Enables namespacing of each library's R class so that its R class includes only the 19 | # resources declared in the library itself and none from the library's dependencies, 20 | # thereby reducing the size of the R class for that library 21 | android.nonTransitiveRClass=true -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | agp = "7.4.2" 3 | 4 | [libraries] 5 | 6 | [plugins] 7 | androidApplication = { id = "com.android.application", version.ref = "agp" } 8 | 9 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mrack/XposedNHook/a250ffcd543b7dad77d43b44af0ac80c873f77f0/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Apr 19 14:57:34 CST 2024 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { 4 | name "aliyunmaven" 5 | url "https://maven.aliyun.com/repository/public" 6 | } 7 | maven { 8 | name "aliyunGoogle" 9 | url "https://maven.aliyun.com/repository/google" 10 | } 11 | maven { url 'https://www.jitpack.io' } 12 | google { 13 | content { 14 | includeGroupByRegex("com\\.android.*") 15 | includeGroupByRegex("com\\.google.*") 16 | includeGroupByRegex("androidx.*") 17 | } 18 | } 19 | mavenCentral() 20 | gradlePluginPortal() 21 | 22 | } 23 | } 24 | dependencyResolutionManagement { 25 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 26 | repositories { 27 | maven { 28 | name "aliyunmaven" 29 | url "https://maven.aliyun.com/repository/public" 30 | } 31 | maven { 32 | name "aliyunGoogle" 33 | url "https://maven.aliyun.com/repository/google" 34 | } 35 | maven { url 'https://www.jitpack.io' } 36 | google() 37 | mavenCentral() 38 | } 39 | } 40 | 41 | rootProject.name = "XposedNHook" 42 | include ':app' 43 | --------------------------------------------------------------------------------