├── 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