diff --git a/native/src/core/zygisk/hook.cpp b/native/src/core/zygisk/hook.cpp index 10018f12f..b6c5c1afc 100644 --- a/native/src/core/zygisk/hook.cpp +++ b/native/src/core/zygisk/hook.cpp @@ -415,10 +415,7 @@ void HookContext::hook_plt() { ZLOGE("plt_hook failed\n"); // Remove unhooked methods - plt_backup.erase( - std::remove_if(plt_backup.begin(), plt_backup.end(), - [](auto &t) { return *std::get<3>(t) == nullptr;}), - plt_backup.end()); + std::erase_if(plt_backup, [](auto &t) { return *std::get<3>(t) == nullptr; }); } void HookContext::hook_unloader() { @@ -467,35 +464,42 @@ void HookContext::hook_jni_methods(JNIEnv *env, const char *clz, JNIMethods meth auto total = runtime_callbacks->getNativeMethodCount(env, clazz); auto old_methods = std::make_unique_for_overwrite(total); runtime_callbacks->getNativeMethods(env, clazz, old_methods.get(), total); - auto new_methods = std::make_unique_for_overwrite(total); - // Replace the method + // WARNING: the signature field returned from getNativeMethods is in a non-standard format. + // DO NOT TRY TO USE IT. This is the reason why we try to call RegisterNatives on every single + // provided JNI methods directly to be 100% sure about whether a signature matches or not. + + // Replace methods for (auto &method : methods) { // It's useful to allow nullptr function pointer for restoring hook if (!method.fnPtr) continue; + // It's normal that the method is not found - if (env->RegisterNatives(clazz, &method, 1) == JNI_ERR || - env->ExceptionCheck() == JNI_TRUE) { + if (env->RegisterNatives(clazz, &method, 1) == JNI_ERR || env->ExceptionCheck() == JNI_TRUE) { if (auto exception = env->ExceptionOccurred()) { env->DeleteLocalRef(exception); } env->ExceptionClear(); method.fnPtr = nullptr; - continue; } - // Find the old function pointer and return to caller - runtime_callbacks->getNativeMethods(env, clazz, new_methods.get(), total); + } + + // Fetch the new set of native methods + auto new_methods = std::make_unique_for_overwrite(total); + runtime_callbacks->getNativeMethods(env, clazz, new_methods.get(), total); + + // Find the old function pointer and return to caller + for (auto &method : methods) { + if (!method.fnPtr) continue; for (auto i = 0; i < total; ++i) { auto &new_method = new_methods[i]; - if (new_method.fnPtr == method.fnPtr && strcmp(new_method.name, method.name) == 0) { + if (new_method.fnPtr == method.fnPtr) { auto &old_method = old_methods[i]; - ZLOGD("replace %s#%s%s %p -> %p\n", clz, - method.name, method.signature, old_method.fnPtr, method.fnPtr); + ZLOGD("replace %s#%s%s %p -> %p\n", clz, method.name, method.signature, old_method.fnPtr, method.fnPtr); method.fnPtr = old_method.fnPtr; break; } } - old_methods.swap(new_methods); } }