fix(native): load config before init

- add native remap apk
This commit is contained in:
rhunk
2024-03-10 16:42:39 +01:00
parent 97806d693e
commit 0d2918adfb
11 changed files with 69 additions and 10 deletions

View File

@ -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"
}
}
},

View File

@ -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) {

View File

@ -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(),
)
)
}

View File

@ -190,13 +190,15 @@ class SnapEnhance {
val libName = param.arg<String>(1)
if (libName != "client") return@hook
unhook()
appContext.native.initOnce()
appContext.native.nativeUnaryCallCallback = { request ->
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() } }
}

View File

@ -24,6 +24,7 @@ android {
cmake {
arguments += listOf(
"-DOBFUSCATED_NAME=$nativeName",
"-DBUILD_PACKAGE=${rootProject.ext["applicationId"]}",
"-DBUILD_NAMESPACE=${namespace!!.replace(".", "/")}"
)
}

View File

@ -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

View File

@ -13,6 +13,7 @@ typedef struct {
bool disable_bitmoji;
bool disable_metrics;
bool hook_asset_open;
bool remap_apk;
} native_config_t;
namespace common {

View File

@ -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) {

View File

@ -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) {

View File

@ -4,4 +4,5 @@ data class NativeConfig(
val disableBitmoji: Boolean = false,
val disableMetrics: Boolean = false,
val hookAssetOpen: Boolean = false,
val remapApk: Boolean = false,
)

View File

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