├── .gitignore ├── .idea ├── .gitignore ├── .name ├── compiler.xml ├── gradle.xml ├── misc.xml ├── uiDesigner.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── org │ │ └── muffin │ │ └── imgui │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── cpp │ │ ├── CMakeLists.txt │ │ ├── Muffin.cpp │ │ ├── includes │ │ │ ├── DrawUtils.h │ │ │ ├── Globals.h │ │ │ ├── Hooks.h │ │ │ ├── Menu.h │ │ │ └── Natives.h │ │ └── misc │ │ │ ├── Obfuscate.h │ │ │ ├── dobby │ │ │ ├── arm64-v8a │ │ │ │ ├── libdobby.a │ │ │ │ └── libdobby.so │ │ │ ├── armeabi-v7a │ │ │ │ ├── libdobby.a │ │ │ │ └── libdobby.so │ │ │ ├── include │ │ │ │ └── dobby.h │ │ │ ├── x86 │ │ │ │ ├── libdobby.a │ │ │ │ └── libdobby.so │ │ │ └── x86_64 │ │ │ │ ├── libdobby.a │ │ │ │ └── libdobby.so │ │ │ ├── imgui │ │ │ ├── MyFont.hpp │ │ │ ├── backends │ │ │ │ ├── imgui_impl_android.cpp │ │ │ │ ├── imgui_impl_android.h │ │ │ │ ├── imgui_impl_opengl3.cpp │ │ │ │ ├── imgui_impl_opengl3.h │ │ │ │ └── imgui_impl_opengl3_loader.h │ │ │ ├── imconfig.h │ │ │ ├── imgui.cpp │ │ │ ├── imgui.h │ │ │ ├── imgui_draw.cpp │ │ │ ├── imgui_internal.h │ │ │ ├── imgui_tables.cpp │ │ │ ├── imgui_widgets.cpp │ │ │ ├── imstb_rectpack.h │ │ │ ├── imstb_textedit.h │ │ │ └── imstb_truetype.h │ │ │ ├── json │ │ │ └── json.hpp │ │ │ └── xdl │ │ │ ├── xdl.c │ │ │ ├── xdl.h │ │ │ ├── xdl_iterate.c │ │ │ ├── xdl_iterate.h │ │ │ ├── xdl_linker.c │ │ │ ├── xdl_linker.h │ │ │ ├── xdl_lzma.c │ │ │ ├── xdl_lzma.h │ │ │ ├── xdl_util.c │ │ │ └── xdl_util.h │ ├── java │ │ └── org │ │ │ └── muffin │ │ │ └── imgui │ │ │ ├── GoogleMobileAdsConsentManager.java │ │ │ ├── MainActivity.java │ │ │ └── muffin │ │ │ ├── Muffin.java │ │ │ ├── MuffinService.java │ │ │ └── MuffinSurface.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── ic_launcher_background.xml │ │ └── muffin.png │ │ ├── layout │ │ ├── activity_main.xml │ │ └── ad_unified.xml │ │ ├── menu │ │ ├── action_menu.xml │ │ └── popup_menu.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-anydpi-v33 │ │ └── ic_launcher.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── values-night │ │ └── themes.xml │ │ ├── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ ├── styles.xml │ │ └── themes.xml │ │ └── xml │ │ ├── backup_rules.xml │ │ └── data_extraction_rules.xml │ └── test │ └── java │ └── org │ └── muffin │ └── imgui │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── license.txt └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | .idea 12 | /build 13 | /captures 14 | .externalNativeBuild 15 | .cxx 16 | local.properties 17 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | ImGui Surface Template -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 12 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 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 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android ImGui Surface - Mod Menu - Template 2 | 3 | ## Build & Run 4 | - [Android Studio](https://developer.android.com/studio) 5 | - [Intellij Idea Free / Ultimate](https://www.jetbrains.com/idea/) 6 | 7 | ## Features 8 | - [x] Simple app with GLSurfaceView 9 | - [x] Render ImGUI window 10 | - [x] Universal touch 11 | - [x] Basic widgets example 12 | - [x] More Styles 13 | - [x] Save config to file 14 | 15 | ## How to add to any app 16 | - Build this project 17 | - Decompile output APK 18 | - Extract smali & lib 19 | - Decompile target app 20 | - Put inside decompiled target app your smali and lib 21 | - Recompile, Sign & Test 22 | 23 | ### HELP 24 | - [How to decompile / recompile APK](https://youtu.be/xWU5Tk3MizY) 25 | - [How to sign an APK](https://youtu.be/GwkQelv3cGk) 26 | - [How to load your own lib from smali](https://youtu.be/JKwPPwnVehw) 27 | - [Full implementation video](https://www.youtube.com/watch?v=uT_DFRfullc) 28 | 29 | ## Result 30 | 31 | [//]: # (![](http://i.imgur.com/hd3nxBg.gif)) 32 | [//]: # (https://github.com/LaughingMuffin/android_imgui_surface_mod_menu_template/assets/97317523/df9081f2-974b-4489-8755-0c3ddd1317aa) 33 | #### Preview - Widgets 34 | https://github.com/LaughingMuffin/android_imgui_surface_mod_menu_template/assets/97317523/8ff2ec8f-964b-4083-a5a5-bff7682c5869 35 | 36 | #### Preview - Save to File 37 | https://github.com/LaughingMuffin/android_imgui_surface_mod_menu_template/assets/97317523/7260bc61-3419-4f85-8228-da77f9e2ef61 38 | 39 | ## Credits 40 | 41 | ImGUI - [ImGUI Official GitHub](https://github.com/ocornut/imgui)
42 | Obfuscator - [Obfuscate by adamyaxley](https://github.com/adamyaxley)
43 | xDL - [xDL by hexhacking](https://github.com/hexhacking/xDL)
44 | Dobby - [Dobby by jmpews](https://github.com/jmpews/Dobby)
45 | ___ 46 | Color Picker - [Online Color Picker](https://rgbcolorpicker.com/0-1)
47 | ___ 48 | ###### Android ImGui Surface - Mod Menu - Template is licensed under the MIT License, see [LICENSE](license.txt) for more information. 49 | ___ 50 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /release -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | } 4 | 5 | apply plugin: 'stringfog' 6 | 7 | // 导入RandomKeyGenerator类,如果不使用RandomKeyGenerator,可以删除此行 8 | 9 | import com.github.megatronking.stringfog.plugin.StringFogMode 10 | import com.github.megatronking.stringfog.plugin.kg.RandomKeyGenerator 11 | 12 | stringfog { 13 | enable true 14 | debug false 15 | // 指定加解密的具体实现类,可以用默认实现的xor库或者aes-cbc库,也可以自己定制实现,记得配置dependencies 16 | implementation 'com.github.megatronking.stringfog.xor.StringFogImpl' 17 | // 指定需加密的代码包路径,可配置多个,未指定将默认全部加密 18 | fogPackages = ["com.github.megatronking.stringfog", "org.muffin.imgui", "org.muffin.imgui.muffin"] 19 | // 可选(3.0版本新增):指定密钥生成器,默认使用长度8的随机密钥(每个字符串均有不同随机密钥), 20 | // 也可以指定一个固定的密钥:HardCodeKeyGenerator("This is a key") 21 | kg new RandomKeyGenerator() 22 | // 可选(4.0版本新增):用于控制字符串加密后在字节码中的存在形式, 默认为base64, 23 | // 也可以使用text或者bytes 24 | mode StringFogMode.base64 25 | } 26 | 27 | android { 28 | namespace 'org.muffin.imgui' 29 | compileSdk 34 30 | 31 | defaultConfig { 32 | applicationId "org.muffin.muffinator" 33 | minSdk 24 34 | targetSdk 34 35 | versionCode 101 36 | versionName "1.0.1" 37 | 38 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 39 | 40 | ndk { 41 | abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' 42 | } 43 | 44 | externalNativeBuild { 45 | cmake { 46 | cppFlags '-std=c++17' 47 | } 48 | } 49 | } 50 | 51 | buildTypes { 52 | release { 53 | minifyEnabled false 54 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 55 | signingConfig signingConfigs.debug 56 | } 57 | } 58 | 59 | compileOptions { 60 | sourceCompatibility JavaVersion.VERSION_1_8 61 | targetCompatibility JavaVersion.VERSION_1_8 62 | } 63 | 64 | externalNativeBuild { 65 | cmake { 66 | path file('src/main/cpp/CMakeLists.txt') 67 | version '3.22.1' 68 | } 69 | } 70 | 71 | buildFeatures { 72 | viewBinding true 73 | buildConfig true 74 | } 75 | } 76 | 77 | dependencies { 78 | 79 | implementation 'androidx.appcompat:appcompat:1.6.1' 80 | implementation 'com.google.android.material:material:1.12.0' 81 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4' 82 | implementation 'com.google.android.gms:play-services-ads:23.0.0' 83 | 84 | testImplementation 'junit:junit:4.13.2' 85 | androidTestImplementation 'androidx.test.ext:junit:1.1.5' 86 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' 87 | 88 | // 这里要和上面选用的加解密算法库一致,用于运行时解密。 89 | implementation 'com.github.megatronking.stringfog:xor:5.0.0' 90 | } -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /app/src/androidTest/java/org/muffin/imgui/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package org.muffin.imgui; 2 | 3 | import android.content.Context; 4 | import androidx.test.platform.app.InstrumentationRegistry; 5 | import androidx.test.ext.junit.runners.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 23 | assertEquals("org.muffin.imgui", appContext.getPackageName()); 24 | } 25 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 39 | 40 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.22.1) 2 | 3 | project("imgui") 4 | 5 | set(CMAKE_CXX_STANDARD 20) 6 | 7 | set(LINKER_FLAGS "-ffixed-x18 -Wl,--hash-style=both") 8 | set(C_FLAGS "-Werror=format -fdata-sections -ffunction-sections -std=c2x -Wno-error=format-security -w -fno-rtti -fpermissive") 9 | set(CXX_FLAGS "${CXX_FLAGS} -Wno-error=format-security -ffunction-sections -fdata-sections -w -Werror -s -std=c++20 -Wno-error=c++20-narrowing -fms-extensions -fno-rtti -fpermissive") 10 | 11 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_FLAGS} -O0") 12 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${C_FLAGS} ${CXX_FLAGS} -O0") 13 | 14 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}") 15 | set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}") 16 | 17 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/includes 18 | ${CMAKE_CURRENT_SOURCE_DIR}/misc 19 | ${CMAKE_CURRENT_SOURCE_DIR}/misc/json 20 | ${CMAKE_CURRENT_SOURCE_DIR}/misc/dobby/include 21 | ${CMAKE_CURRENT_SOURCE_DIR}/misc/imgui 22 | ${CMAKE_CURRENT_SOURCE_DIR}/misc/xdl 23 | ${CMAKE_CURRENT_SOURCE_DIR}/misc/dobby 24 | ${CMAKE_CURRENT_SOURCE_DIR}/misc/imgui/backends 25 | ) 26 | 27 | add_library(imgui SHARED 28 | Muffin.cpp 29 | misc/imgui/imgui.cpp 30 | misc/imgui/imgui_draw.cpp 31 | misc/imgui/imgui_tables.cpp 32 | misc/imgui/imgui_widgets.cpp 33 | misc/imgui/backends/imgui_impl_android.cpp 34 | misc/imgui/backends/imgui_impl_opengl3.cpp 35 | misc/xdl/xdl.c 36 | misc/xdl/xdl_iterate.c 37 | misc/xdl/xdl_linker.c 38 | misc/xdl/xdl_lzma.c 39 | misc/xdl/xdl_util.c 40 | ) 41 | 42 | set(DOBBY_LIB ${CMAKE_CURRENT_SOURCE_DIR}/misc/dobby/${CMAKE_ANDROID_ARCH_ABI}/libdobby.a) 43 | 44 | target_link_libraries(imgui android EGL GLESv3 log ${DOBBY_LIB}) -------------------------------------------------------------------------------- /app/src/main/cpp/Muffin.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Laughing Muffin on 18.09.2023 3 | // 4 | //====================================================================================================================== 5 | #include 6 | #include 7 | #include 8 | //====================================================================================================================== 9 | JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { 10 | 11 | if (vm->GetEnv(reinterpret_cast(&global_env), JNI_VERSION_1_6) != JNI_OK) { 12 | return -1; 13 | } 14 | 15 | if (registerNativeFunctions(global_env) != 0) { 16 | return -1; 17 | } 18 | 19 | Debug_Log("| 1 | dl_open libinput"); 20 | void *g_Input = xdl_open(OBFUSCATE("libinput.so"), 0); 21 | if (g_Input) { 22 | Debug_Log("| 1 | pointer is 0x%08x", g_Input); 23 | Debug_Log( 24 | "| 1 | dl_sym _ZN7android13InputConsumer21initializeMotionEventEPNS_11MotionEventEPKNS_12InputMessageE"); 25 | void *inputSymbolPointer = (void *) xdl_sym(g_Input, OBFUSCATE( 26 | "_ZN7android13InputConsumer21initializeMotionEventEPNS_11MotionEventEPKNS_12InputMessageE"), 27 | nullptr); 28 | if (inputSymbolPointer) { 29 | Debug_Log("| 1 | pointer is 0x%08x", inputSymbolPointer); 30 | Debug_Log( 31 | "| 1 | hook _ZN7android13InputConsumer21initializeMotionEventEPNS_11MotionEventEPKNS_12InputMessageE"); 32 | MUFF(inputSymbolPointer, hook_Input, orig_Input); 33 | } 34 | } 35 | Debug_Log("| 1 | dl_close libinput"); 36 | xdl_close(g_Input); 37 | 38 | // setup path once 39 | setupConfigFile(); 40 | 41 | return JNI_VERSION_1_6; 42 | } 43 | //====================================================================================================================== -------------------------------------------------------------------------------- /app/src/main/cpp/includes/DrawUtils.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Laughing Muffin on 23.09.2023 3 | // 4 | //====================================================================================================================== 5 | #pragma once 6 | //====================================================================================================================== 7 | #include 8 | //====================================================================================================================== 9 | /* 10 | ** Drawing are usually done in the background but you can them on top too 11 | ** -> GetForegroundDrawList 12 | */ 13 | //====================================================================================================================== 14 | void DrawLine(ImVec2 startCoords, ImVec2 endCoords, ImVec4 color) { 15 | auto backgroundDrawList = ImGui::GetBackgroundDrawList(); 16 | if (backgroundDrawList) { 17 | backgroundDrawList->AddLine(startCoords, endCoords, 18 | ImColor(color.x, color.y, color.z, color.w)); 19 | } 20 | } 21 | 22 | //====================================================================================================================== 23 | void DrawText(ImVec2 positionCoords, ImVec4 color, const char *text, float fontSize) { 24 | auto backgroundDrawList = ImGui::GetBackgroundDrawList(); 25 | if (backgroundDrawList) { 26 | backgroundDrawList->AddText(NULL, fontSize, positionCoords, 27 | ImColor(color.x, color.y, color.z, color.w), text); 28 | } 29 | } 30 | 31 | //====================================================================================================================== 32 | void DrawBox(ImVec2 topLeft, ImVec2 bottomRight, ImVec4 color) { 33 | auto backgroundDrawList = ImGui::GetBackgroundDrawList(); 34 | if (backgroundDrawList) { 35 | backgroundDrawList->AddRect(topLeft, bottomRight, ImGui::GetColorU32(color)); 36 | } 37 | } 38 | //====================================================================================================================== -------------------------------------------------------------------------------- /app/src/main/cpp/includes/Globals.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Laughing Muffin on 18.09.2023 3 | // 4 | //====================================================================================================================== 5 | #pragma once 6 | //====================================================================================================================== 7 | //GENERIC INCLUDES ===================================================================================================== 8 | #include 9 | #include 10 | #include 11 | //====================================================================================================================== 12 | //ANDROID INCLUDES ===================================================================================================== 13 | #include 14 | #include 15 | //====================================================================================================================== 16 | //OPENGL INCLUDES ====================================================================================================== 17 | #include 18 | #include 19 | //====================================================================================================================== 20 | //MISC INCLUDES ======================================================================================================== 21 | #include 22 | //====================================================================================================================== 23 | //IMGUI INCLUDES ======================================================================================================= 24 | #include 25 | #include 26 | #include 27 | //====================================================================================================================== 28 | //FONT INCLUDES ======================================================================================================== 29 | #include 30 | //====================================================================================================================== 31 | //JSON ================================================================================================================= 32 | #include 33 | //====================================================================================================================== 34 | //HOOKERS ============================================================================================================== 35 | #include 36 | #include 37 | //====================================================================================================================== 38 | //DEFINE SOME USEFUL STUFF ============================================================================================= 39 | #define LOG_TAG OBFUSCATE("MUFFIN") //logger tag 40 | #define DEBUG_BUILD //used to toggle logging 41 | //====================================================================================================================== 42 | //MORE USEFUL STUFF ==================================================================================================== 43 | #ifdef DEBUG_BUILD 44 | #define Debug_Log(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__); 45 | #define Error_Log(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__); 46 | #define Warning_Log(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__); 47 | #define Info_Log(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__); 48 | #else 49 | #define Debug_Log(...) //__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__); 50 | #define Error_Log(...) //__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__); 51 | #define Warning_Log(...) //__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__); 52 | #define Info_Log(...) //__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__); 53 | #endif 54 | //====================================================================================================================== 55 | #define HOOK_DEF(ret, func, ...) \ 56 | ret (*orig_##func)(__VA_ARGS__); \ 57 | ret hook_##func(__VA_ARGS__) 58 | //====================================================================================================================== 59 | #define MUFF(target, ptr, orig) DobbyHook((void *)target,(void *)ptr,(void **)&orig) 60 | //====================================================================================================================== 61 | ANativeWindow *g_NativeWindow; 62 | bool g_Initialized = false; 63 | int glWidth = 0, glHeight = 0; 64 | JNIEnv *global_env; 65 | //====================================================================================================================== -------------------------------------------------------------------------------- /app/src/main/cpp/includes/Hooks.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Laughing Muffin on 18.09.2023 3 | // 4 | //====================================================================================================================== 5 | #pragma once 6 | //====================================================================================================================== 7 | #include 8 | //====================================================================================================================== 9 | HOOK_DEF(void, Input, void *thiz, void *ex_ab, void *ex_ac) { 10 | orig_Input(thiz, ex_ab, ex_ac); 11 | if (g_Initialized) 12 | ImGui_ImplAndroid_HandleInputEvent((AInputEvent *) thiz); 13 | return; 14 | } 15 | //====================================================================================================================== -------------------------------------------------------------------------------- /app/src/main/cpp/includes/Menu.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Laughing Muffin on 22.09.2023 3 | // 4 | //====================================================================================================================== 5 | #pragma once 6 | //====================================================================================================================== 7 | #include 8 | #include 9 | //====================================================================================================================== 10 | using json = nlohmann::json; 11 | //====================================================================================================================== 12 | const char *style_list[11] = { 13 | OBFUSCATE("Classic"), 14 | OBFUSCATE("Light"), 15 | OBFUSCATE("Dark Blue"), 16 | OBFUSCATE("Green & Blue"), 17 | OBFUSCATE("Dark Red"), 18 | OBFUSCATE("Deep Dark"), 19 | OBFUSCATE("Golden Black"), 20 | OBFUSCATE("Dark Grey"), 21 | OBFUSCATE("Grey"), 22 | OBFUSCATE("Soft Dark Red"), 23 | OBFUSCATE("Steam Half Life") 24 | }; 25 | //====================================================================================================================== 26 | struct Variables { 27 | char StylePath[128] = ""; 28 | } Vars; 29 | //====================================================================================================================== 30 | struct StyleVariables { 31 | std::string name = OBFUSCATE("style.json"); 32 | int style_selection = 0; 33 | } StyleVars; 34 | // if you extend the number of vars remember to declare them here too 35 | NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(StyleVariables, name, style_selection) 36 | 37 | //====================================================================================================================== 38 | StyleVariables LoadStyles() { 39 | 40 | // try open file 41 | FILE *file = fopen(Vars.StylePath, OBFUSCATE("r")); 42 | if (!file) { 43 | // return default if not there 44 | return StyleVars; 45 | } 46 | 47 | json j; 48 | 49 | // try read file 50 | try { 51 | std::ifstream f(Vars.StylePath, std::ifstream::binary); 52 | f >> j; 53 | return j.get(); 54 | } catch (...) { 55 | // return default if errors 56 | return StyleVars; 57 | } 58 | } 59 | 60 | //====================================================================================================================== 61 | void SaveStyle(StyleVariables preset) { 62 | 63 | //save or overwrite file 64 | json j = preset; 65 | std::ofstream o(Vars.StylePath); 66 | o << std::setw(4) << j << std::endl; 67 | } 68 | 69 | //====================================================================================================================== 70 | struct MenuVariables { 71 | float winWidth = 0.0f; 72 | float winHeight = 0.0f; 73 | float winPosWidth = 0.0f; 74 | float winPosHeight = 0.0f; 75 | ImVec4 textColor = ImVec4(0.990f, 0.0396f, 0.816f, 76 | 1.00f); // R G B + GAMMA | Using floats, check readme for picker 77 | ImVec4 color_red = ImVec4(1.0f, 0.0f, 0.0f, 1.00f); // RED - rgb01(1, 0, 0) | #ff0000 78 | ImVec4 color_purple = ImVec4(1.0f, 0.0f, 1.0f, 1.00f); // PURPLE - rgb01(1, 0, 1) | #ff00ff 79 | ImVec4 color_green = ImVec4(0.0f, 1.0f, 0.0f, 1.0f); // GREEN - rgb01(0, 1, 0) | #00ff00 80 | } MenuVars; 81 | //====================================================================================================================== 82 | struct CheatVariables { 83 | float damageMultiplierF = 1.0f; 84 | int damageMultiplier = 1; 85 | int int_radio_A = 0; 86 | int int_button_math = 0; 87 | int drag_A = 0; 88 | int drag_B = 0; 89 | bool bool_checkbox_A = false; 90 | bool bool_draw_line = false; 91 | bool bool_draw_box = false; 92 | } CheatVars; 93 | 94 | //====================================================================================================================== 95 | void HelpMarker(const char *desc) { 96 | ImGui::TextDisabled(OBFUSCATE("(?)")); 97 | if (ImGui::BeginItemTooltip()) { 98 | ImGui::PushTextWrapPos(ImGui::GetFontSize() * 30.0f); 99 | ImGui::TextUnformatted(desc); 100 | ImGui::PopTextWrapPos(); 101 | ImGui::EndTooltip(); 102 | } 103 | } 104 | 105 | //====================================================================================================================== 106 | void DrawLeftColumn() { 107 | // set current column width 108 | ImGui::SetColumnWidth(-1, 400); 109 | 110 | // very shitty separator, it applies to the entire window, be it horizontal or vertical, see better example below 111 | // you will notice the long line on top of the window, that's this 112 | ImGui::Separator(); 113 | 114 | // add your stuff here 115 | 116 | // this is a text separator used with an "empty" string, use ## and write some crap there :) 117 | // it will stay bound to column 118 | ImGui::SeparatorText(OBFUSCATE("##LEFT_COLUMN_TOP_SEPARATOR_1")); 119 | 120 | // this prints a simple text, not suggested for long phrases, see nicer example below 121 | ImGui::Text(OBFUSCATE("This is a normal text!")); 122 | ImGui::Spacing(); 123 | ImGui::Spacing(); 124 | ImGui::Text(OBFUSCATE("This is a normal text but it's a little ...")); 125 | 126 | // this separator will show a text in the middle of it 127 | ImGui::SeparatorText(OBFUSCATE("Separator")); 128 | 129 | // this is a formatted text, it will go to next line wen reaching "EOL" 130 | ImGui::TextWrapped(OBFUSCATE( 131 | "Longer text that will go to next line when reaching the end of the column!")); 132 | 133 | ImGui::SeparatorText(OBFUSCATE("##LEFT_COLUMN_TOP_SEPARATOR_2")); 134 | 135 | // colored text, have fun making it rainbow 136 | ImGui::TextColored(MenuVars.textColor, OBFUSCATE("I'm colored!")); 137 | 138 | ImGui::SeparatorText(OBFUSCATE("##LEFT_COLUMN_TOP_SEPARATOR_3")); 139 | ImGui::Spacing(); 140 | ImGui::BulletText(OBFUSCATE("I'm a bullet text!")); 141 | ImGui::Spacing(); 142 | ImGui::SeparatorText(OBFUSCATE("##LEFT_COLUMN_TOP_SEPARATOR_4")); 143 | 144 | // disabled looking text 145 | ImGui::TextDisabled(OBFUSCATE("Disabled text!")); 146 | 147 | // put next element on the same line of the previous element 148 | ImGui::SameLine(); 149 | 150 | // I'm something like a tool tip 151 | HelpMarker(OBFUSCATE("Short Description!")); 152 | 153 | ImGui::SeparatorText(OBFUSCATE("##LEFT_COLUMN_TOP_SEPARATOR_5")); 154 | } 155 | 156 | //====================================================================================================================== 157 | void DrawCheats() { 158 | 159 | // gives some space btw previous element and next one 160 | ImGui::Spacing(); 161 | ImGui::Spacing(); 162 | ImGui::Text(OBFUSCATE("Cheats Tab!")); 163 | ImGui::SeparatorText(OBFUSCATE("##SEP_MID_1")); 164 | 165 | // make your list of items 166 | const char *items_combo[] = {"AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", 167 | "IIIIIII", "JJJJ", "KKKKKKK"}; 168 | static int item_combo_current = 0; 169 | ImGui::Text("Combo: "); 170 | ImGui::SameLine(); 171 | ImGui::Text("%s", items_combo[item_combo_current]); 172 | 173 | // pass the list, size and current selection pointer reference 174 | ImGui::Combo("##_my_combo", &item_combo_current, items_combo, IM_ARRAYSIZE(items_combo)); 175 | ImGui::SeparatorText("##SEP_MID_1"); 176 | 177 | // same concept here just different widget :) 178 | const char *items_list[] = {"Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", 179 | "Strawberry", "Watermelon"}; 180 | static int item_list_current = 1; 181 | ImGui::Text("List: "); 182 | ImGui::SameLine(); 183 | ImGui::Text("%s", items_list[item_list_current]); 184 | ImGui::ListBox("##_my_list", &item_list_current, items_list, IM_ARRAYSIZE(items_list), 5); 185 | ImGui::SeparatorText("##SEP_MID_1"); 186 | 187 | ImGui::Text("Drag INT, not capped"); 188 | ImGui::DragInt("##drag int", &CheatVars.drag_A, 1); 189 | ImGui::SeparatorText("##SEP_MID_1"); 190 | 191 | // always END the item or you crash!!! 192 | ImGui::EndTabItem(); 193 | } 194 | 195 | //====================================================================================================================== 196 | void DrawMore() { 197 | ImGui::Spacing(); 198 | ImGui::Spacing(); 199 | ImGui::Text(OBFUSCATE("More Tab!")); 200 | ImGui::SeparatorText(OBFUSCATE("##SEP_MID_1")); 201 | 202 | ImGui::TextColored(MenuVars.textColor, "Slider with INTEGERS - 1 to 100"); 203 | ImGui::SliderInt("##_dmg", &CheatVars.damageMultiplier, 1, 100); 204 | ImGui::SameLine(); 205 | HelpMarker("Slider from 1 to 100"); 206 | ImGui::SameLine(); 207 | ImGui::Text("§ %d", CheatVars.damageMultiplier); 208 | ImGui::SeparatorText(OBFUSCATE("##SEP_MID_1")); 209 | 210 | ImGui::TextColored(MenuVars.textColor, "Slider with FLOATS - 1.0 to 10.0"); 211 | ImGui::SliderFloat("##_dmg_f", &CheatVars.damageMultiplierF, 1.0f, 10.0f, "%.1f"); 212 | ImGui::SameLine(); 213 | HelpMarker("Slider from 1.0 to 10.0"); 214 | ImGui::SameLine(); 215 | ImGui::Text("§ %f", CheatVars.damageMultiplierF); 216 | ImGui::SeparatorText(OBFUSCATE("##SEP_MID_1")); 217 | 218 | ImGui::Text("Drag INT, capped 0 - 100"); 219 | ImGui::DragInt("##drag int 0..100_", &CheatVars.drag_B, 1, 0, 100, "%d%", 220 | ImGuiSliderFlags_AlwaysClamp); 221 | ImGui::SeparatorText("##SEP_MID_1"); 222 | 223 | // always END the item or you crash!!! 224 | ImGui::EndTabItem(); 225 | } 226 | 227 | //====================================================================================================================== 228 | void DrawEvenMore() { 229 | ImGui::Spacing(); 230 | ImGui::Spacing(); 231 | ImGui::Text(OBFUSCATE("Even More Tab!")); 232 | ImGui::SeparatorText(OBFUSCATE("##SEP_MID_1")); 233 | 234 | // simple checkbox 235 | ImGui::Checkbox("Check me nii-san!", &CheatVars.bool_checkbox_A); 236 | ImGui::SameLine(); 237 | HelpMarker("Onii-san!"); 238 | ImGui::SeparatorText(OBFUSCATE("##SEP_MID_1")); 239 | 240 | // simple radio buttons 241 | ImGui::RadioButton("Offline!", &CheatVars.int_radio_A, 0); 242 | ImGui::SameLine(); 243 | ImGui::RadioButton("On-AIR!", &CheatVars.int_radio_A, 1); 244 | ImGui::SameLine(); 245 | ImGui::SameLine(); 246 | HelpMarker("Kimochi!"); 247 | ImGui::SeparatorText(OBFUSCATE("##SEP_MID_1")); 248 | 249 | // buttons 250 | ImGui::Button("I do nothing!"); 251 | ImGui::SameLine(); 252 | if (ImGui::Button("I do math")) { 253 | CheatVars.int_button_math++; 254 | } 255 | ImGui::SameLine(); 256 | HelpMarker("Tap to ++!"); 257 | ImGui::SameLine(); 258 | ImGui::Text("Counter is: %d", CheatVars.int_button_math); 259 | ImGui::SeparatorText(OBFUSCATE("##SEP_MID_1")); 260 | 261 | // ESP Control via simple checkboxes 262 | ImGui::Checkbox("Draw Line", &CheatVars.bool_draw_line); 263 | ImGui::SameLine(); 264 | ImGui::Checkbox("Draw Box", &CheatVars.bool_draw_box); 265 | ImGui::SeparatorText(OBFUSCATE("##SEP_MID_1")); 266 | 267 | // always END the item or you crash!!! 268 | ImGui::EndTabItem(); 269 | } 270 | 271 | //====================================================================================================================== 272 | void DrawStyleEditor() { 273 | ImGui::Spacing(); 274 | ImGui::Spacing(); 275 | ImGui::Text(OBFUSCATE("Style Editor Tab!")); 276 | ImGui::SeparatorText(OBFUSCATE("##SEP_MID_1")); 277 | 278 | ImGui::Spacing(); 279 | ImGui::Text(OBFUSCATE("Default Style Picker")); 280 | ImGui::Combo(OBFUSCATE("##Default Style Picker"), &StyleVars.style_selection, style_list, 281 | IM_ARRAYSIZE(style_list), 15); 282 | ImGui::Spacing(); 283 | if (ImGui::Button(OBFUSCATE("Save"), ImVec2(170, 50))) { 284 | // save config 285 | SaveStyle(StyleVars); 286 | } 287 | 288 | // always END the item or you crash!!! 289 | ImGui::EndTabItem(); 290 | } 291 | 292 | //====================================================================================================================== 293 | void DrawOtherStuff() { 294 | 295 | ImGui::SeparatorText(OBFUSCATE("##SEP_MID_0")); 296 | 297 | // let's setup an item bar 298 | if (ImGui::BeginTabBar("_tab_bar", ImGuiTabBarFlags_FittingPolicyScroll)) { 299 | 300 | // first element on the bar 301 | if (ImGui::BeginTabItem("Cheats", NULL, ImGuiTabItemFlags_Leading)) { 302 | DrawCheats(); 303 | } 304 | 305 | // second element of the tab 306 | if (ImGui::BeginTabItem("More")) { 307 | DrawMore(); 308 | } 309 | 310 | // third element of the tab 311 | if (ImGui::BeginTabItem("Even More")) { 312 | DrawEvenMore(); 313 | } 314 | 315 | // fourth and last element of the tab 316 | if (ImGui::BeginTabItem("Style Editor")) { 317 | DrawStyleEditor(); 318 | } 319 | 320 | // always END the bar or you crash!!! 321 | ImGui::EndTabBar(); 322 | } 323 | } 324 | 325 | //====================================================================================================================== 326 | void DrawEsp() { 327 | 328 | // for making things simpler I only draw one thing per element 329 | // but usually you would have to loop and draw for each entity 330 | 331 | if (CheatVars.bool_draw_line) { 332 | /* 333 | ** Start coords as ImVec2 334 | ** End coords as ImVec2 335 | ** Color as ImVec4 336 | */ 337 | DrawLine({0, 0}, {250, 550}, MenuVars.color_red); 338 | 339 | /* 340 | ** Coords as ImVec2 341 | ** Color as ImVec4 342 | ** Text as const char * 343 | ** Font size as float 344 | */ 345 | DrawText({252, 500}, MenuVars.color_purple, "[X] Line from 0:0 to 250:550", 30.0f); 346 | } 347 | 348 | if (CheatVars.bool_draw_box) { 349 | DrawBox({250, 550}, {350, 650}, MenuVars.color_green); 350 | DrawText({350, 650}, MenuVars.color_red, "[X] Box from 250, 550 to 350, 650", 30.0f); 351 | } 352 | } 353 | 354 | //====================================================================================================================== 355 | void DrawColumnsDrivenMenu() { 356 | 357 | // setup how many columns you want 358 | ImGui::Columns(2); 359 | 360 | // draw left section 361 | DrawLeftColumn(); 362 | 363 | // go to next column, here I don't care about the size, let's use it all 364 | ImGui::NextColumn(); 365 | 366 | // draw the rest 367 | DrawOtherStuff(); 368 | 369 | // draw esp stuff 370 | DrawEsp(); 371 | } 372 | //====================================================================================================================== -------------------------------------------------------------------------------- /app/src/main/cpp/includes/Natives.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Laughing Muffin on 18.09.2023 3 | // 4 | //====================================================================================================================== 5 | #pragma once 6 | //====================================================================================================================== 7 | #include 8 | #include 9 | 10 | //====================================================================================================================== 11 | static jobject getGlobalContext() { 12 | jclass activityThread = global_env->FindClass(OBFUSCATE("android/app/ActivityThread")); 13 | jmethodID currentActivityThread = global_env->GetStaticMethodID(activityThread, OBFUSCATE( 14 | "currentActivityThread"), OBFUSCATE("()Landroid/app/ActivityThread;")); 15 | jobject at = global_env->CallStaticObjectMethod(activityThread, currentActivityThread); 16 | 17 | jmethodID getApplication = global_env->GetMethodID(activityThread, OBFUSCATE("getApplication"), 18 | OBFUSCATE("()Landroid/app/Application;")); 19 | jobject context = global_env->CallObjectMethod(at, getApplication); 20 | return context; 21 | } 22 | 23 | //====================================================================================================================== 24 | void setupConfigFile() { 25 | 26 | jobject context = getGlobalContext(); 27 | if (!context) { 28 | Error_Log("I'm stupid and failed to get context apparently!"); 29 | exit(999); 30 | } 31 | 32 | // get context object class once 33 | auto contextClass = global_env->FindClass(OBFUSCATE("android/content/Context")); 34 | 35 | // get files dir absolute path 36 | auto filesDirPtr = global_env->GetMethodID(contextClass, OBFUSCATE("getFilesDir"), 37 | OBFUSCATE("()Ljava/io/File;")); 38 | auto filesDirObject = global_env->CallObjectMethod(context, filesDirPtr); 39 | auto filesDirClass = global_env->GetObjectClass(filesDirObject); 40 | 41 | auto getFilesDirAbsolutePathMethod = global_env->GetMethodID(filesDirClass, 42 | OBFUSCATE("getAbsolutePath"), 43 | OBFUSCATE("()Ljava/lang/String;")); 44 | 45 | const char *filesDir = global_env->GetStringUTFChars( 46 | (jstring) global_env->CallObjectMethod(filesDirObject, getFilesDirAbsolutePathMethod), 47 | 0); 48 | 49 | strcat(Vars.StylePath, filesDir); 50 | strcat(Vars.StylePath, OBFUSCATE("/")); 51 | char *name_cstr = new char[StyleVars.name.length() + 1]; 52 | strcpy(name_cstr, StyleVars.name.c_str()); 53 | strcat(Vars.StylePath, name_cstr); 54 | } 55 | 56 | //====================================================================================================================== 57 | void native_Init(JNIEnv *env, jclass clazz, jobject surface) { 58 | 59 | if (g_Initialized) 60 | return; 61 | 62 | g_NativeWindow = ANativeWindow_fromSurface(env, surface); 63 | 64 | ImGui::CreateContext(); 65 | ImGuiStyle *style = &ImGui::GetStyle(); 66 | style->WindowTitleAlign = ImVec2(0, 0.50); 67 | style->FrameBorderSize = 1; 68 | style->WindowRounding = 5.3f; 69 | style->ScrollbarRounding = 0; 70 | style->FramePadding = ImVec2(8, 6); 71 | style->ScaleAllSizes(2.0f); 72 | style->ScrollbarSize /= 1; 73 | style->WindowMinSize = ImVec2(400, 180); 74 | 75 | ImGuiIO *io = &ImGui::GetIO(); 76 | 77 | ImGui_ImplAndroid_Init(g_NativeWindow); 78 | ImGui_ImplOpenGL3_Init(OBFUSCATE("#version 100")); 79 | 80 | ImFontConfig font_cfg; 81 | io->Fonts->AddFontFromMemoryTTF(const_cast(myFont), sizeof(myFont), 28); 82 | 83 | font_cfg.SizePixels = 28; 84 | io->Fonts->AddFontDefault(&font_cfg); 85 | 86 | // load config once 87 | StyleVars = LoadStyles(); 88 | 89 | g_Initialized = true; 90 | 91 | } 92 | 93 | //====================================================================================================================== 94 | void native_SurfaceChanged(JNIEnv *env, jclass clazz, jobject gl, jint width, jint height) { 95 | 96 | // get some info to setup menu 97 | glWidth = width; 98 | glHeight = height; 99 | Debug_Log("W - %d | H - %d", width, height); 100 | glViewport(0, 0, width, height); 101 | 102 | // update imgui display size 103 | ImGuiIO *io = &ImGui::GetIO(); 104 | io->DisplaySize = ImVec2((float) width, (float) height); 105 | 106 | } 107 | 108 | //====================================================================================================================== 109 | void native_Tick(JNIEnv *env, jclass clazz, jobject thiz) { 110 | 111 | ImGui_ImplOpenGL3_NewFrame(); 112 | ImGui_ImplAndroid_NewFrame(glWidth, glHeight); 113 | ImGui::NewFrame(); 114 | 115 | // setup win initial pos coords and size 116 | MenuVars.winWidth = glWidth * 0.95f; 117 | MenuVars.winHeight = 0.0f; 118 | MenuVars.winPosWidth = glWidth * 0.05f; 119 | MenuVars.winPosHeight = glHeight * 0.10f; 120 | 121 | // init the win 122 | ImGui::SetNextWindowPos(ImVec2(MenuVars.winPosWidth, MenuVars.winPosHeight), 123 | ImGuiCond_FirstUseEver); 124 | ImGui::SetNextWindowSize({MenuVars.winWidth, MenuVars.winHeight}); 125 | 126 | // sets win collapsed, once - second param is kinda useless but it's a good example, you could make use of that kind 127 | // of params for other kind of behaviours :) 128 | ImGui::SetNextWindowCollapsed(true, ImGuiCond_::ImGuiCond_Once); 129 | 130 | // this is the top bar of the menu, collapsed or not 131 | ImGui::Begin(OBFUSCATE("@github.com/LaughingMuffin - ImGUI Surface Template")); 132 | 133 | // draw a menu column based 134 | DrawColumnsDrivenMenu(); 135 | 136 | // setup style 137 | switch (StyleVars.style_selection) { 138 | case 0: 139 | ImGui::StyleColorsClassic(); 140 | break; 141 | case 1: 142 | ImGui::StyleColorsLight(); 143 | break; 144 | case 2: 145 | ImGui::StyleColorsDark(); 146 | break; 147 | case 3: 148 | ImGui::StyleColorsGreenBlue(); 149 | break; 150 | case 4: 151 | ImGui::StyleColorsRedDark(); 152 | break; 153 | case 5: 154 | ImGui::StyleColorsDeepDark(); 155 | break; 156 | case 6: 157 | ImGui::StyleColorsGoldenDark(); 158 | break; 159 | case 7: 160 | ImGui::StyleColorsDarkGray(); 161 | break; 162 | case 8: 163 | ImGui::StyleColorsGray(); 164 | break; 165 | case 9: 166 | ImGui::StyleColorsSoftDarkRed(); 167 | break; 168 | case 10: 169 | ImGui::StyleColorsSteamHalfLife(); 170 | break; 171 | } 172 | 173 | // that's it, now close some stuff and then render it :) 174 | ImGui::End(); 175 | 176 | ImGui::Render(); 177 | glClear(GL_COLOR_BUFFER_BIT); 178 | ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); 179 | } 180 | 181 | //====================================================================================================================== 182 | void native_Shutdown(JNIEnv *env, jclass clazz) { 183 | 184 | if (!g_Initialized) 185 | return; 186 | 187 | // shut down everything 188 | g_Initialized = false; 189 | ImGui_ImplOpenGL3_Shutdown(); 190 | ImGui_ImplAndroid_Shutdown(); 191 | ImGui::DestroyContext(); 192 | ANativeWindow_release(g_NativeWindow); 193 | 194 | } 195 | 196 | //====================================================================================================================== 197 | jboolean native_Initialized(JNIEnv *env, jclass clazz) { return g_Initialized; } 198 | 199 | //====================================================================================================================== 200 | jstring native_stringFromJNI(JNIEnv *env, jclass clazz) { 201 | std::string jniString = "🥴"; 202 | return env->NewStringUTF(jniString.c_str()); 203 | } 204 | 205 | //====================================================================================================================== 206 | int registerNativeFunctions(JNIEnv *env) { 207 | 208 | // declare the array of native methods you want to register 209 | // JAVA NAME | JAVA SIGNATURE | POINTER TO NATIVE IMPLEMENTATION 210 | JNINativeMethod methods[] = { 211 | {OBFUSCATE("Init"), OBFUSCATE( 212 | "(Landroid/view/Surface;)V"), reinterpret_cast(native_Init)}, 213 | {OBFUSCATE("SurfaceChanged"), OBFUSCATE( 214 | "(Ljavax/microedition/khronos/opengles/GL10;II)V"), reinterpret_cast(native_SurfaceChanged)}, 215 | {OBFUSCATE("Tick"), OBFUSCATE( 216 | "(Lorg/muffin/imgui/muffin/MuffinSurface;)V"), reinterpret_cast(native_Tick)}, 217 | {OBFUSCATE("Shutdown"), OBFUSCATE( 218 | "()V"), reinterpret_cast(native_Shutdown)}, 219 | {OBFUSCATE("Initialized"), OBFUSCATE( 220 | "()Z"), reinterpret_cast(native_Initialized)} 221 | }; 222 | 223 | // let's find class and ensure it's there 224 | jclass clazz = env->FindClass(OBFUSCATE("org/muffin/imgui/muffin/MuffinSurface")); 225 | if (!clazz) 226 | return -1; 227 | 228 | // pass everything to register method under JNIEnv 229 | if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])) != 0) 230 | return -1; 231 | 232 | // declare a new array of native methods you want to register, you can do it more than once :) 233 | JNINativeMethod moreMethods[] = { 234 | {OBFUSCATE("stringFromJNI"), OBFUSCATE("()Ljava/lang/String;"), 235 | reinterpret_cast(native_stringFromJNI)} 236 | }; 237 | 238 | // find class and ensure it's there 239 | jclass anotherClazz = env->FindClass(OBFUSCATE("org/muffin/imgui/MainActivity")); 240 | if (!anotherClazz) 241 | return -1; 242 | 243 | // register them :=) 244 | if (env->RegisterNatives(anotherClazz, moreMethods, 245 | sizeof(moreMethods) / sizeof(moreMethods[0])) != 0) 246 | return -1; 247 | 248 | return 0; 249 | } 250 | //====================================================================================================================== -------------------------------------------------------------------------------- /app/src/main/cpp/misc/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 | #ifndef OBF_H 25 | #define OBF_H 26 | 27 | #include 28 | #include 29 | //====================================================================================================================== 30 | #ifndef AY_OBFUSCATE_DEFAULT_KEY 31 | // The default 64 bit key to obfuscate strings with. 32 | // This can be user specified by defining AY_OBFUSCATE_DEFAULT_KEY before 33 | // including obfuscate.h 34 | #define AY_OBFUSCATE_DEFAULT_KEY ay::generate_key(__LINE__) 35 | #endif 36 | //====================================================================================================================== 37 | namespace ay { 38 | using size_type = unsigned long long; 39 | using key_type = unsigned long long; 40 | 41 | // Generate a psuedo-random key that spans all 8 bytes 42 | constexpr key_type generate_key(key_type seed) { 43 | // Use the MurmurHash3 64-bit finalizer to hash our seed 44 | key_type key = seed; 45 | key ^= (key >> 33); 46 | key *= 0xff51afd7ed558ccd; 47 | key ^= (key >> 33); 48 | key *= 0xc4ceb9fe1a85ec53; 49 | key ^= (key >> 33); 50 | 51 | // Make sure that a bit in each byte is set 52 | key |= 0x0101010101010101ull; 53 | 54 | return key; 55 | } 56 | 57 | // Obfuscates or deobfuscates data with key 58 | constexpr void cipher(char *data, size_type size, key_type key) { 59 | // Obfuscate with a simple XOR cipher based on key 60 | for (size_type i = 0; i < size; i++) { 61 | data[i] ^= char(key >> ((i % 8) * 8)); 62 | } 63 | } 64 | 65 | // Obfuscates a string at compile time 66 | template 67 | class obfuscator { 68 | public: 69 | // Obfuscates the string 'data' on construction 70 | constexpr obfuscator(const char *data) { 71 | // Copy data 72 | for (size_type i = 0; i < N; i++) { 73 | m_data[i] = data[i]; 74 | } 75 | 76 | // On construction each of the characters in the string is 77 | // obfuscated with an XOR cipher based on key 78 | cipher(m_data, N, KEY); 79 | } 80 | 81 | constexpr const char *data() const { 82 | return &m_data[0]; 83 | } 84 | 85 | constexpr size_type size() const { 86 | return N; 87 | } 88 | 89 | constexpr key_type key() const { 90 | return KEY; 91 | } 92 | 93 | private: 94 | 95 | char m_data[N]{}; 96 | }; 97 | 98 | // Handles decryption and re-encryption of an encrypted string at runtime 99 | template 100 | class obfuscated_data { 101 | public: 102 | obfuscated_data(const obfuscator &obfuscator) { 103 | // Copy obfuscated data 104 | for (size_type i = 0; i < N; i++) { 105 | m_data[i] = obfuscator.data()[i]; 106 | } 107 | } 108 | 109 | ~obfuscated_data() { 110 | // Zero m_data to remove it from memory 111 | for (size_type i = 0; i < N; i++) { 112 | m_data[i] = 0; 113 | } 114 | } 115 | 116 | // Returns a pointer to the plain text string, decrypting it if 117 | // necessary 118 | operator char *() { 119 | decrypt(); 120 | return m_data; 121 | } 122 | 123 | operator std::string() { 124 | decrypt(); 125 | return m_data; 126 | } 127 | 128 | // Manually decrypt the string 129 | void decrypt() { 130 | if (m_encrypted) { 131 | cipher(m_data, N, KEY); 132 | m_encrypted = false; 133 | } 134 | } 135 | 136 | // Manually re-encrypt the string 137 | void encrypt() { 138 | if (!m_encrypted) { 139 | cipher(m_data, N, KEY); 140 | m_encrypted = true; 141 | } 142 | } 143 | 144 | // Returns true if this string is currently encrypted, false otherwise. 145 | bool is_encrypted() const { 146 | return m_encrypted; 147 | } 148 | 149 | private: 150 | 151 | // Local storage for the string. Call is_encrypted() to check whether or 152 | // not the string is currently obfuscated. 153 | char m_data[N]; 154 | 155 | // Whether data is currently encrypted 156 | bool m_encrypted{true}; 157 | }; 158 | 159 | // This function exists purely to extract the number of elements 'N' in the 160 | // array 'data' 161 | template 162 | constexpr auto make_obfuscator(const char(&data)[N]) { 163 | return obfuscator(data); 164 | } 165 | } 166 | //====================================================================================================================== 167 | // Obfuscates the string 'data' at compile-time and returns a reference to a 168 | // ay::obfuscated_data object with global lifetime that has functions for 169 | // decrypting the string and is also implicitly convertable to a char* 170 | #define OBFUSCATE(data) OBFUSCATE_KEY(data, AY_OBFUSCATE_DEFAULT_KEY) 171 | //====================================================================================================================== 172 | // Obfuscates the string 'data' with 'key' at compile-time and returns a 173 | // reference to a ay::obfuscated_data object with global lifetime that has 174 | // functions for decrypting the string and is also implicitly convertable to a 175 | // char* 176 | #define OBFUSCATE_KEY(data, key) \ 177 | []() -> ay::obfuscated_data& { \ 178 | static_assert(sizeof(decltype(key)) == sizeof(ay::key_type), "key must be a 64 bit unsigned integer"); \ 179 | static_assert((key) >= (1ull << 56), "key must span all 8 bytes"); \ 180 | constexpr auto n = sizeof(data)/sizeof(data[0]); \ 181 | constexpr auto obfuscator = ay::make_obfuscator(data); \ 182 | static auto obfuscated_data = ay::obfuscated_data(obfuscator); \ 183 | return obfuscated_data; \ 184 | }() 185 | #endif 186 | /* -------------------------------- LICENSE ------------------------------------ 187 | Public Domain (http://www.unlicense.org) 188 | This is free and unencumbered software released into the public domain. 189 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 190 | software, either in source code form or as a compiled binary, for any purpose, 191 | commercial or non-commercial, and by any means. 192 | In jurisdictions that recognize copyright laws, the author or authors of this 193 | software dedicate any and all copyright interest in the software to the public 194 | domain. We make this dedication for the benefit of the public at large and to 195 | the detriment of our heirs and successors. We intend this dedication to be an 196 | overt act of relinquishment in perpetuity of all present and future rights to 197 | this software under copyright law. 198 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 199 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 200 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE 201 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 202 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 203 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 204 | ----------------------------------------------------------------------------- */ -------------------------------------------------------------------------------- /app/src/main/cpp/misc/dobby/arm64-v8a/libdobby.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaughingMuffin/android_imgui_surface_mod_menu_template/9f976e88951922cfe4c2c7df37dcf99b31363325/app/src/main/cpp/misc/dobby/arm64-v8a/libdobby.a -------------------------------------------------------------------------------- /app/src/main/cpp/misc/dobby/arm64-v8a/libdobby.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaughingMuffin/android_imgui_surface_mod_menu_template/9f976e88951922cfe4c2c7df37dcf99b31363325/app/src/main/cpp/misc/dobby/arm64-v8a/libdobby.so -------------------------------------------------------------------------------- /app/src/main/cpp/misc/dobby/armeabi-v7a/libdobby.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaughingMuffin/android_imgui_surface_mod_menu_template/9f976e88951922cfe4c2c7df37dcf99b31363325/app/src/main/cpp/misc/dobby/armeabi-v7a/libdobby.a -------------------------------------------------------------------------------- /app/src/main/cpp/misc/dobby/armeabi-v7a/libdobby.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaughingMuffin/android_imgui_surface_mod_menu_template/9f976e88951922cfe4c2c7df37dcf99b31363325/app/src/main/cpp/misc/dobby/armeabi-v7a/libdobby.so -------------------------------------------------------------------------------- /app/src/main/cpp/misc/dobby/include/dobby.h: -------------------------------------------------------------------------------- 1 | #ifndef dobby_h 2 | #define dobby_h 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | 11 | typedef uintptr_t addr_t; 12 | typedef uint32_t addr32_t; 13 | typedef uint64_t addr64_t; 14 | 15 | typedef void *dobby_dummy_func_t; 16 | typedef void *asm_func_t; 17 | 18 | #if defined(__arm__) 19 | typedef struct { 20 | uint32_t dummy_0; 21 | uint32_t dummy_1; 22 | 23 | uint32_t dummy_2; 24 | uint32_t sp; 25 | 26 | union { 27 | uint32_t r[13]; 28 | struct { 29 | uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12; 30 | } regs; 31 | } general; 32 | 33 | uint32_t lr; 34 | } DobbyRegisterContext; 35 | #elif defined(__arm64__) || defined(__aarch64__) 36 | #define ARM64_TMP_REG_NDX_0 17 37 | 38 | typedef union _FPReg { 39 | __int128_t q; 40 | struct { 41 | double d1; 42 | double d2; 43 | } d; 44 | struct { 45 | float f1; 46 | float f2; 47 | float f3; 48 | float f4; 49 | } f; 50 | } FPReg; 51 | 52 | // register context 53 | typedef struct { 54 | uint64_t dmmpy_0; // dummy placeholder 55 | uint64_t sp; 56 | 57 | uint64_t dmmpy_1; // dummy placeholder 58 | union { 59 | uint64_t x[29]; 60 | struct { 61 | uint64_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, 62 | x23, x24, x25, x26, x27, x28; 63 | } regs; 64 | } general; 65 | 66 | uint64_t fp; 67 | uint64_t lr; 68 | 69 | union { 70 | FPReg q[32]; 71 | struct { 72 | FPReg q0, q1, q2, q3, q4, q5, q6, q7; 73 | // [!!! READ ME !!!] 74 | // for Arm64, can't access q8 - q31, unless you enable full floating-point register pack 75 | FPReg q8, q9, q10, q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, q21, q22, q23, q24, q25, q26, q27, q28, q29, 76 | q30, q31; 77 | } regs; 78 | } floating; 79 | } DobbyRegisterContext; 80 | #elif defined(_M_IX86) || defined(__i386__) 81 | typedef struct _RegisterContext { 82 | uint32_t dummy_0; 83 | uint32_t esp; 84 | 85 | uint32_t dummy_1; 86 | uint32_t flags; 87 | 88 | union { 89 | struct { 90 | uint32_t eax, ebx, ecx, edx, ebp, esp, edi, esi; 91 | } regs; 92 | } general; 93 | 94 | } DobbyRegisterContext; 95 | #elif defined(_M_X64) || defined(__x86_64__) 96 | typedef struct { 97 | uint64_t dummy_0; 98 | uint64_t rsp; 99 | 100 | union { 101 | struct { 102 | uint64_t rax, rbx, rcx, rdx, rbp, rsp, rdi, rsi, r8, r9, r10, r11, r12, r13, r14, r15; 103 | } regs; 104 | } general; 105 | 106 | uint64_t dummy_1; 107 | uint64_t flags; 108 | } DobbyRegisterContext; 109 | #endif 110 | 111 | #define install_hook_name(name, fn_ret_t, fn_args_t...) \ 112 | static fn_ret_t fake_##name(fn_args_t); \ 113 | static fn_ret_t (*orig_##name)(fn_args_t); \ 114 | /* __attribute__((constructor)) */ static void install_hook_##name(void *sym_addr) { \ 115 | DobbyHook(sym_addr, (dobby_dummy_func_t)fake_##name, (dobby_dummy_func_t *)&orig_##name); \ 116 | return; \ 117 | } \ 118 | fn_ret_t fake_##name(fn_args_t) 119 | 120 | // memory code patch 121 | int DobbyCodePatch(void *address, uint8_t *buffer, uint32_t buffer_size); 122 | 123 | // function inline hook 124 | int DobbyHook(void *address, dobby_dummy_func_t replace_func, dobby_dummy_func_t *origin_func); 125 | 126 | // dynamic binary instruction instrument 127 | // for Arm64, can't access q8 - q31, unless enable full floating-point register pack 128 | typedef void (*dobby_instrument_callback_t)(void *address, DobbyRegisterContext *ctx); 129 | int DobbyInstrument(void *address, dobby_instrument_callback_t pre_handler); 130 | 131 | // destroy and restore code patch 132 | int DobbyDestroy(void *address); 133 | 134 | const char *DobbyGetVersion(); 135 | 136 | // symbol resolver 137 | void *DobbySymbolResolver(const char *image_name, const char *symbol_name); 138 | 139 | // import table replace 140 | int DobbyImportTableReplace(char *image_name, char *symbol_name, dobby_dummy_func_t fake_func, 141 | dobby_dummy_func_t *orig_func); 142 | 143 | // for arm, Arm64, try use b xxx instead of ldr absolute indirect branch 144 | // for x86, x64, always use absolute indirect jump 145 | void dobby_enable_near_branch_trampoline(); 146 | void dobby_disable_near_branch_trampoline(); 147 | 148 | #ifdef __cplusplus 149 | } 150 | #endif 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /app/src/main/cpp/misc/dobby/x86/libdobby.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaughingMuffin/android_imgui_surface_mod_menu_template/9f976e88951922cfe4c2c7df37dcf99b31363325/app/src/main/cpp/misc/dobby/x86/libdobby.a -------------------------------------------------------------------------------- /app/src/main/cpp/misc/dobby/x86/libdobby.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaughingMuffin/android_imgui_surface_mod_menu_template/9f976e88951922cfe4c2c7df37dcf99b31363325/app/src/main/cpp/misc/dobby/x86/libdobby.so -------------------------------------------------------------------------------- /app/src/main/cpp/misc/dobby/x86_64/libdobby.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaughingMuffin/android_imgui_surface_mod_menu_template/9f976e88951922cfe4c2c7df37dcf99b31363325/app/src/main/cpp/misc/dobby/x86_64/libdobby.a -------------------------------------------------------------------------------- /app/src/main/cpp/misc/dobby/x86_64/libdobby.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaughingMuffin/android_imgui_surface_mod_menu_template/9f976e88951922cfe4c2c7df37dcf99b31363325/app/src/main/cpp/misc/dobby/x86_64/libdobby.so -------------------------------------------------------------------------------- /app/src/main/cpp/misc/imgui/backends/imgui_impl_android.cpp: -------------------------------------------------------------------------------- 1 | // dear imgui: Platform Binding for Android native app 2 | // This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3) 3 | 4 | // Implemented features: 5 | // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] 6 | // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. 7 | // Missing features: 8 | // [ ] Platform: Clipboard support. 9 | // [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. 10 | // [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. 11 | // Important: 12 | // - Consider using SDL or GLFW backend on Android, which will be more full-featured than this. 13 | // - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446) 14 | // - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446) 15 | 16 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 17 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. 18 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 19 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 20 | 21 | // CHANGELOG 22 | // (minor and older changes stripped away, please see git history for details) 23 | // 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported). 24 | // 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion. 25 | // 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+). 26 | // 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range. 27 | // 2021-03-04: Initial version. 28 | 29 | #include "imgui.h" 30 | #ifndef IMGUI_DISABLE 31 | #include "imgui_impl_android.h" 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | // Android data 39 | static double g_Time = 0.0; 40 | static ANativeWindow* g_Window; 41 | #define Info_Log(...) __android_log_print(ANDROID_LOG_INFO, "MUFFIN-IMGUI", __VA_ARGS__); 42 | 43 | static ImGuiKey ImGui_ImplAndroid_KeyCodeToImGuiKey(int32_t key_code) { 44 | switch (key_code) 45 | { 46 | case AKEYCODE_TAB: return ImGuiKey_Tab; 47 | case AKEYCODE_DPAD_LEFT: return ImGuiKey_LeftArrow; 48 | case AKEYCODE_DPAD_RIGHT: return ImGuiKey_RightArrow; 49 | case AKEYCODE_DPAD_UP: return ImGuiKey_UpArrow; 50 | case AKEYCODE_DPAD_DOWN: return ImGuiKey_DownArrow; 51 | case AKEYCODE_PAGE_UP: return ImGuiKey_PageUp; 52 | case AKEYCODE_PAGE_DOWN: return ImGuiKey_PageDown; 53 | case AKEYCODE_MOVE_HOME: return ImGuiKey_Home; 54 | case AKEYCODE_MOVE_END: return ImGuiKey_End; 55 | case AKEYCODE_INSERT: return ImGuiKey_Insert; 56 | case AKEYCODE_FORWARD_DEL: return ImGuiKey_Delete; 57 | case AKEYCODE_DEL: return ImGuiKey_Backspace; 58 | case AKEYCODE_SPACE: return ImGuiKey_Space; 59 | case AKEYCODE_ENTER: return ImGuiKey_Enter; 60 | case AKEYCODE_ESCAPE: return ImGuiKey_Escape; 61 | case AKEYCODE_APOSTROPHE: return ImGuiKey_Apostrophe; 62 | case AKEYCODE_COMMA: return ImGuiKey_Comma; 63 | case AKEYCODE_MINUS: return ImGuiKey_Minus; 64 | case AKEYCODE_PERIOD: return ImGuiKey_Period; 65 | case AKEYCODE_SLASH: return ImGuiKey_Slash; 66 | case AKEYCODE_SEMICOLON: return ImGuiKey_Semicolon; 67 | case AKEYCODE_EQUALS: return ImGuiKey_Equal; 68 | case AKEYCODE_LEFT_BRACKET: return ImGuiKey_LeftBracket; 69 | case AKEYCODE_BACKSLASH: return ImGuiKey_Backslash; 70 | case AKEYCODE_RIGHT_BRACKET: return ImGuiKey_RightBracket; 71 | case AKEYCODE_GRAVE: return ImGuiKey_GraveAccent; 72 | case AKEYCODE_CAPS_LOCK: return ImGuiKey_CapsLock; 73 | case AKEYCODE_SCROLL_LOCK: return ImGuiKey_ScrollLock; 74 | case AKEYCODE_NUM_LOCK: return ImGuiKey_NumLock; 75 | case AKEYCODE_SYSRQ: return ImGuiKey_PrintScreen; 76 | case AKEYCODE_BREAK: return ImGuiKey_Pause; 77 | case AKEYCODE_NUMPAD_0: return ImGuiKey_Keypad0; 78 | case AKEYCODE_NUMPAD_1: return ImGuiKey_Keypad1; 79 | case AKEYCODE_NUMPAD_2: return ImGuiKey_Keypad2; 80 | case AKEYCODE_NUMPAD_3: return ImGuiKey_Keypad3; 81 | case AKEYCODE_NUMPAD_4: return ImGuiKey_Keypad4; 82 | case AKEYCODE_NUMPAD_5: return ImGuiKey_Keypad5; 83 | case AKEYCODE_NUMPAD_6: return ImGuiKey_Keypad6; 84 | case AKEYCODE_NUMPAD_7: return ImGuiKey_Keypad7; 85 | case AKEYCODE_NUMPAD_8: return ImGuiKey_Keypad8; 86 | case AKEYCODE_NUMPAD_9: return ImGuiKey_Keypad9; 87 | case AKEYCODE_NUMPAD_DOT: return ImGuiKey_KeypadDecimal; 88 | case AKEYCODE_NUMPAD_DIVIDE: return ImGuiKey_KeypadDivide; 89 | case AKEYCODE_NUMPAD_MULTIPLY: return ImGuiKey_KeypadMultiply; 90 | case AKEYCODE_NUMPAD_SUBTRACT: return ImGuiKey_KeypadSubtract; 91 | case AKEYCODE_NUMPAD_ADD: return ImGuiKey_KeypadAdd; 92 | case AKEYCODE_NUMPAD_ENTER: return ImGuiKey_KeypadEnter; 93 | case AKEYCODE_NUMPAD_EQUALS: return ImGuiKey_KeypadEqual; 94 | case AKEYCODE_CTRL_LEFT: return ImGuiKey_LeftCtrl; 95 | case AKEYCODE_SHIFT_LEFT: return ImGuiKey_LeftShift; 96 | case AKEYCODE_ALT_LEFT: return ImGuiKey_LeftAlt; 97 | case AKEYCODE_META_LEFT: return ImGuiKey_LeftSuper; 98 | case AKEYCODE_CTRL_RIGHT: return ImGuiKey_RightCtrl; 99 | case AKEYCODE_SHIFT_RIGHT: return ImGuiKey_RightShift; 100 | case AKEYCODE_ALT_RIGHT: return ImGuiKey_RightAlt; 101 | case AKEYCODE_META_RIGHT: return ImGuiKey_RightSuper; 102 | case AKEYCODE_MENU: return ImGuiKey_Menu; 103 | case AKEYCODE_0: return ImGuiKey_0; 104 | case AKEYCODE_1: return ImGuiKey_1; 105 | case AKEYCODE_2: return ImGuiKey_2; 106 | case AKEYCODE_3: return ImGuiKey_3; 107 | case AKEYCODE_4: return ImGuiKey_4; 108 | case AKEYCODE_5: return ImGuiKey_5; 109 | case AKEYCODE_6: return ImGuiKey_6; 110 | case AKEYCODE_7: return ImGuiKey_7; 111 | case AKEYCODE_8: return ImGuiKey_8; 112 | case AKEYCODE_9: return ImGuiKey_9; 113 | case AKEYCODE_A: return ImGuiKey_A; 114 | case AKEYCODE_B: return ImGuiKey_B; 115 | case AKEYCODE_C: return ImGuiKey_C; 116 | case AKEYCODE_D: return ImGuiKey_D; 117 | case AKEYCODE_E: return ImGuiKey_E; 118 | case AKEYCODE_F: return ImGuiKey_F; 119 | case AKEYCODE_G: return ImGuiKey_G; 120 | case AKEYCODE_H: return ImGuiKey_H; 121 | case AKEYCODE_I: return ImGuiKey_I; 122 | case AKEYCODE_J: return ImGuiKey_J; 123 | case AKEYCODE_K: return ImGuiKey_K; 124 | case AKEYCODE_L: return ImGuiKey_L; 125 | case AKEYCODE_M: return ImGuiKey_M; 126 | case AKEYCODE_N: return ImGuiKey_N; 127 | case AKEYCODE_O: return ImGuiKey_O; 128 | case AKEYCODE_P: return ImGuiKey_P; 129 | case AKEYCODE_Q: return ImGuiKey_Q; 130 | case AKEYCODE_R: return ImGuiKey_R; 131 | case AKEYCODE_S: return ImGuiKey_S; 132 | case AKEYCODE_T: return ImGuiKey_T; 133 | case AKEYCODE_U: return ImGuiKey_U; 134 | case AKEYCODE_V: return ImGuiKey_V; 135 | case AKEYCODE_W: return ImGuiKey_W; 136 | case AKEYCODE_X: return ImGuiKey_X; 137 | case AKEYCODE_Y: return ImGuiKey_Y; 138 | case AKEYCODE_Z: return ImGuiKey_Z; 139 | case AKEYCODE_F1: return ImGuiKey_F1; 140 | case AKEYCODE_F2: return ImGuiKey_F2; 141 | case AKEYCODE_F3: return ImGuiKey_F3; 142 | case AKEYCODE_F4: return ImGuiKey_F4; 143 | case AKEYCODE_F5: return ImGuiKey_F5; 144 | case AKEYCODE_F6: return ImGuiKey_F6; 145 | case AKEYCODE_F7: return ImGuiKey_F7; 146 | case AKEYCODE_F8: return ImGuiKey_F8; 147 | case AKEYCODE_F9: return ImGuiKey_F9; 148 | case AKEYCODE_F10: return ImGuiKey_F10; 149 | case AKEYCODE_F11: return ImGuiKey_F11; 150 | case AKEYCODE_F12: return ImGuiKey_F12; 151 | default: return ImGuiKey_None; 152 | } 153 | } 154 | 155 | int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event) { 156 | ImGuiIO& io = ImGui::GetIO(); 157 | 158 | int32_t event_type = AInputEvent_getType(input_event); 159 | switch (event_type) 160 | { 161 | case AINPUT_EVENT_TYPE_KEY: 162 | { 163 | int32_t event_key_code = AKeyEvent_getKeyCode(input_event); 164 | int32_t event_scan_code = AKeyEvent_getScanCode(input_event); 165 | int32_t event_action = AKeyEvent_getAction(input_event); 166 | int32_t event_meta_state = AKeyEvent_getMetaState(input_event); 167 | 168 | io.AddKeyEvent(ImGuiMod_Ctrl, (event_meta_state & AMETA_CTRL_ON) != 0); 169 | io.AddKeyEvent(ImGuiMod_Shift, (event_meta_state & AMETA_SHIFT_ON) != 0); 170 | io.AddKeyEvent(ImGuiMod_Alt, (event_meta_state & AMETA_ALT_ON) != 0); 171 | io.AddKeyEvent(ImGuiMod_Super, (event_meta_state & AMETA_META_ON) != 0); 172 | 173 | switch (event_action) 174 | { 175 | // FIXME: AKEY_EVENT_ACTION_DOWN and AKEY_EVENT_ACTION_UP occur at once as soon as a touch pointer 176 | // goes up from a key. We use a simple key event queue/ and process one event per key per frame in 177 | // ImGui_ImplAndroid_NewFrame()...or consider using IO queue, if suitable: https://github.com/ocornut/imgui/issues/2787 178 | case AKEY_EVENT_ACTION_DOWN: 179 | case AKEY_EVENT_ACTION_UP: 180 | { 181 | ImGuiKey key = ImGui_ImplAndroid_KeyCodeToImGuiKey(event_key_code); 182 | if (key != ImGuiKey_None && (event_action == AKEY_EVENT_ACTION_DOWN || event_action == AKEY_EVENT_ACTION_UP)) 183 | { 184 | io.AddKeyEvent(key, event_action == AKEY_EVENT_ACTION_DOWN); 185 | io.SetKeyEventNativeData(key, event_key_code, event_scan_code); 186 | } 187 | 188 | break; 189 | } 190 | default: 191 | break; 192 | } 193 | break; 194 | } 195 | case AINPUT_EVENT_TYPE_MOTION: 196 | { 197 | int32_t event_action = AMotionEvent_getAction(input_event); 198 | int32_t event_pointer_index = (event_action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; 199 | event_action &= AMOTION_EVENT_ACTION_MASK; 200 | 201 | switch (AMotionEvent_getToolType(input_event, event_pointer_index)) 202 | { 203 | case AMOTION_EVENT_TOOL_TYPE_MOUSE: 204 | io.AddMouseSourceEvent(ImGuiMouseSource_Mouse); 205 | break; 206 | case AMOTION_EVENT_TOOL_TYPE_STYLUS: 207 | case AMOTION_EVENT_TOOL_TYPE_ERASER: 208 | io.AddMouseSourceEvent(ImGuiMouseSource_Pen); 209 | break; 210 | case AMOTION_EVENT_TOOL_TYPE_FINGER: 211 | default: 212 | io.AddMouseSourceEvent(ImGuiMouseSource_TouchScreen); 213 | break; 214 | } 215 | 216 | switch (event_action) 217 | { 218 | case AMOTION_EVENT_ACTION_DOWN: 219 | case AMOTION_EVENT_ACTION_UP: 220 | // Physical mouse buttons (and probably other physical devices) also invoke the actions AMOTION_EVENT_ACTION_DOWN/_UP, 221 | // but we have to process them separately to identify the actual button pressed. This is done below via 222 | // AMOTION_EVENT_ACTION_BUTTON_PRESS/_RELEASE. Here, we only process "FINGER" input (and "UNKNOWN", as a fallback). 223 | if((AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_FINGER) 224 | || (AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_UNKNOWN)) 225 | { 226 | io.MouseDown[0] = (event_action == AMOTION_EVENT_ACTION_DOWN); 227 | ImVec2 pos(AMotionEvent_getRawX(input_event, event_pointer_index), AMotionEvent_getRawY(input_event, event_pointer_index)); 228 | io.MousePos = ImVec2(pos.x, pos.y); 229 | } 230 | break; 231 | case AMOTION_EVENT_ACTION_BUTTON_PRESS: 232 | case AMOTION_EVENT_ACTION_BUTTON_RELEASE: 233 | { 234 | int32_t button_state = AMotionEvent_getButtonState(input_event); 235 | io.AddMouseButtonEvent(0, (button_state & AMOTION_EVENT_BUTTON_PRIMARY) != 0); 236 | io.AddMouseButtonEvent(1, (button_state & AMOTION_EVENT_BUTTON_SECONDARY) != 0); 237 | io.AddMouseButtonEvent(2, (button_state & AMOTION_EVENT_BUTTON_TERTIARY) != 0); 238 | } 239 | break; 240 | case AMOTION_EVENT_ACTION_HOVER_MOVE: // Hovering: Tool moves while NOT pressed (such as a physical mouse) 241 | case AMOTION_EVENT_ACTION_MOVE: // Touch pointer moves while DOWN 242 | { 243 | ImVec2 pos(AMotionEvent_getRawX(input_event, event_pointer_index), AMotionEvent_getRawY(input_event, event_pointer_index)); 244 | io.MousePos = ImVec2(pos.x, pos.y); 245 | } 246 | break; 247 | case AMOTION_EVENT_ACTION_SCROLL: 248 | io.AddMouseWheelEvent(AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_HSCROLL, event_pointer_index), AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_VSCROLL, event_pointer_index)); 249 | break; 250 | default: 251 | break; 252 | } 253 | } 254 | return 1; 255 | default: 256 | break; 257 | } 258 | 259 | return 0; 260 | } 261 | 262 | bool ImGui_ImplAndroid_Init(ANativeWindow* window) { 263 | g_Window = window; 264 | g_Time = 0.0; 265 | 266 | // Setup backend capabilities flags 267 | ImGuiIO& io = ImGui::GetIO(); 268 | io.BackendPlatformName = "imgui_impl_android"; 269 | 270 | return true; 271 | } 272 | 273 | void ImGui_ImplAndroid_Shutdown() { 274 | ImGuiIO& io = ImGui::GetIO(); 275 | io.BackendPlatformName = nullptr; 276 | } 277 | 278 | void ImGui_ImplAndroid_NewFrame() { 279 | ImGuiIO& io = ImGui::GetIO(); 280 | 281 | // Setup display size (every frame to accommodate for window resizing) 282 | int32_t window_width = ANativeWindow_getWidth(g_Window); 283 | int32_t window_height = ANativeWindow_getHeight(g_Window); 284 | int display_width = window_width; 285 | int display_height = window_height; 286 | 287 | io.DisplaySize = ImVec2((float)window_width, (float)window_height); 288 | if (window_width > 0 && window_height > 0) 289 | io.DisplayFramebufferScale = ImVec2((float)display_width / window_width, (float)display_height / window_height); 290 | 291 | // Setup time step 292 | struct timespec current_timespec; 293 | clock_gettime(CLOCK_MONOTONIC, ¤t_timespec); 294 | double current_time = (double)(current_timespec.tv_sec) + (current_timespec.tv_nsec / 1000000000.0); 295 | io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f); 296 | g_Time = current_time; 297 | } 298 | 299 | void ImGui_ImplAndroid_NewFrame(int width, int height) { 300 | ImGuiIO& io = ImGui::GetIO(); 301 | 302 | // Setup display size (every frame to accommodate for window resizing) 303 | int32_t window_width = (int32_t)width; 304 | int32_t window_height = (int32_t)height; 305 | int display_width = window_width; 306 | int display_height = window_height; 307 | 308 | io.DisplaySize = ImVec2((float)window_width, (float)window_height); 309 | if (window_width > 0 && window_height > 0) 310 | io.DisplayFramebufferScale = ImVec2((float)display_width / window_width, (float)display_height / window_height); 311 | 312 | // Setup time step 313 | struct timespec current_timespec; 314 | clock_gettime(CLOCK_MONOTONIC, ¤t_timespec); 315 | double current_time = (double)(current_timespec.tv_sec) + (current_timespec.tv_nsec / 1000000000.0); 316 | io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f); 317 | g_Time = current_time; 318 | } 319 | 320 | //----------------------------------------------------------------------------- 321 | 322 | #endif // #ifndef IMGUI_DISABLE 323 | -------------------------------------------------------------------------------- /app/src/main/cpp/misc/imgui/backends/imgui_impl_android.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Platform Binding for Android native app 2 | // This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3) 3 | 4 | // Implemented features: 5 | // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] 6 | // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. 7 | // Missing features: 8 | // [ ] Platform: Clipboard support. 9 | // [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. 10 | // [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. 11 | // Important: 12 | // - Consider using SDL or GLFW backend on Android, which will be more full-featured than this. 13 | // - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446) 14 | // - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446) 15 | 16 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 17 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. 18 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 19 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 20 | 21 | #pragma once 22 | #include "imgui.h" // IMGUI_IMPL_API 23 | #ifndef IMGUI_DISABLE 24 | 25 | struct ANativeWindow; 26 | struct AInputEvent; 27 | 28 | IMGUI_IMPL_API bool ImGui_ImplAndroid_Init(ANativeWindow* window); 29 | IMGUI_IMPL_API int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event); 30 | IMGUI_IMPL_API void ImGui_ImplAndroid_Shutdown(); 31 | IMGUI_IMPL_API void ImGui_ImplAndroid_NewFrame(); 32 | IMGUI_IMPL_API void ImGui_ImplAndroid_NewFrame(int screen_width = 0, int screen_height = 0); 33 | 34 | #endif // #ifndef IMGUI_DISABLE 35 | -------------------------------------------------------------------------------- /app/src/main/cpp/misc/imgui/backends/imgui_impl_opengl3.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline 2 | // - Desktop GL: 2.x 3.x 4.x 3 | // - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0) 4 | // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) 5 | 6 | // Implemented features: 7 | // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! 8 | // [x] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only). 9 | 10 | // About WebGL/ES: 11 | // - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES. 12 | // - This is done automatically on iOS, Android and Emscripten targets. 13 | // - For other targets, the define needs to be visible from the imgui_impl_opengl3.cpp compilation unit. If unsure, define globally or in imconfig.h. 14 | 15 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 16 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. 17 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 18 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 19 | 20 | // About GLSL version: 21 | // The 'glsl_version' initialization parameter should be nullptr (default) or a "#version XXX" string. 22 | // On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es" 23 | // Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp. 24 | 25 | #pragma once 26 | #include "imgui.h" // IMGUI_IMPL_API 27 | #ifndef IMGUI_DISABLE 28 | 29 | // Backend API 30 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = nullptr); 31 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown(); 32 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame(); 33 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); 34 | 35 | // (Optional) Called by Init/NewFrame/Shutdown 36 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture(); 37 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture(); 38 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects(); 39 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects(); 40 | 41 | // Specific OpenGL ES versions 42 | //#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten 43 | //#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android 44 | 45 | // You can explicitly select GLES2 or GLES3 API by using one of the '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line. 46 | #if !defined(IMGUI_IMPL_OPENGL_ES2) \ 47 | && !defined(IMGUI_IMPL_OPENGL_ES3) 48 | 49 | // Try to detect GLES on matching platforms 50 | #if defined(__APPLE__) 51 | #include 52 | #endif 53 | #if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__)) 54 | #define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es" 55 | #elif defined(__EMSCRIPTEN__) || defined(__amigaos4__) 56 | #define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100" 57 | #else 58 | // Otherwise imgui_impl_opengl3_loader.h will be used. 59 | #endif 60 | 61 | #endif 62 | 63 | #endif // #ifndef IMGUI_DISABLE 64 | -------------------------------------------------------------------------------- /app/src/main/cpp/misc/imgui/imconfig.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // DEAR IMGUI COMPILE-TIME OPTIONS 3 | // Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. 4 | // You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. 5 | //----------------------------------------------------------------------------- 6 | // A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it) 7 | // B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template. 8 | //----------------------------------------------------------------------------- 9 | // You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp 10 | // files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. 11 | // Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. 12 | // Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using. 13 | //----------------------------------------------------------------------------- 14 | 15 | #pragma once 16 | 17 | //---- Define assertion handler. Defaults to calling assert(). 18 | // If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement. 19 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR) 20 | //#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts 21 | 22 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows 23 | // Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. 24 | // DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() 25 | // for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. 26 | //#define IMGUI_API __declspec( dllexport ) 27 | //#define IMGUI_API __declspec( dllimport ) 28 | 29 | //---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names. 30 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS 31 | //#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions. 32 | 33 | //---- Disable all of Dear ImGui or don't implement standard windows/tools. 34 | // It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp. 35 | //#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. 36 | //#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. 37 | //#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowStackToolWindow() will be empty (this was called IMGUI_DISABLE_METRICS_WINDOW before 1.88). 38 | 39 | //---- Don't implement some functions to reduce linkage requirements. 40 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a) 41 | //#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW) 42 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a) 43 | //#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME). 44 | //#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default). 45 | //#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) 46 | //#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. 47 | //#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) 48 | //#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. 49 | //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). 50 | //#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available 51 | 52 | //---- Include imgui_user.h at the end of imgui.h as a convenience 53 | //#define IMGUI_INCLUDE_IMGUI_USER_H 54 | 55 | //---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) 56 | //#define IMGUI_USE_BGRA_PACKED_COLOR 57 | 58 | //---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...) 59 | //#define IMGUI_USE_WCHAR32 60 | 61 | //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version 62 | // By default the embedded implementations are declared static and not available outside of Dear ImGui sources files. 63 | //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" 64 | //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" 65 | //#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined. 66 | //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION 67 | //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION 68 | //#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined. 69 | 70 | //---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined) 71 | // Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h. 72 | //#define IMGUI_USE_STB_SPRINTF 73 | 74 | //---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui) 75 | // Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided). 76 | // On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'. 77 | //#define IMGUI_ENABLE_FREETYPE 78 | 79 | //---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT) 80 | // Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided). 81 | // Only works in combination with IMGUI_ENABLE_FREETYPE. 82 | // (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement) 83 | //#define IMGUI_ENABLE_FREETYPE_LUNASVG 84 | 85 | //---- Use stb_truetype to build and rasterize the font atlas (default) 86 | // The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend. 87 | //#define IMGUI_ENABLE_STB_TRUETYPE 88 | 89 | //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. 90 | // This will be inlined as part of ImVec2 and ImVec4 class declarations. 91 | /* 92 | #define IM_VEC2_CLASS_EXTRA \ 93 | constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \ 94 | operator MyVec2() const { return MyVec2(x,y); } 95 | 96 | #define IM_VEC4_CLASS_EXTRA \ 97 | constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \ 98 | operator MyVec4() const { return MyVec4(x,y,z,w); } 99 | */ 100 | //---- ...Or use Dear ImGui's own very basic math operators. 101 | //#define IMGUI_DEFINE_MATH_OPERATORS 102 | 103 | //---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. 104 | // Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices). 105 | // Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer. 106 | // Read about ImGuiBackendFlags_RendererHasVtxOffset for details. 107 | //#define ImDrawIdx unsigned int 108 | 109 | //---- Override ImDrawCallback signature (will need to modify renderer backends accordingly) 110 | //struct ImDrawList; 111 | //struct ImDrawCmd; 112 | //typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); 113 | //#define ImDrawCallback MyImDrawCallback 114 | 115 | //---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase) 116 | // (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.) 117 | //#define IM_DEBUG_BREAK IM_ASSERT(0) 118 | //#define IM_DEBUG_BREAK __debugbreak() 119 | 120 | //---- Debug Tools: Enable slower asserts 121 | //#define IMGUI_DEBUG_PARANOID 122 | 123 | //---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files) 124 | /* 125 | namespace ImGui 126 | { 127 | void MyFunction(const char* name, MyMatrix44* mtx); 128 | } 129 | */ 130 | -------------------------------------------------------------------------------- /app/src/main/cpp/misc/xdl/xdl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 HexHacking Team 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2020-10-04. 23 | 24 | // 25 | // xDL version: 2.0.0 26 | // 27 | // xDL is an enhanced implementation of the Android DL series functions. 28 | // For more information, documentation, and the latest version please check: 29 | // https://github.com/hexhacking/xDL 30 | // 31 | 32 | #ifndef IO_GITHUB_HEXHACKING_XDL 33 | #define IO_GITHUB_HEXHACKING_XDL 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | typedef struct { 44 | // same as Dl_info: 45 | const char *dli_fname; // Pathname of shared object that contains address. 46 | void *dli_fbase; // Address at which shared object is loaded. 47 | const char *dli_sname; // Name of nearest symbol with address lower than addr. 48 | void *dli_saddr; // Exact address of symbol named in dli_sname. 49 | // added by xDL: 50 | size_t dli_ssize; // Symbol size of nearest symbol with address lower than addr. 51 | const ElfW(Phdr) *dlpi_phdr; // Pointer to array of ELF program headers for this object. 52 | size_t dlpi_phnum; // Number of items in dlpi_phdr. 53 | } xdl_info_t; 54 | 55 | // 56 | // Default value for flags in both xdl_open() and xdl_iterate_phdr(). 57 | // 58 | #define XDL_DEFAULT 0x00 59 | 60 | // 61 | // Enhanced dlopen() / dlclose() / dlsym(). 62 | // 63 | #define XDL_TRY_FORCE_LOAD 0x01 64 | #define XDL_ALWAYS_FORCE_LOAD 0x02 65 | void *xdl_open(const char *filename, int flags); 66 | void *xdl_close(void *handle); 67 | void *xdl_sym(void *handle, const char *symbol, size_t *symbol_size); 68 | void *xdl_dsym(void *handle, const char *symbol, size_t *symbol_size); 69 | 70 | // 71 | // Enhanced dladdr(). 72 | // 73 | int xdl_addr(void *addr, xdl_info_t *info, void **cache); 74 | void xdl_addr_clean(void **cache); 75 | 76 | // 77 | // Enhanced dl_iterate_phdr(). 78 | // 79 | #define XDL_FULL_PATHNAME 0x01 80 | int xdl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), void *data, int flags); 81 | 82 | // 83 | // Custom dlinfo(). 84 | // 85 | #define XDL_DI_DLINFO 1 // type of info: xdl_info_t 86 | int xdl_info(void *handle, int request, void *info); 87 | 88 | #ifdef __cplusplus 89 | } 90 | #endif 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /app/src/main/cpp/misc/xdl/xdl_iterate.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 HexHacking Team 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2020-10-04. 23 | 24 | #include "xdl_iterate.h" 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include "xdl.h" 40 | #include "xdl_linker.h" 41 | #include "xdl_util.h" 42 | 43 | /* 44 | * ========================================================================================================= 45 | * API-LEVEL ANDROID-VERSION SOLUTION 46 | * ========================================================================================================= 47 | * 16 4.1 /proc/self/maps 48 | * 17 4.2 /proc/self/maps 49 | * 18 4.3 /proc/self/maps 50 | * 19 4.4 /proc/self/maps 51 | * 20 4.4W /proc/self/maps 52 | * --------------------------------------------------------------------------------------------------------- 53 | * 21 5.0 dl_iterate_phdr() + __dl__ZL10g_dl_mutex + linker/linker64 from getauxval(3) 54 | * 22 5.1 dl_iterate_phdr() + __dl__ZL10g_dl_mutex + linker/linker64 from getauxval(3) 55 | * --------------------------------------------------------------------------------------------------------- 56 | * 23 >= 6.0 dl_iterate_phdr() + linker/linker64 from getauxval(3) 57 | * ========================================================================================================= 58 | */ 59 | 60 | extern __attribute((weak)) int dl_iterate_phdr(int (*)(struct dl_phdr_info *, size_t, void *), void *); 61 | extern __attribute((weak)) unsigned long int getauxval(unsigned long int); 62 | 63 | static uintptr_t xdl_iterate_get_min_vaddr(struct dl_phdr_info *info) { 64 | uintptr_t min_vaddr = UINTPTR_MAX; 65 | for (size_t i = 0; i < info->dlpi_phnum; i++) { 66 | const ElfW(Phdr) *phdr = &(info->dlpi_phdr[i]); 67 | if (PT_LOAD == phdr->p_type) { 68 | if (min_vaddr > phdr->p_vaddr) min_vaddr = phdr->p_vaddr; 69 | } 70 | } 71 | return min_vaddr; 72 | } 73 | 74 | static int xdl_iterate_open_or_rewind_maps(FILE **maps) { 75 | if (NULL == *maps) { 76 | *maps = fopen("/proc/self/maps", "r"); 77 | if (NULL == *maps) return -1; 78 | } else 79 | rewind(*maps); 80 | 81 | return 0; 82 | } 83 | 84 | static int xdl_iterate_get_pathname_from_maps(uintptr_t base, char *buf, size_t buf_len, FILE **maps) { 85 | // open or rewind maps-file 86 | if (0 != xdl_iterate_open_or_rewind_maps(maps)) return -1; // failed 87 | 88 | char line[1024]; 89 | while (fgets(line, sizeof(line), *maps)) { 90 | // check base address 91 | uintptr_t start, end; 92 | if (2 != sscanf(line, "%" SCNxPTR "-%" SCNxPTR " r", &start, &end)) continue; 93 | if (base < start) break; // failed 94 | if (base >= end) continue; 95 | 96 | // get pathname 97 | char *pathname = strchr(line, '/'); 98 | if (NULL == pathname) break; // failed 99 | xdl_util_trim_ending(pathname); 100 | 101 | // found it 102 | strlcpy(buf, pathname, buf_len); 103 | return 0; // OK 104 | } 105 | 106 | return -1; // failed 107 | } 108 | 109 | static int xdl_iterate_by_linker_cb(struct dl_phdr_info *info, size_t size, void *arg) { 110 | uintptr_t *pkg = (uintptr_t *)arg; 111 | xdl_iterate_phdr_cb_t cb = (xdl_iterate_phdr_cb_t)*pkg++; 112 | void *cb_arg = (void *)*pkg++; 113 | FILE **maps = (FILE **)*pkg++; 114 | uintptr_t linker_load_bias = *pkg++; 115 | int flags = (int)*pkg; 116 | 117 | // ignore invalid ELF 118 | if (0 == info->dlpi_addr || NULL == info->dlpi_name || '\0' == info->dlpi_name[0]) return 0; 119 | 120 | // ignore linker if we have returned it already 121 | if (linker_load_bias == info->dlpi_addr) return 0; 122 | 123 | struct dl_phdr_info info_fixed; 124 | info_fixed.dlpi_addr = info->dlpi_addr; 125 | info_fixed.dlpi_name = info->dlpi_name; 126 | info_fixed.dlpi_phdr = info->dlpi_phdr; 127 | info_fixed.dlpi_phnum = info->dlpi_phnum; 128 | info = &info_fixed; 129 | 130 | // fix dlpi_phdr & dlpi_phnum (from memory) 131 | if (NULL == info->dlpi_phdr || 0 == info->dlpi_phnum) { 132 | ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)info->dlpi_addr; 133 | info->dlpi_phdr = (ElfW(Phdr) *)(info->dlpi_addr + ehdr->e_phoff); 134 | info->dlpi_phnum = ehdr->e_phnum; 135 | } 136 | 137 | // fix dlpi_name (from /proc/self/maps) 138 | if ('/' != info->dlpi_name[0] && '[' != info->dlpi_name[0] && (0 != (flags & XDL_FULL_PATHNAME))) { 139 | // get base address 140 | uintptr_t min_vaddr = xdl_iterate_get_min_vaddr(info); 141 | if (UINTPTR_MAX == min_vaddr) return 0; // ignore this ELF 142 | uintptr_t base = (uintptr_t)(info->dlpi_addr + min_vaddr); 143 | 144 | char buf[1024]; 145 | if (0 != xdl_iterate_get_pathname_from_maps(base, buf, sizeof(buf), maps)) return 0; // ignore this ELF 146 | 147 | info->dlpi_name = (const char *)buf; 148 | } 149 | 150 | // callback 151 | return cb(info, size, cb_arg); 152 | } 153 | 154 | static uintptr_t xdl_iterate_get_linker_base(void) { 155 | if (NULL == getauxval) return 0; 156 | 157 | uintptr_t base = (uintptr_t)getauxval(AT_BASE); 158 | if (0 == base) return 0; 159 | if (0 != memcmp((void *)base, ELFMAG, SELFMAG)) return 0; 160 | 161 | return base; 162 | } 163 | 164 | static int xdl_iterate_do_callback(xdl_iterate_phdr_cb_t cb, void *cb_arg, uintptr_t base, 165 | const char *pathname, uintptr_t *load_bias) { 166 | ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)base; 167 | 168 | struct dl_phdr_info info; 169 | info.dlpi_name = pathname; 170 | info.dlpi_phdr = (const ElfW(Phdr) *)(base + ehdr->e_phoff); 171 | info.dlpi_phnum = ehdr->e_phnum; 172 | 173 | // get load bias 174 | uintptr_t min_vaddr = xdl_iterate_get_min_vaddr(&info); 175 | if (UINTPTR_MAX == min_vaddr) return 0; // ignore invalid ELF 176 | info.dlpi_addr = (ElfW(Addr))(base - min_vaddr); 177 | if (NULL != load_bias) *load_bias = info.dlpi_addr; 178 | 179 | return cb(&info, sizeof(struct dl_phdr_info), cb_arg); 180 | } 181 | 182 | static int xdl_iterate_by_linker(xdl_iterate_phdr_cb_t cb, void *cb_arg, int flags) { 183 | if (NULL == dl_iterate_phdr) return 0; 184 | 185 | int api_level = xdl_util_get_api_level(); 186 | FILE *maps = NULL; 187 | int r; 188 | 189 | // dl_iterate_phdr(3) does NOT contain linker/linker64 when Android version < 8.1 (API level 27). 190 | // Here we always try to get linker base address from auxv. 191 | uintptr_t linker_load_bias = 0; 192 | uintptr_t linker_base = xdl_iterate_get_linker_base(); 193 | if (0 != linker_base) { 194 | if (0 != 195 | (r = xdl_iterate_do_callback(cb, cb_arg, linker_base, XDL_UTIL_LINKER_PATHNAME, &linker_load_bias))) 196 | return r; 197 | } 198 | 199 | // for other ELF 200 | uintptr_t pkg[5] = {(uintptr_t)cb, (uintptr_t)cb_arg, (uintptr_t)&maps, linker_load_bias, (uintptr_t)flags}; 201 | if (__ANDROID_API_L__ == api_level || __ANDROID_API_L_MR1__ == api_level) xdl_linker_lock(); 202 | r = dl_iterate_phdr(xdl_iterate_by_linker_cb, pkg); 203 | if (__ANDROID_API_L__ == api_level || __ANDROID_API_L_MR1__ == api_level) xdl_linker_unlock(); 204 | 205 | if (NULL != maps) fclose(maps); 206 | return r; 207 | } 208 | 209 | #if (defined(__arm__) || defined(__i386__)) && __ANDROID_API__ < __ANDROID_API_L__ 210 | static int xdl_iterate_by_maps(xdl_iterate_phdr_cb_t cb, void *cb_arg) { 211 | FILE *maps = fopen("/proc/self/maps", "r"); 212 | if (NULL == maps) return 0; 213 | 214 | int r = 0; 215 | char buf1[1024], buf2[1024]; 216 | char *line = buf1; 217 | uintptr_t prev_base = 0; 218 | bool try_next_line = false; 219 | 220 | while (fgets(line, sizeof(buf1), maps)) { 221 | // Try to find an ELF which loaded by linker. 222 | uintptr_t base, offset; 223 | char exec; 224 | if (3 != sscanf(line, "%" SCNxPTR "-%*" SCNxPTR " r%*c%cp %" SCNxPTR " ", &base, &exec, &offset)) 225 | goto clean; 226 | 227 | if ('-' == exec && 0 == offset) { 228 | // r--p 229 | prev_base = base; 230 | line = (line == buf1 ? buf2 : buf1); 231 | try_next_line = true; 232 | continue; 233 | } else if (exec == 'x') { 234 | // r-xp 235 | char *pathname = NULL; 236 | if (try_next_line && 0 != offset) { 237 | char *prev = (line == buf1 ? buf2 : buf1); 238 | char *prev_pathname = strchr(prev, '/'); 239 | if (NULL == prev_pathname) goto clean; 240 | 241 | pathname = strchr(line, '/'); 242 | if (NULL == pathname) goto clean; 243 | 244 | xdl_util_trim_ending(prev_pathname); 245 | xdl_util_trim_ending(pathname); 246 | if (0 != strcmp(prev_pathname, pathname)) goto clean; 247 | 248 | // we found the line with r-xp in the next line 249 | base = prev_base; 250 | offset = 0; 251 | } 252 | 253 | if (0 != offset) goto clean; 254 | 255 | // get pathname 256 | if (NULL == pathname) { 257 | pathname = strchr(line, '/'); 258 | if (NULL == pathname) goto clean; 259 | xdl_util_trim_ending(pathname); 260 | } 261 | 262 | if (0 != memcmp((void *)base, ELFMAG, SELFMAG)) goto clean; 263 | ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)base; 264 | struct dl_phdr_info info; 265 | info.dlpi_name = pathname; 266 | info.dlpi_phdr = (const ElfW(Phdr) *)(base + ehdr->e_phoff); 267 | info.dlpi_phnum = ehdr->e_phnum; 268 | 269 | // callback 270 | if (0 != (r = xdl_iterate_do_callback(cb, cb_arg, base, pathname, NULL))) break; 271 | } 272 | 273 | clean: 274 | try_next_line = false; 275 | } 276 | 277 | fclose(maps); 278 | return r; 279 | } 280 | #endif 281 | 282 | int xdl_iterate_phdr_impl(xdl_iterate_phdr_cb_t cb, void *cb_arg, int flags) { 283 | // iterate by /proc/self/maps in Android 4.x (Android 4.x only supports arm32 and x86) 284 | #if (defined(__arm__) || defined(__i386__)) && __ANDROID_API__ < __ANDROID_API_L__ 285 | if (xdl_util_get_api_level() < __ANDROID_API_L__) return xdl_iterate_by_maps(cb, cb_arg); 286 | #endif 287 | 288 | // iterate by dl_iterate_phdr() 289 | return xdl_iterate_by_linker(cb, cb_arg, flags); 290 | } 291 | 292 | int xdl_iterate_get_full_pathname(uintptr_t base, char *buf, size_t buf_len) { 293 | FILE *maps = NULL; 294 | int r = xdl_iterate_get_pathname_from_maps(base, buf, buf_len, &maps); 295 | if (NULL != maps) fclose(maps); 296 | return r; 297 | } 298 | -------------------------------------------------------------------------------- /app/src/main/cpp/misc/xdl/xdl_iterate.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 HexHacking Team 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2020-10-04. 23 | 24 | #ifndef IO_GITHUB_HEXHACKING_XDL_ITERATE 25 | #define IO_GITHUB_HEXHACKING_XDL_ITERATE 26 | 27 | #include 28 | #include 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | typedef int (*xdl_iterate_phdr_cb_t)(struct dl_phdr_info *info, size_t size, void *arg); 35 | int xdl_iterate_phdr_impl(xdl_iterate_phdr_cb_t cb, void *cb_arg, int flags); 36 | 37 | int xdl_iterate_get_full_pathname(uintptr_t base, char *buf, size_t buf_len); 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /app/src/main/cpp/misc/xdl/xdl_linker.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 HexHacking Team 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2021-02-21. 23 | 24 | #include "xdl_linker.h" 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "xdl.h" 32 | #include "xdl_iterate.h" 33 | #include "xdl_util.h" 34 | 35 | #define XDL_LINKER_SYM_MUTEX "__dl__ZL10g_dl_mutex" 36 | #define XDL_LINKER_SYM_DLOPEN_EXT_N "__dl__ZL10dlopen_extPKciPK17android_dlextinfoPv" 37 | #define XDL_LINKER_SYM_DO_DLOPEN_N "__dl__Z9do_dlopenPKciPK17android_dlextinfoPv" 38 | #define XDL_LINKER_SYM_DLOPEN_O "__dl__Z8__dlopenPKciPKv" 39 | #define XDL_LINKER_SYM_LOADER_DLOPEN_P "__loader_dlopen" 40 | 41 | typedef void *(*xdl_linker_dlopen_n_t)(const char *, int, const void *, void *); 42 | typedef void *(*xdl_linker_dlopen_o_t)(const char *, int, const void *); 43 | 44 | static pthread_mutex_t *xdl_linker_mutex = NULL; 45 | static void *xdl_linker_dlopen = NULL; 46 | 47 | static void *xdl_linker_caller_addr[] = { 48 | NULL, // default 49 | NULL, // art 50 | NULL // vendor 51 | }; 52 | 53 | #ifndef __LP64__ 54 | #define XDL_LINKER_LIB "lib" 55 | #else 56 | #define XDL_LINKER_LIB "lib64" 57 | #endif 58 | static const char *xdl_linker_vendor_path[] = { 59 | // order is important 60 | "/vendor/" XDL_LINKER_LIB "/egl/", "/vendor/" XDL_LINKER_LIB "/hw/", 61 | "/vendor/" XDL_LINKER_LIB "/", "/odm/" XDL_LINKER_LIB "/", 62 | "/vendor/" XDL_LINKER_LIB "/vndk-sp/", "/odm/" XDL_LINKER_LIB "/vndk-sp/"}; 63 | 64 | static void xdl_linker_init_symbols_impl(void) { 65 | // find linker from: /proc/self/maps (API level < 18) or getauxval (API level >= 18) 66 | void *handle = xdl_open(XDL_UTIL_LINKER_BASENAME, XDL_DEFAULT); 67 | if (NULL == handle) return; 68 | 69 | int api_level = xdl_util_get_api_level(); 70 | if (__ANDROID_API_L__ == api_level || __ANDROID_API_L_MR1__ == api_level) { 71 | // == Android 5.x 72 | xdl_linker_mutex = (pthread_mutex_t *)xdl_dsym(handle, XDL_LINKER_SYM_MUTEX, NULL); 73 | } else if (__ANDROID_API_N__ == api_level || __ANDROID_API_N_MR1__ == api_level) { 74 | // == Android 7.x 75 | xdl_linker_dlopen = xdl_dsym(handle, XDL_LINKER_SYM_DLOPEN_EXT_N, NULL); 76 | if (NULL == xdl_linker_dlopen) { 77 | xdl_linker_dlopen = xdl_dsym(handle, XDL_LINKER_SYM_DO_DLOPEN_N, NULL); 78 | xdl_linker_mutex = (pthread_mutex_t *)xdl_dsym(handle, XDL_LINKER_SYM_MUTEX, NULL); 79 | } 80 | } else if (__ANDROID_API_O__ == api_level || __ANDROID_API_O_MR1__ == api_level) { 81 | // == Android 8.x 82 | xdl_linker_dlopen = xdl_dsym(handle, XDL_LINKER_SYM_DLOPEN_O, NULL); 83 | } else if (api_level >= __ANDROID_API_P__) { 84 | // >= Android 9.0 85 | xdl_linker_dlopen = xdl_sym(handle, XDL_LINKER_SYM_LOADER_DLOPEN_P, NULL); 86 | } 87 | 88 | xdl_close(handle); 89 | } 90 | 91 | static void xdl_linker_init_symbols(void) { 92 | static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 93 | static bool inited = false; 94 | if (!inited) { 95 | pthread_mutex_lock(&lock); 96 | if (!inited) { 97 | xdl_linker_init_symbols_impl(); 98 | inited = true; 99 | } 100 | pthread_mutex_unlock(&lock); 101 | } 102 | } 103 | 104 | void xdl_linker_lock(void) { 105 | xdl_linker_init_symbols(); 106 | 107 | if (NULL != xdl_linker_mutex) pthread_mutex_lock(xdl_linker_mutex); 108 | } 109 | 110 | void xdl_linker_unlock(void) { 111 | if (NULL != xdl_linker_mutex) pthread_mutex_unlock(xdl_linker_mutex); 112 | } 113 | 114 | static void *xdl_linker_get_caller_addr(struct dl_phdr_info *info) { 115 | for (size_t i = 0; i < info->dlpi_phnum; i++) { 116 | const ElfW(Phdr) *phdr = &(info->dlpi_phdr[i]); 117 | if (PT_LOAD == phdr->p_type) { 118 | return (void *)(info->dlpi_addr + phdr->p_vaddr); 119 | } 120 | } 121 | return NULL; 122 | } 123 | 124 | static int xdl_linker_get_caller_addr_cb(struct dl_phdr_info *info, size_t size, void *arg) { 125 | (void)size; 126 | 127 | size_t *vendor_match = (size_t *)arg; 128 | 129 | if (0 == info->dlpi_addr || NULL == info->dlpi_name) return 0; // continue 130 | 131 | if (NULL == xdl_linker_caller_addr[0] && xdl_util_ends_with(info->dlpi_name, "/libc.so")) 132 | xdl_linker_caller_addr[0] = xdl_linker_get_caller_addr(info); 133 | 134 | if (NULL == xdl_linker_caller_addr[1] && xdl_util_ends_with(info->dlpi_name, "/libart.so")) 135 | xdl_linker_caller_addr[1] = xdl_linker_get_caller_addr(info); 136 | 137 | if (0 != *vendor_match) { 138 | for (size_t i = 0; i < *vendor_match; i++) { 139 | if (xdl_util_starts_with(info->dlpi_name, xdl_linker_vendor_path[i])) { 140 | void *caller_addr = xdl_linker_get_caller_addr(info); 141 | if (NULL != caller_addr) { 142 | xdl_linker_caller_addr[2] = caller_addr; 143 | *vendor_match = i; 144 | } 145 | } 146 | } 147 | } 148 | 149 | if (NULL != xdl_linker_caller_addr[0] && NULL != xdl_linker_caller_addr[1] && 0 == *vendor_match) { 150 | return 1; // finish 151 | } else { 152 | return 0; // continue 153 | } 154 | } 155 | 156 | static void xdl_linker_init_caller_addr_impl(void) { 157 | size_t vendor_match = sizeof(xdl_linker_vendor_path) / sizeof(xdl_linker_vendor_path[0]); 158 | xdl_iterate_phdr_impl(xdl_linker_get_caller_addr_cb, &vendor_match, XDL_DEFAULT); 159 | } 160 | 161 | static void xdl_linker_init_caller_addr(void) { 162 | static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 163 | static bool inited = false; 164 | if (!inited) { 165 | pthread_mutex_lock(&lock); 166 | if (!inited) { 167 | xdl_linker_init_caller_addr_impl(); 168 | inited = true; 169 | } 170 | pthread_mutex_unlock(&lock); 171 | } 172 | } 173 | 174 | void *xdl_linker_force_dlopen(const char *filename) { 175 | int api_level = xdl_util_get_api_level(); 176 | 177 | if (api_level <= __ANDROID_API_M__) { 178 | // <= Android 6.0 179 | return dlopen(filename, RTLD_NOW); 180 | } else { 181 | xdl_linker_init_symbols(); 182 | if (NULL == xdl_linker_dlopen) return NULL; 183 | xdl_linker_init_caller_addr(); 184 | 185 | void *handle = NULL; 186 | if (__ANDROID_API_N__ == api_level || __ANDROID_API_N_MR1__ == api_level) { 187 | // == Android 7.x 188 | xdl_linker_lock(); 189 | for (size_t i = 0; i < sizeof(xdl_linker_caller_addr) / sizeof(xdl_linker_caller_addr[0]); i++) { 190 | if (NULL != xdl_linker_caller_addr[i]) { 191 | handle = 192 | ((xdl_linker_dlopen_n_t)xdl_linker_dlopen)(filename, RTLD_NOW, NULL, xdl_linker_caller_addr[i]); 193 | if (NULL != handle) break; 194 | } 195 | } 196 | xdl_linker_unlock(); 197 | } else { 198 | // >= Android 8.0 199 | for (size_t i = 0; i < sizeof(xdl_linker_caller_addr) / sizeof(xdl_linker_caller_addr[0]); i++) { 200 | if (NULL != xdl_linker_caller_addr[i]) { 201 | handle = ((xdl_linker_dlopen_o_t)xdl_linker_dlopen)(filename, RTLD_NOW, xdl_linker_caller_addr[i]); 202 | if (NULL != handle) break; 203 | } 204 | } 205 | } 206 | return handle; 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /app/src/main/cpp/misc/xdl/xdl_linker.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 HexHacking Team 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2021-02-21. 23 | 24 | #ifndef IO_GITHUB_HEXHACKING_XDL_LINKER 25 | #define IO_GITHUB_HEXHACKING_XDL_LINKER 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | void xdl_linker_lock(void); 32 | void xdl_linker_unlock(void); 33 | 34 | void *xdl_linker_force_dlopen(const char *filename); 35 | 36 | #ifdef __cplusplus 37 | } 38 | #endif 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /app/src/main/cpp/misc/xdl/xdl_lzma.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 HexHacking Team 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2020-11-08. 23 | 24 | #include "xdl_lzma.h" 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "xdl.h" 37 | #include "xdl_util.h" 38 | 39 | // LZMA library pathname & symbol names 40 | #ifndef __LP64__ 41 | #define XDL_LZMA_PATHNAME "/system/lib/liblzma.so" 42 | #else 43 | #define XDL_LZMA_PATHNAME "/system/lib64/liblzma.so" 44 | #endif 45 | #define XDL_LZMA_SYM_CRCGEN "CrcGenerateTable" 46 | #define XDL_LZMA_SYM_CRC64GEN "Crc64GenerateTable" 47 | #define XDL_LZMA_SYM_CONSTRUCT "XzUnpacker_Construct" 48 | #define XDL_LZMA_SYM_ISFINISHED "XzUnpacker_IsStreamWasFinished" 49 | #define XDL_LZMA_SYM_FREE "XzUnpacker_Free" 50 | #define XDL_LZMA_SYM_CODE "XzUnpacker_Code" 51 | 52 | // LZMA data type definition 53 | #define SZ_OK 0 54 | typedef struct ISzAlloc ISzAlloc; 55 | typedef const ISzAlloc *ISzAllocPtr; 56 | struct ISzAlloc { 57 | void *(*Alloc)(ISzAllocPtr p, size_t size); 58 | void (*Free)(ISzAllocPtr p, void *address); /* address can be 0 */ 59 | }; 60 | typedef enum { 61 | CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */ 62 | CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ 63 | CODER_STATUS_NOT_FINISHED, /* stream was not finished */ 64 | CODER_STATUS_NEEDS_MORE_INPUT /* you must provide more input bytes */ 65 | } ECoderStatus; 66 | typedef enum { 67 | CODER_FINISH_ANY, /* finish at any point */ 68 | CODER_FINISH_END /* block must be finished at the end */ 69 | } ECoderFinishMode; 70 | 71 | // LZMA function type definition 72 | typedef void (*xdl_lzma_crcgen_t)(void); 73 | typedef void (*xdl_lzma_crc64gen_t)(void); 74 | typedef void (*xdl_lzma_construct_t)(void *, ISzAllocPtr); 75 | typedef int (*xdl_lzma_isfinished_t)(const void *); 76 | typedef void (*xdl_lzma_free_t)(void *); 77 | typedef int (*xdl_lzma_code_t)(void *, uint8_t *, size_t *, const uint8_t *, size_t *, ECoderFinishMode, 78 | ECoderStatus *); 79 | typedef int (*xdl_lzma_code_q_t)(void *, uint8_t *, size_t *, const uint8_t *, size_t *, int, 80 | ECoderFinishMode, ECoderStatus *); 81 | 82 | // LZMA function pointor 83 | static xdl_lzma_construct_t xdl_lzma_construct = NULL; 84 | static xdl_lzma_isfinished_t xdl_lzma_isfinished = NULL; 85 | static xdl_lzma_free_t xdl_lzma_free = NULL; 86 | static void *xdl_lzma_code = NULL; 87 | 88 | // LZMA init 89 | static void xdl_lzma_init() { 90 | void *lzma = xdl_open(XDL_LZMA_PATHNAME, XDL_TRY_FORCE_LOAD); 91 | if (NULL == lzma) return; 92 | 93 | xdl_lzma_crcgen_t crcgen = NULL; 94 | xdl_lzma_crc64gen_t crc64gen = NULL; 95 | if (NULL == (crcgen = (xdl_lzma_crcgen_t)xdl_sym(lzma, XDL_LZMA_SYM_CRCGEN, NULL))) goto end; 96 | if (NULL == (crc64gen = (xdl_lzma_crc64gen_t)xdl_sym(lzma, XDL_LZMA_SYM_CRC64GEN, NULL))) goto end; 97 | if (NULL == (xdl_lzma_construct = (xdl_lzma_construct_t)xdl_sym(lzma, XDL_LZMA_SYM_CONSTRUCT, NULL))) 98 | goto end; 99 | if (NULL == (xdl_lzma_isfinished = (xdl_lzma_isfinished_t)xdl_sym(lzma, XDL_LZMA_SYM_ISFINISHED, NULL))) 100 | goto end; 101 | if (NULL == (xdl_lzma_free = (xdl_lzma_free_t)xdl_sym(lzma, XDL_LZMA_SYM_FREE, NULL))) goto end; 102 | if (NULL == (xdl_lzma_code = xdl_sym(lzma, XDL_LZMA_SYM_CODE, NULL))) goto end; 103 | crcgen(); 104 | crc64gen(); 105 | 106 | end: 107 | xdl_close(lzma); 108 | } 109 | 110 | // LZMA internal alloc / free 111 | static void *xdl_lzma_internal_alloc(ISzAllocPtr p, size_t size) { 112 | (void)p; 113 | return malloc(size); 114 | } 115 | static void xdl_lzma_internal_free(ISzAllocPtr p, void *address) { 116 | (void)p; 117 | free(address); 118 | } 119 | 120 | int xdl_lzma_decompress(uint8_t *src, size_t src_size, uint8_t **dst, size_t *dst_size) { 121 | size_t src_offset = 0; 122 | size_t dst_offset = 0; 123 | size_t src_remaining; 124 | size_t dst_remaining; 125 | ISzAlloc alloc = {.Alloc = xdl_lzma_internal_alloc, .Free = xdl_lzma_internal_free}; 126 | long long state[4096 / sizeof(long long)]; // must be enough, 8-bit aligned 127 | ECoderStatus status; 128 | int api_level = xdl_util_get_api_level(); 129 | 130 | // init and check 131 | static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 132 | static bool inited = false; 133 | if (!inited) { 134 | pthread_mutex_lock(&lock); 135 | if (!inited) { 136 | xdl_lzma_init(); 137 | inited = true; 138 | } 139 | pthread_mutex_unlock(&lock); 140 | } 141 | if (NULL == xdl_lzma_code) return -1; 142 | 143 | xdl_lzma_construct(&state, &alloc); 144 | 145 | *dst_size = 2 * src_size; 146 | *dst = NULL; 147 | do { 148 | *dst_size *= 2; 149 | if (NULL == (*dst = realloc(*dst, *dst_size))) { 150 | xdl_lzma_free(&state); 151 | return -1; 152 | } 153 | 154 | src_remaining = src_size - src_offset; 155 | dst_remaining = *dst_size - dst_offset; 156 | 157 | int result; 158 | if (api_level >= __ANDROID_API_Q__) { 159 | xdl_lzma_code_q_t lzma_code_q = (xdl_lzma_code_q_t)xdl_lzma_code; 160 | result = lzma_code_q(&state, *dst + dst_offset, &dst_remaining, src + src_offset, &src_remaining, 1, 161 | CODER_FINISH_ANY, &status); 162 | } else { 163 | xdl_lzma_code_t lzma_code = (xdl_lzma_code_t)xdl_lzma_code; 164 | result = lzma_code(&state, *dst + dst_offset, &dst_remaining, src + src_offset, &src_remaining, 165 | CODER_FINISH_ANY, &status); 166 | } 167 | if (SZ_OK != result) { 168 | free(*dst); 169 | xdl_lzma_free(&state); 170 | return -1; 171 | } 172 | 173 | src_offset += src_remaining; 174 | dst_offset += dst_remaining; 175 | } while (status == CODER_STATUS_NOT_FINISHED); 176 | 177 | xdl_lzma_free(&state); 178 | 179 | if (!xdl_lzma_isfinished(&state)) { 180 | free(*dst); 181 | return -1; 182 | } 183 | 184 | *dst_size = dst_offset; 185 | *dst = realloc(*dst, *dst_size); 186 | return 0; 187 | } 188 | -------------------------------------------------------------------------------- /app/src/main/cpp/misc/xdl/xdl_lzma.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 HexHacking Team 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2020-11-08. 23 | 24 | #ifndef IO_GITHUB_HEXHACKING_XDL_LZMA 25 | #define IO_GITHUB_HEXHACKING_XDL_LZMA 26 | 27 | #include 28 | #include 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | int xdl_lzma_decompress(uint8_t *src, size_t src_size, uint8_t **dst, size_t *dst_size); 35 | 36 | #ifdef __cplusplus 37 | } 38 | #endif 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /app/src/main/cpp/misc/xdl/xdl_util.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 HexHacking Team 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2020-10-04. 23 | 24 | #include "xdl_util.h" 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | bool xdl_util_starts_with(const char *str, const char *start) { 37 | while (*str && *str == *start) { 38 | str++; 39 | start++; 40 | } 41 | 42 | return '\0' == *start; 43 | } 44 | 45 | bool xdl_util_ends_with(const char *str, const char *ending) { 46 | size_t str_len = strlen(str); 47 | size_t ending_len = strlen(ending); 48 | 49 | if (ending_len > str_len) return false; 50 | 51 | return 0 == strcmp(str + (str_len - ending_len), ending); 52 | } 53 | 54 | size_t xdl_util_trim_ending(char *start) { 55 | char *end = start + strlen(start); 56 | while (start < end && isspace((int)(*(end - 1)))) { 57 | end--; 58 | *end = '\0'; 59 | } 60 | return (size_t)(end - start); 61 | } 62 | 63 | static int xdl_util_get_api_level_from_build_prop(void) { 64 | char buf[128]; 65 | int api_level = -1; 66 | 67 | FILE *fp = fopen("/system/build.prop", "r"); 68 | if (NULL == fp) goto end; 69 | 70 | while (fgets(buf, sizeof(buf), fp)) { 71 | if (xdl_util_starts_with(buf, "ro.build.version.sdk=")) { 72 | api_level = atoi(buf + 21); 73 | break; 74 | } 75 | } 76 | fclose(fp); 77 | 78 | end: 79 | return (api_level > 0) ? api_level : -1; 80 | } 81 | 82 | int xdl_util_get_api_level(void) { 83 | static int xdl_util_api_level = -1; 84 | 85 | if (xdl_util_api_level < 0) { 86 | int api_level = android_get_device_api_level(); 87 | if (api_level < 0) 88 | api_level = xdl_util_get_api_level_from_build_prop(); // compatible with unusual models 89 | if (api_level < __ANDROID_API_J__) api_level = __ANDROID_API_J__; 90 | 91 | __atomic_store_n(&xdl_util_api_level, api_level, __ATOMIC_SEQ_CST); 92 | } 93 | 94 | return xdl_util_api_level; 95 | } 96 | -------------------------------------------------------------------------------- /app/src/main/cpp/misc/xdl/xdl_util.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2023 HexHacking Team 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | // 21 | 22 | // Created by caikelun on 2020-10-04. 23 | 24 | #ifndef IO_GITHUB_HEXHACKING_XDL_UTIL 25 | #define IO_GITHUB_HEXHACKING_XDL_UTIL 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #ifndef __LP64__ 32 | #define XDL_UTIL_LINKER_BASENAME "linker" 33 | #define XDL_UTIL_LINKER_PATHNAME "/system/bin/linker" 34 | #define XDL_UTIL_APP_PROCESS_BASENAME "app_process32" 35 | #define XDL_UTIL_APP_PROCESS_PATHNAME "/system/bin/app_process32" 36 | #define XDL_UTIL_APP_PROCESS_BASENAME_K "app_process" 37 | #define XDL_UTIL_APP_PROCESS_PATHNAME_K "/system/bin/app_process" 38 | #else 39 | #define XDL_UTIL_LINKER_BASENAME "linker64" 40 | #define XDL_UTIL_LINKER_PATHNAME "/system/bin/linker64" 41 | #define XDL_UTIL_APP_PROCESS_BASENAME "app_process64" 42 | #define XDL_UTIL_APP_PROCESS_PATHNAME "/system/bin/app_process64" 43 | #endif 44 | #define XDL_UTIL_VDSO_BASENAME "[vdso]" 45 | 46 | #define XDL_UTIL_TEMP_FAILURE_RETRY(exp) \ 47 | ({ \ 48 | __typeof__(exp) _rc; \ 49 | do { \ 50 | errno = 0; \ 51 | _rc = (exp); \ 52 | } while (_rc == -1 && errno == EINTR); \ 53 | _rc; \ 54 | }) 55 | 56 | #ifdef __cplusplus 57 | extern "C" { 58 | #endif 59 | 60 | bool xdl_util_starts_with(const char *str, const char *start); 61 | bool xdl_util_ends_with(const char *str, const char *ending); 62 | 63 | size_t xdl_util_trim_ending(char *start); 64 | 65 | int xdl_util_get_api_level(void); 66 | 67 | #ifdef __cplusplus 68 | } 69 | #endif 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /app/src/main/java/org/muffin/imgui/GoogleMobileAdsConsentManager.java: -------------------------------------------------------------------------------- 1 | package org.muffin.imgui; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | 6 | import com.google.android.ump.ConsentDebugSettings; 7 | import com.google.android.ump.ConsentForm.OnConsentFormDismissedListener; 8 | import com.google.android.ump.ConsentInformation; 9 | import com.google.android.ump.ConsentInformation.PrivacyOptionsRequirementStatus; 10 | import com.google.android.ump.ConsentRequestParameters; 11 | import com.google.android.ump.FormError; 12 | import com.google.android.ump.UserMessagingPlatform; 13 | 14 | /** 15 | * The Google Mobile Ads SDK provides the User Messaging Platform (Google's 16 | * IAB Certified consent management platform) as one solution to capture 17 | * consent for users in GDPR impacted countries. This is an example and 18 | * you can choose another consent management platform to capture consent. 19 | */ 20 | @SuppressWarnings("NonFinalStaticField") 21 | public class GoogleMobileAdsConsentManager { 22 | private static GoogleMobileAdsConsentManager instance; 23 | private final ConsentInformation consentInformation; 24 | 25 | /** 26 | * Private constructor. 27 | */ 28 | private GoogleMobileAdsConsentManager(Context context) { 29 | this.consentInformation = UserMessagingPlatform.getConsentInformation(context); 30 | } 31 | 32 | /** 33 | * Public constructor. 34 | */ 35 | public static GoogleMobileAdsConsentManager getInstance(Context context) { 36 | if (instance == null) { 37 | instance = new GoogleMobileAdsConsentManager(context); 38 | } 39 | 40 | return instance; 41 | } 42 | 43 | /** 44 | * Interface definition for a callback to be invoked when consent gathering is complete. 45 | */ 46 | public interface OnConsentGatheringCompleteListener { 47 | void consentGatheringComplete(FormError error); 48 | } 49 | 50 | /** 51 | * Helper variable to determine if the app can request ads. 52 | */ 53 | public boolean canRequestAds() { 54 | return consentInformation.canRequestAds(); 55 | } 56 | 57 | /** 58 | * Helper variable to determine if the privacy options form is required. 59 | */ 60 | public boolean isPrivacyOptionsRequired() { 61 | return consentInformation.getPrivacyOptionsRequirementStatus() 62 | == PrivacyOptionsRequirementStatus.REQUIRED; 63 | } 64 | 65 | /** 66 | * Helper method to call the UMP SDK methods to request consent information and load/present a 67 | * consent form if necessary. 68 | */ 69 | public void gatherConsent( 70 | Activity activity, OnConsentGatheringCompleteListener onConsentGatheringCompleteListener) { 71 | // For testing purposes, you can force a DebugGeography of EEA or NOT_EEA. 72 | ConsentDebugSettings debugSettings = new ConsentDebugSettings.Builder(activity) 73 | // .setDebugGeography(ConsentDebugSettings.DebugGeography.DEBUG_GEOGRAPHY_EEA) 74 | // Check your logcat output for the hashed device ID e.g. 75 | // "Use new ConsentDebugSettings.Builder().addTestDeviceHashedId("ABCDEF012345")" to use 76 | // the debug functionality. 77 | .addTestDeviceHashedId("TEST-DEVICE-HASHED-ID") 78 | .build(); 79 | 80 | ConsentRequestParameters params = new ConsentRequestParameters.Builder() 81 | .setConsentDebugSettings(debugSettings) 82 | .build(); 83 | 84 | // Requesting an update to consent information should be called on every app launch. 85 | consentInformation.requestConsentInfoUpdate( 86 | activity, 87 | params, 88 | () -> 89 | // Consent has been gathered. 90 | UserMessagingPlatform.loadAndShowConsentFormIfRequired( 91 | activity, 92 | onConsentGatheringCompleteListener::consentGatheringComplete), 93 | onConsentGatheringCompleteListener::consentGatheringComplete 94 | ); 95 | } 96 | 97 | /** 98 | * Helper method to call the UMP SDK method to present the privacy options form. 99 | */ 100 | public void showPrivacyOptionsForm( 101 | Activity activity, 102 | OnConsentFormDismissedListener onConsentFormDismissedListener) { 103 | UserMessagingPlatform.showPrivacyOptionsForm(activity, onConsentFormDismissedListener); 104 | } 105 | } -------------------------------------------------------------------------------- /app/src/main/java/org/muffin/imgui/MainActivity.java: -------------------------------------------------------------------------------- 1 | package org.muffin.imgui; 2 | 3 | import android.os.Bundle; 4 | import android.os.Handler; 5 | import android.os.Looper; 6 | import android.util.Log; 7 | import android.view.Menu; 8 | import android.view.MenuItem; 9 | import android.view.View; 10 | import android.widget.Button; 11 | import android.widget.FrameLayout; 12 | import android.widget.ImageView; 13 | import android.widget.RatingBar; 14 | import android.widget.TextView; 15 | import android.widget.Toast; 16 | 17 | import androidx.annotation.NonNull; 18 | import androidx.appcompat.app.AppCompatActivity; 19 | import androidx.appcompat.widget.PopupMenu; 20 | 21 | import com.google.android.gms.ads.AdListener; 22 | import com.google.android.gms.ads.AdLoader; 23 | import com.google.android.gms.ads.AdRequest; 24 | import com.google.android.gms.ads.LoadAdError; 25 | import com.google.android.gms.ads.MobileAds; 26 | import com.google.android.gms.ads.VideoController; 27 | import com.google.android.gms.ads.VideoOptions; 28 | import com.google.android.gms.ads.nativead.NativeAd; 29 | import com.google.android.gms.ads.nativead.NativeAdOptions; 30 | import com.google.android.gms.ads.nativead.NativeAdView; 31 | 32 | import org.muffin.imgui.databinding.ActivityMainBinding; 33 | import org.muffin.imgui.muffin.Muffin; 34 | 35 | import java.util.Locale; 36 | import java.util.concurrent.atomic.AtomicBoolean; 37 | 38 | public class MainActivity extends AppCompatActivity { 39 | 40 | private static final String ADMOB_AD_UNIT_ID = "ca-app-pub-3940256099942544/2247696110"; 41 | private static final String TAG = "MainActivity"; 42 | 43 | private final AtomicBoolean isMobileAdsInitializeCalled = new AtomicBoolean(false); 44 | private GoogleMobileAdsConsentManager googleMobileAdsConsentManager; 45 | private NativeAd nativeAd; 46 | 47 | @Override 48 | protected void onCreate(Bundle savedInstanceState) { 49 | super.onCreate(savedInstanceState); 50 | 51 | Muffin.startMuffin(this); 52 | 53 | ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater()); 54 | setContentView(binding.getRoot()); 55 | 56 | // Example of a call to a native method 57 | TextView tv = binding.sampleText; 58 | tv.setText(stringFromJNI()); 59 | 60 | // Log the Mobile Ads SDK version. 61 | Log.d(TAG, "Google Mobile Ads SDK Version: " + MobileAds.getVersion()); 62 | 63 | googleMobileAdsConsentManager = 64 | GoogleMobileAdsConsentManager.getInstance(getApplicationContext()); 65 | googleMobileAdsConsentManager.gatherConsent( 66 | this, 67 | consentError -> { 68 | if (consentError != null) { 69 | // Consent not obtained in current session. 70 | Log.w( 71 | TAG, 72 | String.format( 73 | "%s: %s", 74 | consentError.getErrorCode(), 75 | consentError.getMessage())); 76 | } 77 | 78 | if (googleMobileAdsConsentManager.canRequestAds()) { 79 | initializeMobileAdsSdk(); 80 | } 81 | 82 | if (googleMobileAdsConsentManager.isPrivacyOptionsRequired()) { 83 | // Regenerate the options menu to include a privacy setting. 84 | invalidateOptionsMenu(); 85 | } 86 | }); 87 | 88 | // This sample attempts to load ads using consent obtained in the previous session. 89 | if (googleMobileAdsConsentManager.canRequestAds()) { 90 | initializeMobileAdsSdk(); 91 | } 92 | 93 | new Handler(Looper.getMainLooper()).postDelayed(() -> { 94 | if (googleMobileAdsConsentManager.canRequestAds()) { 95 | refreshAd(); 96 | } 97 | }, 31000); 98 | } 99 | 100 | @Override 101 | public boolean onCreateOptionsMenu(Menu menu) { 102 | getMenuInflater().inflate(R.menu.action_menu, menu); 103 | MenuItem moreMenu = menu.findItem(R.id.action_more); 104 | moreMenu.setVisible(googleMobileAdsConsentManager.isPrivacyOptionsRequired()); 105 | return true; 106 | } 107 | 108 | @Override 109 | public boolean onOptionsItemSelected(MenuItem item) { 110 | View menuItemView = findViewById(item.getItemId()); 111 | PopupMenu popup = new PopupMenu(this, menuItemView); 112 | popup.getMenuInflater().inflate(R.menu.popup_menu, popup.getMenu()); 113 | popup.show(); 114 | popup.setOnMenuItemClickListener( 115 | popupMenuItem -> { 116 | if (popupMenuItem.getItemId() == R.id.privacy_settings) { 117 | // Handle changes to user consent. 118 | googleMobileAdsConsentManager.showPrivacyOptionsForm( 119 | this, 120 | formError -> { 121 | if (formError != null) { 122 | Toast.makeText( 123 | this, 124 | formError.getMessage(), 125 | Toast.LENGTH_SHORT).show(); 126 | } 127 | }); 128 | return true; 129 | } 130 | return false; 131 | }); 132 | return super.onOptionsItemSelected(item); 133 | } 134 | 135 | /** 136 | * Populates a {@link NativeAdView} object with data from a given {@link NativeAd}. 137 | * 138 | * @param nativeAd the object containing the ad's assets 139 | * @param adView the view to be populated 140 | */ 141 | private void populateNativeAdView(NativeAd nativeAd, NativeAdView adView) { 142 | if (adView != null) { 143 | // Set the media view. 144 | adView.setMediaView(adView.findViewById(R.id.ad_media)); 145 | 146 | // Set other ad assets. 147 | adView.setHeadlineView(adView.findViewById(R.id.ad_headline)); 148 | adView.setBodyView(adView.findViewById(R.id.ad_body)); 149 | adView.setCallToActionView(adView.findViewById(R.id.ad_call_to_action)); 150 | adView.setIconView(adView.findViewById(R.id.ad_app_icon)); 151 | adView.setPriceView(adView.findViewById(R.id.ad_price)); 152 | adView.setStarRatingView(adView.findViewById(R.id.ad_stars)); 153 | adView.setStoreView(adView.findViewById(R.id.ad_store)); 154 | adView.setAdvertiserView(adView.findViewById(R.id.ad_advertiser)); 155 | 156 | // The headline and mediaContent are guaranteed to be in every NativeAd. 157 | ((TextView) adView.getHeadlineView()).setText(nativeAd.getHeadline()); 158 | adView.getMediaView().setMediaContent(nativeAd.getMediaContent()); 159 | 160 | // These assets aren't guaranteed to be in every NativeAd, so it's important to 161 | // check before trying to display them. 162 | if (nativeAd.getBody() == null) { 163 | adView.getBodyView().setVisibility(View.INVISIBLE); 164 | } else { 165 | adView.getBodyView().setVisibility(View.VISIBLE); 166 | ((TextView) adView.getBodyView()).setText(nativeAd.getBody()); 167 | } 168 | 169 | if (nativeAd.getCallToAction() == null) { 170 | adView.getCallToActionView().setVisibility(View.INVISIBLE); 171 | } else { 172 | adView.getCallToActionView().setVisibility(View.VISIBLE); 173 | ((Button) adView.getCallToActionView()).setText(nativeAd.getCallToAction()); 174 | } 175 | 176 | if (nativeAd.getIcon() == null) { 177 | adView.getIconView().setVisibility(View.GONE); 178 | } else { 179 | ((ImageView) adView.getIconView()).setImageDrawable( 180 | nativeAd.getIcon().getDrawable()); 181 | adView.getIconView().setVisibility(View.VISIBLE); 182 | } 183 | 184 | if (nativeAd.getPrice() == null) { 185 | adView.getPriceView().setVisibility(View.INVISIBLE); 186 | } else { 187 | adView.getPriceView().setVisibility(View.VISIBLE); 188 | ((TextView) adView.getPriceView()).setText(nativeAd.getPrice()); 189 | } 190 | 191 | if (nativeAd.getStore() == null) { 192 | adView.getStoreView().setVisibility(View.INVISIBLE); 193 | } else { 194 | adView.getStoreView().setVisibility(View.VISIBLE); 195 | ((TextView) adView.getStoreView()).setText(nativeAd.getStore()); 196 | } 197 | 198 | if (nativeAd.getStarRating() == null) { 199 | adView.getStarRatingView().setVisibility(View.INVISIBLE); 200 | } else { 201 | ((RatingBar) adView.getStarRatingView()) 202 | .setRating(nativeAd.getStarRating().floatValue()); 203 | adView.getStarRatingView().setVisibility(View.VISIBLE); 204 | } 205 | 206 | if (nativeAd.getAdvertiser() == null) { 207 | adView.getAdvertiserView().setVisibility(View.INVISIBLE); 208 | } else { 209 | ((TextView) adView.getAdvertiserView()).setText(nativeAd.getAdvertiser()); 210 | adView.getAdvertiserView().setVisibility(View.VISIBLE); 211 | } 212 | 213 | // This method tells the Google Mobile Ads SDK that you have finished populating your 214 | // native ad view with this native ad. 215 | adView.setNativeAd(nativeAd); 216 | 217 | // Get the video controller for the ad. One will always be provided, even if the ad doesn't 218 | // have a video asset. 219 | VideoController vc = nativeAd.getMediaContent().getVideoController(); 220 | 221 | // Updates the UI to say whether or not this ad has a video asset. 222 | if (nativeAd.getMediaContent() != null && nativeAd.getMediaContent().hasVideoContent()) { 223 | 224 | // Create a new VideoLifecycleCallbacks object and pass it to the VideoController. The 225 | // VideoController will call methods on this object when events occur in the video 226 | // lifecycle. 227 | vc.setVideoLifecycleCallbacks(new VideoController.VideoLifecycleCallbacks() { 228 | @Override 229 | public void onVideoEnd() { 230 | // Publishers should allow native ads to complete video playback before 231 | // refreshing or replacing them with another ad in the same UI location. 232 | super.onVideoEnd(); 233 | } 234 | }); 235 | } 236 | } 237 | } 238 | 239 | /** 240 | * Creates a request for a new native ad based on the boolean parameters and calls the 241 | * corresponding "populate" method when one is successfully returned. 242 | */ 243 | private void refreshAd() { 244 | 245 | AdLoader.Builder builder = new AdLoader.Builder(this, ADMOB_AD_UNIT_ID); 246 | 247 | // OnLoadedListener implementation. 248 | builder.forNativeAd( 249 | nativeAd -> { 250 | // If this callback occurs after the activity is destroyed, you must call 251 | // destroy and return or you may get a memory leak. 252 | boolean isDestroyed = false; 253 | isDestroyed = isDestroyed(); 254 | if (isDestroyed || isFinishing() || isChangingConfigurations()) { 255 | nativeAd.destroy(); 256 | return; 257 | } 258 | // You must call destroy on old ads when you are done with them, 259 | // otherwise you will have a memory leak. 260 | if (MainActivity.this.nativeAd != null) { 261 | MainActivity.this.nativeAd.destroy(); 262 | } 263 | MainActivity.this.nativeAd = nativeAd; 264 | FrameLayout frameLayout = findViewById(R.id.fl_adplaceholder); 265 | NativeAdView adView = 266 | (NativeAdView) getLayoutInflater().inflate(R.layout.ad_unified, frameLayout, false); 267 | populateNativeAdView(nativeAd, adView); 268 | frameLayout.removeAllViews(); 269 | frameLayout.addView(adView); 270 | }); 271 | 272 | VideoOptions videoOptions = 273 | new VideoOptions.Builder().setStartMuted(true).build(); 274 | 275 | NativeAdOptions adOptions = 276 | new NativeAdOptions.Builder().setVideoOptions(videoOptions).build(); 277 | 278 | builder.withNativeAdOptions(adOptions); 279 | 280 | AdLoader adLoader = 281 | builder 282 | .withAdListener( 283 | new AdListener() { 284 | @Override 285 | public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) { 286 | String error = 287 | String.format( 288 | Locale.getDefault(), 289 | "domain: %s, code: %d, message: %s", 290 | loadAdError.getDomain(), 291 | loadAdError.getCode(), 292 | loadAdError.getMessage()); 293 | Toast.makeText( 294 | MainActivity.this, 295 | "Failed to load native ad with error " + error, 296 | Toast.LENGTH_SHORT) 297 | .show(); 298 | } 299 | }) 300 | .build(); 301 | 302 | adLoader.loadAd(new AdRequest.Builder().build()); 303 | } 304 | 305 | private void initializeMobileAdsSdk() { 306 | if (isMobileAdsInitializeCalled.getAndSet(true)) { 307 | return; 308 | } 309 | 310 | // Initialize the Mobile Ads SDK. 311 | MobileAds.initialize( 312 | this, 313 | initializationStatus -> { 314 | // Load an ad. 315 | refreshAd(); 316 | }); 317 | } 318 | 319 | @Override 320 | protected void onDestroy() { 321 | if (nativeAd != null) { 322 | nativeAd.destroy(); 323 | } 324 | super.onDestroy(); 325 | } 326 | 327 | /** 328 | * A native method that is implemented by the 'imgui' native library, 329 | * which is packaged with this application. 330 | */ 331 | public native String stringFromJNI(); 332 | 333 | } -------------------------------------------------------------------------------- /app/src/main/java/org/muffin/imgui/muffin/Muffin.java: -------------------------------------------------------------------------------- 1 | package org.muffin.imgui.muffin; 2 | 3 | import android.app.Activity; 4 | import android.app.AlertDialog; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.net.Uri; 8 | import android.os.Handler; 9 | import android.provider.Settings; 10 | 11 | public class Muffin extends Activity { 12 | 13 | static { 14 | System.loadLibrary("imgui"); 15 | } 16 | 17 | public Muffin(Context context) { 18 | startMuffin(context); 19 | } 20 | 21 | public static void startMuffin(final Context context) { 22 | if (!Settings.canDrawOverlays(context)) { 23 | AlertDialog.Builder builder = new AlertDialog.Builder(context); 24 | builder.setMessage("'Display over other apps' permission is mandatory to run this application.") 25 | .setTitle("Permission required") 26 | .setCancelable(false) 27 | .setPositiveButton("Open settings", (dialog, which) -> { 28 | context.startActivity(new Intent("android.settings.action.MANAGE_OVERLAY_PERMISSION", Uri.parse("package:" + context.getPackageName()))); 29 | dialog.dismiss(); 30 | System.exit(1); 31 | }) 32 | .create().show(); 33 | } else { 34 | new Handler(context.getMainLooper()).postDelayed(() -> context.startService(new Intent(context, MuffinService.class)), 5000); 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/org/muffin/imgui/muffin/MuffinService.java: -------------------------------------------------------------------------------- 1 | package org.muffin.imgui.muffin; 2 | 3 | import android.app.ActivityManager; 4 | import android.app.Service; 5 | import android.content.Intent; 6 | import android.graphics.PixelFormat; 7 | import android.os.Build; 8 | import android.os.Handler; 9 | import android.os.IBinder; 10 | import android.os.Looper; 11 | import android.view.Gravity; 12 | import android.view.View; 13 | import android.view.WindowManager; 14 | 15 | import androidx.annotation.Nullable; 16 | 17 | public class MuffinService extends Service { 18 | 19 | MuffinSurface muffinSurface; 20 | WindowManager windowManager; 21 | 22 | @Override 23 | public void onCreate() { 24 | super.onCreate(); 25 | 26 | muffinSurface = new MuffinSurface(this); 27 | 28 | WindowManager.LayoutParams params = new WindowManager.LayoutParams(); 29 | 30 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 31 | params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; 32 | } 33 | 34 | params.flags = WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED 35 | | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 36 | | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; 37 | 38 | params.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 39 | params.format = PixelFormat.RGBA_8888; 40 | 41 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { 42 | params.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; 43 | } 44 | 45 | params.gravity = Gravity.START | Gravity.TOP; 46 | params.x = params.y = 0; 47 | params.width = params.height = WindowManager.LayoutParams.MATCH_PARENT; 48 | windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); 49 | windowManager.addView(muffinSurface, params); 50 | 51 | final Handler handler = new Handler(Looper.getMainLooper()); 52 | handler.post(new Runnable() { 53 | public void run() { 54 | myThread(); 55 | handler.postDelayed(this, 500); 56 | } 57 | }); 58 | } 59 | 60 | @Override 61 | public int onStartCommand(Intent intent, int i, int i2) { 62 | return START_NOT_STICKY; 63 | } 64 | 65 | private boolean isNotInGame() { 66 | ActivityManager.RunningAppProcessInfo runningAppProcessInfo = new ActivityManager.RunningAppProcessInfo(); 67 | ActivityManager.getMyMemoryState(runningAppProcessInfo); 68 | return runningAppProcessInfo.importance != 100; 69 | } 70 | 71 | @Override 72 | public void onDestroy() { 73 | super.onDestroy(); 74 | windowManager.removeView(muffinSurface); 75 | } 76 | 77 | @Override 78 | public void onTaskRemoved(Intent intent) { 79 | super.onTaskRemoved(intent); 80 | try { 81 | Thread.sleep(100); 82 | } catch (InterruptedException interruptedException) { 83 | interruptedException.printStackTrace(); 84 | throw new RuntimeException(interruptedException); 85 | } 86 | stopSelf(); 87 | } 88 | 89 | private void myThread() { 90 | if (isNotInGame()) { 91 | muffinSurface.setVisibility(View.INVISIBLE); 92 | } else { 93 | muffinSurface.setVisibility(View.VISIBLE); 94 | } 95 | } 96 | 97 | @Nullable 98 | @Override 99 | public IBinder onBind(Intent intent) { 100 | return null; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /app/src/main/java/org/muffin/imgui/muffin/MuffinSurface.java: -------------------------------------------------------------------------------- 1 | package org.muffin.imgui.muffin; 2 | 3 | import android.content.Context; 4 | import android.graphics.PixelFormat; 5 | import android.opengl.GLSurfaceView; 6 | import android.opengl.GLSurfaceView.Renderer; 7 | import android.view.Surface; 8 | 9 | import javax.microedition.khronos.egl.EGLConfig; 10 | import javax.microedition.khronos.opengles.GL10; 11 | 12 | public class MuffinSurface extends GLSurfaceView implements Renderer { 13 | 14 | //Native 15 | public static native void Init(Surface surface); 16 | 17 | public static native boolean Initialized(); 18 | 19 | public static native void SurfaceChanged(GL10 gl, int width, int height); 20 | 21 | public static native void Tick(MuffinSurface imGuiSurface); 22 | 23 | public static native void Shutdown(); 24 | 25 | public MuffinSurface(Context context) { 26 | super(context); 27 | setEGLConfigChooser(8, 8, 8, 8, 16, 0); 28 | getHolder().setFormat(PixelFormat.TRANSLUCENT); 29 | setEGLContextClientVersion(3); 30 | setRenderer(this); 31 | } 32 | 33 | public static void tryShutdown() { 34 | if (Initialized()) 35 | Shutdown(); 36 | } 37 | 38 | @Override 39 | public void onSurfaceCreated(GL10 gl, EGLConfig config) { 40 | Init(getHolder().getSurface()); 41 | } 42 | 43 | @Override 44 | public void onSurfaceChanged(GL10 gl, int width, int height) { 45 | SurfaceChanged(gl, width, height); 46 | } 47 | 48 | @Override 49 | public void onDrawFrame(GL10 gl) { 50 | Tick(this); 51 | } 52 | 53 | @Override 54 | protected void onDetachedFromWindow() { 55 | super.onDetachedFromWindow(); 56 | tryShutdown(); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 9 | 10 | 16 | 19 | 22 | 23 | 24 | 25 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | 42 | 44 | 46 | 48 | 50 | 52 | 54 | 56 | 58 | 60 | 62 | 64 | 66 | 68 | 70 | 72 | 74 | 75 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/muffin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaughingMuffin/android_imgui_surface_mod_menu_template/9f976e88951922cfe4c2c7df37dcf99b31363325/app/src/main/res/drawable/muffin.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 18 | 19 | 26 | 27 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/ad_unified.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | 13 | 14 | 15 | 22 | 23 | 27 | 28 | 36 | 37 | 41 | 42 | 49 | 50 | 53 | 54 | 61 | 62 | 70 | 71 | 72 | 73 | 74 | 75 | 79 | 80 | 87 | 88 | 94 | 95 | 102 | 103 | 112 | 113 | 122 | 123 |