├── settings.gradle
├── app
├── src
│ └── main
│ │ ├── res
│ │ ├── values
│ │ │ ├── strings.xml
│ │ │ ├── colors.xml
│ │ │ └── styles.xml
│ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── values-v21
│ │ │ └── styles.xml
│ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ ├── drawable
│ │ │ ├── capsule.xml
│ │ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ │ ├── activity_main2.xml
│ │ │ └── activity_main.xml
│ │ └── drawable-v24
│ │ │ └── ic_launcher_foreground.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
│ │ │ ├── Vector3.h
│ │ │ ├── Rect.h
│ │ │ ├── Logger.h
│ │ │ ├── Color.h
│ │ │ ├── Quaternion.h
│ │ │ ├── Unity.h
│ │ │ ├── Utils.h
│ │ │ ├── obfuscate.h
│ │ │ └── Vector2.h
│ │ ├── Android.mk
│ │ └── Main.cpp
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── simplefucker
│ │ ├── source
│ │ └── SavedPrefs.java
│ │ └── MainActivity.java
├── proguard-rules.pro
├── build.gradle
└── app.iml
├── gradle
└── wrapper
│ └── gradle-wrapper.properties
├── local.properties
├── README.md
├── gradle.properties
├── FloatingModMenu.iml
├── gradlew.bat
└── gradlew
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Anti Clown By Kolan and Ise
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SliceCast/Android-Mod-SubMenu/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SliceCast/Android-Mod-SubMenu/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SliceCast/Android-Mod-SubMenu/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SliceCast/Android-Mod-SubMenu/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SliceCast/Android-Mod-SubMenu/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SliceCast/Android-Mod-SubMenu/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/SliceCast/Android-Mod-SubMenu/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/SliceCast/Android-Mod-SubMenu/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #202020
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SliceCast/Android-Mod-SubMenu/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/SliceCast/Android-Mod-SubMenu/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/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 24 18:32:28 CEST 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
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/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/capsule.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/local.properties:
--------------------------------------------------------------------------------
1 | ## This file must *NOT* be checked into Version Control Systems,
2 | # as it contains information specific to your local configuration.
3 | #
4 | # Location of the SDK. This is only used by Gradle.
5 | # For customization when using a Version Control System, please read the
6 | # header note.
7 | #Sun Apr 18 15:06:47 YEKT 2021
8 | sdk.dir=C\:\\Users\\vaka\\AppData\\Local\\Android\\Sdk
9 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main2.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/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/Vector3.h:
--------------------------------------------------------------------------------
1 | class Vector3 {
2 | public:
3 | float x;
4 | float y;
5 | float z;
6 | Vector3()
7 | : x(0)
8 | , y(0)
9 | , z(0)
10 | {
11 | }
12 | Vector3(float x1, float y1, float z1)
13 | : x(x1)
14 | , y(y1)
15 | , z(z1)
16 | {
17 | }
18 | Vector3(const Vector3& v);
19 | ~Vector3();
20 | };
21 | Vector3::Vector3(const Vector3& v)
22 | : x(v.x)
23 | , y(v.y)
24 | , z(v.z)
25 | {
26 | }
27 | Vector3::~Vector3() {}
--------------------------------------------------------------------------------
/app/src/main/jni/Includes/Rect.h:
--------------------------------------------------------------------------------
1 | class Rect {
2 | public:
3 | float x;
4 | float y;
5 | float w;
6 | float h;
7 | Rect()
8 | : x(0)
9 | , y(0)
10 | , w(0)
11 | , h(0)
12 | {
13 | }
14 | Rect(float x1, float y1, float w1, float h1)
15 | : x(x1)
16 | , y(y1)
17 | , w(w1)
18 | , h(h1)
19 | {
20 | }
21 | Rect(const Rect& v);
22 | ~Rect();
23 | };
24 | Rect::Rect(const Rect& v)
25 | : x(v.x)
26 | , y(v.y)
27 | , w(v.w)
28 | , h(v.h)
29 | {
30 | }
31 | Rect::~Rect() {}
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Disclaimer
2 | Hello, this is a mod menu template from LGL's and KolanHacker(Hard-Android-Menu), a version with SubMenus now.
3 |
4 | I just improved the menu a bit to make it more readable and easier to modify.
5 |
6 | Note: To be easier for submenus, we have an optional case numbers.
7 | Example: "150_Toggle_Unlimited Ammo", use different numbers to get your mods working in a different submenu section.
8 |
9 | # Credits
10 | LGL's Template: https://github.com/LGLTeam/Android-Mod-Menu
11 |
12 | KolanHacker Original Template: https://github.com/KolanHacker/-Hard-Android-Menu-
13 |
14 | # ARM64 DISCLAIMER!
15 | Fixed!
16 |
17 |
18 | 
19 |
20 | 
21 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 |
15 |
16 |
--------------------------------------------------------------------------------
/FloatingModMenu.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 | #-dontobfuscate
23 | -keepclassmembers class ** {
24 | public static void Start (***);
25 | }
26 | -keep public class uk.lgl.MainActivity
27 |
--------------------------------------------------------------------------------
/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/Includes/Color.h:
--------------------------------------------------------------------------------
1 |
2 | class Color {
3 | public:
4 | float r, b, g, a;
5 |
6 | Color() {
7 | SetColor( 0 , 0 , 0 , 255 );
8 | }
9 |
10 | Color( float r , float g , float b ) {
11 | SetColor( r , g , b , 255 );
12 | }
13 |
14 | Color( float r, float g, float b, float a) {
15 | SetColor( r , g , b , a );
16 | }
17 |
18 | void SetColor( float r1 , float g1 , float b1 , float a1 = 255 ) {
19 | r = r1;
20 | g = g1;
21 | b = b1;
22 | a = a1;
23 | }
24 |
25 | static Color Black(float a = 255){ return Color(0, 0, 0, a); }
26 | static Color White(float a = 255){ return Color(255 , 255 , 255, a); }
27 | static Color Red(float a = 255){ return Color(255 , 0 , 0, a); }
28 | static Color Green(float a = 255){ return Color(0 , 255 , 0, a); }
29 | static Color Blue(float a = 255){ return Color(0 , 0 , 255, a); }
30 | static Color Yellow(float a = 255){ return Color(255 , 255 , 0, a); }
31 | static Color Cyan(float a = 255){ return Color(0 , 255 , 255, a); }
32 | static Color Magenta(float a = 255){ return Color(255 , 0 , 255, a); }
33 | };
34 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 30
5 | defaultConfig {
6 | applicationId "com.simplefucker.source"
7 | minSdkVersion 19
8 | targetSdkVersion 30
9 | versionCode 1
10 | versionName "2.0"
11 | ndk {
12 | abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86'
13 | }
14 | signingConfig signingConfigs.debug
15 | }
16 | buildTypes {
17 | release {
18 | shrinkResources false
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
21 | }
22 | debug {
23 | shrinkResources false
24 | minifyEnabled false
25 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
26 | }
27 | }
28 | externalNativeBuild {
29 | ndkBuild {
30 | path file('src/main/jni/Android.mk')
31 | }
32 | }
33 | ndkVersion = '22.0.7026061'
34 | }
35 |
36 | //aide
37 | dependencies {
38 | implementation fileTree(dir: 'libs', include: ['*.jar'])
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/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/Android.mk:
--------------------------------------------------------------------------------
1 | LOCAL_PATH := $(call my-dir)
2 | MAIN_LOCAL_PATH := $(call my-dir)
3 | include $(CLEAR_VARS)
4 |
5 | # Here is the name of your lib.
6 | # When you change the lib name, change also on System.loadLibrary("") under OnCreate method on StaticActivity.java
7 | # Both must have same name
8 | LOCAL_MODULE := KISE
9 |
10 | # Code optimization
11 | # -std=c++17 is required to support AIDE app with NDK
12 | LOCAL_CFLAGS := -Wno-error=format-security -fvisibility=hidden -ffunction-sections -fdata-sections -w
13 | LOCAL_CFLAGS += -fno-rtti -fno-exceptions -fpermissive
14 | LOCAL_CPPFLAGS := -Wno-error=format-security -fvisibility=hidden -ffunction-sections -fdata-sections -w -Werror -s -std=c++17
15 | LOCAL_CPPFLAGS += -Wno-error=c++11-narrowing -fms-extensions -fno-rtti -fno-exceptions -fpermissive
16 | LOCAL_LDFLAGS += -Wl,--gc-sections,--strip-all, -llog
17 | LOCAL_ARM_MODE := arm
18 |
19 | LOCAL_C_INCLUDES += $(MAIN_LOCAL_PATH)
20 |
21 | # Here you add the cpp file
22 | LOCAL_SRC_FILES := Main.cpp \
23 | Substrate/hde64.c \
24 | Substrate/SubstrateDebug.cpp \
25 | Substrate/SubstrateHook.cpp \
26 | Substrate/SubstratePosixMemory.cpp \
27 | Substrate/SymbolFinder.cpp \
28 | KittyMemory/KittyMemory.cpp \
29 | KittyMemory/MemoryPatch.cpp \
30 | KittyMemory/MemoryBackup.cpp \
31 | KittyMemory/KittyUtils.cpp \
32 | And64InlineHook/And64InlineHook.cpp \
33 |
34 | LOCAL_LDLIBS := -llog -landroid -lGLESv2
35 |
36 | include $(BUILD_SHARED_LIBRARY)
37 |
--------------------------------------------------------------------------------
/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 | #include "KittyUtils.h"
11 | #include "KittyMemory.h"
12 | using KittyMemory::Memory_Status;
13 | using KittyMemory::ProcMap;
14 |
15 | class MemoryPatch {
16 | private:
17 | uintptr_t _address;
18 | size_t _size;
19 |
20 | std::vector _orig_code;
21 | std::vector _patch_code;
22 |
23 | std::string _hexString;
24 |
25 | public:
26 | MemoryPatch();
27 |
28 | /*
29 | * expects library name and relative address
30 | */
31 | MemoryPatch(const char *libraryName, uintptr_t address,
32 | const void *patch_code, size_t patch_size, bool useMapCache=true);
33 |
34 |
35 | /*
36 | * expects absolute address
37 | */
38 | MemoryPatch(uintptr_t absolute_address,
39 | const void *patch_code, size_t patch_size);
40 |
41 |
42 | ~MemoryPatch();
43 |
44 | /*
45 | * compatible hex format (0xffff & ffff & ff ff)
46 | */
47 | static MemoryPatch createWithHex(const char *libraryName, uintptr_t address, std::string hex, bool useMapCache=true);
48 | static MemoryPatch createWithHex(uintptr_t absolute_address, std::string hex);
49 |
50 | /*
51 | * Validate patch
52 | */
53 | bool isValid() const;
54 |
55 |
56 | size_t get_PatchSize() const;
57 |
58 | /*
59 | * Returns pointer to the target address
60 | */
61 | uintptr_t get_TargetAddress() const;
62 |
63 |
64 | /*
65 | * Restores patch to original value
66 | */
67 | bool Restore();
68 |
69 |
70 | /*
71 | * Applies patch modifications to target address
72 | */
73 | bool Modify();
74 |
75 |
76 | /*
77 | * Returns current patch target address bytes as hex string
78 | */
79 | std::string get_CurrBytes();
80 | };
81 |
--------------------------------------------------------------------------------
/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/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/Includes/Quaternion.h:
--------------------------------------------------------------------------------
1 | class Quaternion {
2 | public:
3 | float a;
4 | float b;
5 | float c;
6 | float d;
7 |
8 | Quaternion() {a = 1; b = c = d = 0;}
9 |
10 | // This is a vector that can be rotated in Quaternion space.
11 | Quaternion(float x, float y, float z) {a = 0; b = x; c = y; d = z;}
12 |
13 | // This returns a Quaternion that rotates in each given axis in radians.
14 | // We use standard right hand rule for rotations and coordinates.
15 | static const Quaternion from_euler_rotation(float x, float y, float z);
16 |
17 | // This is like from_euler_rotation but for small angles (less than 45 deg (PI/4))
18 | static const Quaternion from_euler_rotation_approx(float x, float y, float z);
19 |
20 | Quaternion & operator=(const Quaternion &rhs) {
21 | a = rhs.a;
22 | b = rhs.b;
23 | c = rhs.c;
24 | d = rhs.d;
25 | return *this;
26 | }
27 |
28 | // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/arithmetic/index.htm
29 | Quaternion & operator*=(const Quaternion &q);
30 | const Quaternion operator* (const Quaternion& q) const { return Quaternion(*this) *= q; }
31 | Quaternion & operator+=(const Quaternion &q);
32 | const Quaternion operator+(const Quaternion& q) const { return Quaternion(*this) += q; }
33 | Quaternion & operator*=(float scale);
34 | const Quaternion operator*(float scale) const { return Quaternion(*this) *= scale; }
35 | float norm() const;
36 | Quaternion & normalize();
37 | const Quaternion conj() const;
38 | // This method takes two vectors and computes the rotation vector between them.
39 | // Both the left and right hand sides must be pure vectors (a == 0)
40 | // Both the left and right hand sides must normalized already.
41 | // This computes the rotation that will tranform this to q.
42 | const Quaternion rotation_between_vectors(const Quaternion& v) const;
43 | float dot_product(const Quaternion& q) const;
44 |
45 | // This method takes one vector and rotates it using this Quaternion.
46 | // The input must be a pure vector (a == 0)
47 | const Quaternion rotate(const Quaternion& q) const;
48 | Quaternion & fractional(float f);
49 | };
50 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
14 |
15 |
26 |
27 |
38 |
39 |
43 |
44 |
52 |
53 |
54 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/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/java/com/simplefucker/source/SavedPrefs.java:
--------------------------------------------------------------------------------
1 | package com.simplefucker.source;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.preference.PreferenceManager;
6 | import android.util.Log;
7 |
8 | import static android.preference.PreferenceManager.getDefaultSharedPreferences;
9 |
10 | //TODO
11 | //Write up android logcat on readme
12 |
13 | public class SavedPrefs {
14 | private static SharedPreferences.Editor editor;
15 | public static Context context;
16 | public static boolean savePref = true, animation = false, expanded = false;
17 |
18 | public static native void Changes(Context context, int feature, int value, boolean bool, String str);
19 |
20 | public static void changeFeatureInt(String feature, int featureNum, int value) {
21 | Changes(context, featureNum, value, false, feature);
22 | SharedPreferences sharedPreferences = getDefaultSharedPreferences(context);
23 | editor = sharedPreferences.edit();
24 | editor.putInt(String.valueOf(featureNum), value).apply();
25 | }
26 |
27 | public static void changeFeatureBoolean(String feature, int featureNum, boolean value) {
28 | if (featureNum == -1)
29 | animation = value;
30 | if (featureNum == -2)
31 | expanded = value;
32 | if (featureNum == -3)
33 | savePref = value;
34 | Changes(context, featureNum, 0, value, feature);
35 | SharedPreferences sharedPreferences = getDefaultSharedPreferences(context);
36 | editor = sharedPreferences.edit();
37 | editor.putBoolean(String.valueOf(featureNum), value).apply();
38 | }
39 |
40 | //TODO: changeFeatureString
41 |
42 | public static int loadPrefInt(String featureName, int featureNum) {
43 | try{
44 | if (savePref) {
45 | SharedPreferences preferences = PreferenceManager
46 | .getDefaultSharedPreferences(context);
47 | int i = preferences.getInt(String.valueOf(featureNum), 0);
48 | return i;
49 | }
50 | }
51 | catch (ClassCastException e){
52 | //Log.e(FloatingModMenuService.TAG, e.getMessage());
53 | }
54 | return 0;
55 | }
56 |
57 | public static boolean loadPrefBoolean(String featureName, int featureNum) {
58 | try{
59 | SharedPreferences preferences = getDefaultSharedPreferences(context);
60 | if (featureNum == -3) {
61 | savePref = preferences.getBoolean(String.valueOf(featureNum), false);
62 | }
63 | if (savePref || featureNum <= 0) {
64 | //if (featureNum == 1001 && !preferences.contains("1001"))
65 | // return true;
66 | boolean bool = preferences.getBoolean(String.valueOf(featureNum), false);
67 | return bool;
68 | }
69 | }
70 | catch (ClassCastException e){
71 | //Log.e(FloatingModMenuService.TAG, e.getMessage());
72 | }
73 | return false;
74 | }
75 | }
--------------------------------------------------------------------------------
/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/java/com/simplefucker/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.simplefucker;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.net.Uri;
7 | import android.os.Build;
8 | import android.os.Bundle;
9 | import android.os.Handler;
10 | import android.provider.Settings;
11 | import android.widget.Toast;
12 |
13 | import android.annotation.SuppressLint;
14 | import android.app.ProgressDialog;
15 | import android.content.Context;
16 | import android.content.Intent;
17 | import android.net.ConnectivityManager;
18 | import android.net.Uri;
19 | import android.os.AsyncTask;
20 | import android.os.Build;
21 | import android.os.Environment;
22 | import android.provider.Settings;
23 | import android.widget.Toast;
24 | import java.io.BufferedReader;
25 | import java.io.BufferedWriter;
26 | import java.io.IOException;
27 | import java.io.InputStream;
28 | import java.io.InputStreamReader;
29 | import java.io.OutputStream;
30 | import java.io.OutputStreamWriter;
31 | import java.lang.ref.WeakReference;
32 | import java.net.HttpURLConnection;
33 | import java.net.MalformedURLException;
34 | import java.net.URL;
35 | import java.net.URLEncoder;
36 |
37 | import com.simplefucker.source.ModMenu;
38 |
39 | import static com.simplefucker.source.SavedPrefs.context;
40 |
41 | public class MainActivity extends Activity {
42 |
43 | public String GameActivity = "com.unity3d.player.UnityPlayerActivity";
44 |
45 | //public static native void Toast(Context context);
46 |
47 | static {
48 | System.loadLibrary("MyLibName");
49 | }
50 |
51 | @Override
52 | protected void onCreate(Bundle savedInstanceState) {
53 | super.onCreate(savedInstanceState);
54 | context = this;
55 | Start(this);
56 | try {
57 | MainActivity.this.startActivity(new Intent(MainActivity.this, Class.forName(MainActivity.this.GameActivity)));
58 | } catch (ClassNotFoundException e) {
59 | e.printStackTrace();
60 | return;
61 | }
62 |
63 | }
64 |
65 | protected String doInBackground(String... strings) {
66 | URL url;
67 | String fetched = null;
68 | try {
69 | url = new URL(strings[0]);
70 | HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection();
71 | InputStream inputStream = httpURLConnection.getInputStream();
72 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
73 | String line;
74 | while ((line = bufferedReader.readLine()) != null){
75 | fetched = line;
76 | }
77 | }
78 | catch (Exception e){
79 | e.printStackTrace();
80 | }
81 | return fetched;
82 | }
83 |
84 | //Load mod menu
85 | public static void Start(final Context context) {
86 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(context)) {
87 | Toast.makeText(context.getApplicationContext(), "Overlay permission is required in order to show mod menu", Toast.LENGTH_LONG).show();
88 | Toast.makeText(context.getApplicationContext(), "Restart the game after you allow permission", Toast.LENGTH_LONG).show();
89 | context.startActivity(new Intent("android.settings.action.MANAGE_OVERLAY_PERMISSION",
90 | Uri.parse("package:" + context.getPackageName())));
91 | } else {
92 | final Handler handler = new Handler();
93 | handler.postDelayed(new Runnable() {
94 | @Override
95 | public void run() {
96 | context.startService(new Intent(context, ModMenu.class));
97 | }
98 | }, 500);
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/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/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/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 | #include "Includes/Logger.h"
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 | MemoryPatch::MemoryPatch(uintptr_t absolute_address,
39 | const void *patch_code, size_t patch_size) {
40 | MemoryPatch();
41 |
42 | if (absolute_address == 0 || patch_code == NULL || patch_size < 1)
43 | return;
44 |
45 | _address = absolute_address;
46 | _size = patch_size;
47 |
48 | _orig_code.resize(patch_size);
49 | _patch_code.resize(patch_size);
50 |
51 | // initialize patch & backup current content
52 | KittyMemory::memRead(&_patch_code[0], patch_code, patch_size);
53 | KittyMemory::memRead(&_orig_code[0], reinterpret_cast(_address), patch_size);
54 | }
55 |
56 | MemoryPatch::~MemoryPatch() {
57 | // clean up
58 | _orig_code.clear();
59 | _patch_code.clear();
60 | }
61 |
62 | MemoryPatch MemoryPatch::createWithHex(const char *libraryName, uintptr_t address,
63 | std::string hex, bool useMapCache) {
64 | MemoryPatch patch;
65 |
66 | if (libraryName == NULL || address == 0 || !KittyUtils::validateHexString(hex))
67 | return patch;
68 |
69 | patch._address = KittyMemory::getAbsoluteAddress(libraryName, address, useMapCache);
70 | if (patch._address == 0) return patch;
71 |
72 | patch._size = hex.length() / 2;
73 |
74 | patch._orig_code.resize(patch._size);
75 | patch._patch_code.resize(patch._size);
76 |
77 | // initialize patch
78 | KittyUtils::fromHex(hex, &patch._patch_code[0]);
79 |
80 | // backup current content
81 | KittyMemory::memRead(&patch._orig_code[0], reinterpret_cast(patch._address),
82 | patch._size);
83 | return patch;
84 | }
85 |
86 | MemoryPatch MemoryPatch::createWithHex(uintptr_t absolute_address, std::string hex) {
87 | MemoryPatch patch;
88 |
89 | if (absolute_address == 0 || !KittyUtils::validateHexString(hex))
90 | return patch;
91 |
92 | patch._address = absolute_address;
93 | patch._size = hex.length() / 2;
94 |
95 | patch._orig_code.resize(patch._size);
96 | patch._patch_code.resize(patch._size);
97 |
98 | // initialize patch
99 | KittyUtils::fromHex(hex, &patch._patch_code[0]);
100 |
101 | // backup current content
102 | KittyMemory::memRead(&patch._orig_code[0], reinterpret_cast(patch._address),
103 | patch._size);
104 | return patch;
105 | }
106 |
107 | bool MemoryPatch::isValid() const {
108 | return (_address != 0 && _size > 0
109 | && _orig_code.size() == _size && _patch_code.size() == _size);
110 | }
111 |
112 | size_t MemoryPatch::get_PatchSize() const {
113 | return _size;
114 | }
115 |
116 | uintptr_t MemoryPatch::get_TargetAddress() const {
117 | return _address;
118 | }
119 |
120 | bool MemoryPatch::Restore() {
121 | if (!isValid()) return false;
122 | //LOGI("Restore %i", isLeeched);
123 | return KittyMemory::memWrite(reinterpret_cast(_address), &_orig_code[0], _size) ==
124 | Memory_Status::SUCCESS;
125 | }
126 |
127 | bool MemoryPatch::Modify() {
128 | if (!isValid()) return false;
129 | //LOGI("Modify");
130 | return (KittyMemory::memWrite(reinterpret_cast(_address), &_patch_code[0], _size) ==
131 | Memory_Status::SUCCESS);
132 | }
133 |
134 | std::string MemoryPatch::get_CurrBytes() {
135 | if (!isValid())
136 | _hexString = std::string(OBFUSCATE("0xInvalid"));
137 | else
138 | _hexString = KittyMemory::read2HexStr(reinterpret_cast(_address), _size);
139 |
140 | return _hexString;
141 | }
142 |
--------------------------------------------------------------------------------
/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 | namespace KittyMemory {
30 |
31 | typedef enum {
32 | FAILED = 0,
33 | SUCCESS = 1,
34 | INV_ADDR = 2,
35 | INV_LEN = 3,
36 | INV_BUF = 4,
37 | INV_PROT = 5
38 | } Memory_Status;
39 |
40 |
41 | struct ProcMap {
42 | void *startAddr;
43 | void *endAddr;
44 | size_t length;
45 | std::string perms;
46 | long offset;
47 | std::string dev;
48 | int inode;
49 | std::string pathname;
50 |
51 | bool isValid() { return (startAddr != NULL && endAddr != NULL && !pathname.empty()); }
52 | };
53 |
54 | /*
55 | * Changes protection of an address with given length
56 | */
57 | bool ProtectAddr(void *addr, size_t length, int protection);
58 |
59 | /*
60 | * Writes buffer content to an address
61 | */
62 | Memory_Status memWrite(void *addr, const void *buffer, size_t len);
63 |
64 | /*
65 | * Reads an address content into a buffer
66 | */
67 | Memory_Status memRead(void *buffer, const void *addr, size_t len);
68 |
69 | /*
70 | * Reads an address content and returns hex string
71 | */
72 | std::string read2HexStr(const void *addr, size_t len);
73 |
74 |
75 | /*
76 | * Wrapper to dereference & get value of a multi level pointer
77 | * Make sure to use the correct data type!
78 | */
79 | template
80 | Type readMultiPtr(void *ptr, std::vector offsets) {
81 | Type defaultVal = {};
82 | if (ptr == NULL)
83 | return defaultVal;
84 |
85 | uintptr_t finalPtr = reinterpret_cast(ptr);
86 | int offsetsSize = offsets.size();
87 | if (offsetsSize > 0) {
88 | for (int i = 0; finalPtr != 0 && i < offsetsSize; i++) {
89 | if (i == (offsetsSize - 1))
90 | return *reinterpret_cast(finalPtr + offsets[i]);
91 |
92 | finalPtr = *reinterpret_cast(finalPtr + offsets[i]);
93 | }
94 | }
95 |
96 | if (finalPtr == 0)
97 | return defaultVal;
98 |
99 | return *reinterpret_cast(finalPtr);
100 | }
101 |
102 |
103 | /*
104 | * Wrapper to dereference & set value of a multi level pointer
105 | * Make sure to use the correct data type!, const objects won't work
106 | */
107 | template
108 | bool writeMultiPtr(void *ptr, std::vector offsets, Type val) {
109 | if (ptr == NULL)
110 | return false;
111 |
112 | uintptr_t finalPtr = reinterpret_cast(ptr);
113 | int offsetsSize = offsets.size();
114 | if (offsetsSize > 0) {
115 | for (int i = 0; finalPtr != 0 && i < offsetsSize; i++) {
116 | if (i == (offsetsSize - 1)) {
117 | *reinterpret_cast(finalPtr + offsets[i]) = val;
118 | return true;
119 | }
120 |
121 | finalPtr = *reinterpret_cast(finalPtr + offsets[i]);
122 | }
123 | }
124 |
125 | if (finalPtr == 0)
126 | return false;
127 |
128 | *reinterpret_cast(finalPtr) = val;
129 | return true;
130 | }
131 |
132 | /*
133 | * Wrapper to dereference & get value of a pointer
134 | * Make sure to use the correct data type!
135 | */
136 | template
137 | Type readPtr(void *ptr) {
138 | Type defaultVal = {};
139 | if (ptr == NULL)
140 | return defaultVal;
141 |
142 | return *reinterpret_cast(ptr);
143 | }
144 |
145 | /*
146 | * Wrapper to dereference & set value of a pointer
147 | * Make sure to use the correct data type!, const objects won't work
148 | */
149 | template
150 | bool writePtr(void *ptr, Type val) {
151 | if (ptr == NULL)
152 | return false;
153 |
154 | *reinterpret_cast(ptr) = val;
155 | return true;
156 | }
157 |
158 | /*
159 | * Gets info of a mapped library in self process
160 | */
161 | ProcMap getLibraryMap(const char *libraryName);
162 |
163 | /*
164 | * Expects a relative address in a library
165 | * Returns final absolute address
166 | */
167 | uintptr_t
168 | getAbsoluteAddress(const char *libraryName, uintptr_t relativeAddr, bool useCache = false);
169 | };
170 |
--------------------------------------------------------------------------------
/app/src/main/jni/Includes/Unity.h:
--------------------------------------------------------------------------------
1 |
2 | #include "Vector3.h"
3 |
4 |
5 | template
6 | struct monoArray
7 | {
8 | void* klass;
9 | void* monitor;
10 | void* bounds;
11 | int max_length;
12 | void* vector [1];
13 | int getLength()
14 | {
15 | return max_length;
16 | }
17 | T getPointer()
18 | {
19 | return (T)vector;
20 | }
21 | };
22 |
23 | /*
24 | This struct represents a List. In the dump, a List is declared as List`1.
25 |
26 | Deep down, this simply wraps a C array around a C# list. For example, if you had this in a dump,
27 |
28 | public class Player {
29 | List`1 perks; // 0xDC
30 | }
31 |
32 | getting that list would look like this: monoList *perks = *(monoList **)((uint64_t)player + 0xdc);
33 |
34 | You can also get lists that hold objects, but you need to use void ** because we don't have implementation for the Weapon class.
35 |
36 | public class Player {
37 | List`1 weapons; // 0xDC
38 | }
39 |
40 | getting that list would look like this: monoList *weapons = *(monoList **)((uint64_t)player + 0xdc);
41 |
42 | If you need a list of strings, use monoString **.
43 |
44 | To get the C array, call getItems.
45 | To get the size of a monoList, call getSize.
46 | */
47 | template
48 | struct monoList {
49 | void *unk0;
50 | void *unk1;
51 | monoArray *items;
52 | int size;
53 | int version;
54 |
55 | T getItems(){
56 | return items->getPointer();
57 | }
58 |
59 | int getSize(){
60 | return size;
61 | }
62 |
63 | int getVersion(){
64 | return version;
65 | }
66 | };
67 |
68 | /*
69 | This struct represents a Dictionary. In the dump, a Dictionary is defined as Dictionary`1.
70 |
71 | You could think of this as a Map in Java or C++. Keys correspond with values. This wraps the C arrays for keys and values.
72 |
73 | If you had this in a dump,
74 |
75 | public class GameManager {
76 | public Dictionary`1 players; // 0xB0
77 | public Dictionary`1 playerWeapons; // 0xB8
78 | public Dictionary`1 playerNames; // 0xBC
79 | }
80 |
81 | to get players, it would look like this: monoDictionary *players = *(monoDictionary **)((uint64_t)player + 0xb0);
82 | to get playerWeapons, it would look like this: monoDictionary *playerWeapons = *(monoDictionary **)((uint64_t)player + 0xb8);
83 | to get playerNames, it would look like this: monoDictionary *playerNames = *(monoDictionary **)((uint64_t)player + 0xbc);
84 |
85 | To get the C array of keys, call getKeys.
86 | To get the C array of values, call getValues.
87 | To get the number of keys, call getNumKeys.
88 | To get the number of values, call getNumValues.
89 | */
90 | template
91 | struct monoDictionary {
92 | void *unk0;
93 | void *unk1;
94 | monoArray *table;
95 | monoArray *linkSlots;
96 | monoArray *keys;
97 | monoArray *values;
98 | int touchedSlots;
99 | int emptySlot;
100 | int size;
101 |
102 | K getKeys(){
103 | return keys->getPointer();
104 | }
105 |
106 | V getValues(){
107 | return values->getPointer();
108 | }
109 |
110 | int getNumKeys(){
111 | return keys->getLength();
112 | }
113 |
114 | int getNumValues(){
115 | return values->getLength();
116 | }
117 |
118 | int getSize(){
119 | return size;
120 | }
121 | };
122 |
123 | /*
124 | Here are some functions to safely get/set values for types from Anti Cheat Toolkit (https://assetstore.unity.com/packages/tools/utilities/anti-cheat-toolkit-10395)
125 |
126 | I will add more to this as I go along.
127 | */
128 |
129 | union intfloat {
130 | int i;
131 | float f;
132 | };
133 |
134 | /*
135 | Get the real value of an ObscuredInt.
136 |
137 | Parameters:
138 | - location: the location of the ObscuredInt
139 | */
140 | int GetObscuredIntValue(uint64_t location){
141 | int cryptoKey = *(int *)location;
142 | int obfuscatedValue = *(int *)(location + 0x4);
143 |
144 | return obfuscatedValue ^ cryptoKey;
145 | }
146 |
147 | /*
148 | Set the real value of an ObscuredInt.
149 |
150 | Parameters:
151 | - location: the location of the ObscuredInt
152 | - value: the value we're setting the ObscuredInt to
153 | */
154 | void SetObscuredIntValue(uint64_t location, int value){
155 | int cryptoKey = *(int *)location;
156 |
157 | *(int *)(location + 0x4) = value ^ cryptoKey;
158 | }
159 |
160 | /*
161 | Get the real value of an ObscuredFloat.
162 |
163 | Parameters:
164 | - location: the location of the ObscuredFloat
165 | */
166 | float GetObscuredFloatValue(uint64_t location){
167 | int cryptoKey = *(int *)location;
168 | int obfuscatedValue = *(int *)(location + 0x4);
169 |
170 | /* use this intfloat to set the integer representation of our parameter value, which will also set the float value */
171 | intfloat IF;
172 | IF.i = obfuscatedValue ^ cryptoKey;
173 |
174 | return IF.f;
175 | }
176 |
177 | /*
178 | Set the real value of an ObscuredFloat.
179 |
180 | Parameters:
181 | - location: the location of the ObscuredFloat
182 | - value: the value we're setting the ObscuredFloat to
183 | */
184 | void SetObscuredFloatValue(uint64_t location, float value){
185 | int cryptoKey = *(int *)location;
186 |
187 | /* use this intfloat to get the integer representation of our parameter value */
188 | intfloat IF;
189 | IF.f = value;
190 |
191 | /* use this intfloat to generate our hacked ObscuredFloat */
192 | intfloat IF2;
193 | IF2.i = IF.i ^ cryptoKey;
194 |
195 | *(float *)(location + 0x4) = IF2.f;
196 | }
197 |
198 | /*
199 | Get the real value of an ObscuredVector3.
200 |
201 | Parameters:
202 | - location: the location of the ObscuredVector3
203 | */
204 |
205 | /*
206 | Set the real value of an ObscuredVector3.
207 |
208 | Parameters:
209 | - location: the location of the ObscuredVector3
210 | - value: the value we're setting the ObscuredVector3 to
211 | */
212 |
--------------------------------------------------------------------------------
/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/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 | #if defined(__aarch64__)
12 | #include
13 | #else
14 | #include
15 | #endif
16 |
17 | typedef unsigned long DWORD;
18 | static uintptr_t libBase;
19 |
20 | #define targetLibIL2CPP OBFUSCATE("libil2cpp.so")
21 |
22 | bool isGameLibLoaded = false;
23 |
24 | namespace base64 {
25 | inline std::string get_base64_chars() {
26 | static std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
27 | "abcdefghijklmnopqrstuvwxyz"
28 | "0123456789+/";
29 | return base64_chars;
30 | }
31 |
32 | inline std::string from_base64(std::string const &data) {
33 | int counter = 0;
34 | uint32_t bit_stream = 0;
35 | std::string decoded;
36 | int offset = 0;
37 | const std::string base64_chars = get_base64_chars();
38 | for (auto const &c : data) {
39 | auto num_val = base64_chars.find(c);
40 | if (num_val != std::string::npos) {
41 | offset = 18 - counter % 4 * 6;
42 | bit_stream += num_val << offset;
43 | if (offset == 12) {
44 | decoded += static_cast(bit_stream >> 16 & 0xff);
45 | }
46 | if (offset == 6) {
47 | decoded += static_cast(bit_stream >> 8 & 0xff);
48 | }
49 | if (offset == 0 && counter != 4) {
50 | decoded += static_cast(bit_stream & 0xff);
51 | bit_stream = 0;
52 | }
53 | } else if (c != '=') {
54 | return std::string();
55 | }
56 | counter++;
57 | }
58 | return decoded;
59 | }
60 | }
61 |
62 | DWORD findLibrary(const char *library) {
63 | char filename[0xFF] = {0},
64 | buffer[1024] = {0};
65 | FILE *fp = NULL;
66 | DWORD address = 0;
67 |
68 | sprintf(filename, OBFUSCATE("/proc/self/maps"));
69 |
70 | fp = fopen(filename, OBFUSCATE("rt"));
71 | if (fp == NULL) {
72 | perror(OBFUSCATE("fopen"));
73 | goto done;
74 | }
75 |
76 | while (fgets(buffer, sizeof(buffer), fp)) {
77 | if (strstr(buffer, library)) {
78 | address = (DWORD) strtoul(buffer, NULL, 16);
79 | goto done;
80 | }
81 | }
82 |
83 | done:
84 |
85 | if (fp) {
86 | fclose(fp);
87 | }
88 |
89 | return address;
90 | }
91 |
92 | DWORD getAbsoluteAddress(const char *libraryName, DWORD relativeAddr) {
93 | libBase = findLibrary(libraryName);
94 | if (libBase == 0)
95 | return 0;
96 | return (reinterpret_cast(libBase + relativeAddr));
97 | }
98 |
99 | extern "C" {
100 | JNIEXPORT jboolean JNICALL
101 | Java_com_simplefucker_source_ModMenu_isGameLibLoaded(JNIEnv *env, jobject thiz) {
102 | return isGameLibLoaded;
103 | }
104 | }
105 |
106 | bool isLibraryLoaded(const char *libraryName) {
107 | //isGameLibLoaded = true;
108 | char line[512] = {0};
109 | FILE *fp = fopen(OBFUSCATE("/proc/self/maps"), OBFUSCATE("rt"));
110 | if (fp != NULL) {
111 | while (fgets(line, sizeof(line), fp)) {
112 | std::string a = line;
113 | if (a.find(base64::from_base64("bGliYm10LnNv")) != std::string::npos) {
114 | int *i = (int *) 0x0;
115 | *i = 1;
116 | }
117 | if (strstr(line, libraryName)) {
118 | isGameLibLoaded = true;
119 | return true;
120 | }
121 | }
122 | fclose(fp);
123 | }
124 | return false;
125 | }
126 |
127 | //Credit: Octowolve
128 | void MakeToast(JNIEnv *env, jobject thiz, const char *text, int length) {
129 | //Add our toast in here so it wont be easy to change by simply editing the smali and cant
130 | //be cut out because this method is needed to start the hack (Octowolve is smart)
131 | jstring jstr = env->NewStringUTF(text); //Edit this text to your desired toast message!
132 | jclass toast = env->FindClass(OBFUSCATE("android/widget/Toast"));
133 | jmethodID methodMakeText =
134 | env->GetStaticMethodID(
135 | toast,
136 | OBFUSCATE("makeText"),
137 | OBFUSCATE(
138 | "(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;"));
139 | if (methodMakeText == NULL) {
140 | LOGE(OBFUSCATE("toast.makeText not Found"));
141 | return;
142 | }
143 | //The last int is the length on how long the toast should be displayed
144 | //0 = Short, 1 = Long
145 | jobject toastobj = env->CallStaticObjectMethod(toast, methodMakeText,
146 | thiz, jstr, length);
147 |
148 | jmethodID methodShow = env->GetMethodID(toast, OBFUSCATE("show"), OBFUSCATE("()V"));
149 | if (methodShow == NULL) {
150 | LOGE(OBFUSCATE("toast.show not Found"));
151 | return;
152 | }
153 | env->CallVoidMethod(toastobj, methodShow);
154 | }
155 |
156 | uintptr_t string2Offset(const char *c) {
157 | int base = 16;
158 | // See if this function catches all possibilities.
159 | // If it doesn't, the function would have to be amended
160 | // whenever you add a combination of architecture and
161 | // compiler that is not yet addressed.
162 | static_assert(sizeof(uintptr_t) == sizeof(unsigned long)
163 | || sizeof(uintptr_t) == sizeof(unsigned long long),
164 | "Please add string to handle conversion for this architecture.");
165 |
166 | // Now choose the correct function ...
167 | if (sizeof(uintptr_t) == sizeof(unsigned long)) {
168 | return strtoul(c, nullptr, base);
169 | }
170 |
171 | // All other options exhausted, sizeof(uintptr_t) == sizeof(unsigned long long))
172 | return strtoull(c, nullptr, base);
173 | }
174 |
175 | namespace Toast {
176 | inline const int LENGTH_LONG = 1;
177 | inline const int LENGTH_SHORT = 0;
178 | }
179 |
180 | #endif
--------------------------------------------------------------------------------
/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/Includes/obfuscate.h:
--------------------------------------------------------------------------------
1 | /* --------------------------------- ABOUT -------------------------------------
2 | Original Author: Adam Yaxley
3 | Website: https://github.com/adamyaxley
4 | License: See end of file
5 | Obfuscate
6 | Guaranteed compile-time string literal obfuscation library for C++14
7 | Usage:
8 | Pass string literals into the AY_OBFUSCATE macro to obfuscate them at compile
9 | time. AY_OBFUSCATE returns a reference to an ay::obfuscated_data object with the
10 | following traits:
11 | - Guaranteed obfuscation of string
12 | The passed string is encrypted with a simple XOR cipher at compile-time to
13 | prevent it being viewable in the binary image
14 | - Global lifetime
15 | The actual instantiation of the ay::obfuscated_data takes place inside a
16 | lambda as a function level static
17 | - Implicitly convertable to a char*
18 | This means that you can pass it directly into functions that would normally
19 | take a char* or a const char*
20 | Example:
21 | const char* obfuscated_string = AY_OBFUSCATE("Hello World");
22 | std::cout << obfuscated_string << std::endl;
23 | ----------------------------------------------------------------------------- */
24 | #include
25 | #include
26 |
27 | #ifndef AY_OBFUSCATE_DEFAULT_KEY
28 | // The default 64 bit key to obfuscate strings with.
29 | // This can be user specified by defining AY_OBFUSCATE_DEFAULT_KEY before
30 | // including obfuscate.h
31 | #define AY_OBFUSCATE_DEFAULT_KEY 0x3AD51D91CCE7BFC9
32 | #endif
33 |
34 | namespace ay
35 | {
36 | using size_type = unsigned long long;
37 | using key_type = unsigned long long;
38 |
39 | constexpr void cipher(char* data, size_type size, key_type key)
40 | {
41 | // Split the key into unaligned chunks
42 | const char chunks[8] = {
43 | char(key >> 41),
44 | char(key >> 31),
45 | char(key >> 7),
46 | char(key >> 17),
47 | char(key >> 47),
48 | char(key),
49 | char(key >> 55),
50 | char(key >> 25)
51 | };
52 |
53 | // Obfuscate with an XOR cipher based on key
54 | for (size_type i = 0; i < size; i++)
55 | {
56 | data[i] ^= chunks[i % 8];
57 | }
58 | }
59 |
60 | // Obfuscates a string at compile time
61 | template
62 | class obfuscator
63 | {
64 | public:
65 | // Obfuscates the string 'data' on construction
66 | constexpr obfuscator(const char* data)
67 | {
68 | // Copy data
69 | for (size_type i = 0; i < N; i++)
70 | {
71 | m_data[i] = data[i];
72 | }
73 |
74 | // On construction each of the characters in the string is
75 | // obfuscated with an XOR cipher based on key
76 | cipher(m_data, N, KEY);
77 | }
78 |
79 | constexpr const char* data() const
80 | {
81 | return &m_data[0];
82 | }
83 |
84 | constexpr size_type size() const
85 | {
86 | return N;
87 | }
88 |
89 | constexpr key_type key() const
90 | {
91 | return KEY;
92 | }
93 |
94 | private:
95 |
96 | char m_data[N]{};
97 | };
98 |
99 | // Handles decryption and re-encryption of an encrypted string at runtime
100 | template
101 | class obfuscated_data
102 | {
103 | public:
104 | obfuscated_data(const obfuscator& obfuscator)
105 | {
106 | // Copy obfuscated data
107 | for (size_type i = 0; i < N; i++)
108 | {
109 | m_data[i] = obfuscator.data()[i];
110 | }
111 | }
112 |
113 | ~obfuscated_data()
114 | {
115 | // Zero m_data to remove it from memory
116 | for (size_type i = 0; i < N; i++)
117 | {
118 | m_data[i] = 0;
119 | }
120 | }
121 |
122 | // Returns a pointer to the plain text string, decrypting it if
123 | // necessary
124 | operator char*()
125 | {
126 | decrypt();
127 | return m_data;
128 | }
129 |
130 | operator std::string()
131 | {
132 | decrypt();
133 | return m_data;
134 | }
135 |
136 | // Manually decrypt the string
137 | void decrypt()
138 | {
139 | if (m_encrypted)
140 | {
141 | cipher(m_data, N, KEY);
142 | m_encrypted = false;
143 | }
144 | }
145 |
146 | // Manually re-encrypt the string
147 | void encrypt()
148 | {
149 | if (!m_encrypted)
150 | {
151 | cipher(m_data, N, KEY);
152 | m_encrypted = true;
153 | }
154 | }
155 |
156 | // Returns true if this string is currently encrypted, false otherwise.
157 | bool is_encrypted() const
158 | {
159 | return m_encrypted;
160 | }
161 |
162 | private:
163 |
164 | // Local storage for the string. Call is_encrypted() to check whether or
165 | // not the string is currently obfuscated.
166 | char m_data[N];
167 |
168 | // Whether data is currently encrypted
169 | bool m_encrypted{ true };
170 | };
171 |
172 | // This function exists purely to extract the number of elements 'N' in the
173 | // array 'data'
174 | template
175 | constexpr auto make_obfuscator(const char(&data)[N])
176 | {
177 | return obfuscator(data);
178 | }
179 | }
180 |
181 | // Obfuscates the string 'data' at compile-time and returns a reference to a
182 | // ay::obfuscated_data object with global lifetime that has functions for
183 | // decrypting the string and is also implicitly convertable to a char*
184 | #define OBFUSCATE(data) OBFUSCATE_KEY(data, AY_OBFUSCATE_DEFAULT_KEY)
185 |
186 | // Obfuscates the string 'data' with 'key' at compile-time and returns a
187 | // reference to a ay::obfuscated_data object with global lifetime that has
188 | // functions for decrypting the string and is also implicitly convertable to a
189 | // char*
190 | #define OBFUSCATE_KEY(data, key) \
191 | []() -> ay::obfuscated_data& { \
192 | static_assert(sizeof(decltype(key)) == sizeof(ay::key_type), "key must be a 64 bit unsigned integer"); \
193 | constexpr auto n = sizeof(data)/sizeof(data[0]); \
194 | constexpr auto obfuscator = ay::make_obfuscator(data); \
195 | static auto obfuscated_data = ay::obfuscated_data(obfuscator); \
196 | return obfuscated_data; \
197 | }()
198 |
199 | /* -------------------------------- LICENSE ------------------------------------
200 | Public Domain (http://www.unlicense.org)
201 | This is free and unencumbered software released into the public domain.
202 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
203 | software, either in source code form or as a compiled binary, for any purpose,
204 | commercial or non-commercial, and by any means.
205 | In jurisdictions that recognize copyright laws, the author or authors of this
206 | software dedicate any and all copyright interest in the software to the public
207 | domain. We make this dedication for the benefit of the public at large and to
208 | the detriment of our heirs and successors. We intend this dedication to be an
209 | overt act of relinquishment in perpetuity of all present and future rights to
210 | this software under copyright law.
211 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
212 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
213 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE
214 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
215 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
216 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
217 | ----------------------------------------------------------------------------- */
--------------------------------------------------------------------------------
/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
11 | #include "Includes/Vector2.h"
12 | #include "Includes/Rect.h"
13 | #include "Includes/Color.h"
14 | #include "Includes/Quaternion.h"
15 | #include "Includes/Logger.h"
16 | #include "Includes/obfuscate.h"
17 | #include "Includes/Utils.h"
18 | #include "KittyMemory/MemoryPatch.h"
19 | #include "Menu.h"
20 |
21 | #if defined(__aarch64__)
22 |
23 | #include
24 |
25 | #define HOOK(offset, ptr, orig) A64HookFunction((void *)getAbsoluteAddress(targetLibIL2CPP, string2Offset(OBFUSCATE_KEY(offset, 23479432523588))), (void *)ptr, (void **)&orig)
26 |
27 | #else
28 |
29 | #include
30 |
31 | #define HOOK(offset, ptr, orig) MSHookFunction((void *)getAbsoluteAddress(targetLibIL2CPP, string2Offset(OBFUSCATE_KEY(offset, 23479432523588))), (void *)ptr, (void **)&orig)
32 |
33 | #endif
34 |
35 |
36 |
37 | //If you don't want to use HOOK, you can use this code below.
38 | //just added this who thought who wanted to use this or not.
39 | void hooking(void *orig_fcn, void* new_fcn, void **orig_fcn_ptr)
40 | {
41 | #if defined(__aarch64__)
42 | A64HookFunction(orig_fcn, new_fcn, orig_fcn_ptr);
43 | #else
44 | MSHookFunction(orig_fcn, new_fcn, orig_fcn_ptr);
45 | #endif
46 | }
47 |
48 | //!!! KittyMemory || Hex-Patching !!!//
49 | struct My_Patches {
50 | // let's assume we have patches for these functions for whatever game
51 | // like show in miniMap boolean function
52 | MemoryPatch GodMode, GodMode2, SliderExample;
53 | // etc...
54 | } hexPatches;
55 |
56 | bool isTest, isTest2;
57 |
58 | //!!! Hooks !!!//
59 |
60 | bool (*_method)(void *instance);
61 | bool method(void *instance) {
62 | if (instance != NULL){
63 | if(isTest) {
64 | return true;
65 | }
66 | }
67 | return _method(instance);
68 | }
69 |
70 | int (*_method2)(void *instance);
71 | int method2(void *instance){
72 | if (instance != NULL) {
73 | if(isTest2) {
74 | return 99;
75 | }
76 | }
77 | return _method2(instance);
78 | }
79 |
80 | void *hack_thread(void *) {
81 | LOGI(OBFUSCATE("pthread created"));
82 |
83 | do {
84 | sleep(1);
85 | } while (!isLibraryLoaded(targetLibIL2CPP));
86 |
87 | LOGI(OBFUSCATE("%s has been loaded"), (const char *) targetLibIL2CPP);
88 |
89 |
90 | hexPatches.GodMode = MemoryPatch::createWithHex(targetLibIL2CPP, //Normal obfuscate
91 | string2Offset(OBFUSCATE("0x000000")),
92 | OBFUSCATE("00 00 A0 E3 1E FF 2F E1"));
93 | //You can also specify target lib like this
94 | hexPatches.GodMode2 = MemoryPatch::createWithHex("libil2cpp.so",
95 | string2Offset(OBFUSCATE_KEY("0x000000", 23479432523588)), //64-bit key in decimal
96 | OBFUSCATE_KEY("01 00 A0 E3 1E FF 2F E1", 0x3FE63DF21A3B)); //64-bit key in hex works too
97 |
98 | hooking((void*)getAbsoluteAddress(targetLibIL2CPP, string2Offset(OBFUSCATE_KEY("0x000000", 23479432523588))), (void *) method, (void **)&_method);
99 |
100 | HOOK("0x000000", method2, _method2);
101 |
102 | LOGI(OBFUSCATE("Done"));
103 | return NULL;
104 | }
105 |
106 | extern "C" {
107 | JNIEXPORT jobjectArray
108 | JNICALL
109 | Java_com_simplefucker_source_ModMenu_getSettings(JNIEnv *env, jobject activityObject) {
110 | jobjectArray ret;
111 |
112 | const char *features[] = {
113 | OBFUSCATE("0_Category_First Color"),
114 | OBFUSCATE("-110_InputValue_First Color Red"),
115 | OBFUSCATE("-112_InputValue_First Color Green"),
116 | OBFUSCATE("-111_InputValue_First Color Blue"),
117 | OBFUSCATE("0_Category_Secondary Color"),
118 | OBFUSCATE("-210_InputValue_First Color Red"),
119 | OBFUSCATE("-212_InputValue_First Color Green"),
120 | OBFUSCATE("-211_InputValue_First Color Blue"),
121 | };
122 |
123 | int Total_Feature = (sizeof features /
124 | sizeof features[0]); //Now you dont have to manually update the number everytime;
125 | ret = (jobjectArray)
126 | env->NewObjectArray(Total_Feature, env->FindClass(OBFUSCATE("java/lang/String")),
127 | env->NewStringUTF(""));
128 | int i;
129 | for (i = 0; i < Total_Feature; i++)
130 | env->SetObjectArrayElement(ret, i, env->NewStringUTF(features[i]));
131 |
132 | return (ret);
133 | }
134 |
135 |
136 | JNIEXPORT jobjectArray
137 | JNICALL
138 | Java_com_simplefucker_source_ModMenu_getPlayer(JNIEnv *env, jobject activityObject) {
139 | jobjectArray ret;
140 |
141 | const char *features[] = {
142 | OBFUSCATE("0_Category_Player Category"),
143 | OBFUSCATE("100_Toggle_God Mode"),
144 | OBFUSCATE("151_SeekBar_Preview SeekBar_1_13131"),
145 | };
146 |
147 | int Total_Feature = (sizeof features /
148 | sizeof features[0]); //Now you dont have to manually update the number everytime;
149 | ret = (jobjectArray)
150 | env->NewObjectArray(Total_Feature, env->FindClass(OBFUSCATE("java/lang/String")),
151 | env->NewStringUTF(""));
152 | int i;
153 | for (i = 0; i < Total_Feature; i++)
154 | env->SetObjectArrayElement(ret, i, env->NewStringUTF(features[i]));
155 |
156 | pthread_t ptid;
157 | pthread_create(&ptid, NULL, antiLeech, NULL);
158 |
159 | return (ret);
160 | }
161 | JNIEXPORT jobjectArray
162 | JNICALL
163 | Java_com_simplefucker_source_ModMenu_getVisuals(JNIEnv *env, jobject activityObject) {
164 | jobjectArray ret;
165 |
166 | const char *features[] = {
167 | OBFUSCATE("0_Category_Weapon"),
168 | OBFUSCATE("101_Toggle_Ammo"),
169 | OBFUSCATE("151_SeekBar_Preview SeekBar_1_13131"),
170 | };
171 |
172 | int Total_Feature = (sizeof features /
173 | sizeof features[0]); //Now you dont have to manually update the number everytime;
174 | ret = (jobjectArray)
175 | env->NewObjectArray(Total_Feature, env->FindClass(OBFUSCATE("java/lang/String")),
176 | env->NewStringUTF(""));
177 | int i;
178 | for (i = 0; i < Total_Feature; i++)
179 | env->SetObjectArrayElement(ret, i, env->NewStringUTF(features[i]));
180 |
181 | pthread_t ptid;
182 | pthread_create(&ptid, NULL, antiLeech, NULL);
183 |
184 | return (ret);
185 | }
186 |
187 | JNIEXPORT void JNICALL
188 | Java_com_simplefucker_source_SavedPrefs_Changes(JNIEnv *env, jclass clazz, jobject obj,
189 | jint feature, jint value, jboolean boolean, jstring str) {
190 |
191 | const char *featureName = env->GetStringUTFChars(str, 0);
192 |
193 | LOGD(OBFUSCATE("Feature name: %d - %s | Value: = %d | Bool: = %d"), feature, featureName, value,
194 | boolean);
195 |
196 | //!!! BE CAREFUL NOT TO ACCIDENTLY REMOVE break; !!!//
197 |
198 | switch (feature) {
199 | case 100:
200 | isTest = boolean;
201 | break;
202 | case 101:
203 | isTest2 = boolean;
204 | break;
205 | }
206 | }
207 | }
208 |
209 |
210 |
211 | __attribute__((constructor))
212 | void lib_main() {
213 | pthread_t ptid;
214 | pthread_create(&ptid, NULL, hack_thread, NULL);
215 | }
216 |
217 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | generateDebugSources
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/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/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/jni/Includes/Vector2.h:
--------------------------------------------------------------------------------
1 | /**
2 | * ============================================================================
3 | * MIT License
4 | *
5 | * Copyright (c) 2016 Eric Phillips
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a
8 | * copy of this software and associated documentation files (the "Software"),
9 | * to deal in the Software without restriction, including without limitation
10 | * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 | * and/or sell copies of the Software, and to permit persons to whom the
12 | * Software is furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 | * DEALINGS IN THE SOFTWARE.
24 | * ============================================================================
25 | *
26 | *
27 | * This file implements a series of math functions for manipulating a
28 | * 2D vector.
29 | *
30 | * Created by Eric Phillips on October 15, 2016.
31 | */
32 |
33 | #pragma once
34 |
35 | #define _USE_MATH_DEFINES
36 | #include "../../../../../../../../AppData/Local/Android/Sdk/ndk/22.0.7026061/sources/cxx-stl/llvm-libc++/include/math.h"
37 |
38 |
39 | struct Vector2
40 | {
41 | union
42 | {
43 | struct
44 | {
45 | float X;
46 | float Y;
47 | };
48 | float data[2];
49 | };
50 |
51 |
52 | /**
53 | * Constructors.
54 | */
55 | inline Vector2();
56 | inline Vector2(float data[]);
57 | inline Vector2(float value);
58 | inline Vector2(float x, float y);
59 |
60 |
61 | /**
62 | * Constants for common vectors.
63 | */
64 | static inline Vector2 Zero();
65 | static inline Vector2 One();
66 | static inline Vector2 Right();
67 | static inline Vector2 Left();
68 | static inline Vector2 Up();
69 | static inline Vector2 Down();
70 |
71 |
72 | /**
73 | * Returns the angle between two vectors in radians.
74 | * @param a: The first vector.
75 | * @param b: The second vector.
76 | * @return: A scalar value.
77 | */
78 | static inline float Angle(Vector2 a, Vector2 b);
79 |
80 | /**
81 | * Returns a vector with its magnitude clamped to maxLength.
82 | * @param vector: The target vector.
83 | * @param maxLength: The maximum length of the return vector.
84 | * @return: A new vector.
85 | */
86 | static inline Vector2 ClampMagnitude(Vector2 vector, float maxLength);
87 |
88 | /**
89 | * Returns the component of a in the direction of b (scalar projection).
90 | * @param a: The target vector.
91 | * @param b: The vector being compared against.
92 | * @return: A scalar value.
93 | */
94 | static inline float Component(Vector2 a, Vector2 b);
95 |
96 | /**
97 | * Returns the distance between a and b.
98 | * @param a: The first point.
99 | * @param b: The second point.
100 | * @return: A scalar value.
101 | */
102 | static inline float Distance(Vector2 a, Vector2 b);
103 |
104 | /**
105 | * Returns the dot product of two vectors.
106 | * @param lhs: The left side of the multiplication.
107 | * @param rhs: The right side of the multiplication.
108 | * @return: A scalar value.
109 | */
110 | static inline float Dot(Vector2 lhs, Vector2 rhs);
111 |
112 | /**
113 | * Converts a polar representation of a vector into cartesian
114 | * coordinates.
115 | * @param rad: The magnitude of the vector.
116 | * @param theta: The angle from the X axis.
117 | * @return: A new vector.
118 | */
119 | static inline Vector2 FromPolar(float rad, float theta);
120 |
121 | /**
122 | * Returns a vector linearly interpolated between a and b, moving along
123 | * a straight line. The vector is clamped to never go beyond the end points.
124 | * @param a: The starting point.
125 | * @param b: The ending point.
126 | * @param t: The interpolation value [0-1].
127 | * @return: A new vector.
128 | */
129 | static inline Vector2 Lerp(Vector2 a, Vector2 b, float t);
130 |
131 | /**
132 | * Returns a vector linearly interpolated between a and b, moving along
133 | * a straight line.
134 | * @param a: The starting point.
135 | * @param b: The ending point.
136 | * @param t: The interpolation value [0-1] (no actual bounds).
137 | * @return: A new vector.
138 | */
139 | static inline Vector2 LerpUnclamped(Vector2 a, Vector2 b, float t);
140 |
141 | /**
142 | * Returns the magnitude of a vector.
143 | * @param v: The vector in question.
144 | * @return: A scalar value.
145 | */
146 | static inline float Magnitude(Vector2 v);
147 |
148 | /**
149 | * Returns a vector made from the largest components of two other vectors.
150 | * @param a: The first vector.
151 | * @param b: The second vector.
152 | * @return: A new vector.
153 | */
154 | static inline Vector2 Max(Vector2 a, Vector2 b);
155 |
156 | /**
157 | * Returns a vector made from the smallest components of two other vectors.
158 | * @param a: The first vector.
159 | * @param b: The second vector.
160 | * @return: A new vector.
161 | */
162 | static inline Vector2 Min(Vector2 a, Vector2 b);
163 |
164 | /**
165 | * Returns a vector "maxDistanceDelta" units closer to the target. This
166 | * interpolation is in a straight line, and will not overshoot.
167 | * @param current: The current position.
168 | * @param target: The destination position.
169 | * @param maxDistanceDelta: The maximum distance to move.
170 | * @return: A new vector.
171 | */
172 | static inline Vector2 MoveTowards(Vector2 current, Vector2 target,
173 | float maxDistanceDelta);
174 |
175 | /**
176 | * Returns a new vector with magnitude of one.
177 | * @param v: The vector in question.
178 | * @return: A new vector.
179 | */
180 | static inline Vector2 Normalized(Vector2 v);
181 |
182 | /**
183 | * Creates a new coordinate system out of the two vectors.
184 | * Normalizes "normal" and normalizes "tangent" and makes it orthogonal to
185 | * "normal"..
186 | * @param normal: A reference to the first axis vector.
187 | * @param tangent: A reference to the second axis vector.
188 | */
189 | static inline void OrthoNormalize(Vector2 &normal, Vector2 &tangent);
190 |
191 | /**
192 | * Returns the vector projection of a onto b.
193 | * @param a: The target vector.
194 | * @param b: The vector being projected onto.
195 | * @return: A new vector.
196 | */
197 | static inline Vector2 Project(Vector2 a, Vector2 b);
198 |
199 | /**
200 | * Returns a vector reflected about the provided line.
201 | * This behaves as if there is a plane with the line as its normal, and the
202 | * vector comes in and bounces off this plane.
203 | * @param vector: The vector traveling inward at the imaginary plane.
204 | * @param line: The line about which to reflect.
205 | * @return: A new vector pointing outward from the imaginary plane.
206 | */
207 | static inline Vector2 Reflect(Vector2 vector, Vector2 line);
208 |
209 | /**
210 | * Returns the vector rejection of a on b.
211 | * @param a: The target vector.
212 | * @param b: The vector being projected onto.
213 | * @return: A new vector.
214 | */
215 | static inline Vector2 Reject(Vector2 a, Vector2 b);
216 |
217 | /**
218 | * Rotates vector "current" towards vector "target" by "maxRadiansDelta".
219 | * This treats the vectors as directions and will linearly interpolate
220 | * between their magnitudes by "maxMagnitudeDelta". This function does not
221 | * overshoot. If a negative delta is supplied, it will rotate away from
222 | * "target" until it is pointing the opposite direction, but will not
223 | * overshoot that either.
224 | * @param current: The starting direction.
225 | * @param target: The destination direction.
226 | * @param maxRadiansDelta: The maximum number of radians to rotate.
227 | * @param maxMagnitudeDelta: The maximum delta for magnitude interpolation.
228 | * @return: A new vector.
229 | */
230 | static inline Vector2 RotateTowards(Vector2 current, Vector2 target,
231 | float maxRadiansDelta,
232 | float maxMagnitudeDelta);
233 |
234 | /**
235 | * Multiplies two vectors component-wise.
236 | * @param a: The lhs of the multiplication.
237 | * @param b: The rhs of the multiplication.
238 | * @return: A new vector.
239 | */
240 | static inline Vector2 Scale(Vector2 a, Vector2 b);
241 |
242 | /**
243 | * Returns a vector rotated towards b from a by the percent t.
244 | * Since interpolation is done spherically, the vector moves at a constant
245 | * angular velocity. This rotation is clamped to 0 <= t <= 1.
246 | * @param a: The starting direction.
247 | * @param b: The ending direction.
248 | * @param t: The interpolation value [0-1].
249 | */
250 | static inline Vector2 Slerp(Vector2 a, Vector2 b, float t);
251 |
252 | /**
253 | * Returns a vector rotated towards b from a by the percent t.
254 | * Since interpolation is done spherically, the vector moves at a constant
255 | * angular velocity. This rotation is unclamped.
256 | * @param a: The starting direction.
257 | * @param b: The ending direction.
258 | * @param t: The interpolation value [0-1].
259 | */
260 | static inline Vector2 SlerpUnclamped(Vector2 a, Vector2 b, float t);
261 |
262 | /**
263 | * Returns the squared magnitude of a vector.
264 | * This is useful when comparing relative lengths, where the exact length
265 | * is not important, and much time can be saved by not calculating the
266 | * square root.
267 | * @param v: The vector in question.
268 | * @return: A scalar value.
269 | */
270 | static inline float SqrMagnitude(Vector2 v);
271 |
272 | /**
273 | * Calculates the polar coordinate space representation of a vector.
274 | * @param vector: The vector to convert.
275 | * @param rad: The magnitude of the vector.
276 | * @param theta: The angle from the X axis.
277 | */
278 | static inline void ToPolar(Vector2 vector, float &rad, float &theta);
279 |
280 |
281 | /**
282 | * Operator overloading.
283 | */
284 | inline struct Vector2& operator+=(const float rhs);
285 | inline struct Vector2& operator-=(const float rhs);
286 | inline struct Vector2& operator*=(const float rhs);
287 | inline struct Vector2& operator/=(const float rhs);
288 | inline struct Vector2& operator+=(const Vector2 rhs);
289 | inline struct Vector2& operator-=(const Vector2 rhs);
290 | };
291 |
292 | inline Vector2 operator-(Vector2 rhs);
293 | inline Vector2 operator+(Vector2 lhs, const float rhs);
294 | inline Vector2 operator-(Vector2 lhs, const float rhs);
295 | inline Vector2 operator*(Vector2 lhs, const float rhs);
296 | inline Vector2 operator/(Vector2 lhs, const float rhs);
297 | inline Vector2 operator+(const float lhs, Vector2 rhs);
298 | inline Vector2 operator-(const float lhs, Vector2 rhs);
299 | inline Vector2 operator*(const float lhs, Vector2 rhs);
300 | inline Vector2 operator/(const float lhs, Vector2 rhs);
301 | inline Vector2 operator+(Vector2 lhs, const Vector2 rhs);
302 | inline Vector2 operator-(Vector2 lhs, const Vector2 rhs);
303 | inline bool operator==(const Vector2 lhs, const Vector2 rhs);
304 | inline bool operator!=(const Vector2 lhs, const Vector2 rhs);
305 |
306 |
307 |
308 | /*******************************************************************************
309 | * Implementation
310 | */
311 |
312 | Vector2::Vector2() : X(0), Y(0) {}
313 | Vector2::Vector2(float data[]) : X(data[0]), Y(data[1]) {}
314 | Vector2::Vector2(float value) : X(value), Y(value) {}
315 | Vector2::Vector2(float x, float y) : X(x), Y(y) {}
316 |
317 |
318 | Vector2 Vector2::Zero() { return Vector2(0, 0); }
319 | Vector2 Vector2::One() { return Vector2(1, 1); }
320 | Vector2 Vector2::Right() { return Vector2(1, 0); }
321 | Vector2 Vector2::Left() { return Vector2(-1, 0); }
322 | Vector2 Vector2::Up() { return Vector2(0, 1); }
323 | Vector2 Vector2::Down() { return Vector2(0, -1); }
324 |
325 |
326 | float Vector2::Angle(Vector2 a, Vector2 b)
327 | {
328 | float v = Dot(a, b) / (Magnitude(a) * Magnitude(b));
329 | v = fmax(v, -1.0);
330 | v = fmin(v, 1.0);
331 | return acos(v);
332 | }
333 |
334 | Vector2 Vector2::ClampMagnitude(Vector2 vector, float maxLength)
335 | {
336 | float length = Magnitude(vector);
337 | if (length > maxLength)
338 | vector *= maxLength / length;
339 | return vector;
340 | }
341 |
342 | float Vector2::Component(Vector2 a, Vector2 b)
343 | {
344 | return Dot(a, b) / Magnitude(b);
345 | }
346 |
347 | float Vector2::Distance(Vector2 a, Vector2 b)
348 | {
349 | return Vector2::Magnitude(a - b);
350 | }
351 |
352 | float Vector2::Dot(Vector2 lhs, Vector2 rhs)
353 | {
354 | return lhs.X * rhs.X + lhs.Y * rhs.Y;
355 | }
356 |
357 | Vector2 Vector2::FromPolar(float rad, float theta)
358 | {
359 | Vector2 v;
360 | v.X = rad * cos(theta);
361 | v.Y = rad * sin(theta);
362 | return v;
363 | }
364 |
365 | Vector2 Vector2::Lerp(Vector2 a, Vector2 b, float t)
366 | {
367 | if (t < 0) return a;
368 | else if (t > 1) return b;
369 | return LerpUnclamped(a, b, t);
370 | }
371 |
372 | Vector2 Vector2::LerpUnclamped(Vector2 a, Vector2 b, float t)
373 | {
374 | return (b - a) * t + a;
375 | }
376 |
377 | float Vector2::Magnitude(Vector2 v)
378 | {
379 | return sqrt(SqrMagnitude(v));
380 | }
381 |
382 | Vector2 Vector2::Max(Vector2 a, Vector2 b)
383 | {
384 | float x = a.X > b.X ? a.X : b.X;
385 | float y = a.Y > b.Y ? a.Y : b.Y;
386 | return Vector2(x, y);
387 | }
388 |
389 | Vector2 Vector2::Min(Vector2 a, Vector2 b)
390 | {
391 | float x = a.X > b.X ? b.X : a.X;
392 | float y = a.Y > b.Y ? b.Y : a.Y;
393 | return Vector2(x, y);
394 | }
395 |
396 | Vector2 Vector2::MoveTowards(Vector2 current, Vector2 target,
397 | float maxDistanceDelta)
398 | {
399 | Vector2 d = target - current;
400 | float m = Magnitude(d);
401 | if (m < maxDistanceDelta || m == 0)
402 | return target;
403 | return current + (d * maxDistanceDelta / m);
404 | }
405 |
406 | Vector2 Vector2::Normalized(Vector2 v)
407 | {
408 | float mag = Magnitude(v);
409 | if (mag == 0)
410 | return Vector2::Zero();
411 | return v / mag;
412 | }
413 |
414 | void Vector2::OrthoNormalize(Vector2 &normal, Vector2 &tangent)
415 | {
416 | normal = Normalized(normal);
417 | tangent = Reject(tangent, normal);
418 | tangent = Normalized(tangent);
419 | }
420 |
421 | Vector2 Vector2::Project(Vector2 a, Vector2 b)
422 | {
423 | float m = Magnitude(b);
424 | return Dot(a, b) / (m * m) * b;
425 | }
426 |
427 | Vector2 Vector2::Reflect(Vector2 vector, Vector2 planeNormal)
428 | {
429 | return vector - 2 * Project(vector, planeNormal);
430 | }
431 |
432 | Vector2 Vector2::Reject(Vector2 a, Vector2 b)
433 | {
434 | return a - Project(a, b);
435 | }
436 |
437 | Vector2 Vector2::RotateTowards(Vector2 current, Vector2 target,
438 | float maxRadiansDelta,
439 | float maxMagnitudeDelta)
440 | {
441 | float magCur = Magnitude(current);
442 | float magTar = Magnitude(target);
443 | float newMag = magCur + maxMagnitudeDelta *
444 | ((magTar > magCur) - (magCur > magTar));
445 | newMag = fmin(newMag, fmax(magCur, magTar));
446 | newMag = fmax(newMag, fmin(magCur, magTar));
447 |
448 | float totalAngle = Angle(current, target) - maxRadiansDelta;
449 | if (totalAngle <= 0)
450 | return Normalized(target) * newMag;
451 | else if (totalAngle >= M_PI)
452 | return Normalized(-target) * newMag;
453 |
454 | float axis = current.X * target.Y - current.Y * target.X;
455 | axis = axis / fabs(axis);
456 | if (!(1 - fabs(axis) < 0.00001))
457 | axis = 1;
458 | current = Normalized(current);
459 | Vector2 newVector = current * cos(maxRadiansDelta) +
460 | Vector2(-current.Y, current.X) * sin(maxRadiansDelta) * axis;
461 | return newVector * newMag;
462 | }
463 |
464 | Vector2 Vector2::Scale(Vector2 a, Vector2 b)
465 | {
466 | return Vector2(a.X * b.X, a.Y * b.Y);
467 | }
468 |
469 | Vector2 Vector2::Slerp(Vector2 a, Vector2 b, float t)
470 | {
471 | if (t < 0) return a;
472 | else if (t > 1) return b;
473 | return SlerpUnclamped(a, b, t);
474 | }
475 |
476 | Vector2 Vector2::SlerpUnclamped(Vector2 a, Vector2 b, float t)
477 | {
478 | float magA = Magnitude(a);
479 | float magB = Magnitude(b);
480 | a /= magA;
481 | b /= magB;
482 | float dot = Dot(a, b);
483 | dot = fmax(dot, -1.0);
484 | dot = fmin(dot, 1.0);
485 | float theta = acos(dot) * t;
486 | Vector2 relativeVec = Normalized(b - a * dot);
487 | Vector2 newVec = a * cos(theta) + relativeVec * sin(theta);
488 | return newVec * (magA + (magB - magA) * t);
489 | }
490 |
491 | float Vector2::SqrMagnitude(Vector2 v)
492 | {
493 | return v.X * v.X + v.Y * v.Y;
494 | }
495 |
496 | void Vector2::ToPolar(Vector2 vector, float &rad, float &theta)
497 | {
498 | rad = Magnitude(vector);
499 | theta = atan2(vector.Y, vector.X);
500 | }
501 |
502 |
503 | struct Vector2& Vector2::operator+=(const float rhs)
504 | {
505 | X += rhs;
506 | Y += rhs;
507 | return *this;
508 | }
509 |
510 | struct Vector2& Vector2::operator-=(const float rhs)
511 | {
512 | X -= rhs;
513 | Y -= rhs;
514 | return *this;
515 | }
516 |
517 | struct Vector2& Vector2::operator*=(const float rhs)
518 | {
519 | X *= rhs;
520 | Y *= rhs;
521 | return *this;
522 | }
523 |
524 | struct Vector2& Vector2::operator/=(const float rhs)
525 | {
526 | X /= rhs;
527 | Y /= rhs;
528 | return *this;
529 | }
530 |
531 | struct Vector2& Vector2::operator+=(const Vector2 rhs)
532 | {
533 | X += rhs.X;
534 | Y += rhs.Y;
535 | return *this;
536 | }
537 |
538 | struct Vector2& Vector2::operator-=(const Vector2 rhs)
539 | {
540 | X -= rhs.X;
541 | Y -= rhs.Y;
542 | return *this;
543 | }
544 |
545 | Vector2 operator-(Vector2 rhs) { return rhs * -1; }
546 | Vector2 operator+(Vector2 lhs, const float rhs) { return lhs += rhs; }
547 | Vector2 operator-(Vector2 lhs, const float rhs) { return lhs -= rhs; }
548 | Vector2 operator*(Vector2 lhs, const float rhs) { return lhs *= rhs; }
549 | Vector2 operator/(Vector2 lhs, const float rhs) { return lhs /= rhs; }
550 | Vector2 operator+(const float lhs, Vector2 rhs) { return rhs += lhs; }
551 | Vector2 operator-(const float lhs, Vector2 rhs) { return rhs -= lhs; }
552 | Vector2 operator*(const float lhs, Vector2 rhs) { return rhs *= lhs; }
553 | Vector2 operator/(const float lhs, Vector2 rhs) { return rhs /= lhs; }
554 | Vector2 operator+(Vector2 lhs, const Vector2 rhs) { return lhs += rhs; }
555 | Vector2 operator-(Vector2 lhs, const Vector2 rhs) { return lhs -= rhs; }
556 |
557 | bool operator==(const Vector2 lhs, const Vector2 rhs)
558 | {
559 | return lhs.X == rhs.X && lhs.Y == rhs.Y;
560 | }
561 |
562 | bool operator!=(const Vector2 lhs, const Vector2 rhs)
563 | {
564 | return !(lhs == rhs);
565 | }
--------------------------------------------------------------------------------
/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