fix(native): remap executable

Signed-off-by: rhunk <101876869+rhunk@users.noreply.github.com>
This commit is contained in:
rhunk
2024-06-13 01:16:40 +02:00
parent a2f56d11c2
commit 552c1e4011
9 changed files with 27 additions and 12 deletions

View File

@@ -992,6 +992,10 @@
"custom_emoji_font": {
"name": "Custom Emoji Font",
"description": "Allows you to use a custom emoji font. Only works with .ttf fonts"
},
"remap_executable": {
"name": "Remap Executable",
"description": "Remaps executable regions in memory"
}
}
},

View File

@@ -39,6 +39,7 @@ class Experimental : ConfigContainer() {
addFlags(ConfigFlag.USER_IMPORT)
filenameFilter = { it.endsWith(".ttf") }
}
val remapExecutable = boolean("remap_executable") { requireRestart(); addNotices(FeatureNotice.INTERNAL_BEHAVIOR, FeatureNotice.UNSTABLE) }
}
class E2EEConfig : ConfigContainer(hasGlobalState = true) {

View File

@@ -159,6 +159,7 @@ class ModContext(
disableBitmoji = config.experimental.nativeHooks.disableBitmoji.get(),
disableMetrics = config.global.disableMetrics.get(),
composerHooks = config.experimental.nativeHooks.composerHooks.globalState == true,
remapExecutable = config.experimental.nativeHooks.remapExecutable.get(),
customEmojiFontPath = getCustomEmojiFontPath(this)
)
)

View File

@@ -208,11 +208,11 @@ class SnapEnhance {
request.canceled = canceled
}
}
BaseDexClassLoader::class.java.hookConstructor(HookStage.AFTER) {
appContext.native.hideAnonymousDexFiles()
}
appContext.reloadNativeConfig()
}
BaseDexClassLoader::class.java.hookConstructor(HookStage.AFTER) {
appContext.native.hideAnonymousDexFiles()
}
}.also { unhook = { it.unhook() } }
}

View File

@@ -13,6 +13,7 @@ typedef struct {
bool disable_bitmoji;
bool disable_metrics;
bool composer_hooks;
bool remap_executable;
char custom_emoji_font_path[256];
} native_config_t;

View File

@@ -9,6 +9,8 @@ static pthread_mutex_t hook_mutex = PTHREAD_MUTEX_INITIALIZER;
static void inline SafeHook(void *addr, void *hook, void **original) {
pthread_mutex_lock(&hook_mutex);
DobbyHook(addr, hook, original);
mprotect((void *)((uintptr_t) *original & PAGE_MASK), PAGE_SIZE, PROT_EXEC);
if (common::native_config->remap_executable) {
mprotect((void *)((uintptr_t) *original & PAGE_MASK), PAGE_SIZE, PROT_EXEC);
}
pthread_mutex_unlock(&hook_mutex);
}

View File

@@ -17,6 +17,9 @@
bool JNICALL init(JNIEnv *env, jobject clazz) {
LOGD("Initializing native");
using namespace common;
util::remap_sections([](const std::string &line, size_t size) {
return line.find(BUILD_PACKAGE) != std::string::npos;
}, native_config->remap_executable);
native_lib_object = env->NewGlobalRef(clazz);
client_module = util::get_module("libclient.so");
@@ -63,6 +66,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->composer_hooks = GET_CONFIG_BOOL("composerHooks");
native_config->remap_executable = GET_CONFIG_BOOL("remapExecutable");
memset(native_config->custom_emoji_font_path, 0, sizeof(native_config->custom_emoji_font_path));
auto custom_emoji_font_path = env->GetObjectField(config_object, env->GetFieldID(native_config_clazz, "customEmojiFontPath", "Ljava/lang/String;"));
@@ -96,11 +100,11 @@ void JNICALL lock_database(JNIEnv *env, jobject, jstring database_name, jobject
void JNICALL hide_anonymous_dex_files(JNIEnv *, jobject) {
util::remap_sections([](const std::string &line, size_t size) {
return (
(size == PAGE_SIZE && line.find("r-xp 00000000") != std::string::npos && line.find("[v") == std::string::npos) ||
(common::native_config->remap_executable && size == PAGE_SIZE && line.find("r-xp 00000000 00") != std::string::npos && line.find("[v") == std::string::npos) ||
line.find("dalvik-DEX") != std::string::npos ||
line.find("dalvik-classes") != std::string::npos
);
});
}, common::native_config->remap_executable);
}
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *_) {
@@ -117,9 +121,5 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *_) {
methods.push_back({"hideAnonymousDexFiles", "()V", (void *)hide_anonymous_dex_files});
env->RegisterNatives(env->FindClass(std::string(BUILD_NAMESPACE "/NativeLib").c_str()), methods.data(), methods.size());
util::remap_sections([](const std::string &line, size_t size) {
return line.find(BUILD_PACKAGE) != std::string::npos;
});
hide_anonymous_dex_files(env, nullptr);
return JNI_VERSION_1_6;
}

View File

@@ -52,7 +52,7 @@ namespace util {
return { start_offset, end_offset - start_offset };
}
static void remap_sections(std::function<bool(const std::string &, size_t)> filter) {
static void remap_sections(std::function<bool(const std::string &, size_t)> filter, bool remove_read_permission) {
char buff[256];
auto maps = fopen("/proc/self/maps", "rt");
@@ -84,7 +84,7 @@ namespace util {
}
auto new_prot = (flags[0] == 'r' ? PROT_READ : 0) | (flags[1] == 'w' ? PROT_WRITE : 0) | (flags[2] == 'x' ? PROT_EXEC : 0);
if (new_prot & PROT_EXEC) {
if (remove_read_permission && flags[0] == 'r' && flags[2] == 'x') {
new_prot &= ~PROT_READ;
}
mprotect((void *)start, section_size, new_prot);

View File

@@ -1,8 +1,14 @@
package me.rhunk.snapenhance.nativelib
data class NativeConfig(
@JvmField
val disableBitmoji: Boolean = false,
@JvmField
val disableMetrics: Boolean = false,
@JvmField
val composerHooks: Boolean = false,
@JvmField
val remapExecutable: Boolean = false,
@JvmField
val customEmojiFontPath: String? = null,
)