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:
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")
}
}