commit 0d2918adfbbab606cc907a4e3cda0c22442bc97d
parent 97806d693e3cbf8e8cfe57bee4d414a80fe15651
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date:   Sun, 10 Mar 2024 16:42:39 +0100

fix(native): load config before init
- add native remap apk

Diffstat:
Mcommon/src/main/assets/lang/en_US.json | 4++++
Mcommon/src/main/kotlin/me/rhunk/snapenhance/common/config/impl/Experimental.kt | 1+
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/ModContext.kt | 7++++++-
Mcore/src/main/kotlin/me/rhunk/snapenhance/core/SnapEnhance.kt | 12+++++++-----
Mnative/build.gradle.kts | 1+
Mnative/jni/CMakeLists.txt | 1+
Mnative/jni/src/common.h | 1+
Mnative/jni/src/library.cpp | 6+++++-
Mnative/jni/src/util.h | 39++++++++++++++++++++++++++++++++++++++-
Mnative/src/main/kotlin/me/rhunk/snapenhance/nativelib/NativeConfig.kt | 1+
Mnative/src/main/kotlin/me/rhunk/snapenhance/nativelib/NativeLib.kt | 6++++--
11 files changed, 69 insertions(+), 10 deletions(-)

diff --git a/common/src/main/assets/lang/en_US.json b/common/src/main/assets/lang/en_US.json @@ -627,6 +627,10 @@ "disable_bitmoji": { "name": "Disable Bitmoji", "description": "Disables Friends Profile Bitmoji" + }, + "remap_apk": { + "name": "Remap APK", + "description": "Hides SnapEnhance apk path in /proc/self/maps" } } }, diff --git a/common/src/main/kotlin/me/rhunk/snapenhance/common/config/impl/Experimental.kt b/common/src/main/kotlin/me/rhunk/snapenhance/common/config/impl/Experimental.kt @@ -11,6 +11,7 @@ class Experimental : ConfigContainer() { class NativeHooks : ConfigContainer(hasGlobalState = true) { val disableBitmoji = boolean("disable_bitmoji") + val remapApk = boolean("remap_apk") { addNotices(FeatureNotice.UNSTABLE) } } class E2EEConfig : ConfigContainer(hasGlobalState = true) { diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/ModContext.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/ModContext.kt @@ -147,11 +147,16 @@ class ModContext( _config.loadFromCallback { file -> file.loadFromBridge(bridgeClient) } + reloadNativeConfig() + } + + fun reloadNativeConfig() { native.loadNativeConfig( NativeConfig( disableBitmoji = config.experimental.nativeHooks.disableBitmoji.get(), disableMetrics = config.global.disableMetrics.get(), - hookAssetOpen = config.experimental.disableComposerModules.get().isNotEmpty() + hookAssetOpen = config.experimental.disableComposerModules.get().isNotEmpty(), + remapApk = config.experimental.nativeHooks.remapApk.get(), ) ) } diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/SnapEnhance.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/SnapEnhance.kt @@ -190,12 +190,14 @@ class SnapEnhance { val libName = param.arg<String>(1) if (libName != "client") return@hook unhook() - appContext.native.initOnce() - appContext.native.nativeUnaryCallCallback = { request -> - appContext.event.post(NativeUnaryCallEvent(request.uri, request.buffer)) { - request.buffer = buffer - request.canceled = canceled + appContext.native.initOnce { + nativeUnaryCallCallback = { request -> + appContext.event.post(NativeUnaryCallEvent(request.uri, request.buffer)) { + request.buffer = buffer + request.canceled = canceled + } } + appContext.reloadNativeConfig() } }.also { unhook = { it.unhook() } } } diff --git a/native/build.gradle.kts b/native/build.gradle.kts @@ -24,6 +24,7 @@ android { cmake { arguments += listOf( "-DOBFUSCATED_NAME=$nativeName", + "-DBUILD_PACKAGE=${rootProject.ext["applicationId"]}", "-DBUILD_NAMESPACE=${namespace!!.replace(".", "/")}" ) } diff --git a/native/jni/CMakeLists.txt b/native/jni/CMakeLists.txt @@ -16,6 +16,7 @@ add_library(${CMAKE_PROJECT_NAME} SHARED ) add_compile_definitions(BUILD_NAMESPACE="${BUILD_NAMESPACE}") +add_compile_definitions(BUILD_PACKAGE="${BUILD_PACKAGE}") target_link_libraries(${CMAKE_PROJECT_NAME} android log diff --git a/native/jni/src/common.h b/native/jni/src/common.h @@ -13,6 +13,7 @@ typedef struct { bool disable_bitmoji; bool disable_metrics; bool hook_asset_open; + bool remap_apk; } native_config_t; namespace common { diff --git a/native/jni/src/library.cpp b/native/jni/src/library.cpp @@ -15,7 +15,6 @@ void JNICALL init(JNIEnv *env, jobject clazz) { LOGD("Initializing native"); using namespace common; - native_config = new native_config_t; native_lib_object = env->NewGlobalRef(clazz); client_module = util::get_module("libclient.so"); @@ -32,6 +31,10 @@ void JNICALL init(JNIEnv *env, jobject clazz) { SqliteMutexHook::init(); DuplexHook::init(env); + if (native_config->remap_apk) { + util::remap_sections(BUILD_PACKAGE); + } + LOGD("Native initialized"); } @@ -43,6 +46,7 @@ void JNICALL load_config(JNIEnv *env, jobject _, jobject config_object) { native_config->disable_bitmoji = GET_CONFIG_BOOL("disableBitmoji"); native_config->disable_metrics = GET_CONFIG_BOOL("disableMetrics"); native_config->hook_asset_open = GET_CONFIG_BOOL("hookAssetOpen"); + native_config->remap_apk = GET_CONFIG_BOOL("remapApk"); } void JNICALL lock_database(JNIEnv *env, jobject _, jstring database_name, jobject runnable) { diff --git a/native/jni/src/util.h b/native/jni/src/util.h @@ -1,6 +1,7 @@ #pragma once #include <unistd.h> +#include <sys/mman.h> #define HOOK_DEF(ret, func, ...) ret (*func##_original)(__VA_ARGS__); ret func(__VA_ARGS__) @@ -51,7 +52,43 @@ namespace util { return { start_offset, end_offset - start_offset }; } - uintptr_t find_signature(uintptr_t module_base, uintptr_t size, const std::string &pattern, int offset = 0) { + static void remap_sections(const char* path) { + char buff[256]; + auto maps = fopen("/proc/self/maps", "rt"); + + while (fgets(buff, sizeof buff, maps) != NULL) { + int len = strlen(buff); + if (len > 0 && buff[len - 1] == '\n') buff[--len] = '\0'; + if (strstr(buff, path) == nullptr) continue; + + size_t start, end, offset; + char flags[4]; + + if (sscanf(buff, "%zx-%zx %c%c%c%c %zx", &start, &end, + &flags[0], &flags[1], &flags[2], &flags[3], &offset) != 7) continue; + + LOGD("Remapping 0x%zx-0x%zx", start, end); + + auto section_size = end - start; + auto section_ptr = mmap(0, section_size, PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + if (section_ptr == MAP_FAILED) { + LOGE("mmap failed: %s", strerror(errno)); + return; + } + + memcpy(section_ptr, (void *)start, section_size); + + if (mremap(section_ptr, section_size, section_size, MREMAP_MAYMOVE | MREMAP_FIXED, start) == MAP_FAILED) { + LOGE("mremap failed: %s", strerror(errno)); + return; + } + + mprotect((void *)start, section_size, (flags[0] == 'r' ? PROT_READ : 0) | (flags[1] == 'w' ? PROT_WRITE : 0) | (flags[2] == 'x' ? PROT_EXEC : 0)); + } + } + + static uintptr_t find_signature(uintptr_t module_base, uintptr_t size, const std::string &pattern, int offset = 0) { std::vector<char> bytes; std::vector<char> mask; for (size_t i = 0; i < pattern.size(); i += 3) { diff --git a/native/src/main/kotlin/me/rhunk/snapenhance/nativelib/NativeConfig.kt b/native/src/main/kotlin/me/rhunk/snapenhance/nativelib/NativeConfig.kt @@ -4,4 +4,5 @@ data class NativeConfig( val disableBitmoji: Boolean = false, val disableMetrics: Boolean = false, val hookAssetOpen: Boolean = false, + val remapApk: Boolean = false, ) \ No newline at end of file diff --git a/native/src/main/kotlin/me/rhunk/snapenhance/nativelib/NativeLib.kt b/native/src/main/kotlin/me/rhunk/snapenhance/nativelib/NativeLib.kt @@ -11,13 +11,15 @@ class NativeLib { private set } - fun initOnce() { + fun initOnce(callback: NativeLib.() -> Unit) { if (initialized) throw IllegalStateException("NativeLib already initialized") runCatching { System.loadLibrary(BuildConfig.NATIVE_NAME) - init() initialized = true + callback(this) + init() }.onFailure { + initialized = false Log.e("SnapEnhance", "NativeLib init failed") } }