diff --git a/core/src/main/cpp/main/api/zygisk_main.cpp b/core/src/main/cpp/main/api/zygisk_main.cpp index 4f5d060b..b51ec72e 100644 --- a/core/src/main/cpp/main/api/zygisk_main.cpp +++ b/core/src/main/cpp/main/api/zygisk_main.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "jni/zygisk.h" #include "logging.h" diff --git a/core/src/main/cpp/main/include/jni_helper.h b/core/src/main/cpp/main/include/jni_helper.h index 5ad77f16..17a0ab35 100644 --- a/core/src/main/cpp/main/include/jni_helper.h +++ b/core/src/main/cpp/main/include/jni_helper.h @@ -24,10 +24,19 @@ #include "macros.h" #include #include "logging.h" -#include "base/object.h" #define JNI_START JNIEnv *env, [[maybe_unused]] jclass clazz +namespace JNIHelper { + template class> + struct is_instance : public std::false_type { + }; + + template class U> + struct is_instance, U> : public std::true_type { + }; +} + class JUTFString { public: inline JUTFString(JNIEnv *env, jstring jstr) : JUTFString(env, jstr, nullptr) { @@ -170,7 +179,7 @@ template [[maybe_unused]] inline auto unwrap_scope(T &&x) { if constexpr (std::is_same_v, std::string_view>) return x.data(); - else if constexpr (lspd::is_instance, ScopedLocalRef>::value) return x.get(); + else if constexpr (JNIHelper::is_instance, ScopedLocalRef>::value) return x.get(); else return std::forward(x); } diff --git a/core/src/main/cpp/main/src/context.cpp b/core/src/main/cpp/main/src/context.cpp index a78cdfee..e98445ea 100644 --- a/core/src/main/cpp/main/src/context.cpp +++ b/core/src/main/cpp/main/src/context.cpp @@ -128,7 +128,7 @@ namespace lspd { RegisterResourcesHook(env); RegisterArtClassLinker(env); - RegisterYahfa(env); + RegisterYahfa(env, obfuscated_signature_); RegisterPendingHooks(env); RegisterNativeAPI(env); } @@ -195,6 +195,7 @@ namespace lspd { instance->HookBridge(*this, env); if (binder) { + obfuscated_signature_ = std::move(std::get<2>(dex)); InstallInlineHooks(); Init(env); FindAndCall(env, "forkSystemServerPost", "(Landroid/os/IBinder;)V", binder); @@ -256,6 +257,7 @@ namespace lspd { InstallInlineHooks(); auto dex = instance->RequestLSPDex(env, binder); LoadDex(env, std::get<0>(dex), std::get<1>(dex)); + obfuscated_signature_ = std::move(std::get<2>(dex)); Init(env); LOGD("Done prepare"); FindAndCall(env, "forkAndSpecializePost", diff --git a/core/src/main/cpp/main/src/context.h b/core/src/main/cpp/main/src/context.h index 59ec744b..966c8421 100644 --- a/core/src/main/cpp/main/src/context.h +++ b/core/src/main/cpp/main/src/context.h @@ -69,6 +69,7 @@ namespace lspd { jclass class_linker_class_ = nullptr; jmethodID post_fixup_static_mid_ = nullptr; bool skip_ = false; + std::string obfuscated_signature_; struct PreloadedDex { diff --git a/core/src/main/cpp/main/src/jni/yahfa.cpp b/core/src/main/cpp/main/src/jni/yahfa.cpp index a2732584..f903522c 100644 --- a/core/src/main/cpp/main/src/jni/yahfa.cpp +++ b/core/src/main/cpp/main/src/jni/yahfa.cpp @@ -38,6 +38,8 @@ namespace lspd { std::vector> jit_movements_; std::shared_mutex jit_movements_lock_; + + std::string obfuscated_signature_; } bool isHooked(void *art_method) { @@ -119,7 +121,7 @@ namespace lspd { cbuilder.set_source_file("LSP"); auto hooker_type = - TypeDescriptor::FromClassname("ac.ksmm.notioss.lspdaa.LspHooker"); + TypeDescriptor::FromClassname(obfuscated_signature_.c_str()); auto *hooker_field = cbuilder.CreateField("hooker", hooker_type) .access_flags(dex::kAccStatic) @@ -214,7 +216,10 @@ namespace lspd { "(Ljava/lang/ClassLoader;C[CLjava/lang/String;)Ljava/lang/Class;"), }; - void RegisterYahfa(JNIEnv *env) { + void RegisterYahfa(JNIEnv *env, std::string obfuscated_signature) { + std::replace(obfuscated_signature.begin(), obfuscated_signature.end(), '/', '.'); + obfuscated_signature_ = obfuscated_signature.substr(1) + ".LspHooker"; + LOGD("RegisterYahfa: obfuscated_signature_=%s", obfuscated_signature_.c_str()); REGISTER_LSP_NATIVE_METHODS(Yahfa); } diff --git a/core/src/main/cpp/main/src/jni/yahfa.h b/core/src/main/cpp/main/src/jni/yahfa.h index fe16429f..ae39fe5d 100644 --- a/core/src/main/cpp/main/src/jni/yahfa.h +++ b/core/src/main/cpp/main/src/jni/yahfa.h @@ -30,6 +30,6 @@ namespace lspd { std::vector> getJitMovements(); - void RegisterYahfa(JNIEnv *); + void RegisterYahfa(JNIEnv *, std::string obfuscated_signature); } // namespace lspd diff --git a/core/src/main/cpp/main/src/service.cpp b/core/src/main/cpp/main/src/service.cpp index 2557010d..5d3a8533 100644 --- a/core/src/main/cpp/main/src/service.cpp +++ b/core/src/main/cpp/main/src/service.cpp @@ -120,6 +120,8 @@ namespace lspd { read_long_method_ = JNI_GetMethodID(env, parcel_class_, "readLong", "()J"); read_strong_binder_method_ = JNI_GetMethodID(env, parcel_class_, "readStrongBinder", "()Landroid/os/IBinder;"); + read_string_method_ = JNI_GetMethodID(env, parcel_class_, "readString", + "()Ljava/lang/String;"); read_file_descriptor_method_ = JNI_GetMethodID(env, parcel_class_, "readFileDescriptor", "()Landroid/os/ParcelFileDescriptor;"); // createStringArray_ = env->GetMethodID(parcel_class_, "createStringArray", @@ -307,7 +309,7 @@ namespace lspd { return app_binder; } - std::tuple Service::RequestLSPDex(JNIEnv *env, const ScopedLocalRef &binder) { + std::tuple Service::RequestLSPDex(JNIEnv *env, const ScopedLocalRef &binder) { auto data = JNI_CallStaticObjectMethod(env, parcel_class_, obtain_method_); auto reply = JNI_CallStaticObjectMethod(env, parcel_class_, obtain_method_); auto res = JNI_CallBooleanMethod(env, binder, transact_method_, @@ -316,15 +318,18 @@ namespace lspd { reply, 0); if (!res) { LOGE("Service::RequestLSPDex: transaction failed?"); - return {-1, 0}; + return {-1, 0, ""}; } auto parcel_fd = JNI_CallObjectMethod(env, reply, read_file_descriptor_method_); int fd = JNI_CallIntMethod(env, parcel_fd, get_fd_method); auto size = JNI_CallLongMethod(env, reply, read_long_method_); + auto signature = JNI_CallObjectMethod(env, reply, read_string_method_); JNI_CallVoidMethod(env, data, recycleMethod_); JNI_CallVoidMethod(env, reply, recycleMethod_); - LOGD("Service::RequestLSPDex fd=%d, size=%zu", fd, size); - return {fd, size}; + JUTFString sign(env, static_cast(signature.get())); + + LOGD("Service::RequestLSPDex fd=%d, size=%zu, sign=%s", fd, size, sign.get()); + return {fd, size, sign.get()}; } } // namespace lspd diff --git a/core/src/main/cpp/main/src/service.h b/core/src/main/cpp/main/src/service.h index 15e6b46d..fd74e68e 100644 --- a/core/src/main/cpp/main/src/service.h +++ b/core/src/main/cpp/main/src/service.h @@ -55,7 +55,7 @@ namespace lspd { ScopedLocalRef RequestBinderForSystemServer(JNIEnv *env); - std::tuple RequestLSPDex(JNIEnv *env, const ScopedLocalRef &binder); + std::tuple RequestLSPDex(JNIEnv *env, const ScopedLocalRef &binder); private: inline static std::unique_ptr instance_ = std::make_unique(); @@ -98,6 +98,7 @@ namespace lspd { jmethodID write_strong_binder_method_ = nullptr; jmethodID read_file_descriptor_method_ = nullptr; jmethodID read_long_method_ = nullptr; + jmethodID read_string_method_ = nullptr; jclass parcel_file_descriptor_class_ = nullptr; jmethodID get_fd_method = nullptr; diff --git a/daemon/src/main/cpp/Android.mk b/daemon/src/main/cpp/Android.mk index ddfc9e4b..059387d0 100644 --- a/daemon/src/main/cpp/Android.mk +++ b/daemon/src/main/cpp/Android.mk @@ -2,7 +2,7 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := daemon -LOCAL_C_INCLUDES := $(LOCAL_PATH)../../../../core/src/main/cpp/main/include/ +LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../../core/src/main/cpp/main/include/ LOCAL_SRC_FILES := logcat.cpp obfuscation.cpp ../../../../core/src/main/cpp/main/api/config.cpp LOCAL_STATIC_LIBRARIES := cxx dex_builder LOCAL_ALLOW_UNDEFINED_SYMBOLS := true diff --git a/daemon/src/main/cpp/obfuscation.cpp b/daemon/src/main/cpp/obfuscation.cpp index a6f1088d..7c0883c1 100644 --- a/daemon/src/main/cpp/obfuscation.cpp +++ b/daemon/src/main/cpp/obfuscation.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -12,8 +13,8 @@ #include #include "slicer/reader.h" #include "slicer/writer.h" -// TODO: BAD -#include "../../../../core/src/main/cpp/main/include/config.h" +#include "config.h" +#include "jni_helper.h" class WA: public dex::Writer::Allocator { std::unordered_map allocated_; @@ -29,16 +30,51 @@ public: } }; +static std::string obfuscated_signature; +static const std::string old_signature = "Lde/robv/android/xposed"; + +extern "C" +JNIEXPORT jstring JNICALL +Java_org_lsposed_lspd_service_ObfuscationManager_getObfuscatedSignature(JNIEnv *env, jclass ) { + if (!obfuscated_signature.empty()) { + return env->NewStringUTF(obfuscated_signature.c_str()); + } + + static auto& chrs = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + thread_local static std::mt19937 rg{std::random_device{}()}; + thread_local static std::uniform_int_distribution pick(0, sizeof(chrs) - 2); + thread_local static std::uniform_int_distribution choose_slash(0, 10); + + size_t length = old_signature.size(); + obfuscated_signature.reserve(length); + obfuscated_signature += "L"; + + for (size_t i = 1; i < length; i++) { + if (choose_slash(rg) > 8 && // 80% alphabet + 20% slashes + obfuscated_signature[i - 1] != '/' && // slashes could not stick together + i != 1 && // the first character should not be slash + i != length - 1) { // and the last character + obfuscated_signature += "/"; + } else { + obfuscated_signature += chrs[pick(rg)]; + } + } + LOGD("ObfuscationManager.getObfuscatedSignature: %s", obfuscated_signature.c_str()); + return env->NewStringUTF(obfuscated_signature.c_str()); +} + using ustring = std::basic_string; ustring obfuscateDex(void *dex, size_t size) { - const char* new_sig = "Lac/ksmm/notioss/lspdaa"; + const char* new_sig = obfuscated_signature.c_str(); dex::Reader reader{reinterpret_cast(dex), size}; reader.CreateFullIr(); auto ir = reader.GetIr(); for (auto &i: ir->strings) { const char *s = i->c_str(); - char* p = const_cast(strstr(s, "Lde/robv/android/xposed")); + char* p = const_cast(strstr(s, old_signature.c_str())); if (p) { memcpy(p, new_sig, strlen(new_sig)); } @@ -53,8 +89,6 @@ ustring obfuscateDex(void *dex, size_t size) { return new_dex; } -static jobject lspdDex = nullptr; - jobject new_sharedmem(JNIEnv* env, jint size) { jclass clazz = env->FindClass("android/os/SharedMemory"); auto *ref = env->NewGlobalRef(clazz); @@ -66,11 +100,14 @@ jobject new_sharedmem(JNIEnv* env, jint size) { return new_mem; } +static jobject lspdDex = nullptr; +static std::mutex dex_lock; + extern "C" JNIEXPORT jint JNICALL -Java_org_lsposed_lspd_service_LSPApplicationService_preloadDex(JNIEnv *env, jclass ) { +Java_org_lsposed_lspd_service_ObfuscationManager_preloadDex(JNIEnv *env, jclass ) { using namespace std::string_literals; - // TODO: Lock? + std::lock_guard lg(dex_lock); if (lspdDex) return ASharedMemory_dupFromJava(env, lspdDex); std::string dex_path = "/data/adb/modules/"s + lspd::moduleName + "/" + lspd::kDexPath; @@ -109,7 +146,7 @@ Java_org_lsposed_lspd_service_LSPApplicationService_preloadDex(JNIEnv *env, jcla extern "C" JNIEXPORT jlong JNICALL -Java_org_lsposed_lspd_service_LSPApplicationService_getPreloadedDexSize(JNIEnv *env, jclass ) { +Java_org_lsposed_lspd_service_ObfuscationManager_getPreloadedDexSize(JNIEnv *env, jclass ) { if (lspdDex) { auto fd = ASharedMemory_dupFromJava(env, lspdDex); return ASharedMemory_getSize(fd); @@ -119,7 +156,7 @@ Java_org_lsposed_lspd_service_LSPApplicationService_getPreloadedDexSize(JNIEnv * extern "C" JNIEXPORT jobject -Java_org_lsposed_lspd_service_LSPApplicationService_obfuscateDex(JNIEnv *env, jclass /*clazz*/, +Java_org_lsposed_lspd_service_ObfuscationManager_obfuscateDex(JNIEnv *env, jclass /*clazz*/, jobject memory) { int fd = ASharedMemory_dupFromJava(env, memory); auto size = ASharedMemory_getSize(fd); diff --git a/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java b/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java index 59d1e136..8cf4d9e5 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java @@ -296,7 +296,7 @@ public class ConfigFileManager { var byteBuffer = memory.mapReadWrite(); Channels.newChannel(in).read(byteBuffer); SharedMemory.unmap(byteBuffer); - memory = LSPApplicationService.obfuscateDex(memory); + memory = ObfuscationManager.obfuscateDex(memory); memory.setProtect(OsConstants.PROT_READ); preLoadedDexes.add(memory); } catch (IOException | ErrnoException e) { diff --git a/daemon/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java b/daemon/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java index 3456e991..6ed0371f 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java @@ -51,9 +51,10 @@ public class LSPApplicationService extends ILSPApplicationService.Stub { Log.i(TAG, "LSPApplicationService.onTransact: code=" + code); if (code == DEX_TRANSACTION_CODE) { try { - ParcelFileDescriptor pfd = ParcelFileDescriptor.fromFd(preloadDex()); + ParcelFileDescriptor pfd = ParcelFileDescriptor.fromFd(ObfuscationManager.preloadDex()); reply.writeFileDescriptor(pfd.getFileDescriptor()); - reply.writeLong(getPreloadedDexSize()); + reply.writeLong(ObfuscationManager.getPreloadedDexSize()); + reply.writeString(ObfuscationManager.getObfuscatedSignature()); } catch (IOException ignored) { Log.e(TAG, "LSPApplicationService.onTransact: ParcelFileDescriptor.fromFd failed"); return false; @@ -87,14 +88,6 @@ public class LSPApplicationService extends ILSPApplicationService.Stub { } } - static native SharedMemory obfuscateDex(SharedMemory memory); - - // preload lspd dex only, on daemon startup. - // it will cache the result, so we could obtain it back on startup. - static native int preloadDex(); - - static native long getPreloadedDexSize(); - @Override public List getModulesList(String processName) throws RemoteException { ensureRegistered(); diff --git a/daemon/src/main/java/org/lsposed/lspd/service/ObfuscationManager.java b/daemon/src/main/java/org/lsposed/lspd/service/ObfuscationManager.java new file mode 100644 index 00000000..eed0b671 --- /dev/null +++ b/daemon/src/main/java/org/lsposed/lspd/service/ObfuscationManager.java @@ -0,0 +1,17 @@ +package org.lsposed.lspd.service; + +import android.os.SharedMemory; + +public class ObfuscationManager { + // For module dexes + static native SharedMemory obfuscateDex(SharedMemory memory); + + // preload lspd dex only, on daemon startup. + // it will cache the result, so we could obtain it back on startup. + static native int preloadDex(); + + static native long getPreloadedDexSize(); + + // generates signature + static native String getObfuscatedSignature(); +} diff --git a/daemon/src/main/java/org/lsposed/lspd/service/ServiceManager.java b/daemon/src/main/java/org/lsposed/lspd/service/ServiceManager.java index 996c4e96..90928b0a 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/ServiceManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ServiceManager.java @@ -98,7 +98,8 @@ public class ServiceManager { logcatService.start(); Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND); - LSPApplicationService.preloadDex(); + ObfuscationManager.getObfuscatedSignature(); + ObfuscationManager.preloadDex(); Looper.prepareMainLooper(); mainService = new LSPosedService(); applicationService = new LSPApplicationService();