fix: native crash

This commit is contained in:
rhunk 2024-01-18 09:18:06 +01:00
parent 94b519614d
commit fe9164b423
3 changed files with 30 additions and 77 deletions

View File

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

View File

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

View File

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