├── settings.gradle ├── README.md ├── app ├── src │ └── main │ │ ├── res │ │ ├── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ └── drawable │ │ │ └── ic_launcher_background.xml │ │ ├── jni │ │ ├── Application.mk │ │ ├── Substrate │ │ │ ├── SymbolFinder.h │ │ │ ├── SubstrateHook.h │ │ │ ├── SubstrateDebug.hpp │ │ │ ├── Buffer.hpp │ │ │ ├── SubstrateLog.hpp │ │ │ ├── SubstrateARM.hpp │ │ │ ├── SubstratePosixMemory.cpp │ │ │ ├── hde64.h │ │ │ ├── SubstrateDebug.cpp │ │ │ ├── table64.h │ │ │ ├── CydiaSubstrate.h │ │ │ ├── SubstrateX86.hpp │ │ │ ├── hde64.c │ │ │ └── SymbolFinder.cpp │ │ ├── KittyMemory │ │ │ ├── KittyUtils.h │ │ │ ├── MemoryBackup.h │ │ │ ├── MemoryPatch.h │ │ │ ├── MemoryBackup.cpp │ │ │ ├── KittyUtils.cpp │ │ │ ├── KittyMemory.cpp │ │ │ ├── MemoryPatch.cpp │ │ │ └── KittyMemory.h │ │ ├── And64InlineHook │ │ │ ├── README.md │ │ │ ├── LICENSE │ │ │ ├── And64InlineHook.hpp │ │ │ └── And64InlineHook.cpp │ │ ├── Includes │ │ │ ├── Logger.h │ │ │ ├── Utils.h │ │ │ └── obfuscate.h │ │ ├── Android.mk │ │ ├── MethodsDark.h │ │ ├── UtilsDark.h │ │ └── Main.cpp │ │ ├── java │ │ └── dark │ │ │ └── rx │ │ │ ├── MainMod.java │ │ │ ├── LoaderMod.java │ │ │ └── Floater.java │ │ └── AndroidManifest.xml ├── proguard-rules.pro └── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── gradle.properties ├── gradlew.bat └── gradlew /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = "DarkMod" 2 | include ':app' 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DarkMod-Floating 2 | Base To Create ModMenus Android By MrDarkRX 3 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | DarkMod 3 | 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrDarkRXx/DarkMod-Floating/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrDarkRXx/DarkMod-Floating/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrDarkRXx/DarkMod-Floating/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrDarkRXx/DarkMod-Floating/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrDarkRXx/DarkMod-Floating/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrDarkRXx/DarkMod-Floating/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrDarkRXx/DarkMod-Floating/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrDarkRXx/DarkMod-Floating/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrDarkRXx/DarkMod-Floating/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrDarkRXx/DarkMod-Floating/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrDarkRXx/DarkMod-Floating/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_ABI := armeabi-v7a arm64-v8a x86 2 | #APP_PLATFORM := android-18 #APP_PLATFORM does not need to be set. It will automatically defaulting 3 | APP_STL := c++_static 4 | APP_OPTIM := release 5 | APP_THIN_ARCHIVE := true 6 | APP_PIE := true 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Oct 16 10:11:02 CST 2021 2 | distributionBase=GRADLE_USER_HOME 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /app/src/main/jni/Substrate/SymbolFinder.h: -------------------------------------------------------------------------------- 1 | #ifndef SYMBOL_FINDER 2 | #define SYMBOL_FINDER 3 | 4 | #include 5 | 6 | extern int find_name(pid_t pid, const char *name,const char *libn, unsigned long *addr); 7 | extern int find_libbase(pid_t pid, const char *libn, unsigned long *addr); 8 | #endif -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/jni/KittyMemory/KittyUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace KittyUtils { 7 | 8 | bool validateHexString(std::string &xstr); 9 | void toHex(void *const data, const size_t dataLength, std::string &dest); 10 | void fromHex(const std::string &in, void *const data); 11 | 12 | } -------------------------------------------------------------------------------- /app/src/main/java/dark/rx/MainMod.java: -------------------------------------------------------------------------------- 1 | package dark.rx; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | 6 | public class MainMod extends Activity { 7 | 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | LoaderMod.Start(this); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/java/dark/rx/LoaderMod.java: -------------------------------------------------------------------------------- 1 | package dark.rx; 2 | 3 | import android.content.Context; 4 | 5 | public class LoaderMod { 6 | 7 | static { 8 | System.loadLibrary("DarkMod"); 9 | } 10 | 11 | static native void setDarkStart(Context ctx); 12 | 13 | public static void Start(Context ctx) { 14 | setDarkStart(ctx); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/jni/Substrate/SubstrateHook.h: -------------------------------------------------------------------------------- 1 | #ifndef __SUBSTRATEHOOK_H__ 2 | #define __SUBSTRATEHOOK_H__ 3 | 4 | 5 | #include 6 | 7 | #define _extern extern "C" __attribute__((__visibility__("hidden"))) 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | void MSHookFunction(void *symbol, void *replace, void **result); 14 | 15 | #ifdef __cplusplus 16 | } 17 | #endif 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /app/src/main/jni/And64InlineHook/README.md: -------------------------------------------------------------------------------- 1 | # And64InlineHook 2 | Lightweight ARMv8-A(ARM64, AArch64, Little-Endian) Inline Hook Library for Android C/C++ 3 | 4 | # References 5 | [Arm Compiler armasm User Guide](http://infocenter.arm.com/help/topic/com.arm.doc.100069_0610_00_en/pge1427898258836.html) 6 | [Procedure Call Standard for the Arm® 64-bit Architecture (AArch64)](https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst) 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/jni/Includes/Logger.h: -------------------------------------------------------------------------------- 1 | #ifndef DAWN_LOGGER_H 2 | #define DAWN_LOGGER_H 3 | 4 | #include 5 | 6 | enum daLogType { 7 | daDEBUG = 3, 8 | daERROR = 6, 9 | daINFO = 4, 10 | daWARN = 5 11 | }; 12 | 13 | //Change this to another Log Tag if ya want. IN the batch script I provide you change the log tag then too 14 | #define TAG OBFUSCATE("Mod_Menu") 15 | 16 | #define LOGD(...) ((void)__android_log_print(daDEBUG, TAG, __VA_ARGS__)) 17 | #define LOGE(...) ((void)__android_log_print(daERROR, TAG, __VA_ARGS__)) 18 | #define LOGI(...) ((void)__android_log_print(daINFO, TAG, __VA_ARGS__)) 19 | #define LOGW(...) ((void)__android_log_print(daWARN, TAG, __VA_ARGS__)) 20 | 21 | #endif //DAWN_LOGGER_H -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /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. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec: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 -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | } 4 | 5 | android { 6 | compileSdkVersion 30 7 | 8 | defaultConfig { 9 | applicationId "dark.rx.mod" 10 | minSdkVersion 16 11 | targetSdkVersion 30 12 | versionCode 1 13 | versionName "1.0" 14 | 15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 16 | ndk { 17 | abiFilters 'armeabi-v7a' 18 | } 19 | } 20 | 21 | buildTypes { 22 | release { 23 | minifyEnabled false 24 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 25 | } 26 | } 27 | compileOptions { 28 | sourceCompatibility JavaVersion.VERSION_1_8 29 | targetCompatibility JavaVersion.VERSION_1_8 30 | } 31 | sourceSets { main { jni.srcDirs = ['src/main/jni', 'src/main/jni/'] } } 32 | externalNativeBuild { 33 | ndkBuild { 34 | path file('src/main/jni/Android.mk') 35 | } 36 | } 37 | } 38 | 39 | dependencies { 40 | 41 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/jni/And64InlineHook/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 RLib 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /app/src/main/jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | MAIN_LOCAL_PATH := $(call my-dir) 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_MODULE := DarkMod 6 | 7 | LOCAL_CFLAGS := -Wno-error=format-security -fvisibility=hidden -ffunction-sections -fdata-sections -w 8 | LOCAL_CFLAGS += -fno-rtti -fno-exceptions -fpermissive 9 | LOCAL_CPPFLAGS := -Wno-error=format-security -fvisibility=hidden -ffunction-sections -fdata-sections -w -Werror -s -std=c++17 10 | LOCAL_CPPFLAGS += -Wno-error=c++11-narrowing -fms-extensions -fno-rtti -fno-exceptions -fpermissive 11 | LOCAL_LDFLAGS += -Wl,--gc-sections,--strip-all, -llog 12 | LOCAL_ARM_MODE := arm 13 | 14 | LOCAL_C_INCLUDES += $(MAIN_LOCAL_PATH) 15 | 16 | # Here you add the cpp file 17 | LOCAL_SRC_FILES := Main.cpp \ 18 | Substrate/hde64.c \ 19 | Substrate/SubstrateDebug.cpp \ 20 | Substrate/SubstrateHook.cpp \ 21 | Substrate/SubstratePosixMemory.cpp \ 22 | Substrate/SymbolFinder.cpp \ 23 | KittyMemory/KittyMemory.cpp \ 24 | KittyMemory/MemoryPatch.cpp \ 25 | KittyMemory/MemoryBackup.cpp \ 26 | KittyMemory/KittyUtils.cpp \ 27 | And64InlineHook/And64InlineHook.cpp \ 28 | 29 | LOCAL_LDLIBS := -llog -landroid -lGLESv2 30 | 31 | include $(BUILD_SHARED_LIBRARY) 32 | -------------------------------------------------------------------------------- /app/src/main/jni/KittyMemory/MemoryBackup.h: -------------------------------------------------------------------------------- 1 | // 2 | // MemoryBackup.h 3 | // 4 | // Created by MJ (Ruit) on 4/19/20. 5 | // 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include "KittyMemory.h" 12 | using KittyMemory::Memory_Status; 13 | using KittyMemory::ProcMap; 14 | 15 | 16 | class MemoryBackup { 17 | private: 18 | uintptr_t _address; 19 | size_t _size; 20 | 21 | std::vector _orig_code; 22 | 23 | std::string _hexString; 24 | 25 | public: 26 | MemoryBackup(); 27 | 28 | /* 29 | * expects library name and relative address 30 | */ 31 | MemoryBackup(const char *libraryName, uintptr_t address, size_t backup_size, bool useMapCache=true); 32 | 33 | /* 34 | * expects absolute address 35 | */ 36 | MemoryBackup(uintptr_t absolute_address, size_t backup_size); 37 | 38 | 39 | ~MemoryBackup(); 40 | 41 | 42 | /* 43 | * Validate patch 44 | */ 45 | bool isValid() const; 46 | 47 | 48 | size_t get_BackupSize() const; 49 | 50 | /* 51 | * Returns pointer to the target address 52 | */ 53 | uintptr_t get_TargetAddress() const; 54 | 55 | 56 | /* 57 | * Restores backup code 58 | */ 59 | bool Restore(); 60 | 61 | 62 | /* 63 | * Returns current target address bytes as hex string 64 | */ 65 | std::string get_CurrBytes(); 66 | }; 67 | -------------------------------------------------------------------------------- /app/src/main/jni/Substrate/SubstrateDebug.hpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #ifndef SUBSTRATE_DEBUG_HPP 23 | #define SUBSTRATE_DEBUG_HPP 24 | 25 | #include "SubstrateLog.hpp" 26 | #define lprintf(format, ...) \ 27 | MSLog(MSLogLevelNotice, format, ## __VA_ARGS__) 28 | 29 | extern "C" bool MSDebug; 30 | void MSLogHexEx(const void *vdata, size_t size, size_t stride, const char *mark = 0); 31 | void MSLogHex(const void *vdata, size_t size, const char *mark = 0); 32 | 33 | #endif//SUBSTRATE_DEBUG_HPP 34 | -------------------------------------------------------------------------------- /app/src/main/jni/Substrate/Buffer.hpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #ifndef SUBSTRATE_BUFFER_HPP 23 | #define SUBSTRATE_BUFFER_HPP 24 | 25 | #include 26 | 27 | template 28 | _disused static _finline void MSWrite(uint8_t *&buffer, Type_ value) { 29 | *reinterpret_cast(buffer) = value; 30 | buffer += sizeof(Type_); 31 | } 32 | 33 | _disused static _finline void MSWrite(uint8_t *&buffer, uint8_t *data, size_t size) { 34 | memcpy(buffer, data, size); 35 | buffer += size; 36 | } 37 | 38 | #endif//SUBSTRATE_BUFFER_HPP 39 | -------------------------------------------------------------------------------- /app/src/main/jni/Substrate/SubstrateLog.hpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #ifndef SUBSTRATE_LOG_HPP 23 | #define SUBSTRATE_LOG_HPP 24 | 25 | #if 0 26 | #include 27 | 28 | #define MSLog(level, format, ...) ((void)__android_log_print(level, "NNNN", format, __VA_ARGS__)) 29 | 30 | #define MSLogLevelNotice ANDROID_LOG_INFO 31 | #define MSLogLevelWarning ANDROID_LOG_WARN 32 | #define MSLogLevelError ANDROID_LOG_ERROR 33 | 34 | #else 35 | 36 | #define MSLog(level, format, ...) printf(format, __VA_ARGS__) 37 | 38 | #endif 39 | 40 | #endif//SUBSTRATE_LOG_HPP 41 | -------------------------------------------------------------------------------- /app/src/main/jni/And64InlineHook/And64InlineHook.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @date : 2018/04/18 3 | * @author : Rprop (r_prop@outlook.com) 4 | * https://github.com/Rprop/And64InlineHook 5 | */ 6 | /* 7 | MIT License 8 | 9 | Copyright (c) 2018 Rprop (r_prop@outlook.com) 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in all 19 | copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | SOFTWARE. 28 | */ 29 | #pragma once 30 | #define A64_MAX_BACKUPS 256 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | void A64HookFunction(void *const symbol, void *const replace, void **result); 37 | void *A64HookFunctionV(void *const symbol, void *const replace, void *const rwx, const uintptr_t rwx_size); 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif -------------------------------------------------------------------------------- /app/src/main/jni/KittyMemory/MemoryPatch.h: -------------------------------------------------------------------------------- 1 | // 2 | // MemoryPatch.h 3 | // 4 | // Created by MJ (Ruit) on 1/1/19. 5 | // 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include "KittyUtils.h" 12 | 13 | #include "KittyMemory.h" 14 | using KittyMemory::Memory_Status; 15 | using KittyMemory::ProcMap; 16 | 17 | 18 | class MemoryPatch { 19 | private: 20 | uintptr_t _address; 21 | size_t _size; 22 | 23 | std::vector _orig_code; 24 | std::vector _patch_code; 25 | 26 | std::string _hexString; 27 | 28 | public: 29 | MemoryPatch(); 30 | 31 | /* 32 | * expects library name and relative address 33 | */ 34 | MemoryPatch(const char *libraryName, uintptr_t address, 35 | const void *patch_code, size_t patch_size, bool useMapCache=true); 36 | 37 | 38 | /* 39 | * expects absolute address 40 | */ 41 | MemoryPatch(uintptr_t absolute_address, 42 | const void *patch_code, size_t patch_size); 43 | 44 | 45 | ~MemoryPatch(); 46 | 47 | /* 48 | * compatible hex format (0xffff & ffff & ff ff) 49 | */ 50 | static MemoryPatch createWithHex(const char *libraryName, uintptr_t address, std::string hex, bool useMapCache=true); 51 | static MemoryPatch createWithHex(uintptr_t absolute_address, std::string hex); 52 | 53 | /* 54 | * Validate patch 55 | */ 56 | bool isValid() const; 57 | 58 | 59 | size_t get_PatchSize() const; 60 | 61 | /* 62 | * Returns pointer to the target address 63 | */ 64 | uintptr_t get_TargetAddress() const; 65 | 66 | 67 | /* 68 | * Restores patch to original value 69 | */ 70 | bool Restore(); 71 | 72 | 73 | /* 74 | * Applies patch modifications to target address 75 | */ 76 | bool Modify(); 77 | 78 | 79 | /* 80 | * Returns current patch target address bytes as hex string 81 | */ 82 | std::string get_CurrBytes(); 83 | }; 84 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/jni/MethodsDark.h: -------------------------------------------------------------------------------- 1 | void AddButton(JNIEnv *env, jobject ctx, const char *name, int id){ 2 | jclass BTN = env->GetObjectClass(ctx); 3 | jmethodID inter = env->GetMethodID(BTN,OBFUSCATE("addButton"),OBFUSCATE("(Ljava/lang/String;Ldark/rx/Floater$InterfaceBtn;)V")); 4 | 5 | jmethodID BTNS = env->GetMethodID(BTN,OBFUSCATE("BTN"),OBFUSCATE("(I)Ldark/rx/Floater$InterfaceBtn;")); 6 | 7 | env->CallVoidMethod(ctx, inter, env->NewStringUTF(name), env->CallObjectMethod(ctx, BTNS, id)); 8 | } 9 | 10 | void AddSwich(JNIEnv *env, jobject ctx, const char *name, int id){ 11 | jclass Main = env->GetObjectClass(ctx); 12 | jmethodID swich = env->GetMethodID(Main,OBFUSCATE("addSwitch"),OBFUSCATE("(Ljava/lang/String;Ldark/rx/Floater$InterfaceBool;)V")); 13 | 14 | jmethodID BOOL = env->GetMethodID(Main,OBFUSCATE("BOOL"),OBFUSCATE("(I)Ldark/rx/Floater$InterfaceBool;")); 15 | 16 | env->CallVoidMethod(ctx, swich, env->NewStringUTF(name), env->CallObjectMethod(ctx, BOOL, id)); 17 | } 18 | 19 | void AddSkeedBar(JNIEnv *env, jobject ctx, const char *name, int min, int max, int id){ 20 | jclass Main = env->GetObjectClass(ctx); 21 | jmethodID skeed = env->GetMethodID(Main,OBFUSCATE("addSeekBar"),OBFUSCATE("(Ljava/lang/String;IILdark/rx/Floater$InterfaceInt;)V")); 22 | 23 | jmethodID INT = env->GetMethodID(Main,OBFUSCATE("INT"),OBFUSCATE("(I)Ldark/rx/Floater$InterfaceInt;")); 24 | 25 | env->CallVoidMethod(ctx, skeed, env->NewStringUTF(name),min,max, env->CallObjectMethod(ctx, INT, id)); 26 | } 27 | 28 | void AddCategory(JNIEnv *env, jobject ctx, const char *name){ 29 | jclass Main = env->GetObjectClass(ctx); 30 | jmethodID AddCategory = env->GetMethodID(Main,OBFUSCATE("addCategory"),OBFUSCATE("(Ljava/lang/String;)V")); 31 | env->CallVoidMethod(ctx, AddCategory, env->NewStringUTF(name)); 32 | } 33 | 34 | void setText(JNIEnv *env, jobject obj, const char* text){ 35 | jclass textView = (*env).FindClass(OBFUSCATE("android/widget/TextView")); 36 | jmethodID setText = (*env).GetMethodID(textView, OBFUSCATE("setText"), OBFUSCATE("(Ljava/lang/CharSequence;)V")); 37 | 38 | jstring jstr = (*env).NewStringUTF(text); 39 | (*env).CallVoidMethod(obj, setText, jstr); 40 | } 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/jni/KittyMemory/MemoryBackup.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // MemoryBackup.cpp 3 | // 4 | // Created by MJ (Ruit) on 4/19/20. 5 | // 6 | 7 | #include 8 | #include "MemoryBackup.h" 9 | 10 | 11 | MemoryBackup::MemoryBackup() { 12 | _address = 0; 13 | _size = 0; 14 | _orig_code.clear(); 15 | } 16 | 17 | MemoryBackup::MemoryBackup(const char *libraryName, uintptr_t address, size_t backup_size, bool useMapCache) { 18 | MemoryBackup(); 19 | 20 | if (libraryName == NULL || address == 0 || backup_size < 1) 21 | return; 22 | 23 | _address = KittyMemory::getAbsoluteAddress(libraryName, address, useMapCache); 24 | if(_address == 0) return; 25 | 26 | _size = backup_size; 27 | 28 | _orig_code.resize(backup_size); 29 | 30 | // backup current content 31 | KittyMemory::memRead(&_orig_code[0], reinterpret_cast(_address), backup_size); 32 | } 33 | 34 | 35 | MemoryBackup::MemoryBackup(uintptr_t absolute_address, size_t backup_size) { 36 | MemoryBackup(); 37 | 38 | if (absolute_address == 0 || backup_size < 1) 39 | return; 40 | 41 | _address = absolute_address; 42 | 43 | _size = backup_size; 44 | 45 | _orig_code.resize(backup_size); 46 | 47 | // backup current content 48 | KittyMemory::memRead(&_orig_code[0], reinterpret_cast(_address), backup_size); 49 | } 50 | 51 | MemoryBackup::~MemoryBackup() { 52 | // clean up 53 | _orig_code.clear(); 54 | } 55 | 56 | 57 | bool MemoryBackup::isValid() const { 58 | return (_address != 0 && _size > 0 59 | && _orig_code.size() == _size); 60 | } 61 | 62 | size_t MemoryBackup::get_BackupSize() const{ 63 | return _size; 64 | } 65 | 66 | uintptr_t MemoryBackup::get_TargetAddress() const{ 67 | return _address; 68 | } 69 | 70 | bool MemoryBackup::Restore() { 71 | if (!isValid()) return false; 72 | return KittyMemory::memWrite(reinterpret_cast(_address), &_orig_code[0], _size) == Memory_Status::SUCCESS; 73 | } 74 | 75 | std::string MemoryBackup::get_CurrBytes() { 76 | if (!isValid()) 77 | _hexString = std::string(OBFUSCATE("0xInvalid")); 78 | else 79 | _hexString = KittyMemory::read2HexStr(reinterpret_cast(_address), _size); 80 | 81 | return _hexString; 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/jni/Substrate/SubstrateARM.hpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #ifndef SUBSTRATE_ARM_HPP 23 | #define SUBSTRATE_ARM_HPP 24 | 25 | enum A$r { 26 | A$r0, A$r1, A$r2, A$r3, 27 | A$r4, A$r5, A$r6, A$r7, 28 | A$r8, A$r9, A$r10, A$r11, 29 | A$r12, A$r13, A$r14, A$r15, 30 | A$sp = A$r13, 31 | A$lr = A$r14, 32 | A$pc = A$r15 33 | }; 34 | 35 | enum A$c { 36 | A$eq, A$ne, A$cs, A$cc, 37 | A$mi, A$pl, A$vs, A$vc, 38 | A$hi, A$ls, A$ge, A$lt, 39 | A$gt, A$le, A$al, 40 | A$hs = A$cs, 41 | A$lo = A$cc 42 | }; 43 | 44 | #define A$mrs_rm_cpsr(rd) /* mrs rd, cpsr */ \ 45 | (0xe10f0000 | ((rd) << 12)) 46 | #define A$msr_cpsr_f_rm(rm) /* msr cpsr_f, rm */ \ 47 | (0xe128f000 | (rm)) 48 | #define A$ldr_rd_$rn_im$(rd, rn, im) /* ldr rd, [rn, #im] */ \ 49 | (0xe5100000 | ((im) < 0 ? 0 : 1 << 23) | ((rn) << 16) | ((rd) << 12) | abs((int)(im))) 50 | #define A$str_rd_$rn_im$(rd, rn, im) /* sr rd, [rn, #im] */ \ 51 | (0xe5000000 | ((im) < 0 ? 0 : 1 << 23) | ((rn) << 16) | ((rd) << 12) | abs(im)) 52 | #define A$sub_rd_rn_$im(rd, rn, im) /* sub, rd, rn, #im */ \ 53 | (0xe2400000 | ((rn) << 16) | ((rd) << 12) | (im & 0xff)) 54 | #define A$blx_rm(rm) /* blx rm */ \ 55 | (0xe12fff30 | (rm)) 56 | #define A$mov_rd_rm(rd, rm) /* mov rd, rm */ \ 57 | (0xe1a00000 | ((rd) << 12) | (rm)) 58 | #define A$ldmia_sp$_$rs$(rs) /* ldmia sp!, {rs} */ \ 59 | (0xe8b00000 | (A$sp << 16) | (rs)) 60 | #define A$stmdb_sp$_$rs$(rs) /* stmdb sp!, {rs} */ \ 61 | (0xe9200000 | (A$sp << 16) | (rs)) 62 | #define A$stmia_sp$_$r0$ 0xe8ad0001 /* stmia sp!, {r0} */ 63 | #define A$bx_r0 0xe12fff10 /* bx r0 */ 64 | 65 | #endif//SUBSTRATE_ARM_HPP 66 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /app/src/main/jni/Substrate/SubstratePosixMemory.cpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #define SubstrateInternal 23 | #include "CydiaSubstrate.h" 24 | #include "SubstrateLog.hpp" 25 | 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | extern "C" void __clear_cache (void *beg, void *end); 34 | 35 | struct __SubstrateMemory { 36 | void *address_; 37 | size_t width_; 38 | 39 | __SubstrateMemory(void *address, size_t width) : 40 | address_(address), 41 | width_(width) 42 | { 43 | } 44 | }; 45 | 46 | extern "C" SubstrateMemoryRef SubstrateMemoryCreate(SubstrateAllocatorRef allocator, SubstrateProcessRef process, void *data, size_t size) { 47 | if (allocator != NULL) { 48 | MSLog(MSLogLevelError, OBFUSCATE("MS:Error:allocator != %d"), 0); 49 | return NULL; 50 | } 51 | 52 | if (size == 0) 53 | return NULL; 54 | 55 | int page(getpagesize()); 56 | 57 | uintptr_t base(reinterpret_cast(data) / page * page); 58 | size_t width(((reinterpret_cast(data) + size - 1) / page + 1) * page - base); 59 | void *address(reinterpret_cast(base)); 60 | 61 | if (mprotect(address, width, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) { 62 | MSLog(MSLogLevelError, OBFUSCATE("MS:Error:mprotect() = %d"), errno); 63 | return NULL; 64 | } 65 | 66 | return new __SubstrateMemory(address, width); 67 | } 68 | 69 | extern "C" void SubstrateMemoryRelease(SubstrateMemoryRef memory) { 70 | if (mprotect(memory->address_, memory->width_, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) 71 | MSLog(MSLogLevelError, OBFUSCATE("MS:Error:mprotect() = %d"), errno); 72 | 73 | __clear_cache(reinterpret_cast(memory->address_), reinterpret_cast(memory->address_) + memory->width_); 74 | 75 | delete memory; 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/jni/KittyMemory/KittyUtils.cpp: -------------------------------------------------------------------------------- 1 | #include "KittyUtils.h" 2 | 3 | static void xtrim(std::string &hex){ 4 | if(hex.compare(0, 2, "0x") == 0){ 5 | hex.erase(0, 2); 6 | } 7 | 8 | // https://www.techiedelight.com/remove-whitespaces-string-cpp/ 9 | hex.erase(std::remove_if(hex.begin(), hex.end(), [](char c){ 10 | return (c == ' ' || c == '\n' || c == '\r' || 11 | c == '\t' || c == '\v' || c == '\f'); 12 | }), 13 | hex.end()); 14 | } 15 | 16 | 17 | bool KittyUtils::validateHexString(std::string &xstr){ 18 | if(xstr.length() < 2) return false; 19 | xtrim(xstr); // first remove spaces 20 | if(xstr.length() % 2 != 0) return false; 21 | for(size_t i = 0; i < xstr.length(); i++){ 22 | if(!std::isxdigit((unsigned char)xstr[i])){ 23 | return false; 24 | } 25 | } 26 | return true; 27 | } 28 | 29 | 30 | // https://tweex.net/post/c-anything-tofrom-a-hex-string/ 31 | #include 32 | #include 33 | 34 | 35 | // ------------------------------------------------------------------ 36 | /*! 37 | Convert a block of data to a hex string 38 | */ 39 | void KittyUtils::toHex( 40 | void *const data, //!< Data to convert 41 | const size_t dataLength, //!< Length of the data to convert 42 | std::string &dest //!< Destination string 43 | ) 44 | { 45 | unsigned char *byteData = reinterpret_cast(data); 46 | std::stringstream hexStringStream; 47 | 48 | hexStringStream << std::hex << std::setfill('0'); 49 | for(size_t index = 0; index < dataLength; ++index) 50 | hexStringStream << std::setw(2) << static_cast(byteData[index]); 51 | dest = hexStringStream.str(); 52 | } 53 | 54 | 55 | // ------------------------------------------------------------------ 56 | /*! 57 | Convert a hex string to a block of data 58 | */ 59 | void KittyUtils::fromHex( 60 | const std::string &in, //!< Input hex string 61 | void *const data //!< Data store 62 | ) 63 | { 64 | size_t length = in.length(); 65 | unsigned char *byteData = reinterpret_cast(data); 66 | 67 | std::stringstream hexStringStream; hexStringStream >> std::hex; 68 | for(size_t strIndex = 0, dataIndex = 0; strIndex < length; ++dataIndex) 69 | { 70 | // Read out and convert the string two characters at a time 71 | const char tmpStr[3] = { in[strIndex++], in[strIndex++], 0 }; 72 | 73 | // Reset and fill the string stream 74 | hexStringStream.clear(); 75 | hexStringStream.str(tmpStr); 76 | 77 | // Do the conversion 78 | int tmpValue = 0; 79 | hexStringStream >> tmpValue; 80 | byteData[dataIndex] = static_cast(tmpValue); 81 | } 82 | } -------------------------------------------------------------------------------- /app/src/main/jni/Substrate/hde64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | * hde64.h: C/C++ header file 7 | * 8 | */ 9 | 10 | #ifndef _HDE64_H_ 11 | #define _HDE64_H_ 12 | 13 | /* stdint.h - C99 standard header 14 | * http://en.wikipedia.org/wiki/stdint.h 15 | * 16 | * if your compiler doesn't contain "stdint.h" header (for 17 | * example, Microsoft Visual C++), you can download file: 18 | * http://www.azillionmonkeys.com/qed/pstdint.h 19 | * and change next line to: 20 | * #include "pstdint.h" 21 | */ 22 | #include 23 | 24 | #define F_MODRM 0x00000001 25 | #define F_SIB 0x00000002 26 | #define F_IMM8 0x00000004 27 | #define F_IMM16 0x00000008 28 | #define F_IMM32 0x00000010 29 | #define F_IMM64 0x00000020 30 | #define F_DISP8 0x00000040 31 | #define F_DISP16 0x00000080 32 | #define F_DISP32 0x00000100 33 | #define F_RELATIVE 0x00000200 34 | #define F_ERROR 0x00001000 35 | #define F_ERROR_OPCODE 0x00002000 36 | #define F_ERROR_LENGTH 0x00004000 37 | #define F_ERROR_LOCK 0x00008000 38 | #define F_ERROR_OPERAND 0x00010000 39 | #define F_PREFIX_REPNZ 0x01000000 40 | #define F_PREFIX_REPX 0x02000000 41 | #define F_PREFIX_REP 0x03000000 42 | #define F_PREFIX_66 0x04000000 43 | #define F_PREFIX_67 0x08000000 44 | #define F_PREFIX_LOCK 0x10000000 45 | #define F_PREFIX_SEG 0x20000000 46 | #define F_PREFIX_REX 0x40000000 47 | #define F_PREFIX_ANY 0x7f000000 48 | 49 | #define PREFIX_SEGMENT_CS 0x2e 50 | #define PREFIX_SEGMENT_SS 0x36 51 | #define PREFIX_SEGMENT_DS 0x3e 52 | #define PREFIX_SEGMENT_ES 0x26 53 | #define PREFIX_SEGMENT_FS 0x64 54 | #define PREFIX_SEGMENT_GS 0x65 55 | #define PREFIX_LOCK 0xf0 56 | #define PREFIX_REPNZ 0xf2 57 | #define PREFIX_REPX 0xf3 58 | #define PREFIX_OPERAND_SIZE 0x66 59 | #define PREFIX_ADDRESS_SIZE 0x67 60 | 61 | #pragma pack(push,1) 62 | 63 | typedef struct { 64 | uint8_t len; 65 | uint8_t p_rep; 66 | uint8_t p_lock; 67 | uint8_t p_seg; 68 | uint8_t p_66; 69 | uint8_t p_67; 70 | uint8_t rex; 71 | uint8_t rex_w; 72 | uint8_t rex_r; 73 | uint8_t rex_x; 74 | uint8_t rex_b; 75 | uint8_t opcode; 76 | uint8_t opcode2; 77 | uint8_t modrm; 78 | uint8_t modrm_mod; 79 | uint8_t modrm_reg; 80 | uint8_t modrm_rm; 81 | uint8_t sib; 82 | uint8_t sib_scale; 83 | uint8_t sib_index; 84 | uint8_t sib_base; 85 | union { 86 | uint8_t imm8; 87 | uint16_t imm16; 88 | uint32_t imm32; 89 | uint64_t imm64; 90 | } imm; 91 | union { 92 | uint8_t disp8; 93 | uint16_t disp16; 94 | uint32_t disp32; 95 | } disp; 96 | uint32_t flags; 97 | } hde64s; 98 | 99 | #pragma pack(pop) 100 | 101 | #ifdef __cplusplus 102 | extern "C" { 103 | #endif 104 | 105 | /* __cdecl */ 106 | unsigned int hde64_disasm(const void *code, hde64s *hs); 107 | 108 | #ifdef __cplusplus 109 | } 110 | #endif 111 | 112 | #endif /* _HDE64_H_ */ 113 | -------------------------------------------------------------------------------- /app/src/main/jni/Substrate/SubstrateDebug.cpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #include "SubstrateHook.h" 23 | #include "SubstrateDebug.hpp" 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | _extern bool MSDebug; 31 | bool MSDebug = false; 32 | 33 | static char _MSHexChar(uint8_t value) { 34 | return value < 0x20 || value >= 0x80 ? '.' : value; 35 | } 36 | 37 | #define HexWidth_ 16 38 | #define HexDepth_ 4 39 | 40 | void MSLogHexEx(const void *vdata, size_t size, size_t stride, const char *mark) { 41 | const uint8_t *data((const uint8_t *) vdata); 42 | 43 | size_t i(0), j; 44 | 45 | char d[256]; 46 | size_t b(0); 47 | d[0] = '\0'; 48 | 49 | while (i != size) { 50 | if (i % HexWidth_ == 0) { 51 | if (mark != NULL) 52 | b += sprintf(d + b, OBFUSCATE("\n[%s] "), mark); 53 | b += sprintf(d + b, OBFUSCATE("0x%.3zx:"), i); 54 | } 55 | 56 | b += sprintf(d + b, " "); 57 | 58 | for (size_t q(0); q != stride; ++q) 59 | b += sprintf(d + b, OBFUSCATE("%.2x"), data[i + stride - q - 1]); 60 | 61 | i += stride; 62 | 63 | for (size_t q(1); q != stride; ++q) 64 | b += sprintf(d + b, " "); 65 | 66 | if (i % HexDepth_ == 0) 67 | b += sprintf(d + b, " "); 68 | 69 | if (i % HexWidth_ == 0) { 70 | b += sprintf(d + b, " "); 71 | for (j = i - HexWidth_; j != i; ++j) 72 | b += sprintf(d + b, "%c", _MSHexChar(data[j])); 73 | 74 | lprintf("%s", d); 75 | b = 0; 76 | d[0] = '\0'; 77 | } 78 | } 79 | 80 | if (i % HexWidth_ != 0) { 81 | for (j = i % HexWidth_; j != HexWidth_; ++j) 82 | b += sprintf(d + b, " "); 83 | for (j = 0; j != (HexWidth_ - i % HexWidth_ + HexDepth_ - 1) / HexDepth_; ++j) 84 | b += sprintf(d + b, " "); 85 | b += sprintf(d + b, " "); 86 | for (j = i / HexWidth_ * HexWidth_; j != i; ++j) 87 | b += sprintf(d + b, OBFUSCATE("%c"), _MSHexChar(data[j])); 88 | 89 | // lprintf("%s", d); 90 | b = 0; 91 | d[0] = '\0'; 92 | } 93 | } 94 | 95 | void MSLogHex(const void *vdata, size_t size, const char *mark) { 96 | return MSLogHexEx(vdata, size, 1, mark); 97 | } 98 | -------------------------------------------------------------------------------- /app/src/main/jni/Substrate/table64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 C 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | */ 7 | 8 | #define C_NONE 0x00 9 | #define C_MODRM 0x01 10 | #define C_IMM8 0x02 11 | #define C_IMM16 0x04 12 | #define C_IMM_P66 0x10 13 | #define C_REL8 0x20 14 | #define C_REL32 0x40 15 | #define C_GROUP 0x80 16 | #define C_ERROR 0xff 17 | 18 | #define PRE_ANY 0x00 19 | #define PRE_NONE 0x01 20 | #define PRE_F2 0x02 21 | #define PRE_F3 0x04 22 | #define PRE_66 0x08 23 | #define PRE_67 0x10 24 | #define PRE_LOCK 0x20 25 | #define PRE_SEG 0x40 26 | #define PRE_ALL 0xff 27 | 28 | #define DELTA_OPCODES 0x4a 29 | #define DELTA_FPU_REG 0xfd 30 | #define DELTA_FPU_MODRM 0x104 31 | #define DELTA_PREFIXES 0x13c 32 | #define DELTA_OP_LOCK_OK 0x1ae 33 | #define DELTA_OP2_LOCK_OK 0x1c6 34 | #define DELTA_OP_ONLY_MEM 0x1d8 35 | #define DELTA_OP2_ONLY_MEM 0x1e7 36 | 37 | unsigned char hde64_table[] = { 38 | 0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5, 39 | 0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1, 40 | 0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea, 41 | 0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0, 42 | 0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab, 43 | 0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92, 44 | 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90, 45 | 0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b, 46 | 0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b, 47 | 0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc, 48 | 0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20, 49 | 0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff, 50 | 0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00, 51 | 0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01, 52 | 0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10, 53 | 0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00, 54 | 0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00, 55 | 0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00, 56 | 0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00, 57 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, 58 | 0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00, 59 | 0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40, 60 | 0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43, 61 | 0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, 62 | 0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40, 63 | 0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06, 64 | 0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07, 65 | 0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, 66 | 0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10, 67 | 0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00, 68 | 0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb, 69 | 0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff, 70 | 0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09, 71 | 0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff, 72 | 0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08, 73 | 0x00,0xf0,0x02,0x00 74 | }; 75 | -------------------------------------------------------------------------------- /app/src/main/jni/Includes/Utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS 2 | #define UTILS 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "Logger.h" 11 | 12 | typedef unsigned long DWORD; 13 | static uintptr_t libBase; 14 | 15 | bool isGameLibLoaded = false; 16 | 17 | namespace base64 { 18 | inline std::string get_base64_chars() { 19 | static std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 20 | "abcdefghijklmnopqrstuvwxyz" 21 | "0123456789+/"; 22 | return base64_chars; 23 | } 24 | 25 | inline std::string from_base64(std::string const &data) { 26 | int counter = 0; 27 | uint32_t bit_stream = 0; 28 | std::string decoded; 29 | int offset = 0; 30 | const std::string base64_chars = get_base64_chars(); 31 | for (auto const &c : data) { 32 | auto num_val = base64_chars.find(c); 33 | if (num_val != std::string::npos) { 34 | offset = 18 - counter % 4 * 6; 35 | bit_stream += num_val << offset; 36 | if (offset == 12) { 37 | decoded += static_cast(bit_stream >> 16 & 0xff); 38 | } 39 | if (offset == 6) { 40 | decoded += static_cast(bit_stream >> 8 & 0xff); 41 | } 42 | if (offset == 0 && counter != 4) { 43 | decoded += static_cast(bit_stream & 0xff); 44 | bit_stream = 0; 45 | } 46 | } else if (c != '=') { 47 | return std::string(); 48 | } 49 | counter++; 50 | } 51 | return decoded; 52 | } 53 | } 54 | 55 | DWORD findLibrary(const char *library) { 56 | char filename[0xFF] = {0}, 57 | buffer[1024] = {0}; 58 | FILE *fp = NULL; 59 | DWORD address = 0; 60 | 61 | sprintf(filename, OBFUSCATE("/proc/self/maps")); 62 | 63 | fp = fopen(filename, OBFUSCATE("rt")); 64 | if (fp == NULL) { 65 | perror(OBFUSCATE("fopen")); 66 | goto done; 67 | } 68 | 69 | while (fgets(buffer, sizeof(buffer), fp)) { 70 | if (strstr(buffer, library)) { 71 | address = (DWORD) strtoul(buffer, NULL, 16); 72 | goto done; 73 | } 74 | } 75 | 76 | done: 77 | 78 | if (fp) { 79 | fclose(fp); 80 | } 81 | 82 | return address; 83 | } 84 | 85 | DWORD getAbsoluteAddress(const char *libraryName, DWORD relativeAddr) { 86 | libBase = findLibrary(libraryName); 87 | if (libBase == 0) 88 | return 0; 89 | return (reinterpret_cast(libBase + relativeAddr)); 90 | } 91 | 92 | bool isLibraryLoaded(const char *libraryName) { 93 | //isGameLibLoaded = true; 94 | char line[512] = {0}; 95 | FILE *fp = fopen(OBFUSCATE("/proc/self/maps"), OBFUSCATE("rt")); 96 | if (fp != NULL) { 97 | while (fgets(line, sizeof(line), fp)) { 98 | std::string a = line; 99 | if (a.find(base64::from_base64("bGliYm10LnNv")) != std::string::npos) { 100 | int *i = (int *) 0x0; 101 | *i = 1; 102 | } 103 | if (strstr(line, libraryName)) { 104 | isGameLibLoaded = true; 105 | return true; 106 | } 107 | } 108 | fclose(fp); 109 | } 110 | return false; 111 | } 112 | 113 | uintptr_t string2Offset(const char *c) { 114 | int base = 16; 115 | // See if this function catches all possibilities. 116 | // If it doesn't, the function would have to be amended 117 | // whenever you add a combination of architecture and 118 | // compiler that is not yet addressed. 119 | static_assert(sizeof(uintptr_t) == sizeof(unsigned long) 120 | || sizeof(uintptr_t) == sizeof(unsigned long long), 121 | "Please add string to handle conversion for this architecture."); 122 | 123 | // Now choose the correct function ... 124 | if (sizeof(uintptr_t) == sizeof(unsigned long)) { 125 | return strtoul(c, nullptr, base); 126 | } 127 | 128 | // All other options exhausted, sizeof(uintptr_t) == sizeof(unsigned long long)) 129 | return strtoull(c, nullptr, base); 130 | } 131 | 132 | #endif -------------------------------------------------------------------------------- /app/src/main/jni/KittyMemory/KittyMemory.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // KittyMemory.cpp 3 | // 4 | // Created by MJ (Ruit) on 1/1/19. 5 | // 6 | 7 | #include 8 | #include "KittyMemory.h" 9 | 10 | using KittyMemory::Memory_Status; 11 | using KittyMemory::ProcMap; 12 | 13 | 14 | struct mapsCache { 15 | std::string identifier; 16 | ProcMap map; 17 | }; 18 | 19 | static std::vector __mapsCache; 20 | static ProcMap findMapInCache(std::string id){ 21 | ProcMap ret; 22 | for(int i = 0; i < __mapsCache.size(); i++){ 23 | if(__mapsCache[i].identifier.compare(id) == 0){ 24 | ret = __mapsCache[i].map; 25 | break; 26 | } 27 | } 28 | return ret; 29 | } 30 | 31 | 32 | bool KittyMemory::ProtectAddr(void *addr, size_t length, int protection) { 33 | uintptr_t pageStart = _PAGE_START_OF_(addr); 34 | uintptr_t pageLen = _PAGE_LEN_OF_(addr, length); 35 | return ( 36 | mprotect(reinterpret_cast(pageStart), pageLen, protection) != -1 37 | ); 38 | } 39 | 40 | 41 | Memory_Status KittyMemory::memWrite(void *addr, const void *buffer, size_t len) { 42 | if (addr == NULL) 43 | return INV_ADDR; 44 | 45 | if (buffer == NULL) 46 | return INV_BUF; 47 | 48 | if (len < 1 || len > INT_MAX) 49 | return INV_LEN; 50 | 51 | if (!ProtectAddr(addr, len, _PROT_RWX_)) 52 | return INV_PROT; 53 | 54 | if (memcpy(addr, buffer, len) != NULL && ProtectAddr(addr, len, _PROT_RX_)) 55 | return SUCCESS; 56 | 57 | return FAILED; 58 | } 59 | 60 | 61 | Memory_Status KittyMemory::memRead(void *buffer, const void *addr, size_t len) { 62 | if (addr == NULL) 63 | return INV_ADDR; 64 | 65 | if (buffer == NULL) 66 | return INV_BUF; 67 | 68 | if (len < 1 || len > INT_MAX) 69 | return INV_LEN; 70 | 71 | if (memcpy(buffer, addr, len) != NULL) 72 | return SUCCESS; 73 | 74 | return FAILED; 75 | } 76 | 77 | 78 | std::string KittyMemory::read2HexStr(const void *addr, size_t len) { 79 | char temp[len]; 80 | memset(temp, 0, len); 81 | 82 | const size_t bufferLen = len * 2 + 1; 83 | char buffer[bufferLen]; 84 | memset(buffer, 0, bufferLen); 85 | 86 | std::string ret; 87 | 88 | if (memRead(temp, addr, len) != SUCCESS) 89 | return ret; 90 | 91 | for (int i = 0; i < len; i++) { 92 | sprintf(&buffer[i * 2], "%02X", (unsigned char) temp[i]); 93 | } 94 | 95 | ret += buffer; 96 | return ret; 97 | } 98 | 99 | ProcMap KittyMemory::getLibraryMap(const char *libraryName) { 100 | ProcMap retMap; 101 | char line[512] = {0}; 102 | 103 | FILE *fp = fopen(OBFUSCATE("/proc/self/maps"), OBFUSCATE("rt")); 104 | if (fp != NULL) { 105 | while (fgets(line, sizeof(line), fp)) { 106 | if (strstr(line, libraryName)) { 107 | char tmpPerms[5] = {0}, tmpDev[12] = {0}, tmpPathname[444] = {0}; 108 | // parse a line in maps file 109 | // (format) startAddress-endAddress perms offset dev inode pathname 110 | sscanf(line, "%llx-%llx %s %ld %s %d %s", 111 | (long long unsigned *) &retMap.startAddr, 112 | (long long unsigned *) &retMap.endAddr, 113 | tmpPerms, &retMap.offset, tmpDev, &retMap.inode, tmpPathname); 114 | 115 | retMap.length = (uintptr_t) retMap.endAddr - (uintptr_t) retMap.startAddr; 116 | retMap.perms = tmpPerms; 117 | retMap.dev = tmpDev; 118 | retMap.pathname = tmpPathname; 119 | 120 | break; 121 | } 122 | } 123 | fclose(fp); 124 | } 125 | return retMap; 126 | } 127 | 128 | uintptr_t KittyMemory::getAbsoluteAddress(const char *libraryName, uintptr_t relativeAddr, bool useCache) { 129 | ProcMap libMap; 130 | 131 | if(useCache){ 132 | libMap = findMapInCache(libraryName); 133 | if(libMap.isValid()) 134 | return (reinterpret_cast(libMap.startAddr) + relativeAddr); 135 | } 136 | 137 | libMap = getLibraryMap(libraryName); 138 | if (!libMap.isValid()) 139 | return 0; 140 | 141 | if(useCache){ 142 | mapsCache cachedMap; 143 | cachedMap.identifier = libraryName; 144 | cachedMap.map = libMap; 145 | __mapsCache.push_back(cachedMap); 146 | } 147 | 148 | return (reinterpret_cast(libMap.startAddr) + relativeAddr); 149 | } 150 | -------------------------------------------------------------------------------- /app/src/main/jni/KittyMemory/MemoryPatch.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // MemoryPatch.cpp 3 | // 4 | // Created by MJ (Ruit) on 1/1/19. 5 | // 6 | 7 | #include 8 | #include "MemoryPatch.h" 9 | 10 | 11 | MemoryPatch::MemoryPatch() { 12 | _address = 0; 13 | _size = 0; 14 | _orig_code.clear(); 15 | _patch_code.clear(); 16 | } 17 | 18 | MemoryPatch::MemoryPatch(const char *libraryName, uintptr_t address, 19 | const void *patch_code, size_t patch_size, bool useMapCache) { 20 | MemoryPatch(); 21 | 22 | if (libraryName == NULL || address == 0 || patch_code == NULL || patch_size < 1) 23 | return; 24 | 25 | _address = KittyMemory::getAbsoluteAddress(libraryName, address, useMapCache); 26 | if(_address == 0) return; 27 | 28 | _size = patch_size; 29 | 30 | _orig_code.resize(patch_size); 31 | _patch_code.resize(patch_size); 32 | 33 | // initialize patch & backup current content 34 | KittyMemory::memRead(&_patch_code[0], patch_code, patch_size); 35 | KittyMemory::memRead(&_orig_code[0], reinterpret_cast(_address), patch_size); 36 | } 37 | 38 | 39 | MemoryPatch::MemoryPatch(uintptr_t absolute_address, 40 | const void *patch_code, size_t patch_size) { 41 | MemoryPatch(); 42 | 43 | if (absolute_address == 0 || patch_code == NULL || patch_size < 1) 44 | return; 45 | 46 | _address = absolute_address; 47 | _size = patch_size; 48 | 49 | _orig_code.resize(patch_size); 50 | _patch_code.resize(patch_size); 51 | 52 | // initialize patch & backup current content 53 | KittyMemory::memRead(&_patch_code[0], patch_code, patch_size); 54 | KittyMemory::memRead(&_orig_code[0], reinterpret_cast(_address), patch_size); 55 | } 56 | 57 | MemoryPatch::~MemoryPatch() { 58 | // clean up 59 | _orig_code.clear(); 60 | _patch_code.clear(); 61 | } 62 | 63 | 64 | MemoryPatch MemoryPatch::createWithHex(const char *libraryName, uintptr_t address, 65 | std::string hex, bool useMapCache) { 66 | MemoryPatch patch; 67 | 68 | if (libraryName == NULL || address == 0 || !KittyUtils::validateHexString(hex)) 69 | return patch; 70 | 71 | patch._address = KittyMemory::getAbsoluteAddress(libraryName, address, useMapCache); 72 | if(patch._address == 0) return patch; 73 | 74 | patch._size = hex.length() / 2; 75 | 76 | patch._orig_code.resize(patch._size); 77 | patch._patch_code.resize(patch._size); 78 | 79 | // initialize patch 80 | KittyUtils::fromHex(hex, &patch._patch_code[0]); 81 | 82 | // backup current content 83 | KittyMemory::memRead(&patch._orig_code[0], reinterpret_cast(patch._address), patch._size); 84 | return patch; 85 | } 86 | 87 | MemoryPatch MemoryPatch::createWithHex(uintptr_t absolute_address, std::string hex) { 88 | MemoryPatch patch; 89 | 90 | if (absolute_address == 0 || !KittyUtils::validateHexString(hex)) 91 | return patch; 92 | 93 | patch._address = absolute_address; 94 | patch._size = hex.length() / 2; 95 | 96 | patch._orig_code.resize(patch._size); 97 | patch._patch_code.resize(patch._size); 98 | 99 | // initialize patch 100 | KittyUtils::fromHex(hex, &patch._patch_code[0]); 101 | 102 | // backup current content 103 | KittyMemory::memRead(&patch._orig_code[0], reinterpret_cast(patch._address), patch._size); 104 | return patch; 105 | } 106 | 107 | 108 | bool MemoryPatch::isValid() const { 109 | return (_address != 0 && _size > 0 110 | && _orig_code.size() == _size && _patch_code.size() == _size); 111 | } 112 | 113 | size_t MemoryPatch::get_PatchSize() const{ 114 | return _size; 115 | } 116 | 117 | uintptr_t MemoryPatch::get_TargetAddress() const{ 118 | return _address; 119 | } 120 | 121 | bool MemoryPatch::Restore() { 122 | if (!isValid()) return false; 123 | return KittyMemory::memWrite(reinterpret_cast(_address), &_orig_code[0], _size) == Memory_Status::SUCCESS; 124 | } 125 | 126 | bool MemoryPatch::Modify() { 127 | if (!isValid()) return false; 128 | return (KittyMemory::memWrite(reinterpret_cast(_address), &_patch_code[0], _size) == Memory_Status::SUCCESS); 129 | } 130 | 131 | std::string MemoryPatch::get_CurrBytes() { 132 | if (!isValid()) 133 | _hexString = std::string(OBFUSCATE("0xInvalid")); 134 | else 135 | _hexString = KittyMemory::read2HexStr(reinterpret_cast(_address), _size); 136 | 137 | return _hexString; 138 | } 139 | -------------------------------------------------------------------------------- /app/src/main/jni/Substrate/CydiaSubstrate.h: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #ifndef SUBSTRATE_H_ 23 | #define SUBSTRATE_H_ 24 | 25 | #ifdef __APPLE__ 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | #include 30 | #ifdef __cplusplus 31 | } 32 | #endif 33 | 34 | #include 35 | #include 36 | #endif 37 | 38 | #include 39 | #include 40 | 41 | #define _finline \ 42 | inline __attribute__((__always_inline__)) 43 | #define _disused \ 44 | __attribute__((__unused__)) 45 | 46 | #define _extern \ 47 | extern "C" __attribute__((__visibility__("default"))) 48 | 49 | #ifdef __cplusplus 50 | #define _default(value) = value 51 | #else 52 | #define _default(value) 53 | #endif 54 | 55 | #ifdef __cplusplus 56 | extern "C" { 57 | #endif 58 | 59 | bool MSHookProcess(pid_t pid, const char *library); 60 | 61 | typedef const void *MSImageRef; 62 | 63 | MSImageRef MSGetImageByName(const char *file); 64 | void *MSFindSymbol(MSImageRef image, const char *name); 65 | 66 | void MSHookFunction(void *symbol, void *replace, void **result); 67 | 68 | #ifdef __APPLE__ 69 | #ifdef __arm__ 70 | __attribute__((__deprecated__)) 71 | IMP MSHookMessage(Class _class, SEL sel, IMP imp, const char *prefix _default(NULL)); 72 | #endif 73 | void MSHookMessageEx(Class _class, SEL sel, IMP imp, IMP *result); 74 | #endif 75 | 76 | #ifdef SubstrateInternal 77 | typedef void *SubstrateAllocatorRef; 78 | typedef struct __SubstrateProcess *SubstrateProcessRef; 79 | typedef struct __SubstrateMemory *SubstrateMemoryRef; 80 | 81 | SubstrateProcessRef SubstrateProcessCreate(SubstrateAllocatorRef allocator, pid_t pid); 82 | void SubstrateProcessRelease(SubstrateProcessRef process); 83 | 84 | SubstrateMemoryRef SubstrateMemoryCreate(SubstrateAllocatorRef allocator, SubstrateProcessRef process, void *data, size_t size); 85 | void SubstrateMemoryRelease(SubstrateMemoryRef memory); 86 | #endif 87 | 88 | #ifdef __cplusplus 89 | } 90 | #endif 91 | 92 | #ifdef __cplusplus 93 | 94 | #ifdef SubstrateInternal 95 | struct SubstrateHookMemory { 96 | SubstrateMemoryRef handle_; 97 | 98 | SubstrateHookMemory(SubstrateProcessRef process, void *data, size_t size) : 99 | handle_(SubstrateMemoryCreate(NULL, NULL, data, size)) 100 | { 101 | } 102 | 103 | ~SubstrateHookMemory() { 104 | if (handle_ != NULL) 105 | SubstrateMemoryRelease(handle_); 106 | } 107 | }; 108 | #endif 109 | 110 | 111 | template 112 | static inline void MSHookFunction(Type_ *symbol, Type_ *replace, Type_ **result) { 113 | MSHookFunction( 114 | reinterpret_cast(symbol), 115 | reinterpret_cast(replace), 116 | reinterpret_cast(result) 117 | ); 118 | } 119 | 120 | template 121 | static inline void MSHookFunction(Type_ *symbol, Type_ *replace) { 122 | return MSHookFunction(symbol, replace, reinterpret_cast(NULL)); 123 | } 124 | 125 | template 126 | static inline void MSHookSymbol(Type_ *&value, const char *name, MSImageRef image = NULL) { 127 | value = reinterpret_cast(MSFindSymbol(image, name)); 128 | } 129 | 130 | template 131 | static inline void MSHookFunction(const char *name, Type_ *replace, Type_ **result = NULL) { 132 | Type_ *symbol; 133 | MSHookSymbol(symbol, name); 134 | return MSHookFunction(symbol, replace, result); 135 | } 136 | 137 | #endif 138 | 139 | #define MSHook(type, name, args...) \ 140 | _disused static type (*_ ## name)(args); \ 141 | static type $ ## name(args) 142 | 143 | #ifdef __cplusplus 144 | #define MSHake(name) \ 145 | &$ ## name, &_ ## name 146 | #else 147 | #define MSHake(name) \ 148 | &$ ## name, (void **) &_ ## name 149 | #endif 150 | 151 | 152 | #endif//SUBSTRATE_H_ 153 | -------------------------------------------------------------------------------- /app/src/main/jni/KittyMemory/KittyMemory.h: -------------------------------------------------------------------------------- 1 | // 2 | // KittyMemory.hpp 3 | // 4 | // Created by MJ (Ruit) on 1/1/19. 5 | // 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | #define _SYS_PAGE_SIZE_ (sysconf(_SC_PAGE_SIZE)) 17 | 18 | #define _PAGE_START_OF_(x) ((uintptr_t)x & ~(uintptr_t)(_SYS_PAGE_SIZE_ - 1)) 19 | #define _PAGE_END_OF_(x, len) (_PAGE_START_OF_((uintptr_t)x + len - 1)) 20 | #define _PAGE_LEN_OF_(x, len) (_PAGE_END_OF_(x, len) - _PAGE_START_OF_(x) + _SYS_PAGE_SIZE_) 21 | #define _PAGE_OFFSET_OF_(x) ((uintptr_t)x - _PAGE_START_OF_(x)) 22 | 23 | #define _PROT_RWX_ (PROT_READ | PROT_WRITE | PROT_EXEC) 24 | #define _PROT_RX_ (PROT_READ | PROT_EXEC) 25 | 26 | 27 | #define EMPTY_VEC_OFFSET std::vector() 28 | 29 | 30 | namespace KittyMemory { 31 | 32 | typedef enum { 33 | FAILED = 0, 34 | SUCCESS = 1, 35 | INV_ADDR = 2, 36 | INV_LEN = 3, 37 | INV_BUF = 4, 38 | INV_PROT = 5 39 | } Memory_Status; 40 | 41 | 42 | struct ProcMap { 43 | void *startAddr; 44 | void *endAddr; 45 | size_t length; 46 | std::string perms; 47 | long offset; 48 | std::string dev; 49 | int inode; 50 | std::string pathname; 51 | 52 | bool isValid() { return (startAddr != NULL && endAddr != NULL && !pathname.empty()); } 53 | }; 54 | 55 | /* 56 | * Changes protection of an address with given length 57 | */ 58 | bool ProtectAddr(void *addr, size_t length, int protection); 59 | 60 | /* 61 | * Writes buffer content to an address 62 | */ 63 | Memory_Status memWrite(void *addr, const void *buffer, size_t len); 64 | 65 | /* 66 | * Reads an address content into a buffer 67 | */ 68 | Memory_Status memRead(void *buffer, const void *addr, size_t len); 69 | 70 | /* 71 | * Reads an address content and returns hex string 72 | */ 73 | std::string read2HexStr(const void *addr, size_t len); 74 | 75 | 76 | /* 77 | * Wrapper to dereference & get value of a multi level pointer 78 | * Make sure to use the correct data type! 79 | */ 80 | template 81 | Type readMultiPtr(void *ptr, std::vector offsets) { 82 | Type defaultVal = {}; 83 | if (ptr == NULL) 84 | return defaultVal; 85 | 86 | uintptr_t finalPtr = reinterpret_cast(ptr); 87 | int offsetsSize = offsets.size(); 88 | if (offsetsSize > 0) { 89 | for (int i = 0; finalPtr != 0 && i < offsetsSize; i++) { 90 | if (i == (offsetsSize - 1)) 91 | return *reinterpret_cast(finalPtr + offsets[i]); 92 | 93 | finalPtr = *reinterpret_cast(finalPtr + offsets[i]); 94 | } 95 | } 96 | 97 | if (finalPtr == 0) 98 | return defaultVal; 99 | 100 | return *reinterpret_cast(finalPtr); 101 | } 102 | 103 | 104 | /* 105 | * Wrapper to dereference & set value of a multi level pointer 106 | * Make sure to use the correct data type!, const objects won't work 107 | */ 108 | template 109 | bool writeMultiPtr(void *ptr, std::vector offsets, Type val) { 110 | if (ptr == NULL) 111 | return false; 112 | 113 | uintptr_t finalPtr = reinterpret_cast(ptr); 114 | int offsetsSize = offsets.size(); 115 | if (offsetsSize > 0) { 116 | for (int i = 0; finalPtr != 0 && i < offsetsSize; i++) { 117 | if (i == (offsetsSize - 1)) { 118 | *reinterpret_cast(finalPtr + offsets[i]) = val; 119 | return true; 120 | } 121 | 122 | finalPtr = *reinterpret_cast(finalPtr + offsets[i]); 123 | } 124 | } 125 | 126 | if (finalPtr == 0) 127 | return false; 128 | 129 | *reinterpret_cast(finalPtr) = val; 130 | return true; 131 | } 132 | 133 | /* 134 | * Wrapper to dereference & get value of a pointer 135 | * Make sure to use the correct data type! 136 | */ 137 | template 138 | Type readPtr(void *ptr) { 139 | Type defaultVal = {}; 140 | if (ptr == NULL) 141 | return defaultVal; 142 | 143 | return *reinterpret_cast(ptr); 144 | } 145 | 146 | /* 147 | * Wrapper to dereference & set value of a pointer 148 | * Make sure to use the correct data type!, const objects won't work 149 | */ 150 | template 151 | bool writePtr(void *ptr, Type val) { 152 | if (ptr == NULL) 153 | return false; 154 | 155 | *reinterpret_cast(ptr) = val; 156 | return true; 157 | } 158 | 159 | /* 160 | * Gets info of a mapped library in self process 161 | */ 162 | ProcMap getLibraryMap(const char *libraryName); 163 | 164 | /* 165 | * Expects a relative address in a library 166 | * Returns final absolute address 167 | */ 168 | uintptr_t 169 | getAbsoluteAddress(const char *libraryName, uintptr_t relativeAddr, bool useCache = false); 170 | }; 171 | -------------------------------------------------------------------------------- /app/src/main/jni/UtilsDark.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void setDialog(jobject ctx, JNIEnv *env, const char *title, const char *msg){ 4 | jclass Alert = env->FindClass(OBFUSCATE("android/app/AlertDialog$Builder")); 5 | jmethodID AlertCons = env->GetMethodID(Alert, OBFUSCATE(""), OBFUSCATE("(Landroid/content/Context;)V")); 6 | 7 | jobject MainAlert = env->NewObject(Alert, AlertCons, ctx); 8 | 9 | jmethodID setTitle = env->GetMethodID(Alert, OBFUSCATE("setTitle"), OBFUSCATE("(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder;")); 10 | env->CallObjectMethod(MainAlert, setTitle, env->NewStringUTF(title)); 11 | 12 | jmethodID setMsg = env->GetMethodID(Alert, OBFUSCATE("setMessage"), OBFUSCATE("(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder;")); 13 | env->CallObjectMethod(MainAlert, setMsg, env->NewStringUTF(msg)); 14 | 15 | jmethodID setCa = env->GetMethodID(Alert, OBFUSCATE("setCancelable"), OBFUSCATE("(Z)Landroid/app/AlertDialog$Builder;")); 16 | env->CallObjectMethod(MainAlert, setCa, false); 17 | 18 | jmethodID setPB = env->GetMethodID(Alert, OBFUSCATE("setPositiveButton"), OBFUSCATE("(Ljava/lang/CharSequence;Landroid/content/DialogInterface$OnClickListener;)Landroid/app/AlertDialog$Builder;")); 19 | env->CallObjectMethod(MainAlert, setPB, env->NewStringUTF("Ok"), static_cast(NULL)); 20 | 21 | jmethodID create = env->GetMethodID(Alert, OBFUSCATE("create"), OBFUSCATE("()Landroid/app/AlertDialog;")); 22 | jobject creaetob = env->CallObjectMethod(MainAlert, create); 23 | 24 | jclass AlertN = env->FindClass(OBFUSCATE("android/app/AlertDialog")); 25 | 26 | jmethodID show = env->GetMethodID(AlertN, OBFUSCATE("show"), OBFUSCATE("()V")); 27 | env->CallVoidMethod(creaetob, show); 28 | } 29 | 30 | void Toast(JNIEnv *env, jobject thiz, const char *text, int length) { 31 | jstring jstr = env->NewStringUTF(text); 32 | jclass toast = env->FindClass(OBFUSCATE("android/widget/Toast")); 33 | jmethodID methodMakeText =env->GetStaticMethodID(toast,OBFUSCATE("makeText"),OBFUSCATE("(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;")); 34 | jobject toastobj = env->CallStaticObjectMethod(toast, methodMakeText,thiz, jstr, length); 35 | jmethodID methodShow = env->GetMethodID(toast, OBFUSCATE("show"), OBFUSCATE("()V")); 36 | env->CallVoidMethod(toastobj, methodShow); 37 | } 38 | 39 | void startActivityPermisson(JNIEnv *env, jobject ctx){ 40 | jclass native_context = env->GetObjectClass(ctx); 41 | jmethodID startActivity = env->GetMethodID(native_context, OBFUSCATE("startActivity"),OBFUSCATE("(Landroid/content/Intent;)V")); 42 | 43 | jmethodID pack = env->GetMethodID(native_context, OBFUSCATE("getPackageName"),OBFUSCATE("()Ljava/lang/String;")); 44 | jstring packetname = static_cast(env->CallObjectMethod(ctx, pack)); 45 | 46 | const char *pkg = env->GetStringUTFChars(packetname, 0); 47 | 48 | std::stringstream pkgg; 49 | pkgg << OBFUSCATE("package:"); 50 | pkgg << pkg; 51 | std::string pakg = pkgg.str(); 52 | 53 | jclass Uri = env->FindClass(OBFUSCATE("android/net/Uri")); 54 | jmethodID Parce = env->GetStaticMethodID(Uri, OBFUSCATE("parse"), OBFUSCATE("(Ljava/lang/String;)Landroid/net/Uri;")); 55 | jobject UriMethod = env->CallStaticObjectMethod(Uri, Parce, env->NewStringUTF(pakg.c_str())); 56 | 57 | jclass intentclass = env->FindClass(OBFUSCATE("android/content/Intent")); 58 | jmethodID newIntent = env->GetMethodID(intentclass, OBFUSCATE(""), OBFUSCATE("(Ljava/lang/String;Landroid/net/Uri;)V")); 59 | jobject intent = env->NewObject(intentclass,newIntent,env->NewStringUTF(OBFUSCATE("android.settings.action.MANAGE_OVERLAY_PERMISSION")), UriMethod); 60 | 61 | env->CallVoidMethod(ctx, startActivity, intent); 62 | } 63 | 64 | void startMod(JNIEnv *env, jobject ctx){ 65 | jclass native_context = env->GetObjectClass(ctx); 66 | jclass intentClass = env->FindClass(OBFUSCATE("android/content/Intent")); 67 | jclass actionString = env->FindClass(OBFUSCATE("dark/rx/Floater")); 68 | jmethodID newIntent = env->GetMethodID(intentClass, OBFUSCATE(""), OBFUSCATE("(Landroid/content/Context;Ljava/lang/Class;)V")); 69 | jobject intent = env->NewObject(intentClass,newIntent,ctx,actionString); 70 | jmethodID startActivityMethodId = env->GetMethodID(native_context, OBFUSCATE("startService"), OBFUSCATE("(Landroid/content/Intent;)Landroid/content/ComponentName;")); 71 | env->CallObjectMethod(ctx, startActivityMethodId, intent); 72 | } 73 | 74 | void CheckFloatingPermison(JNIEnv *env, jobject ctx){ 75 | jclass Settigs = env->FindClass(OBFUSCATE("android/provider/Settings")); 76 | jmethodID canDraw =env->GetStaticMethodID(Settigs,OBFUSCATE("canDrawOverlays"),OBFUSCATE("(Landroid/content/Context;)Z")); 77 | if (!env->CallStaticBooleanMethod(Settigs, canDraw, ctx)){ 78 | Toast(env,ctx,OBFUSCATE("Overlay permission is required in order to show mod menu. Restart the game after you allow permission"),1); 79 | Toast(env,ctx,OBFUSCATE("Overlay permission is required in order to show mod menu. Restart the game after you allow permission"),1); 80 | startActivityPermisson(env, ctx); 81 | return; 82 | } 83 | 84 | //StartMod Normal 85 | startMod(env, ctx); 86 | //Dialog Example 87 | setDialog(ctx,env,OBFUSCATE("Title"),OBFUSCATE("Message Example")); 88 | //Toast Example 89 | Toast(env,ctx,OBFUSCATE("By MrDarkkRX"),1); 90 | } 91 | 92 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /app/src/main/jni/Includes/obfuscate.h: -------------------------------------------------------------------------------- 1 | /* --------------------------------- ABOUT ------------------------------------- 2 | 3 | Original Author: Adam Yaxley 4 | Website: https://github.com/adamyaxley 5 | License: See end of file 6 | 7 | Obfuscate 8 | Guaranteed compile-time string literal obfuscation library for C++14 9 | 10 | Usage: 11 | Pass string literals into the AY_OBFUSCATE macro to obfuscate them at compile 12 | time. AY_OBFUSCATE returns a reference to an ay::OBFUSCATE_data object with the 13 | following traits: 14 | - Guaranteed obfuscation of string 15 | The passed string is encrypted with a simple XOR cipher at compile-time to 16 | prevent it being viewable in the binary image 17 | - Global lifetime 18 | The actual instantiation of the ay::OBFUSCATE_data takes place inside a 19 | lambda as a function level static 20 | - Implicitly convertable to a char* 21 | This means that you can pass it directly into functions that would normally 22 | take a char* or a const char* 23 | 24 | Example: 25 | const char* OBFUSCATE_string = AY_OBFUSCATE("Hello World"); 26 | std::cout << OBFUSCATE_string << std::endl; 27 | 28 | ----------------------------------------------------------------------------- */ 29 | 30 | #include 31 | #include 32 | namespace ay 33 | { 34 | // Obfuscates a string at compile time 35 | template 36 | class obfuscator 37 | { 38 | public: 39 | // Obfuscates the string 'data' on construction 40 | constexpr obfuscator(const char* data) 41 | { 42 | static_assert(KEY != '\0', "KEY must not be the null character."); 43 | 44 | // On construction each of the characters in the string is 45 | // OBFUSCATE with an XOR cipher based on KEY 46 | for (std::size_t i = 0; i < N; i++) 47 | { 48 | m_data[i] = data[i] ^ KEY; 49 | } 50 | } 51 | 52 | constexpr const char* getData() const 53 | { 54 | return &m_data[0]; 55 | } 56 | 57 | constexpr std::size_t getSize() const 58 | { 59 | return N; 60 | } 61 | 62 | constexpr char getKey() const 63 | { 64 | return KEY; 65 | } 66 | 67 | private: 68 | 69 | char m_data[N]{}; 70 | }; 71 | 72 | // Handles decryption and re-encryption of an encrypted string at runtime 73 | template 74 | class OBFUSCATE_data 75 | { 76 | public: 77 | OBFUSCATE_data(const obfuscator& obfuscator) 78 | { 79 | for (std::size_t i = 0; i < N; i++) 80 | { 81 | m_data[i] = obfuscator.getData()[i]; 82 | } 83 | } 84 | 85 | ~OBFUSCATE_data() 86 | { 87 | // Zero m_data to remove it from memory 88 | for (std::size_t i = 0; i < N; i++) 89 | { 90 | m_data[i] = 0; 91 | } 92 | } 93 | 94 | // Returns a pointer to the plain text string, decrypting it if 95 | // necessary 96 | operator char*() 97 | { 98 | decrypt(); 99 | return m_data; 100 | } 101 | operator std::string() 102 | { 103 | decrypt(); 104 | return m_data; 105 | } 106 | // Manually decrypt the string 107 | void decrypt() 108 | { 109 | if (is_encrypted()) 110 | { 111 | for (std::size_t i = 0; i < N; i++) 112 | { 113 | m_data[i] ^= KEY; 114 | } 115 | } 116 | } 117 | 118 | // Manually re-encrypt the string 119 | void encrypt() 120 | { 121 | if (!is_encrypted()) 122 | { 123 | for (std::size_t i = 0; i < N; i++) 124 | { 125 | m_data[i] ^= KEY; 126 | } 127 | } 128 | } 129 | 130 | // Returns true if this string is currently encrypted, false otherwise. 131 | bool is_encrypted() const 132 | { 133 | return m_data[N - 1] != '\0'; 134 | } 135 | 136 | private: 137 | 138 | // Local storage for the string. Call is_encrypted() to check whether or 139 | // not the string is currently OBFUSCATE. 140 | char m_data[N]; 141 | }; 142 | 143 | // This function exists purely to extract the number of elements 'N' in the 144 | // array 'data' 145 | template 146 | constexpr auto make_obfuscator(const char(&data)[N]) 147 | { 148 | return obfuscator(data); 149 | } 150 | } 151 | 152 | // Obfuscates the string 'data' at compile-time and returns a reference to a 153 | // ay::OBFUSCATE_data object with global lifetime that has functions for 154 | // decrypting the string and is also implicitly convertable to a char* 155 | #define OBFUSCATE(data) OBFUSCATE_KEY(data, '.') 156 | 157 | // Obfuscates the string 'data' with 'key' at compile-time and returns a 158 | // reference to a ay::OBFUSCATE_data object with global lifetime that has 159 | // functions for decrypting the string and is also implicitly convertable to a 160 | // char* 161 | #define OBFUSCATE_KEY(data, key) \ 162 | []() -> ay::OBFUSCATE_data& { \ 163 | constexpr auto n = sizeof(data)/sizeof(data[0]); \ 164 | static_assert(data[n - 1] == '\0', "String must be null terminated"); \ 165 | constexpr auto obfuscator = ay::make_obfuscator(data); \ 166 | static auto OBFUSCATE_data = ay::OBFUSCATE_data(obfuscator); \ 167 | return OBFUSCATE_data; \ 168 | }() 169 | 170 | /* -------------------------------- LICENSE ------------------------------------ 171 | 172 | Public Domain (http://www.unlicense.org) 173 | 174 | This is free and unencumbered software released into the public domain. 175 | 176 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 177 | software, either in source code form or as a compiled binary, for any purpose, 178 | commercial or non-commercial, and by any means. 179 | 180 | In jurisdictions that recognize copyright laws, the author or authors of this 181 | software dedicate any and all copyright interest in the software to the public 182 | domain. We make this dedication for the benefit of the public at large and to 183 | the detriment of our heirs and successors. We intend this dedication to be an 184 | overt act of relinquishment in perpetuity of all present and future rights to 185 | this software under copyright law. 186 | 187 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 188 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 189 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE 190 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 191 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 192 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 193 | 194 | ----------------------------------------------------------------------------- */ 195 | -------------------------------------------------------------------------------- /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/jni/Substrate/SubstrateX86.hpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #ifndef SUBSTRATE_X86_HPP 23 | #define SUBSTRATE_X86_HPP 24 | 25 | #include "Buffer.hpp" 26 | 27 | #ifdef __LP64__ 28 | static const bool ia32 = false; 29 | #else 30 | static const bool ia32 = true; 31 | #endif 32 | 33 | enum I$r { 34 | I$rax, I$rcx, I$rdx, I$rbx, 35 | I$rsp, I$rbp, I$rsi, I$rdi, 36 | I$r8, I$r9, I$r10, I$r11, 37 | I$r12, I$r13, I$r14, I$r15, 38 | }; 39 | 40 | _disused static bool MSIs32BitOffset(uintptr_t target, uintptr_t source) { 41 | intptr_t offset(target - source); 42 | return int32_t(offset) == offset; 43 | } 44 | 45 | _disused static size_t MSSizeOfSkip() { 46 | return 5; 47 | } 48 | 49 | _disused static size_t MSSizeOfPushPointer(uintptr_t target) { 50 | return uint64_t(target) >> 32 == 0 ? 5 : 13; 51 | } 52 | 53 | _disused static size_t MSSizeOfPushPointer(void *target) { 54 | return MSSizeOfPushPointer(reinterpret_cast(target)); 55 | } 56 | 57 | _disused static size_t MSSizeOfJump(bool blind, uintptr_t target, uintptr_t source = 0) { 58 | if (ia32 || !blind && MSIs32BitOffset(target, source + 5)) 59 | return MSSizeOfSkip(); 60 | else 61 | return MSSizeOfPushPointer(target) + 1; 62 | } 63 | 64 | _disused static size_t MSSizeOfJump(uintptr_t target, uintptr_t source) { 65 | return MSSizeOfJump(false, target, source); 66 | } 67 | 68 | _disused static size_t MSSizeOfJump(uintptr_t target) { 69 | return MSSizeOfJump(true, target); 70 | } 71 | 72 | _disused static size_t MSSizeOfJump(void *target, void *source) { 73 | return MSSizeOfJump(reinterpret_cast(target), reinterpret_cast(source)); 74 | } 75 | 76 | _disused static size_t MSSizeOfJump(void *target) { 77 | return MSSizeOfJump(reinterpret_cast(target)); 78 | } 79 | 80 | _disused static void MSWriteSkip(uint8_t *¤t, ssize_t size) { 81 | MSWrite(current, 0xe9); 82 | MSWrite(current, size); 83 | } 84 | 85 | _disused static void MSPushPointer(uint8_t *¤t, uintptr_t target) { 86 | MSWrite(current, 0x68); 87 | MSWrite(current, target); 88 | 89 | if (uint32_t high = uint64_t(target) >> 32) { 90 | MSWrite(current, 0xc7); 91 | MSWrite(current, 0x44); 92 | MSWrite(current, 0x24); 93 | MSWrite(current, 0x04); 94 | MSWrite(current, high); 95 | } 96 | } 97 | 98 | _disused static void MSPushPointer(uint8_t *¤t, void *target) { 99 | return MSPushPointer(current, reinterpret_cast(target)); 100 | } 101 | 102 | _disused static void MSWriteCall(uint8_t *¤t, I$r target) { 103 | if (target >> 3 != 0) 104 | MSWrite(current, 0x40 | (target & 0x08) >> 3); 105 | MSWrite(current, 0xff); 106 | MSWrite(current, 0xd0 | target & 0x07); 107 | } 108 | 109 | _disused static void MSWriteCall(uint8_t *¤t, uintptr_t target) { 110 | uintptr_t source(reinterpret_cast(current)); 111 | 112 | if (ia32 || MSIs32BitOffset(target, source + 5)) { 113 | MSWrite(current, 0xe8); 114 | MSWrite(current, target - (source + 5)); 115 | } else { 116 | MSPushPointer(current, target); 117 | 118 | MSWrite(current, 0x83); 119 | MSWrite(current, 0xc4); 120 | MSWrite(current, 0x08); 121 | 122 | MSWrite(current, 0x67); 123 | MSWrite(current, 0xff); 124 | MSWrite(current, 0x54); 125 | MSWrite(current, 0x24); 126 | MSWrite(current, 0xf8); 127 | } 128 | } 129 | 130 | template 131 | _disused static void MSWriteCall(uint8_t *¤t, Type_ *target) { 132 | return MSWriteCall(current, reinterpret_cast(target)); 133 | } 134 | 135 | _disused static void MSWriteJump(uint8_t *¤t, uintptr_t target) { 136 | uintptr_t source(reinterpret_cast(current)); 137 | 138 | if (ia32 || MSIs32BitOffset(target, source + 5)) 139 | MSWriteSkip(current, target - (source + 5)); 140 | else { 141 | MSPushPointer(current, target); 142 | MSWrite(current, 0xc3); 143 | } 144 | } 145 | 146 | _disused static void MSWriteJump(uint8_t *¤t, void *target) { 147 | return MSWriteJump(current, reinterpret_cast(target)); 148 | } 149 | 150 | _disused static void MSWriteJump(uint8_t *¤t, I$r target) { 151 | if (target >> 3 != 0) 152 | MSWrite(current, 0x40 | (target & 0x08) >> 3); 153 | MSWrite(current, 0xff); 154 | MSWrite(current, 0xe0 | target & 0x07); 155 | } 156 | 157 | _disused static void MSWritePop(uint8_t *¤t, uint8_t target) { 158 | if (target >> 3 != 0) 159 | MSWrite(current, 0x40 | (target & 0x08) >> 3); 160 | MSWrite(current, 0x58 | target & 0x07); 161 | } 162 | 163 | _disused static size_t MSSizeOfPop(uint8_t target) { 164 | return target >> 3 != 0 ? 2 : 1; 165 | } 166 | 167 | _disused static void MSWritePush(uint8_t *¤t, I$r target) { 168 | if (target >> 3 != 0) 169 | MSWrite(current, 0x40 | (target & 0x08) >> 3); 170 | MSWrite(current, 0x50 | target & 0x07); 171 | } 172 | 173 | _disused static void MSWriteAdd(uint8_t *¤t, I$r target, uint8_t source) { 174 | MSWrite(current, 0x83); 175 | MSWrite(current, 0xc4 | target & 0x07); 176 | MSWrite(current, source); 177 | } 178 | 179 | _disused static void MSWriteSet64(uint8_t *¤t, I$r target, uintptr_t source) { 180 | MSWrite(current, 0x48 | (target & 0x08) >> 3 << 2); 181 | MSWrite(current, 0xb8 | target & 0x7); 182 | MSWrite(current, source); 183 | } 184 | 185 | template 186 | _disused static void MSWriteSet64(uint8_t *¤t, I$r target, Type_ *source) { 187 | return MSWriteSet64(current, target, reinterpret_cast(source)); 188 | } 189 | 190 | _disused static void MSWriteMove64(uint8_t *¤t, uint8_t source, uint8_t target) { 191 | MSWrite(current, 0x48 | (target & 0x08) >> 3 << 2 | (source & 0x08) >> 3); 192 | MSWrite(current, 0x8b); 193 | MSWrite(current, (target & 0x07) << 3 | source & 0x07); 194 | } 195 | 196 | _disused static size_t MSSizeOfMove64() { 197 | return 3; 198 | } 199 | 200 | #endif//SUBSTRATE_X86_HPP 201 | -------------------------------------------------------------------------------- /app/src/main/jni/Substrate/hde64.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 C 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | #include "hde64.h" 12 | #include "table64.h" 13 | 14 | unsigned int hde64_disasm(const void *code, hde64s *hs) 15 | { 16 | uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0; 17 | uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0; 18 | uint8_t op64 = 0; 19 | 20 | memset(hs,0,sizeof(hde64s)); 21 | char *tmp=(char*)hs; 22 | 23 | for (x = 16; x; x--) 24 | switch (c = *p++) { 25 | case 0xf3: 26 | hs->p_rep = c; 27 | pref |= PRE_F3; 28 | break; 29 | case 0xf2: 30 | hs->p_rep = c; 31 | pref |= PRE_F2; 32 | break; 33 | case 0xf0: 34 | hs->p_lock = c; 35 | pref |= PRE_LOCK; 36 | break; 37 | case 0x26: case 0x2e: case 0x36: 38 | case 0x3e: case 0x64: case 0x65: 39 | hs->p_seg = c; 40 | pref |= PRE_SEG; 41 | break; 42 | case 0x66: 43 | hs->p_66 = c; 44 | pref |= PRE_66; 45 | break; 46 | case 0x67: 47 | hs->p_67 = c; 48 | pref |= PRE_67; 49 | break; 50 | default: 51 | goto pref_done; 52 | } 53 | pref_done: 54 | 55 | hs->flags = (uint32_t)pref << 23; 56 | 57 | if (!pref) 58 | pref |= PRE_NONE; 59 | 60 | if ((c & 0xf0) == 0x40) { 61 | hs->flags |= F_PREFIX_REX; 62 | if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8) 63 | op64++; 64 | hs->rex_r = (c & 7) >> 2; 65 | hs->rex_x = (c & 3) >> 1; 66 | hs->rex_b = c & 1; 67 | if (((c = *p++) & 0xf0) == 0x40) { 68 | opcode = c; 69 | goto error_opcode; 70 | } 71 | } 72 | 73 | if ((hs->opcode = c) == 0x0f) { 74 | hs->opcode2 = c = *p++; 75 | ht += DELTA_OPCODES; 76 | } else if (c >= 0xa0 && c <= 0xa3) { 77 | op64++; 78 | if (pref & PRE_67) 79 | pref |= PRE_66; 80 | else 81 | pref &= ~PRE_66; 82 | } 83 | 84 | opcode = c; 85 | cflags = ht[ht[opcode / 4] + (opcode % 4)]; 86 | 87 | if (cflags == C_ERROR) { 88 | error_opcode: 89 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 90 | cflags = 0; 91 | if ((opcode & -3) == 0x24) 92 | cflags++; 93 | } 94 | 95 | x = 0; 96 | if (cflags & C_GROUP) { 97 | uint16_t t; 98 | t = *(uint16_t *)(ht + (cflags & 0x7f)); 99 | cflags = (uint8_t)t; 100 | x = (uint8_t)(t >> 8); 101 | } 102 | 103 | if (hs->opcode2) { 104 | ht = hde64_table + DELTA_PREFIXES; 105 | if (ht[ht[opcode / 4] + (opcode % 4)] & pref) 106 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 107 | } 108 | 109 | if (cflags & C_MODRM) { 110 | hs->flags |= F_MODRM; 111 | hs->modrm = c = *p++; 112 | hs->modrm_mod = m_mod = c >> 6; 113 | hs->modrm_rm = m_rm = c & 7; 114 | hs->modrm_reg = m_reg = (c & 0x3f) >> 3; 115 | 116 | if (x && ((x << m_reg) & 0x80)) 117 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 118 | 119 | if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { 120 | uint8_t t = opcode - 0xd9; 121 | if (m_mod == 3) { 122 | ht = hde64_table + DELTA_FPU_MODRM + t*8; 123 | t = ht[m_reg] << m_rm; 124 | } else { 125 | ht = hde64_table + DELTA_FPU_REG; 126 | t = ht[t] << m_reg; 127 | } 128 | if (t & 0x80) 129 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 130 | } 131 | 132 | if (pref & PRE_LOCK) { 133 | if (m_mod == 3) { 134 | hs->flags |= F_ERROR | F_ERROR_LOCK; 135 | } else { 136 | uint8_t *table_end, op = opcode; 137 | if (hs->opcode2) { 138 | ht = hde64_table + DELTA_OP2_LOCK_OK; 139 | table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; 140 | } else { 141 | ht = hde64_table + DELTA_OP_LOCK_OK; 142 | table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; 143 | op &= -2; 144 | } 145 | for (; ht != table_end; ht++) 146 | if (*ht++ == op) { 147 | if (!((*ht << m_reg) & 0x80)) 148 | goto no_lock_error; 149 | else 150 | break; 151 | } 152 | hs->flags |= F_ERROR | F_ERROR_LOCK; 153 | no_lock_error: 154 | ; 155 | } 156 | } 157 | 158 | if (hs->opcode2) { 159 | switch (opcode) { 160 | case 0x20: case 0x22: 161 | m_mod = 3; 162 | if (m_reg > 4 || m_reg == 1) 163 | goto error_operand; 164 | else 165 | goto no_error_operand; 166 | case 0x21: case 0x23: 167 | m_mod = 3; 168 | if (m_reg == 4 || m_reg == 5) 169 | goto error_operand; 170 | else 171 | goto no_error_operand; 172 | } 173 | } else { 174 | switch (opcode) { 175 | case 0x8c: 176 | if (m_reg > 5) 177 | goto error_operand; 178 | else 179 | goto no_error_operand; 180 | case 0x8e: 181 | if (m_reg == 1 || m_reg > 5) 182 | goto error_operand; 183 | else 184 | goto no_error_operand; 185 | } 186 | } 187 | 188 | if (m_mod == 3) { 189 | uint8_t *table_end; 190 | if (hs->opcode2) { 191 | ht = hde64_table + DELTA_OP2_ONLY_MEM; 192 | table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM; 193 | } else { 194 | ht = hde64_table + DELTA_OP_ONLY_MEM; 195 | table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; 196 | } 197 | for (; ht != table_end; ht += 2) 198 | if (*ht++ == opcode) { 199 | if (*ht++ & pref && !((*ht << m_reg) & 0x80)) 200 | goto error_operand; 201 | else 202 | break; 203 | } 204 | goto no_error_operand; 205 | } else if (hs->opcode2) { 206 | switch (opcode) { 207 | case 0x50: case 0xd7: case 0xf7: 208 | if (pref & (PRE_NONE | PRE_66)) 209 | goto error_operand; 210 | break; 211 | case 0xd6: 212 | if (pref & (PRE_F2 | PRE_F3)) 213 | goto error_operand; 214 | break; 215 | case 0xc5: 216 | goto error_operand; 217 | } 218 | goto no_error_operand; 219 | } else 220 | goto no_error_operand; 221 | 222 | error_operand: 223 | hs->flags |= F_ERROR | F_ERROR_OPERAND; 224 | no_error_operand: 225 | 226 | c = *p++; 227 | if (m_reg <= 1) { 228 | if (opcode == 0xf6) 229 | cflags |= C_IMM8; 230 | else if (opcode == 0xf7) 231 | cflags |= C_IMM_P66; 232 | } 233 | 234 | switch (m_mod) { 235 | case 0: 236 | if (pref & PRE_67) { 237 | if (m_rm == 6) 238 | disp_size = 2; 239 | } else 240 | if (m_rm == 5) 241 | disp_size = 4; 242 | break; 243 | case 1: 244 | disp_size = 1; 245 | break; 246 | case 2: 247 | disp_size = 2; 248 | if (!(pref & PRE_67)) 249 | disp_size <<= 1; 250 | } 251 | 252 | if (m_mod != 3 && m_rm == 4) { 253 | hs->flags |= F_SIB; 254 | p++; 255 | hs->sib = c; 256 | hs->sib_scale = c >> 6; 257 | hs->sib_index = (c & 0x3f) >> 3; 258 | if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) 259 | disp_size = 4; 260 | } 261 | 262 | p--; 263 | switch (disp_size) { 264 | case 1: 265 | hs->flags |= F_DISP8; 266 | hs->disp.disp8 = *p; 267 | break; 268 | case 2: 269 | hs->flags |= F_DISP16; 270 | hs->disp.disp16 = *(uint16_t *)p; 271 | break; 272 | case 4: 273 | hs->flags |= F_DISP32; 274 | hs->disp.disp32 = *(uint32_t *)p; 275 | } 276 | p += disp_size; 277 | } else if (pref & PRE_LOCK) 278 | hs->flags |= F_ERROR | F_ERROR_LOCK; 279 | 280 | if (cflags & C_IMM_P66) { 281 | if (cflags & C_REL32) { 282 | if (pref & PRE_66) { 283 | hs->flags |= F_IMM16 | F_RELATIVE; 284 | hs->imm.imm16 = *(uint16_t *)p; 285 | p += 2; 286 | goto disasm_done; 287 | } 288 | goto rel32_ok; 289 | } 290 | if (op64) { 291 | hs->flags |= F_IMM64; 292 | hs->imm.imm64 = *(uint64_t *)p; 293 | p += 8; 294 | } else if (!(pref & PRE_66)) { 295 | hs->flags |= F_IMM32; 296 | hs->imm.imm32 = *(uint32_t *)p; 297 | p += 4; 298 | } else 299 | goto imm16_ok; 300 | } 301 | 302 | 303 | if (cflags & C_IMM16) { 304 | imm16_ok: 305 | hs->flags |= F_IMM16; 306 | hs->imm.imm16 = *(uint16_t *)p; 307 | p += 2; 308 | } 309 | if (cflags & C_IMM8) { 310 | hs->flags |= F_IMM8; 311 | hs->imm.imm8 = *p++; 312 | } 313 | 314 | if (cflags & C_REL32) { 315 | rel32_ok: 316 | hs->flags |= F_IMM32 | F_RELATIVE; 317 | hs->imm.imm32 = *(uint32_t *)p; 318 | p += 4; 319 | } else if (cflags & C_REL8) { 320 | hs->flags |= F_IMM8 | F_RELATIVE; 321 | hs->imm.imm8 = *p++; 322 | } 323 | 324 | disasm_done: 325 | 326 | if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { 327 | hs->flags |= F_ERROR | F_ERROR_LENGTH; 328 | hs->len = 15; 329 | } 330 | 331 | return (unsigned int)hs->len; 332 | } 333 | -------------------------------------------------------------------------------- /app/src/main/jni/Main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "Includes/obfuscate.h" 11 | #include "KittyMemory/MemoryPatch.h" 12 | #include "Includes/Logger.h" 13 | #include "Includes/Utils.h" 14 | #include "UtilsDark.h" 15 | #include "MethodsDark.h" 16 | 17 | #if defined(__aarch64__) 18 | #include 19 | #else 20 | #include 21 | #include 22 | #endif 23 | 24 | __attribute__((constructor)) 25 | void lib_main() { 26 | 27 | } 28 | 29 | struct My_Patches { 30 | MemoryPatch Example; 31 | } Options; 32 | 33 | 34 | void *Load_Mod(void *) { 35 | do { 36 | sleep(1); 37 | } while (!isLibraryLoaded(OBFUSCATE("libName.so"))); 38 | 39 | Options.Example = MemoryPatch(OBFUSCATE("libName.so"), 0x00000, 40 | "\x00\x00\x00\x00\x00\x00\x00\x00", 8); 41 | return NULL; 42 | } 43 | 44 | extern "C" 45 | JNIEXPORT void JNICALL 46 | Java_dark_rx_LoaderMod_setDarkStart(JNIEnv *env, jobject thiz, jobject ctx) { 47 | CheckFloatingPermison(env, ctx); 48 | } 49 | 50 | extern "C" 51 | JNIEXPORT jstring JNICALL 52 | Java_dark_rx_Floater_Icon(JNIEnv *env, jobject thiz) { 53 | return env->NewStringUTF(OBFUSCATE("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" )); 54 | } 55 | 56 | bool ex = false; 57 | bool ex2 = false; 58 | 59 | extern "C" 60 | JNIEXPORT void JNICALL 61 | Java_dark_rx_Floater_Changes(JNIEnv *env, jobject thiz, jint feature, jint value, jobject ctx) { 62 | //Toast Example 63 | // setDialog(ctx,env,"Title","Message Example"); 64 | //Toast Example 65 | // Toast(env,ctx,"By MrDarkkRX",1); 66 | switch (feature) { 67 | case 0: 68 | ex = !ex; 69 | if (ex){ 70 | Toast(env,ctx,OBFUSCATE("ON"),1); 71 | } else { 72 | Toast(env,ctx,OBFUSCATE("OFF"),1); 73 | } 74 | break; 75 | case 1: 76 | ex2 = !ex2; 77 | if (ex2){ 78 | Options.Example.Modify(); 79 | } else { 80 | Options.Example.Restore(); 81 | } 82 | break; 83 | case 2: 84 | if (value == 0){ 85 | Toast(env,ctx,OBFUSCATE("Value: 0"),1); 86 | } 87 | break; 88 | } 89 | } 90 | 91 | extern "C" 92 | JNIEXPORT void JNICALL 93 | Java_dark_rx_Floater_StartOptionsDark(JNIEnv *env, jobject thiz, jobject ctx, jobject title, jobject subtitle) { 94 | //Set Title 95 | setText(env, title, OBFUSCATE("DarkMod")); 96 | //Set SubTitle 97 | setText(env, subtitle, OBFUSCATE("ByMrDarkRX")); 98 | 99 | //Category 100 | AddCategory(env, ctx, OBFUSCATE("Menu Example")); 101 | //Botton ON OFF 102 | AddButton(env, ctx, OBFUSCATE("Example 1"), 0); 103 | //Swicht 104 | AddSwich(env, ctx, OBFUSCATE("Example 2"), 1); 105 | //SkeedBar 106 | AddSkeedBar(env, ctx, OBFUSCATE("Example 3"),0,100, 2); 107 | 108 | pthread_t ptid; 109 | pthread_create(&ptid, NULL, Load_Mod, NULL); 110 | } -------------------------------------------------------------------------------- /app/src/main/jni/Substrate/SymbolFinder.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "SymbolFinder.h" 11 | 12 | #define TAG "MSHook" 13 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) 14 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) 15 | /* memory map for libraries */ 16 | #define MAX_NAME_LEN 256 17 | #define MEMORY_ONLY "[memory]" 18 | struct mm { 19 | char name[MAX_NAME_LEN]; 20 | unsigned long start, end; 21 | }; 22 | 23 | typedef struct symtab *symtab_t; 24 | struct symlist { 25 | Elf32_Sym *sym; /* symbols */ 26 | char *str; /* symbol strings */ 27 | unsigned num; /* number of symbols */ 28 | }; 29 | struct symtab { 30 | struct symlist *st; /* "static" symbols */ 31 | struct symlist *dyn; /* dynamic symbols */ 32 | }; 33 | 34 | static void *xmalloc(size_t size) { 35 | void *p; 36 | p = malloc(size); 37 | if (!p) { 38 | printf(OBFUSCATE("Out of memory\n")); 39 | exit(1); 40 | } 41 | return p; 42 | } 43 | 44 | static int my_pread(int fd, void *buf, size_t count, off_t offset) { 45 | lseek(fd, offset, SEEK_SET); 46 | return read(fd, buf, count); 47 | } 48 | 49 | static struct symlist *get_syms(int fd, Elf32_Shdr *symh, Elf32_Shdr *strh) { 50 | struct symlist *sl, *ret; 51 | int rv; 52 | 53 | ret = NULL; 54 | sl = (struct symlist *) xmalloc(sizeof(struct symlist)); 55 | sl->str = NULL; 56 | sl->sym = NULL; 57 | 58 | /* sanity */ 59 | if (symh->sh_size % sizeof(Elf32_Sym)) { 60 | //printf("elf_error\n"); 61 | goto out; 62 | } 63 | 64 | /* symbol table */ 65 | sl->num = symh->sh_size / sizeof(Elf32_Sym); 66 | sl->sym = (Elf32_Sym *) xmalloc(symh->sh_size); 67 | rv = my_pread(fd, sl->sym, symh->sh_size, symh->sh_offset); 68 | if (0 > rv) { 69 | //perror("read"); 70 | goto out; 71 | } 72 | if (rv != symh->sh_size) { 73 | //printf("elf error\n"); 74 | goto out; 75 | } 76 | 77 | /* string table */ 78 | sl->str = (char *) xmalloc(strh->sh_size); 79 | rv = my_pread(fd, sl->str, strh->sh_size, strh->sh_offset); 80 | if (0 > rv) { 81 | //perror("read"); 82 | goto out; 83 | } 84 | if (rv != strh->sh_size) { 85 | //printf("elf error"); 86 | goto out; 87 | } 88 | 89 | ret = sl; 90 | out: 91 | return ret; 92 | } 93 | 94 | static int do_load(int fd, symtab_t symtab) { 95 | int rv; 96 | size_t size; 97 | Elf32_Ehdr ehdr; 98 | Elf32_Shdr *shdr = NULL, *p; 99 | Elf32_Shdr *dynsymh, *dynstrh; 100 | Elf32_Shdr *symh, *strh; 101 | char *shstrtab = NULL; 102 | int i; 103 | int ret = -1; 104 | 105 | /* elf header */ 106 | rv = read(fd, &ehdr, sizeof(ehdr)); 107 | if (0 > rv) { 108 | LOGD(OBFUSCATE("read\n")); 109 | goto out; 110 | } 111 | if (rv != sizeof(ehdr)) { 112 | LOGD(OBFUSCATE("elf error 1\n")); 113 | goto out; 114 | } 115 | if (strncmp((const char *) ELFMAG, (const char *) ehdr.e_ident, SELFMAG)) { /* sanity */ 116 | LOGD(OBFUSCATE("not an elf\n")); 117 | goto out; 118 | } 119 | if (sizeof(Elf32_Shdr) != ehdr.e_shentsize) { /* sanity */ 120 | LOGD(OBFUSCATE("elf error 2\n")); 121 | goto out; 122 | } 123 | 124 | /* section header table */ 125 | size = ehdr.e_shentsize * ehdr.e_shnum; 126 | shdr = (Elf32_Shdr *) xmalloc(size); 127 | rv = my_pread(fd, shdr, size, ehdr.e_shoff); 128 | if (0 > rv) { 129 | LOGD(OBFUSCATE("read\n")); 130 | goto out; 131 | } 132 | if (rv != size) { 133 | LOGD(OBFUSCATE("elf error 3 %d %d\n"), rv, size); 134 | goto out; 135 | } 136 | 137 | /* section header string table */ 138 | size = shdr[ehdr.e_shstrndx].sh_size; 139 | shstrtab = (char *) xmalloc(size); 140 | rv = my_pread(fd, shstrtab, size, shdr[ehdr.e_shstrndx].sh_offset); 141 | if (0 > rv) { 142 | LOGD(OBFUSCATE("read\n")); 143 | goto out; 144 | } 145 | if (rv != size) { 146 | LOGD(OBFUSCATE("elf error 4 %d %d\n"), rv, size); 147 | goto out; 148 | } 149 | 150 | /* symbol table headers */ 151 | symh = dynsymh = NULL; 152 | strh = dynstrh = NULL; 153 | for (i = 0, p = shdr; i < ehdr.e_shnum; i++, p++) 154 | if (SHT_SYMTAB == p->sh_type) { 155 | if (symh) { 156 | LOGD(OBFUSCATE("too many symbol tables\n")); 157 | goto out; 158 | } 159 | symh = p; 160 | } else if (SHT_DYNSYM == p->sh_type) { 161 | if (dynsymh) { 162 | LOGD(OBFUSCATE("too many symbol tables\n")); 163 | goto out; 164 | } 165 | dynsymh = p; 166 | } else if (SHT_STRTAB == p->sh_type 167 | && !strncmp(shstrtab + p->sh_name, OBFUSCATE(".strtab"), 7)) { 168 | if (strh) { 169 | LOGD(OBFUSCATE("too many string tables\n")); 170 | goto out; 171 | } 172 | strh = p; 173 | } else if (SHT_STRTAB == p->sh_type 174 | && !strncmp(shstrtab + p->sh_name, OBFUSCATE(".dynstr"), 7)) { 175 | if (dynstrh) { 176 | LOGD(OBFUSCATE("too many string tables\n")); 177 | goto out; 178 | } 179 | dynstrh = p; 180 | } 181 | /* sanity checks */ 182 | if ((!dynsymh && dynstrh) || (dynsymh && !dynstrh)) { 183 | LOGD(OBFUSCATE("bad dynamic symbol table\n")); 184 | goto out; 185 | } 186 | if ((!symh && strh) || (symh && !strh)) { 187 | LOGD(OBFUSCATE("bad symbol table\n")); 188 | goto out; 189 | } 190 | if (!dynsymh && !symh) { 191 | LOGD(OBFUSCATE("no symbol table\n")); 192 | goto out; 193 | } 194 | 195 | /* symbol tables */ 196 | if (dynsymh) 197 | symtab->dyn = get_syms(fd, dynsymh, dynstrh); 198 | if (symh) 199 | symtab->st = get_syms(fd, symh, strh); 200 | ret = 0; 201 | out: 202 | free(shstrtab); 203 | free(shdr); 204 | return ret; 205 | } 206 | 207 | static symtab_t load_symtab(char *filename) { 208 | int fd; 209 | symtab_t symtab; 210 | 211 | symtab = (symtab_t) xmalloc(sizeof(*symtab)); 212 | memset(symtab, 0, sizeof(*symtab)); 213 | 214 | fd = open(filename, O_RDONLY); 215 | if (0 > fd) { 216 | LOGE(OBFUSCATE("%s open\n"), __func__); 217 | return NULL; 218 | } 219 | if (0 > do_load(fd, symtab)) { 220 | LOGE(OBFUSCATE("Error ELF parsing %s\n"), filename); 221 | free(symtab); 222 | symtab = NULL; 223 | } 224 | close(fd); 225 | return symtab; 226 | } 227 | 228 | static int load_memmap(pid_t pid, struct mm *mm, int *nmmp) { 229 | size_t buf_size = 0x40000; 230 | char *p_buf = (char *) malloc(buf_size); // increase this if needed for larger "maps" 231 | char name[MAX_NAME_LEN] = {0}; 232 | char *p; 233 | unsigned long start, end; 234 | struct mm *m; 235 | int nmm = 0; 236 | int fd, rv; 237 | int i; 238 | 239 | sprintf(p_buf, OBFUSCATE("/proc/%d/maps"), pid); 240 | fd = open(p_buf, O_RDONLY); 241 | if (0 > fd) { 242 | LOGE(OBFUSCATE("Can't open %s for reading\n"), p_buf); 243 | free(p_buf); 244 | return -1; 245 | } 246 | 247 | /* Zero to ensure data is null terminated */ 248 | memset(p_buf, 0, buf_size); 249 | 250 | p = p_buf; 251 | while (1) { 252 | rv = read(fd, p, buf_size - (p - p_buf)); 253 | if (0 > rv) { 254 | LOGE(OBFUSCATE("%s read"), __FUNCTION__); 255 | free(p_buf); 256 | return -1; 257 | } 258 | if (0 == rv) 259 | break; 260 | p += rv; 261 | if (p - p_buf >= buf_size) { 262 | LOGE(OBFUSCATE("Too many memory mapping\n")); 263 | free(p_buf); 264 | return -1; 265 | } 266 | } 267 | close(fd); 268 | 269 | p = strtok(p_buf, "\n"); 270 | m = mm; 271 | while (p) { 272 | /* parse current map line */ 273 | rv = sscanf(p, OBFUSCATE("%08lx-%08lx %*s %*s %*s %*s %s\n"), &start, &end, name); 274 | 275 | p = strtok(NULL, "\n"); 276 | 277 | if (rv == 2) { 278 | m = &mm[nmm++]; 279 | m->start = start; 280 | m->end = end; 281 | memcpy(m->name, MEMORY_ONLY, sizeof(MEMORY_ONLY)); 282 | continue; 283 | } 284 | 285 | /* search backward for other mapping with same name */ 286 | for (i = nmm - 1; i >= 0; i--) { 287 | m = &mm[i]; 288 | if (!strcmp(m->name, name)) 289 | break; 290 | } 291 | 292 | if (i >= 0) { 293 | if (start < m->start) 294 | m->start = start; 295 | if (end > m->end) 296 | m->end = end; 297 | } else { 298 | /* new entry */ 299 | m = &mm[nmm++]; 300 | m->start = start; 301 | m->end = end; 302 | memcpy(m->name, name, strlen(name)); 303 | } 304 | } 305 | 306 | *nmmp = nmm; 307 | free(p_buf); 308 | return 0; 309 | } 310 | 311 | /* Find libc in MM, storing no more than LEN-1 chars of 312 | its name in NAME and set START to its starting 313 | address. If libc cannot be found return -1 and 314 | leave NAME and START untouched. Otherwise return 0 315 | and null-terminated NAME. */ 316 | static int find_libname(const char *libn, char *name, int len, unsigned long *start, 317 | struct mm *mm, int nmm) { 318 | int i; 319 | struct mm *m; 320 | char *p; 321 | for (i = 0, m = mm; i < nmm; i++, m++) { 322 | if (!strcmp(m->name, MEMORY_ONLY)) 323 | continue; 324 | p = strrchr(m->name, '/'); 325 | if (!p) 326 | continue; 327 | p++; 328 | if (strncmp(libn, p, strlen(libn))) 329 | continue; 330 | p += strlen(libn); 331 | 332 | /* here comes our crude test -> 'libc.so' or 'libc-[0-9]' */ 333 | if (!strncmp(OBFUSCATE("so"), p, 2) || 1) // || (p[0] == '-' && isdigit(p[1]))) 334 | break; 335 | } 336 | if (i >= nmm) 337 | /* not found */ 338 | return -1; 339 | 340 | *start = m->start; 341 | strncpy(name, m->name, len); 342 | if (strlen(m->name) >= len) 343 | name[len - 1] = '\0'; 344 | 345 | mprotect((void *) m->start, m->end - m->start, 346 | PROT_READ | PROT_WRITE | PROT_EXEC); 347 | return 0; 348 | } 349 | 350 | static int lookup2(struct symlist *sl, unsigned char type, char *name, 351 | unsigned long *val) { 352 | Elf32_Sym *p; 353 | int len; 354 | int i; 355 | 356 | len = strlen(name); 357 | for (i = 0, p = sl->sym; i < sl->num; i++, p++) { 358 | //LOGD("name: %s %x\n", sl->str+p->st_name, p->st_value) 359 | if (!strncmp(sl->str + p->st_name, name, len) 360 | && *(sl->str + p->st_name + len) == 0 361 | && ELF32_ST_TYPE(p->st_info) == type) { 362 | //if (p->st_value != 0) { 363 | *val = p->st_value; 364 | return 0; 365 | //} 366 | } 367 | } 368 | return -1; 369 | } 370 | 371 | static int lookup_sym(symtab_t s, unsigned char type, char *name, 372 | unsigned long *val) { 373 | if (s->dyn && !lookup2(s->dyn, type, name, val)) 374 | return 0; 375 | if (s->st && !lookup2(s->st, type, name, val)) 376 | return 0; 377 | return -1; 378 | } 379 | 380 | static int lookup_func_sym(symtab_t s, char *name, unsigned long *val) { 381 | return lookup_sym(s, STT_FUNC, name, val); 382 | } 383 | 384 | int find_name(pid_t pid, const char *name, const char *libn, 385 | unsigned long *addr) { 386 | struct mm mm[1000] = {0}; 387 | unsigned long libcaddr; 388 | int nmm; 389 | char libc[1024] = {0}; 390 | symtab_t s; 391 | 392 | if (0 > load_memmap(pid, mm, &nmm)) { 393 | LOGD(OBFUSCATE("cannot read memory map\n")); 394 | return -1; 395 | } 396 | if (0 397 | > find_libname((char *) libn, (char *) libc, sizeof(libc), 398 | &libcaddr, mm, nmm)) { 399 | LOGD(OBFUSCATE("cannot find lib: %s\n"), libn); 400 | return -1; 401 | } 402 | //LOGD("lib: >%s<\n", libc) 403 | s = load_symtab(libc); 404 | if (!s) { 405 | LOGD(OBFUSCATE("cannot read symbol table\n")); 406 | return -1; 407 | } 408 | if (0 > lookup_func_sym(s, (char *) name, addr)) { 409 | LOGD(OBFUSCATE("cannot find function: %s\n"), name); 410 | return -1; 411 | } 412 | *addr += libcaddr; 413 | return 0; 414 | } 415 | 416 | int find_libbase(pid_t pid, const char *libn, unsigned long *addr) { 417 | struct mm mm[1000] = {0}; 418 | unsigned long libcaddr; 419 | int nmm; 420 | char libc[1024] = {0}; 421 | symtab_t s; 422 | 423 | if (0 > load_memmap(pid, mm, &nmm)) { 424 | LOGD(OBFUSCATE("cannot read memory map\n")); 425 | return -1; 426 | } 427 | if (0 > find_libname(libn, libc, sizeof(libc), &libcaddr, mm, nmm)) { 428 | LOGD(OBFUSCATE("cannot find lib\n")); 429 | return -1; 430 | } 431 | *addr = libcaddr; 432 | return 0; 433 | } 434 | -------------------------------------------------------------------------------- /app/src/main/java/dark/rx/Floater.java: -------------------------------------------------------------------------------- 1 | package dark.rx; 2 | 3 | import android.animation.ArgbEvaluator; 4 | import android.animation.TimeAnimator; 5 | import android.animation.ValueAnimator; 6 | import android.annotation.TargetApi; 7 | import android.app.ActivityManager; 8 | import android.app.ActivityManager.RunningAppProcessInfo; 9 | import android.app.AlertDialog; 10 | import android.app.Service; 11 | import android.content.Context; 12 | import android.content.Intent; 13 | import android.content.res.ColorStateList; 14 | import android.graphics.BitmapFactory; 15 | import android.graphics.Color; 16 | import android.graphics.Paint; 17 | import android.graphics.PorterDuff; 18 | import android.graphics.Typeface; 19 | import android.graphics.drawable.GradientDrawable; 20 | import android.media.MediaPlayer; 21 | import android.net.Uri; 22 | import android.os.Build; 23 | import android.os.Handler; 24 | import android.os.IBinder; 25 | 26 | import android.text.Html; 27 | import android.text.InputFilter; 28 | import android.text.InputType; 29 | import android.text.method.DigitsKeyListener; 30 | import android.util.Base64; 31 | import android.util.Log; 32 | import android.util.TypedValue; 33 | import android.view.Gravity; 34 | import android.view.MotionEvent; 35 | import android.view.View; 36 | import android.view.ViewGroup; 37 | import android.view.WindowManager; 38 | import android.view.inputmethod.InputMethodManager; 39 | import android.webkit.WebSettings; 40 | import android.webkit.WebView; 41 | import android.widget.AdapterView; 42 | import android.widget.ArrayAdapter; 43 | import android.widget.Button; 44 | import android.widget.CompoundButton; 45 | import android.widget.EditText; 46 | import android.widget.FrameLayout; 47 | import android.widget.ImageView; 48 | import android.widget.LinearLayout; 49 | import android.widget.RelativeLayout; 50 | import android.widget.ScrollView; 51 | import android.widget.SeekBar; 52 | import android.widget.Spinner; 53 | import android.widget.Switch; 54 | import android.widget.TextView; 55 | import android.widget.Toast; 56 | 57 | import java.io.File; 58 | import java.util.Arrays; 59 | import java.util.LinkedList; 60 | import java.util.List; 61 | import java.util.Objects; 62 | 63 | public class Floater extends Service { 64 | public View mFloatingView; 65 | private Button close; 66 | private Button kill; 67 | private LinearLayout mButtonPanel; 68 | public RelativeLayout mCollapsed; 69 | public LinearLayout mExpanded; 70 | private RelativeLayout mRootContainer; 71 | public WindowManager mWindowManager; 72 | public WindowManager.LayoutParams params; 73 | private LinearLayout patches; 74 | private FrameLayout rootFrame; 75 | private ImageView startimage; 76 | 77 | private GradientDrawable gdAnimation = new GradientDrawable(); 78 | 79 | private native String Icon(); 80 | 81 | public native void Changes(int feature, int value, Context ctx); 82 | 83 | private native void StartOptionsDark(Context ctx, TextView tx, TextView tx2); 84 | 85 | @Override 86 | public IBinder onBind(Intent intent) { 87 | return null; 88 | } 89 | 90 | public int onStartCommand(Intent intent, int i, int i2) { 91 | return Service.START_NOT_STICKY; 92 | } 93 | 94 | @Override 95 | public void onCreate() { 96 | super.onCreate(); 97 | startAnimation(); 98 | initFloating(); 99 | } 100 | 101 | private void startAnimation() { 102 | final int start = Color.RED; 103 | final int end = Color.BLACK; 104 | 105 | final ArgbEvaluator evaluator = new ArgbEvaluator(); 106 | gdAnimation.setOrientation(GradientDrawable.Orientation.TL_BR); 107 | final GradientDrawable gradient = gdAnimation; 108 | 109 | ValueAnimator animator = TimeAnimator.ofFloat(0.0f, 1.0f); 110 | animator.setDuration(5000); 111 | animator.setRepeatCount(ValueAnimator.INFINITE); 112 | animator.setRepeatMode(ValueAnimator.REVERSE); 113 | animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 114 | @Override 115 | public void onAnimationUpdate(ValueAnimator valueAnimator) { 116 | Float fraction = valueAnimator.getAnimatedFraction(); 117 | int newStrat = (int) evaluator.evaluate(fraction, start, end); 118 | int newEnd = (int) evaluator.evaluate(fraction, end, start); 119 | int[] newArray = {newStrat, newEnd}; 120 | gradient.setColors(newArray); 121 | } 122 | }); 123 | 124 | animator.start(); 125 | } 126 | 127 | private void initFloating() { 128 | rootFrame = new FrameLayout(getBaseContext()); 129 | mRootContainer = new RelativeLayout(getBaseContext()); 130 | mCollapsed = new RelativeLayout(getBaseContext()); 131 | mExpanded = new LinearLayout(getBaseContext()); 132 | patches = new LinearLayout(getBaseContext()); 133 | mButtonPanel = new LinearLayout(getBaseContext()); 134 | 135 | RelativeLayout relativeLayout = new RelativeLayout(this); 136 | relativeLayout.setLayoutParams(new RelativeLayout.LayoutParams(-2, -1)); 137 | relativeLayout.setPadding(3, 0, 3, 3); 138 | relativeLayout.setVerticalGravity(16); 139 | 140 | RelativeLayout.LayoutParams DARK = new RelativeLayout.LayoutParams(-2, dp(40)); 141 | kill = new Button(this); 142 | kill.setBackgroundColor(Color.RED); 143 | kill.setText("HIDE"); 144 | kill.setTextColor(Color.WHITE); 145 | kill.setLayoutParams(DARK); 146 | 147 | RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(-2, dp(40)); 148 | layoutParams.addRule(11); 149 | 150 | 151 | close = new Button(this); 152 | close.setBackgroundColor(Color.RED); 153 | close.setText("CLOSE"); 154 | close.setTextColor(Color.WHITE); 155 | close.setLayoutParams(layoutParams); 156 | 157 | relativeLayout.addView(kill); 158 | relativeLayout.addView(close); 159 | 160 | rootFrame.setLayoutParams(new FrameLayout.LayoutParams(-1, -1)); 161 | mRootContainer.setLayoutParams(new FrameLayout.LayoutParams(-2, -2)); 162 | mCollapsed.setLayoutParams(new RelativeLayout.LayoutParams(-2, -2)); 163 | mCollapsed.setVisibility(View.VISIBLE); 164 | startimage = new ImageView(getBaseContext()); 165 | startimage.setLayoutParams(new RelativeLayout.LayoutParams(-2, -2)); 166 | int applyDimension = (int) TypedValue.applyDimension(1, (float) 60, getResources().getDisplayMetrics()); 167 | startimage.getLayoutParams().height = applyDimension; 168 | startimage.getLayoutParams().width = applyDimension; 169 | startimage.requestLayout(); 170 | startimage.setScaleType(ImageView.ScaleType.FIT_XY); 171 | byte[] decode = Base64.decode(Icon(), 0); 172 | startimage.setImageBitmap(BitmapFactory.decodeByteArray(decode, 0, decode.length)); 173 | startimage.setImageAlpha(200); 174 | ((ViewGroup.MarginLayoutParams) startimage.getLayoutParams()).topMargin = convertDipToPixels(10); 175 | 176 | mExpanded.setVisibility(View.GONE); 177 | mExpanded.setBackgroundColor(Color.BLACK); 178 | mExpanded.setAlpha(0.95f); 179 | mExpanded.setGravity(17); 180 | mExpanded.setOrientation(LinearLayout.VERTICAL); 181 | mExpanded.setPadding(0, 0, 0, 0); 182 | 183 | mExpanded.setLayoutParams(new LinearLayout.LayoutParams(dp(210), -2)); 184 | 185 | ScrollView scrollView = new ScrollView(getBaseContext()); 186 | scrollView.setLayoutParams(new LinearLayout.LayoutParams(-1, dp(200))); 187 | scrollView.setBackground(gdAnimation); 188 | 189 | patches.setLayoutParams(new LinearLayout.LayoutParams(-1, -1)); 190 | patches.setOrientation(LinearLayout.VERTICAL); 191 | 192 | mButtonPanel.setLayoutParams(new LinearLayout.LayoutParams(-2, -2)); 193 | 194 | //Title text 195 | TextView textView = new TextView(getBaseContext()); 196 | textView.setTextColor(Color.RED); 197 | textView.setTypeface(Typeface.DEFAULT_BOLD); 198 | textView.setTextSize(20.0f); 199 | textView.setPadding(0, 10, 0, 5); 200 | LinearLayout.LayoutParams layoutParams2 = new LinearLayout.LayoutParams(-2, -2); 201 | layoutParams2.gravity = 17; 202 | //textView.setLayoutParams(layoutParams2); 203 | 204 | //Heading text 205 | TextView textView2 = new TextView(getBaseContext()); 206 | textView2.setTextColor(Color.RED); 207 | textView2.setTypeface(Typeface.DEFAULT_BOLD); 208 | textView2.setTextSize(10.0f); 209 | textView2.setPadding(10, 5, 10, 10); 210 | 211 | LinearLayout.LayoutParams layoutParams3 = new LinearLayout.LayoutParams(-2, -2); 212 | layoutParams3.gravity = 17; 213 | textView.setLayoutParams(layoutParams2); 214 | textView2.setLayoutParams(layoutParams3); 215 | new LinearLayout.LayoutParams(-1, dp(25)).topMargin = dp(2); 216 | rootFrame.addView(mRootContainer); 217 | mRootContainer.addView(mCollapsed); 218 | mRootContainer.addView(mExpanded); 219 | 220 | mCollapsed.addView(startimage); 221 | 222 | mExpanded.addView(textView); 223 | mExpanded.addView(textView2); 224 | mExpanded.addView(scrollView); 225 | scrollView.addView(patches); 226 | mExpanded.addView(relativeLayout); 227 | mFloatingView = rootFrame; 228 | if (Build.VERSION.SDK_INT >= 26) { 229 | params = new WindowManager.LayoutParams(-2, -2, 2038, 8, -3); 230 | } else { 231 | params = new WindowManager.LayoutParams(-2, -2, 2002, 8, -3); 232 | } 233 | WindowManager.LayoutParams layoutParams4 = params; 234 | layoutParams4.gravity = 51; 235 | layoutParams4.x = 0; 236 | layoutParams4.y = 100; 237 | mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); 238 | mWindowManager.addView(mFloatingView, params); 239 | RelativeLayout relativeLayout2 = mCollapsed; 240 | LinearLayout linearLayout = mExpanded; 241 | mFloatingView.setOnTouchListener(onTouchListener()); 242 | startimage.setOnTouchListener(onTouchListener()); 243 | initMenuButton(relativeLayout2, linearLayout); 244 | StartOptionsDark(this, textView, textView2); 245 | } 246 | 247 | public InterfaceInt INT(int z1){ 248 | return new InterfaceInt() { 249 | @Override 250 | public void OnWrite(int i) { 251 | Changes(z1, i, Floater.this); 252 | } 253 | }; 254 | } 255 | 256 | public InterfaceBool BOOL(int z2){ 257 | return new InterfaceBool() { 258 | @Override 259 | public void OnWrite(boolean z) { 260 | Changes(z2, 0, Floater.this); 261 | } 262 | }; 263 | } 264 | 265 | public InterfaceBtn BTN(int i1){ 266 | return new InterfaceBtn() { 267 | @Override 268 | public void OnWrite() { 269 | Changes(i1, 0, Floater.this); 270 | } 271 | }; 272 | } 273 | 274 | private View.OnTouchListener onTouchListener() { 275 | return new View.OnTouchListener() { 276 | final View collapsedView = mCollapsed; 277 | final View expandedView = mExpanded; 278 | private float initialTouchX; 279 | private float initialTouchY; 280 | private int initialX; 281 | private int initialY; 282 | 283 | public boolean onTouch(View view, MotionEvent motionEvent) { 284 | switch (motionEvent.getAction()) { 285 | case MotionEvent.ACTION_DOWN: 286 | initialX = params.x; 287 | initialY = params.y; 288 | initialTouchX = motionEvent.getRawX(); 289 | initialTouchY = motionEvent.getRawY(); 290 | return true; 291 | case MotionEvent.ACTION_UP: 292 | int rawX = (int) (motionEvent.getRawX() - initialTouchX); 293 | int rawY = (int) (motionEvent.getRawY() - initialTouchY); 294 | 295 | if (rawX < 10 && rawY < 10 && isViewCollapsed()) { 296 | collapsedView.setVisibility(View.GONE); 297 | expandedView.setVisibility(View.VISIBLE); 298 | } 299 | return true; 300 | case MotionEvent.ACTION_MOVE: 301 | params.x = initialX + ((int) (motionEvent.getRawX() - initialTouchX)); 302 | params.y = initialY + ((int) (motionEvent.getRawY() - initialTouchY)); 303 | 304 | mWindowManager.updateViewLayout(mFloatingView, params); 305 | return true; 306 | default: 307 | return false; 308 | } 309 | } 310 | }; 311 | } 312 | 313 | private void initMenuButton(final View view2, final View view3) { 314 | startimage.setOnClickListener(new View.OnClickListener() { 315 | public void onClick(View view) { 316 | view2.setVisibility(View.GONE); 317 | view3.setVisibility(View.VISIBLE); 318 | } 319 | }); 320 | kill.setOnClickListener(new View.OnClickListener() { 321 | public void onClick(View view) { 322 | //Floater.stopSelf(); 323 | // view2.setVisibility(View.VISIBLE) 324 | view2.setVisibility(View.VISIBLE); 325 | view2.setAlpha(0); 326 | view3.setVisibility(View.GONE); 327 | Toast.makeText(view.getContext(), "Icon hidden. Remember the hidden icon position", Toast.LENGTH_LONG).show(); 328 | } 329 | }); 330 | close.setOnClickListener(new View.OnClickListener() { 331 | public void onClick(View view) { 332 | view2.setVisibility(View.VISIBLE); 333 | view2.setAlpha(0.95f); 334 | view3.setVisibility(View.GONE); 335 | } 336 | }); 337 | } 338 | 339 | public void addCategory(String text) { 340 | TextView textView = new TextView(this); 341 | textView.setBackgroundColor(0); 342 | textView.setText(text); 343 | textView.setGravity(17); 344 | textView.setTextSize(14.0f); 345 | textView.setTextColor(Color.WHITE); 346 | textView.setTypeface(null, Typeface.BOLD); 347 | textView.setPadding(10, 5, 0, 5); 348 | patches.addView(textView); 349 | } 350 | 351 | public void addButton(String feature, final InterfaceBtn interfaceBtn) { 352 | final Button button = new Button(this); 353 | LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(-1, -1); 354 | layoutParams.setMargins(7, 5, 7, 5); 355 | button.setLayoutParams(layoutParams); 356 | button.setPadding(10, 5, 10, 5); 357 | button.setTextSize(13.0f); 358 | button.setGravity(17); 359 | button.setTextColor(Color.WHITE); 360 | button.setBackgroundColor(0); 361 | 362 | button.setText(feature + ": OFF"); 363 | final String feature2 = feature; 364 | button.setOnClickListener(new View.OnClickListener() { 365 | private boolean isActive = true; 366 | 367 | public void onClick(View v) { 368 | interfaceBtn.OnWrite(); 369 | if (isActive) { 370 | button.setText(feature2 + ": ON"); 371 | button.setBackgroundColor(Color.RED); 372 | isActive = false; 373 | return; 374 | } 375 | button.setText(feature2 + ": OFF"); 376 | button.setBackgroundColor(0); 377 | isActive = true; 378 | } 379 | }); 380 | patches.addView(button); 381 | } 382 | 383 | public void addSwitch(String feature, final InterfaceBool sw) { 384 | Switch switchR = new Switch(this); 385 | switchR.setText(Html.fromHtml("" + feature + "")); 386 | switchR.setTextColor(Color.WHITE); 387 | switchR.setPadding(10, 5, 0, 5); 388 | switchR.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 389 | public void onCheckedChanged(CompoundButton compoundButton, boolean z) { 390 | if (z) { 391 | } else { 392 | } 393 | sw.OnWrite(z); 394 | } 395 | }); 396 | patches.addView(switchR); 397 | } 398 | 399 | public void addSeekBar(final String feature, final int prog, int max, final InterfaceInt interInt) { 400 | LinearLayout linearLayout = new LinearLayout(this); 401 | LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(-1, -1); 402 | linearLayout.setPadding(10, 5, 0, 5); 403 | linearLayout.setOrientation(LinearLayout.VERTICAL); 404 | linearLayout.setGravity(17); 405 | linearLayout.setLayoutParams(layoutParams); 406 | final TextView textView = new TextView(this); 407 | textView.setText(Html.fromHtml("" + feature + ": " + prog + "")); 408 | textView.setTextColor(Color.parseColor("#DEEDF6")); 409 | SeekBar seekBar = new SeekBar(this); 410 | seekBar.setPadding(25, 10, 35, 10); 411 | seekBar.setLayoutParams(new LinearLayout.LayoutParams(-1, -1)); 412 | seekBar.setMax(max); 413 | seekBar.setProgress(prog); 414 | 415 | final TextView textView2 = textView; 416 | seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { 417 | public void onStartTrackingTouch(SeekBar seekBar) { 418 | } 419 | 420 | public void onStopTrackingTouch(SeekBar seekBar) { 421 | } 422 | 423 | int l; 424 | 425 | public void onProgressChanged(SeekBar seekBar, int i, boolean z) { 426 | if (l < i) { 427 | } else { 428 | } 429 | l = i; 430 | 431 | if (i < prog) { 432 | seekBar.setProgress(prog); 433 | interInt.OnWrite(prog); 434 | TextView textView = textView2; 435 | textView.setText(Html.fromHtml("" + feature + ": " + prog + "")); 436 | return; 437 | } 438 | interInt.OnWrite(i); 439 | textView.setText(Html.fromHtml("" + feature + ": " + i + "")); 440 | } 441 | }); 442 | 443 | linearLayout.addView(textView); 444 | linearLayout.addView(seekBar); 445 | patches.addView(linearLayout); 446 | } 447 | 448 | public boolean isViewCollapsed() { 449 | return mFloatingView == null || mCollapsed.getVisibility() == View.VISIBLE; 450 | } 451 | 452 | private int convertDipToPixels(int i) { 453 | return (int) ((((float) i) * getResources().getDisplayMetrics().density) + 0.5f); 454 | } 455 | 456 | private int dp(int i) { 457 | return (int) TypedValue.applyDimension(1, (float) i, getResources().getDisplayMetrics()); 458 | } 459 | 460 | public void onDestroy() { 461 | super.onDestroy(); 462 | View view = mFloatingView; 463 | if (view != null) { 464 | mWindowManager.removeView(view); 465 | } 466 | } 467 | 468 | public void onTaskRemoved(Intent intent) { 469 | stopSelf(); 470 | try { 471 | Thread.sleep(100); 472 | } catch (InterruptedException e) { 473 | e.printStackTrace(); 474 | } 475 | super.onTaskRemoved(intent); 476 | } 477 | 478 | private interface InterfaceBtn { 479 | void OnWrite(); 480 | } 481 | 482 | private interface InterfaceInt { 483 | void OnWrite(int i); 484 | } 485 | 486 | private interface InterfaceBool { 487 | void OnWrite(boolean z); 488 | } 489 | } -------------------------------------------------------------------------------- /app/src/main/jni/And64InlineHook/And64InlineHook.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @date : 2018/04/18 3 | * @author : Rprop (r_prop@outlook.com) 4 | * https://github.com/Rprop/And64InlineHook 5 | */ 6 | /* 7 | MIT License 8 | 9 | Copyright (c) 2018 Rprop (r_prop@outlook.com) 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in all 19 | copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | SOFTWARE. 28 | */ 29 | #define __STDC_FORMAT_MACROS 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #if defined(__aarch64__) 39 | 40 | #include "And64InlineHook.hpp" 41 | 42 | #define A64_MAX_INSTRUCTIONS 5 43 | #define A64_MAX_REFERENCES (A64_MAX_INSTRUCTIONS * 2) 44 | #define A64_NOP 0xd503201fu 45 | #define A64_JNIEXPORT __attribute__((visibility("hidden"))) 46 | #define A64_LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "A64_HOOK", __VA_ARGS__)) 47 | #ifndef NDEBUG 48 | # define A64_LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "A64_HOOK", __VA_ARGS__)) 49 | #else 50 | # define A64_LOGI(...) ((void)0) 51 | #endif // NDEBUG 52 | typedef uint32_t *__restrict *__restrict instruction; 53 | typedef struct { 54 | struct fix_info { 55 | uint32_t *bp; 56 | uint32_t ls; // left-shift counts 57 | uint32_t ad; // & operand 58 | }; 59 | struct insns_info { 60 | union { 61 | uint64_t insu; 62 | int64_t ins; 63 | void *insp; 64 | }; 65 | fix_info fmap[A64_MAX_REFERENCES]; 66 | }; 67 | int64_t basep; 68 | int64_t endp; 69 | insns_info dat[A64_MAX_INSTRUCTIONS]; 70 | 71 | public: 72 | inline bool is_in_fixing_range(const int64_t absolute_addr) { 73 | return absolute_addr >= this->basep && absolute_addr < this->endp; 74 | } 75 | 76 | inline intptr_t get_ref_ins_index(const int64_t absolute_addr) { 77 | return static_cast((absolute_addr - this->basep) / sizeof(uint32_t)); 78 | } 79 | 80 | inline intptr_t get_and_set_current_index(uint32_t *__restrict inp, uint32_t *__restrict outp) { 81 | intptr_t current_idx = this->get_ref_ins_index(reinterpret_cast(inp)); 82 | this->dat[current_idx].insp = outp; 83 | return current_idx; 84 | } 85 | 86 | inline void reset_current_ins(const intptr_t idx, uint32_t *__restrict outp) { 87 | this->dat[idx].insp = outp; 88 | } 89 | 90 | void 91 | insert_fix_map(const intptr_t idx, uint32_t *bp, uint32_t ls = 0u, uint32_t ad = 0xffffffffu) { 92 | for (auto &f : this->dat[idx].fmap) { 93 | if (f.bp == NULL) { 94 | f.bp = bp; 95 | f.ls = ls; 96 | f.ad = ad; 97 | return; 98 | } //if 99 | } 100 | // What? GGing.. 101 | } 102 | 103 | void process_fix_map(const intptr_t idx) { 104 | for (auto &f : this->dat[idx].fmap) { 105 | if (f.bp == NULL) break; 106 | *(f.bp) = *(f.bp) | 107 | (((int32_t(this->dat[idx].ins - reinterpret_cast(f.bp)) >> 2) 108 | << f.ls) & f.ad); 109 | f.bp = NULL; 110 | } 111 | } 112 | } context; 113 | 114 | //------------------------------------------------------------------------- 115 | 116 | static bool __fix_branch_imm(instruction inpp, instruction outpp, context *ctxp) { 117 | static constexpr uint32_t mbits = 6u; 118 | static constexpr uint32_t mask = 0xfc000000u; // 0b11111100000000000000000000000000 119 | static constexpr uint32_t rmask = 0x03ffffffu; // 0b00000011111111111111111111111111 120 | static constexpr uint32_t op_b = 0x14000000u; // "b" ADDR_PCREL26 121 | static constexpr uint32_t op_bl = 0x94000000u; // "bl" ADDR_PCREL26 122 | 123 | const uint32_t ins = *(*inpp); 124 | const uint32_t opc = ins & mask; 125 | switch (opc) { 126 | case op_b: 127 | case op_bl: { 128 | intptr_t current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); 129 | int64_t absolute_addr = reinterpret_cast(*inpp) + 130 | (static_cast(ins << mbits) 131 | >> (mbits - 2u)); // sign-extended 132 | int64_t new_pc_offset = 133 | static_cast(absolute_addr - reinterpret_cast(*outpp)) 134 | >> 2; // shifted 135 | bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr); 136 | // whether the branch should be converted to absolute jump 137 | if (!special_fix_type && llabs(new_pc_offset) >= (rmask >> 1)) { 138 | bool b_aligned = (reinterpret_cast(*outpp + 2) & 7u) == 0u; 139 | if (opc == op_b) { 140 | if (b_aligned != true) { 141 | (*outpp)[0] = A64_NOP; 142 | ctxp->reset_current_ins(current_idx, ++(*outpp)); 143 | } //if 144 | (*outpp)[0] = 0x58000051u; // LDR X17, #0x8 145 | (*outpp)[1] = 0xd61f0220u; // BR X17 146 | memcpy(*outpp + 2, &absolute_addr, sizeof(absolute_addr)); 147 | *outpp += 4; 148 | } else { 149 | if (b_aligned == true) { 150 | (*outpp)[0] = A64_NOP; 151 | ctxp->reset_current_ins(current_idx, ++(*outpp)); 152 | } //if 153 | (*outpp)[0] = 0x58000071u; // LDR X17, #12 154 | (*outpp)[1] = 0x1000009eu; // ADR X30, #16 155 | (*outpp)[2] = 0xd61f0220u; // BR X17 156 | memcpy(*outpp + 3, &absolute_addr, sizeof(absolute_addr)); 157 | *outpp += 5; 158 | } //if 159 | } else { 160 | if (special_fix_type) { 161 | intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr); 162 | if (ref_idx <= current_idx) { 163 | new_pc_offset = static_cast(ctxp->dat[ref_idx].ins - 164 | reinterpret_cast(*outpp)) 165 | >> 2; 166 | } else { 167 | ctxp->insert_fix_map(ref_idx, *outpp, 0u, rmask); 168 | new_pc_offset = 0; 169 | } //if 170 | } //if 171 | 172 | (*outpp)[0] = opc | (new_pc_offset & ~mask); 173 | ++(*outpp); 174 | } //if 175 | 176 | ++(*inpp); 177 | return ctxp->process_fix_map(current_idx), true; 178 | } 179 | } 180 | return false; 181 | } 182 | 183 | //------------------------------------------------------------------------- 184 | 185 | static bool __fix_cond_comp_test_branch(instruction inpp, instruction outpp, context *ctxp) { 186 | static constexpr uint32_t lsb = 5u; 187 | static constexpr uint32_t lmask01 = 0xff00001fu; // 0b11111111000000000000000000011111 188 | static constexpr uint32_t mask0 = 0xff000010u; // 0b11111111000000000000000000010000 189 | static constexpr uint32_t op_bc = 0x54000000u; // "b.c" ADDR_PCREL19 190 | static constexpr uint32_t mask1 = 0x7f000000u; // 0b01111111000000000000000000000000 191 | static constexpr uint32_t op_cbz = 0x34000000u; // "cbz" Rt, ADDR_PCREL19 192 | static constexpr uint32_t op_cbnz = 0x35000000u; // "cbnz" Rt, ADDR_PCREL19 193 | static constexpr uint32_t lmask2 = 0xfff8001fu; // 0b11111111111110000000000000011111 194 | static constexpr uint32_t mask2 = 0x7f000000u; // 0b01111111000000000000000000000000 195 | static constexpr uint32_t op_tbz = 0x36000000u; // 0b00110110000000000000000000000000 "tbz" Rt, BIT_NUM, ADDR_PCREL14 196 | static constexpr uint32_t op_tbnz = 0x37000000u; // 0b00110111000000000000000000000000 "tbnz" Rt, BIT_NUM, ADDR_PCREL14 197 | 198 | const uint32_t ins = *(*inpp); 199 | uint32_t lmask = lmask01; 200 | if ((ins & mask0) != op_bc) { 201 | uint32_t opc = ins & mask1; 202 | if (opc != op_cbz && opc != op_cbnz) { 203 | opc = ins & mask2; 204 | if (opc != op_tbz && opc != op_tbnz) { 205 | return false; 206 | } //if 207 | lmask = lmask2; 208 | } //if 209 | } //if 210 | 211 | intptr_t current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); 212 | int64_t absolute_addr = reinterpret_cast(*inpp) + ((ins & ~lmask) >> (lsb - 2u)); 213 | int64_t new_pc_offset = 214 | static_cast(absolute_addr - reinterpret_cast(*outpp)) >> 2; // shifted 215 | bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr); 216 | if (!special_fix_type && llabs(new_pc_offset) >= (~lmask >> (lsb + 1))) { 217 | if ((reinterpret_cast(*outpp + 4) & 7u) != 0u) { 218 | (*outpp)[0] = A64_NOP; 219 | ctxp->reset_current_ins(current_idx, ++(*outpp)); 220 | } //if 221 | (*outpp)[0] = (((8u >> 2u) << lsb) & ~lmask) | (ins & lmask); // B.C #0x8 222 | (*outpp)[1] = 0x14000005u; // B #0x14 223 | (*outpp)[2] = 0x58000051u; // LDR X17, #0x8 224 | (*outpp)[3] = 0xd61f0220u; // BR X17 225 | memcpy(*outpp + 4, &absolute_addr, sizeof(absolute_addr)); 226 | *outpp += 6; 227 | } else { 228 | if (special_fix_type) { 229 | intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr); 230 | if (ref_idx <= current_idx) { 231 | new_pc_offset = static_cast(ctxp->dat[ref_idx].ins - 232 | reinterpret_cast(*outpp)) >> 2; 233 | } else { 234 | ctxp->insert_fix_map(ref_idx, *outpp, lsb, ~lmask); 235 | new_pc_offset = 0; 236 | } //if 237 | } //if 238 | 239 | (*outpp)[0] = (static_cast(new_pc_offset << lsb) & ~lmask) | (ins & lmask); 240 | ++(*outpp); 241 | } //if 242 | 243 | ++(*inpp); 244 | return ctxp->process_fix_map(current_idx), true; 245 | } 246 | 247 | //------------------------------------------------------------------------- 248 | 249 | static bool __fix_loadlit(instruction inpp, instruction outpp, context *ctxp) { 250 | const uint32_t ins = *(*inpp); 251 | 252 | // memory prefetch("prfm"), just skip it 253 | // http://infocenter.arm.com/help/topic/com.arm.doc.100069_0608_00_en/pge1427897420050.html 254 | if ((ins & 0xff000000u) == 0xd8000000u) { 255 | ctxp->process_fix_map(ctxp->get_and_set_current_index(*inpp, *outpp)); 256 | ++(*inpp); 257 | return true; 258 | } //if 259 | 260 | static constexpr uint32_t msb = 8u; 261 | static constexpr uint32_t lsb = 5u; 262 | static constexpr uint32_t mask_30 = 0x40000000u; // 0b01000000000000000000000000000000 263 | static constexpr uint32_t mask_31 = 0x80000000u; // 0b10000000000000000000000000000000 264 | static constexpr uint32_t lmask = 0xff00001fu; // 0b11111111000000000000000000011111 265 | static constexpr uint32_t mask_ldr = 0xbf000000u; // 0b10111111000000000000000000000000 266 | static constexpr uint32_t op_ldr = 0x18000000u; // 0b00011000000000000000000000000000 "LDR Wt/Xt, label" | ADDR_PCREL19 267 | static constexpr uint32_t mask_ldrv = 0x3f000000u; // 0b00111111000000000000000000000000 268 | static constexpr uint32_t op_ldrv = 0x1c000000u; // 0b00011100000000000000000000000000 "LDR St/Dt/Qt, label" | ADDR_PCREL19 269 | static constexpr uint32_t mask_ldrsw = 0xff000000u; // 0b11111111000000000000000000000000 270 | static constexpr uint32_t op_ldrsw = 0x98000000u; // "LDRSW Xt, label" | ADDR_PCREL19 | load register signed word 271 | // LDR S0, #0 | 0b00011100000000000000000000000000 | 32-bit 272 | // LDR D0, #0 | 0b01011100000000000000000000000000 | 64-bit 273 | // LDR Q0, #0 | 0b10011100000000000000000000000000 | 128-bit 274 | // INVALID | 0b11011100000000000000000000000000 | may be 256-bit 275 | 276 | uint32_t mask = mask_ldr; 277 | uintptr_t faligned = (ins & mask_30) ? 7u : 3u; 278 | if ((ins & mask_ldr) != op_ldr) { 279 | mask = mask_ldrv; 280 | if (faligned != 7u) 281 | faligned = (ins & mask_31) ? 15u : 3u; 282 | if ((ins & mask_ldrv) != op_ldrv) { 283 | if ((ins & mask_ldrsw) != op_ldrsw) { 284 | return false; 285 | } //if 286 | mask = mask_ldrsw; 287 | faligned = 7u; 288 | } //if 289 | } //if 290 | 291 | intptr_t current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); 292 | int64_t absolute_addr = reinterpret_cast(*inpp) + 293 | ((static_cast(ins << msb) >> (msb + lsb - 2u)) & ~3u); 294 | int64_t new_pc_offset = 295 | static_cast(absolute_addr - reinterpret_cast(*outpp)) >> 2; // shifted 296 | bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr); 297 | // special_fix_type may encounter issue when there are mixed data and code 298 | if (special_fix_type || (llabs(new_pc_offset) + (faligned + 1u - 4u) / 4u) >= 299 | (~lmask >> (lsb + 1))) { // inaccurate, but it works 300 | while ((reinterpret_cast(*outpp + 2) & faligned) != 0u) { 301 | *(*outpp)++ = A64_NOP; 302 | } 303 | ctxp->reset_current_ins(current_idx, *outpp); 304 | 305 | // Note that if memory at absolute_addr is writeable (non-const), we will fail to fetch it. 306 | // And what's worse, we may unexpectedly overwrite something if special_fix_type is true... 307 | uint32_t ns = static_cast((faligned + 1) / sizeof(uint32_t)); 308 | (*outpp)[0] = (((8u >> 2u) << lsb) & ~mask) | (ins & lmask); // LDR #0x8 309 | (*outpp)[1] = 0x14000001u + ns; // B #0xc 310 | memcpy(*outpp + 2, reinterpret_cast(absolute_addr), faligned + 1); 311 | *outpp += 2 + ns; 312 | } else { 313 | faligned >>= 2; // new_pc_offset is shifted and 4-byte aligned 314 | while ((new_pc_offset & faligned) != 0) { 315 | *(*outpp)++ = A64_NOP; 316 | new_pc_offset = 317 | static_cast(absolute_addr - reinterpret_cast(*outpp)) >> 2; 318 | } 319 | ctxp->reset_current_ins(current_idx, *outpp); 320 | 321 | (*outpp)[0] = (static_cast(new_pc_offset << lsb) & ~mask) | (ins & lmask); 322 | ++(*outpp); 323 | } //if 324 | 325 | ++(*inpp); 326 | return ctxp->process_fix_map(current_idx), true; 327 | } 328 | 329 | //------------------------------------------------------------------------- 330 | 331 | static bool __fix_pcreladdr(instruction inpp, instruction outpp, context *ctxp) { 332 | // Load a PC-relative address into a register 333 | // http://infocenter.arm.com/help/topic/com.arm.doc.100069_0608_00_en/pge1427897645644.html 334 | static constexpr uint32_t msb = 8u; 335 | static constexpr uint32_t lsb = 5u; 336 | static constexpr uint32_t mask = 0x9f000000u; // 0b10011111000000000000000000000000 337 | static constexpr uint32_t rmask = 0x0000001fu; // 0b00000000000000000000000000011111 338 | static constexpr uint32_t lmask = 0xff00001fu; // 0b11111111000000000000000000011111 339 | static constexpr uint32_t fmask = 0x00ffffffu; // 0b00000000111111111111111111111111 340 | static constexpr uint32_t max_val = 0x001fffffu; // 0b00000000000111111111111111111111 341 | static constexpr uint32_t op_adr = 0x10000000u; // "adr" Rd, ADDR_PCREL21 342 | static constexpr uint32_t op_adrp = 0x90000000u; // "adrp" Rd, ADDR_ADRP 343 | 344 | const uint32_t ins = *(*inpp); 345 | intptr_t current_idx; 346 | switch (ins & mask) { 347 | case op_adr: { 348 | current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); 349 | int64_t lsb_bytes = static_cast(ins << 1u) >> 30u; 350 | int64_t absolute_addr = reinterpret_cast(*inpp) + 351 | (((static_cast(ins << msb) >> (msb + lsb - 2u)) & 352 | ~3u) | lsb_bytes); 353 | int64_t new_pc_offset = static_cast(absolute_addr - 354 | reinterpret_cast(*outpp)); 355 | bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr); 356 | if (!special_fix_type && llabs(new_pc_offset) >= (max_val >> 1)) { 357 | if ((reinterpret_cast(*outpp + 2) & 7u) != 0u) { 358 | (*outpp)[0] = A64_NOP; 359 | ctxp->reset_current_ins(current_idx, ++(*outpp)); 360 | } //if 361 | 362 | (*outpp)[0] = 363 | 0x58000000u | (((8u >> 2u) << lsb) & ~mask) | (ins & rmask); // LDR #0x8 364 | (*outpp)[1] = 0x14000003u; // B #0xc 365 | memcpy(*outpp + 2, &absolute_addr, sizeof(absolute_addr)); 366 | *outpp += 4; 367 | } else { 368 | if (special_fix_type) { 369 | intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr & ~3ull); 370 | if (ref_idx <= current_idx) { 371 | new_pc_offset = static_cast(ctxp->dat[ref_idx].ins - 372 | reinterpret_cast(*outpp)); 373 | } else { 374 | ctxp->insert_fix_map(ref_idx, *outpp, lsb, fmask); 375 | new_pc_offset = 0; 376 | } //if 377 | } //if 378 | 379 | // the lsb_bytes will never be changed, so we can use lmask to keep it 380 | (*outpp)[0] = (static_cast(new_pc_offset << (lsb - 2u)) & fmask) | 381 | (ins & lmask); 382 | ++(*outpp); 383 | } //if 384 | } 385 | break; 386 | case op_adrp: { 387 | current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); 388 | int32_t lsb_bytes = static_cast(ins << 1u) >> 30u; 389 | int64_t absolute_addr = (reinterpret_cast(*inpp) & ~0xfffll) + 390 | ((((static_cast(ins << msb) >> (msb + lsb - 2u)) & 391 | ~3u) | lsb_bytes) << 12); 392 | A64_LOGI("ins = 0x%.8X, pc = %p, abs_addr = %p", 393 | ins, *inpp, reinterpret_cast(absolute_addr)); 394 | if (ctxp->is_in_fixing_range(absolute_addr)) { 395 | intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr/* & ~3ull*/); 396 | if (ref_idx > current_idx) { 397 | // the bottom 12 bits of absolute_addr are masked out, 398 | // so ref_idx must be less than or equal to current_idx! 399 | A64_LOGE("ref_idx must be less than or equal to current_idx!"); 400 | } //if 401 | 402 | // *absolute_addr may be changed due to relocation fixing 403 | A64_LOGI("What is the correct way to fix this?"); 404 | *(*outpp)++ = ins; // 0x90000000u; 405 | } else { 406 | if ((reinterpret_cast(*outpp + 2) & 7u) != 0u) { 407 | (*outpp)[0] = A64_NOP; 408 | ctxp->reset_current_ins(current_idx, ++(*outpp)); 409 | } //if 410 | 411 | (*outpp)[0] = 412 | 0x58000000u | (((8u >> 2u) << lsb) & ~mask) | (ins & rmask); // LDR #0x8 413 | (*outpp)[1] = 0x14000003u; // B #0xc 414 | memcpy(*outpp + 2, &absolute_addr, sizeof(absolute_addr)); // potential overflow? 415 | *outpp += 4; 416 | } //if 417 | } 418 | break; 419 | default: 420 | return false; 421 | } 422 | 423 | ctxp->process_fix_map(current_idx); 424 | ++(*inpp); 425 | return true; 426 | } 427 | 428 | //------------------------------------------------------------------------- 429 | #define __flush_cache(c, n) __builtin___clear_cache(reinterpret_cast(c), reinterpret_cast(c) + n) 430 | 431 | static void __fix_instructions(uint32_t *__restrict inp, int32_t count, uint32_t *__restrict outp) { 432 | context ctx; 433 | ctx.basep = reinterpret_cast(inp); 434 | ctx.endp = reinterpret_cast(inp + count); 435 | memset(ctx.dat, 0, sizeof(ctx.dat)); 436 | static_assert(sizeof(ctx.dat) / sizeof(ctx.dat[0]) == A64_MAX_INSTRUCTIONS, 437 | "please use A64_MAX_INSTRUCTIONS!"); 438 | #ifndef NDEBUG 439 | if (count > A64_MAX_INSTRUCTIONS) { 440 | A64_LOGE("too many fixing instructions!"); 441 | } //if 442 | #endif // NDEBUG 443 | 444 | uint32_t *const outp_base = outp; 445 | 446 | while (--count >= 0) { 447 | if (__fix_branch_imm(&inp, &outp, &ctx)) continue; 448 | if (__fix_cond_comp_test_branch(&inp, &outp, &ctx)) continue; 449 | if (__fix_loadlit(&inp, &outp, &ctx)) continue; 450 | if (__fix_pcreladdr(&inp, &outp, &ctx)) continue; 451 | 452 | // without PC-relative offset 453 | ctx.process_fix_map(ctx.get_and_set_current_index(inp, outp)); 454 | *(outp++) = *(inp++); 455 | } 456 | 457 | static constexpr uint_fast64_t mask = 0x03ffffffu; // 0b00000011111111111111111111111111 458 | auto callback = reinterpret_cast(inp); 459 | auto pc_offset = static_cast(callback - reinterpret_cast(outp)) >> 2; 460 | if (llabs(pc_offset) >= (mask >> 1)) { 461 | if ((reinterpret_cast(outp + 2) & 7u) != 0u) { 462 | outp[0] = A64_NOP; 463 | ++outp; 464 | } //if 465 | outp[0] = 0x58000051u; // LDR X17, #0x8 466 | outp[1] = 0xd61f0220u; // BR X17 467 | *reinterpret_cast(outp + 2) = callback; 468 | outp += 4; 469 | } else { 470 | outp[0] = 0x14000000u | (pc_offset & mask); // "B" ADDR_PCREL26 471 | ++outp; 472 | } //if 473 | 474 | const uintptr_t total = (outp - outp_base) * sizeof(uint32_t); 475 | __flush_cache(outp_base, total); // necessary 476 | } 477 | 478 | //------------------------------------------------------------------------- 479 | 480 | extern "C" { 481 | #define __attribute __attribute__ 482 | #define aligned(x) __aligned__(x) 483 | #define __intval(p) reinterpret_cast(p) 484 | #define __uintval(p) reinterpret_cast(p) 485 | #define __ptr(p) reinterpret_cast(p) 486 | #define __page_size 4096 487 | #define __page_align(n) __align_up(static_cast(n), __page_size) 488 | #define __ptr_align(x) __ptr(__align_down(reinterpret_cast(x), __page_size)) 489 | #define __align_up(x, n) (((x) + ((n) - 1)) & ~((n) - 1)) 490 | #define __align_down(x, n) ((x) & -(n)) 491 | #define __countof(x) static_cast(sizeof(x) / sizeof((x)[0])) // must be signed 492 | #define __atomic_increase(p) __sync_add_and_fetch(p, 1) 493 | #define __sync_cmpswap(p, v, n) __sync_bool_compare_and_swap(p, v, n) 494 | #define __predict_true(exp) __builtin_expect((exp) != 0, 1) 495 | #define __make_rwx(p, n) ::mprotect(__ptr_align(p), \ 496 | __page_align(__uintval(p) + n) != __page_align(__uintval(p)) ? __page_align(n) + __page_size : __page_align(n), \ 497 | PROT_READ | PROT_WRITE | PROT_EXEC) 498 | 499 | //------------------------------------------------------------------------- 500 | 501 | static __attribute((aligned(__page_size))) uint32_t __insns_pool[A64_MAX_BACKUPS][ 502 | A64_MAX_INSTRUCTIONS * 10]; 503 | 504 | //------------------------------------------------------------------------- 505 | 506 | class A64HookInit { 507 | public: 508 | A64HookInit() { 509 | __make_rwx(__insns_pool, sizeof(__insns_pool)); 510 | A64_LOGI("insns pool initialized."); 511 | } 512 | }; 513 | static A64HookInit __init; 514 | 515 | //------------------------------------------------------------------------- 516 | 517 | static uint32_t *FastAllocateTrampoline() { 518 | static_assert((A64_MAX_INSTRUCTIONS * 10 * sizeof(uint32_t)) % 8 == 0, "8-byte align"); 519 | static volatile int32_t __index = -1; 520 | 521 | int32_t i = __atomic_increase(&__index); 522 | if (__predict_true(i >= 0 && i < __countof(__insns_pool))) { 523 | return __insns_pool[i]; 524 | } //if 525 | 526 | A64_LOGE("failed to allocate trampoline!"); 527 | return NULL; 528 | } 529 | 530 | //------------------------------------------------------------------------- 531 | 532 | A64_JNIEXPORT void *A64HookFunctionV(void *const symbol, void *const replace, 533 | void *const rwx, const uintptr_t rwx_size) { 534 | static constexpr uint_fast64_t mask = 0x03ffffffu; // 0b00000011111111111111111111111111 535 | 536 | uint32_t *trampoline = static_cast(rwx), *original = static_cast(symbol); 537 | 538 | static_assert(A64_MAX_INSTRUCTIONS >= 5, "please fix A64_MAX_INSTRUCTIONS!"); 539 | auto pc_offset = static_cast(__intval(replace) - __intval(symbol)) >> 2; 540 | if (llabs(pc_offset) >= (mask >> 1)) { 541 | int32_t count = (reinterpret_cast(original + 2) & 7u) != 0u ? 5 : 4; 542 | if (trampoline) { 543 | if (rwx_size < count * 10u) { 544 | A64_LOGI("rwx size is too small to hold %u bytes backup instructions!", 545 | count * 10u); 546 | return NULL; 547 | } //if 548 | __fix_instructions(original, count, trampoline); 549 | } //if 550 | 551 | if (__make_rwx(original, 5 * sizeof(uint32_t)) == 0) { 552 | if (count == 5) { 553 | original[0] = A64_NOP; 554 | ++original; 555 | } //if 556 | original[0] = 0x58000051u; // LDR X17, #0x8 557 | original[1] = 0xd61f0220u; // BR X17 558 | *reinterpret_cast(original + 2) = __intval(replace); 559 | __flush_cache(symbol, 5 * sizeof(uint32_t)); 560 | 561 | A64_LOGI("inline hook %p->%p successfully! %zu bytes overwritten", 562 | symbol, replace, 5 * sizeof(uint32_t)); 563 | } else { 564 | A64_LOGE("mprotect failed with errno = %d, p = %p, size = %zu", 565 | errno, original, 5 * sizeof(uint32_t)); 566 | trampoline = NULL; 567 | } //if 568 | } else { 569 | if (trampoline) { 570 | if (rwx_size < 1u * 10u) { 571 | A64_LOGI("rwx size is too small to hold %u bytes backup instructions!", 1u * 10u); 572 | return NULL; 573 | } //if 574 | __fix_instructions(original, 1, trampoline); 575 | } //if 576 | 577 | if (__make_rwx(original, 1 * sizeof(uint32_t)) == 0) { 578 | __sync_cmpswap(original, *original, 579 | 0x14000000u | (pc_offset & mask)); // "B" ADDR_PCREL26 580 | __flush_cache(symbol, 1 * sizeof(uint32_t)); 581 | 582 | A64_LOGI("inline hook %p->%p successfully! %zu bytes overwritten", 583 | symbol, replace, 1 * sizeof(uint32_t)); 584 | } else { 585 | A64_LOGE("mprotect failed with errno = %d, p = %p, size = %zu", 586 | errno, original, 1 * sizeof(uint32_t)); 587 | trampoline = NULL; 588 | } //if 589 | } //if 590 | 591 | return trampoline; 592 | } 593 | 594 | //------------------------------------------------------------------------- 595 | 596 | A64_JNIEXPORT void A64HookFunction(void *const symbol, void *const replace, void **result) { 597 | void *trampoline = NULL; 598 | if (result != NULL) { 599 | trampoline = FastAllocateTrampoline(); 600 | *result = trampoline; 601 | if (trampoline == NULL) return; 602 | } //if 603 | 604 | trampoline = A64HookFunctionV(symbol, replace, trampoline, A64_MAX_INSTRUCTIONS * 10u); 605 | if (trampoline == NULL && result != NULL) { 606 | *result = NULL; 607 | } //if 608 | } 609 | } 610 | 611 | #endif // defined(__aarch64__) --------------------------------------------------------------------------------