commit fe9164b423cbaa4ff6af6cb3e9d89b4d83ed0b5e
parent 94b519614d0e00af0623be239a7ba4d3e5708643
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date: Thu, 18 Jan 2024 09:18:06 +0100
fix: native crash
Diffstat:
3 files changed, 30 insertions(+), 77 deletions(-)
diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/SnapEnhance.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/SnapEnhance.kt
@@ -135,8 +135,8 @@ class SnapEnhance {
reloadConfig()
actionManager.init()
initConfigListener()
+ initNative()
scope.launch(Dispatchers.IO) {
- initNative()
translation.userLocale = getConfigLocale()
translation.loadFromCallback { locale ->
bridgeClient.fetchLocales(locale)
@@ -170,16 +170,23 @@ class SnapEnhance {
private fun initNative() {
// don't initialize native when not logged in
if (!appContext.database.hasArroyo()) return
- appContext.native.apply {
- if (appContext.config.experimental.nativeHooks.globalState != true) return@apply
- initOnce(appContext.androidContext.classLoader)
- nativeUnaryCallCallback = { request ->
+ if (appContext.config.experimental.nativeHooks.globalState != true) return
+
+ lateinit var unhook: () -> Unit
+ Runtime::class.java.declaredMethods.first {
+ it.name == "loadLibrary0" && it.parameterTypes.contentEquals(arrayOf(ClassLoader::class.java, Class::class.java, String::class.java))
+ }.hook(HookStage.AFTER) { param ->
+ val libName = param.arg<String>(2)
+ if (libName != "client") return@hook
+ unhook()
+ appContext.native.initOnce(appContext.androidContext.classLoader)
+ appContext.native.nativeUnaryCallCallback = { request ->
appContext.event.post(NativeUnaryCallEvent(request.uri, request.buffer)) {
request.buffer = buffer
request.canceled = canceled
}
}
- }
+ }.also { unhook = { it.unhook() } }
}
private fun initConfigListener() {
diff --git a/native/jni/src/library.cpp b/native/jni/src/library.cpp
@@ -71,11 +71,10 @@ static void *unaryCall_hook(void *unk1, const char *uri, grpc::grpc_byte_buffer
return nullptr;
}
- auto new_buffer = env->GetObjectField(native_request_data_object, env->GetFieldID(native_request_data_class, "buffer", "[B"));
- auto new_buffer_length = env->GetArrayLength((jbyteArray)new_buffer);
- auto new_buffer_data = env->GetByteArrayElements((jbyteArray)new_buffer, nullptr);
+ auto new_buffer = (jbyteArray)env->GetObjectField(native_request_data_object, env->GetFieldID(native_request_data_class, "buffer", "[B"));
+ auto new_buffer_length = env->GetArrayLength(new_buffer);
+ auto new_buffer_data = env->GetByteArrayElements(new_buffer, nullptr);
- LOGD("rewrote request for %s (length: %d)", uri, new_buffer_length);
//we need to allocate a new ref_counter struct and copy the old ref_counter and the new_buffer to it
const static auto ref_counter_struct_size = (uintptr_t)slice_buffer->data - (uintptr_t)slice_buffer->ref_counter;
@@ -119,17 +118,13 @@ void JNICALL init(JNIEnv *env, jobject clazz, jobject classloader) {
native_lib_on_unary_call_method = env->GetMethodID(env->GetObjectClass(clazz), "onNativeUnaryCall", "(Ljava/lang/String;[B)L" BUILD_NAMESPACE "/NativeRequestData;");
native_lib_on_asset_load = env->GetMethodID(env->GetObjectClass(clazz), "shouldLoadAsset", "(Ljava/lang/String;)Z");
- // load libclient.so
- util::load_library(env, classloader, "client");
auto client_module = util::get_module("libclient.so");
if (client_module.base == 0) {
- LOGE("libclient not found");
+ LOGE("libclient not loaded!");
return;
}
- // client_module.base -= 0x1000;
- // debugging purposes
LOGD("libclient.so base=0x%0lx, size=0x%0lx", client_module.base, client_module.size);
// hooks
@@ -142,6 +137,7 @@ void JNICALL init(JNIEnv *env, jobject clazz, jobject classloader) {
);
if (unaryCall_func != 0) {
+ LOGD("found unaryCall at 0x%0lx", unaryCall_func);
DobbyHook((void *)unaryCall_func, (void *)unaryCall_hook, (void **)&unaryCall_original);
} else {
LOGE("can't find unaryCall signature");
diff --git a/native/jni/src/util.h b/native/jni/src/util.h
@@ -8,25 +8,11 @@ namespace util {
size_t size;
} module_info_t;
- static void hexDump(void *ptr, uint8_t line_length, uint32_t lines) {
- auto *p = (unsigned char *) ptr;
- for (uint8_t i = 0; i < lines; i++) {
- std::string line;
- for (uint8_t j = 0; j < line_length; j++) {
- char buf[3];
- sprintf(buf, "%02x", p[i * line_length + j]);
- line += buf;
- line += " ";
- }
- LOGI("%s", line.c_str());
- }
- }
-
static module_info_t get_module(const char *libname) {
char buff[256];
int len_libname = strlen(libname);
- uintptr_t addr = 0;
- size_t size = 0;
+ uintptr_t start_offset = 0;
+ uintptr_t end_offset = 0;
auto file = fopen("/proc/self/smaps", "rt");
if (file == NULL)
@@ -47,25 +33,20 @@ namespace util {
continue;
}
- if (addr == 0 && flags[0] == 'r' && flags[2] == 'x') {
- addr = start - offset;
+ if (flags[0] != 'r' || flags[2] != 'x') {
+ continue;
}
- if (addr != 0) {
- size += end - start;
+
+ if (start_offset == 0) {
+ start_offset = start;
}
+ end_offset = end;
}
fclose(file);
- return {addr, size};
- }
-
- void load_library(JNIEnv *env, jobject classLoader, const char *libName) {
- auto runtimeClass = env->FindClass("java/lang/Runtime");
- auto getRuntimeMethod = env->GetStaticMethodID(runtimeClass, "getRuntime",
- "()Ljava/lang/Runtime;");
- auto runtime = env->CallStaticObjectMethod(runtimeClass, getRuntimeMethod);
- auto loadLibraryMethod = env->GetMethodID(runtimeClass, "loadLibrary0",
- "(Ljava/lang/ClassLoader;Ljava/lang/String;)V");
- env->CallVoidMethod(runtime, loadLibraryMethod, classLoader, env->NewStringUTF(libName));
+ if (start_offset == 0) {
+ return {0, 0};
+ }
+ 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) {
@@ -96,35 +77,4 @@ namespace util {
}
return 0;
}
-
- std::vector<uintptr_t> find_signatures(uintptr_t module_base, uintptr_t size, const std::string &pattern, int offset = 0) {
- std::vector<uintptr_t> results;
- std::vector<char> bytes;
- std::vector<char> mask;
-
- for (size_t i = 0; i < pattern.size(); i += 3) {
- if (pattern[i] == '?') {
- bytes.push_back(0);
- mask.push_back('?');
- } else {
- bytes.push_back(std::stoi(pattern.substr(i, 2), nullptr, 16));
- mask.push_back('x');
- }
- }
-
- for (size_t i = 0; i < size; i++) {
- bool found = true;
- for (size_t j = 0; j < bytes.size(); j++) {
- if (mask[j] == '?' || bytes[j] == *(char *) (module_base + i + j)) {
- continue;
- }
- found = false;
- break;
- }
- if (found) {
- results.push_back(module_base + i + offset);
- }
- }
- return results;
- }
}
\ No newline at end of file