diff --git a/core/src/main/jni/include/ConfigBridge.h b/core/src/main/jni/include/ConfigBridge.h new file mode 100644 index 00000000..341afc4f --- /dev/null +++ b/core/src/main/jni/include/ConfigBridge.h @@ -0,0 +1,46 @@ +/* + * This file is part of LSPosed. + * + * LSPosed is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LSPosed is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LSPosed. If not, see . + * + * Copyright (C) 2022 LSPosed Contributors + */ + +// +// Created by Kotori0 on 2022/4/14. +// + +#ifndef LSPOSED_CONFIGBRIDGE_H +#define LSPOSED_CONFIGBRIDGE_H +#include + +using obfuscation_map_t = std::map; +class ConfigBridge { +public: + inline static ConfigBridge *GetInstance() { + return instance_.get(); + } + + inline static std::unique_ptr ReleaseInstance() { + return std::move(instance_); + } + + virtual obfuscation_map_t& obfuscation_map() = 0; + virtual void obfuscation_map(obfuscation_map_t) = 0; + +protected: + inline static std::unique_ptr instance_ = nullptr; +}; + +#endif //LSPOSED_CONFIGBRIDGE_H diff --git a/core/src/main/jni/include/native_util.h b/core/src/main/jni/include/native_util.h index 537420fd..3ba6040a 100644 --- a/core/src/main/jni/include/native_util.h +++ b/core/src/main/jni/include/native_util.h @@ -15,7 +15,7 @@ * along with LSPosed. If not, see . * * Copyright (C) 2020 EdXposed Contributors - * Copyright (C) 2021 LSPosed Contributors + * Copyright (C) 2021 - 2022 LSPosed Contributors */ #include @@ -31,6 +31,7 @@ #include "logging.h" #include "config.h" #include +#include "ConfigBridge.h" #define _uintval(p) reinterpret_cast(p) #define _ptr(p) reinterpret_cast(p) @@ -47,13 +48,13 @@ namespace lspd { [[gnu::always_inline]] inline bool RegisterNativeMethodsInternal(JNIEnv *env, - const char *class_name, + std::string_view class_name, const JNINativeMethod *methods, jint method_count) { - auto clazz = Context::GetInstance()->FindClassFromCurrentLoader(env, class_name); + auto clazz = Context::GetInstance()->FindClassFromCurrentLoader(env, class_name.data()); if (clazz.get() == nullptr) { - LOGF("Couldn't find class: {}", class_name); + LOGF("Couldn't find class: {}", class_name.data()); return false; } return JNI_RegisterNatives(env, clazz, methods, method_count); @@ -83,7 +84,7 @@ inline bool RegisterNativeMethodsInternal(JNIEnv *env, #endif #define REGISTER_LSP_NATIVE_METHODS(class_name) \ - RegisterNativeMethodsInternal(env, "org.lsposed.lspd.nativebridge." #class_name, gMethods, arraysize(gMethods)) + RegisterNativeMethodsInternal(env, GetNativeBridgeSignature() + #class_name, gMethods, arraysize(gMethods)) inline int HookFunction(void *original, void *replace, void **backup) { _make_rwx(original, _page_size); @@ -108,6 +109,12 @@ inline int UnhookFunction(void *original) { return DobbyDestroy(original); } +static std::string GetNativeBridgeSignature() { + const auto &obfs_map = ConfigBridge::GetInstance()->obfuscation_map(); + static auto signature = obfs_map.at("org.lsposed.lspd.nativebridge."); + return signature; +} + } // namespace lspd #pragma clang diagnostic pop diff --git a/core/src/main/jni/include/utils.h b/core/src/main/jni/include/utils.h index 8d28ddd9..37ffe2e9 100644 --- a/core/src/main/jni/include/utils.h +++ b/core/src/main/jni/include/utils.h @@ -43,6 +43,11 @@ namespace lspd { }(); return api_level; } + + inline std::string JavaNameToSignature(std::string s) { + std::replace(s.begin(), s.end(), '.', '/'); + return "L" + s; + } } #pragma clang diagnostic pop diff --git a/core/src/main/jni/src/jni/native_api.cpp b/core/src/main/jni/src/jni/native_api.cpp index 8cb82101..ff41f4ed 100644 --- a/core/src/main/jni/src/jni/native_api.cpp +++ b/core/src/main/jni/src/jni/native_api.cpp @@ -15,7 +15,7 @@ * along with LSPosed. If not, see . * * Copyright (C) 2020 EdXposed Contributors - * Copyright (C) 2021 LSPosed Contributors + * Copyright (C) 2021 - 2022 LSPosed Contributors */ // diff --git a/core/src/main/jni/src/jni/resources_hook.cpp b/core/src/main/jni/src/jni/resources_hook.cpp index 69b7b9cf..e1d0608f 100644 --- a/core/src/main/jni/src/jni/resources_hook.cpp +++ b/core/src/main/jni/src/jni/resources_hook.cpp @@ -15,7 +15,7 @@ * along with LSPosed. If not, see . * * Copyright (C) 2020 EdXposed Contributors - * Copyright (C) 2021 LSPosed Contributors + * Copyright (C) 2021 - 2022 LSPosed Contributors */ #include @@ -24,12 +24,11 @@ #include "elf_util.h" #include "native_util.h" #include "resources_hook.h" +#include "ConfigBridge.h" using namespace lsplant; namespace lspd { - static constexpr const char *kXResourcesClassName = "android/content/res/XResources"; - using TYPE_GET_ATTR_NAME_ID = int32_t (*)(void *, int); using TYPE_STRING_AT = char16_t *(*)(const void *, int32_t, size_t *); @@ -46,6 +45,18 @@ namespace lspd { static TYPE_RESTART ResXMLParser_restart = nullptr; static TYPE_GET_ATTR_NAME_ID ResXMLParser_getAttributeNameID = nullptr; + static std::string GetXResourcesClassName() { + auto &obfs_map = ConfigBridge::GetInstance()->obfuscation_map(); + if (obfs_map.empty()) { + LOGW("GetXResourcesClassName: obfuscation_map empty?????"); + } + static auto name = lspd::JavaNameToSignature( + obfs_map.at("android.content.res.X")) // TODO: kill this hardcoded name + .substr(1) + "Resources"; + LOGD("{}", name.c_str()); + return name; + } + static bool PrepareSymbols() { SandHook::ElfImg fw(kLibFwName); if (!fw.isValid()) { @@ -72,22 +83,23 @@ namespace lspd { } LSP_DEF_NATIVE_METHOD(jboolean, ResourcesHook, initXResourcesNative) { + const auto x_resources_class_name = GetXResourcesClassName(); if (auto classXResources_ = Context::GetInstance()->FindClassFromCurrentLoader(env, - kXResourcesClassName)) { + x_resources_class_name)) { classXResources = JNI_NewGlobalRef(env, classXResources_); } else { - LOGE("Error while loading XResources class '{}':", kXResourcesClassName); + LOGE("Error while loading XResources class '{}':", x_resources_class_name); return JNI_FALSE; } methodXResourcesTranslateResId = JNI_GetStaticMethodID( env, classXResources, "translateResId", - "(ILandroid/content/res/XResources;Landroid/content/res/Resources;)I"); + fmt::format("(IL{};Landroid/content/res/Resources;)I", x_resources_class_name)); if (!methodXResourcesTranslateResId) { return JNI_FALSE; } methodXResourcesTranslateAttrId = JNI_GetStaticMethodID( env, classXResources, "translateAttrId", - "(Ljava/lang/String;Landroid/content/res/XResources;)I"); + fmt::format("(Ljava/lang/String;L{};)I", x_resources_class_name)); if (!methodXResourcesTranslateAttrId) { return JNI_FALSE; } @@ -210,6 +222,9 @@ namespace lspd { }; void RegisterResourcesHook(JNIEnv *env) { + auto sign = fmt::format("(JL{};Landroid/content/res/Resources;)V", GetXResourcesClassName()); + gMethods[3].signature = sign.c_str(); + REGISTER_LSP_NATIVE_METHODS(ResourcesHook); } } diff --git a/core/src/main/jni/src/jni/resources_hook.h b/core/src/main/jni/src/jni/resources_hook.h index 68843769..5b26063d 100644 --- a/core/src/main/jni/src/jni/resources_hook.h +++ b/core/src/main/jni/src/jni/resources_hook.h @@ -15,7 +15,7 @@ * along with LSPosed. If not, see . * * Copyright (C) 2020 EdXposed Contributors - * Copyright (C) 2021 LSPosed Contributors + * Copyright (C) 2021 - 2022 LSPosed Contributors */ #pragma once @@ -23,9 +23,6 @@ #include "jni.h" namespace lspd { - - static constexpr uint32_t kAccFinal = 0x0010; - void RegisterResourcesHook(JNIEnv *); } // namespace lspd 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 dbabb0bc..c55fd1d0 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ConfigFileManager.java @@ -375,12 +375,14 @@ public class ConfigFileManager { if (moduleClassNames.isEmpty()) return null; if (obfuscate) { + var signatures = ObfuscationManager.getSignatures(); for (int i = 0; i < moduleClassNames.size(); i++) { var s = moduleClassNames.get(i); - var original = ObfuscationManager.getOriginalSignature(); - if (s.startsWith(original)) { - var obfuscated = ObfuscationManager.getObfuscatedSignature(); - moduleClassNames.add(i, s.replace(original, obfuscated)); + for (String key : signatures.keySet()) { + if (s.startsWith(key)) { + // value should not be null, but idk how to ignore this warning + moduleClassNames.add(i, s.replace(key, signatures.get(key))); + } } } } 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 029041ee..d82be98d 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java @@ -40,6 +40,7 @@ import java.util.concurrent.ConcurrentHashMap; public class LSPApplicationService extends ILSPApplicationService.Stub { final static int DEX_TRANSACTION_CODE = 1310096052; + final static int OBFUSCATION_MAP_TRANSACTION_CODE = 724533732; // key: private final static Map, ProcessInfo> processes = new ConcurrentHashMap<>(); @@ -81,13 +82,24 @@ public class LSPApplicationService extends ILSPApplicationService.Stub { @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { Log.d(TAG, "LSPApplicationService.onTransact: code=" + code); - if (code == DEX_TRANSACTION_CODE) { - var shm = ConfigManager.getInstance().getPreloadDex(); - if (shm == null) return false; - // assume that write only a fd - shm.writeToParcel(reply, 0); - reply.writeLong(shm.getSize()); - return true; + switch (code) { + case DEX_TRANSACTION_CODE: { + var shm = ConfigManager.getInstance().getPreloadDex(); + if (shm == null) return false; + // assume that write only a fd + shm.writeToParcel(reply, 0); + reply.writeLong(shm.getSize()); + return true; + } + case OBFUSCATION_MAP_TRANSACTION_CODE: { + var signatures = ObfuscationManager.getSignatures(); + reply.writeInt(signatures.size() * 2); + for(Map.Entry entry : signatures.entrySet()){ + reply.writeString(entry.getKey()); + reply.writeString(entry.getValue()); + } + return true; + } } return super.onTransact(code, data, reply, flags); } diff --git a/daemon/src/main/java/org/lsposed/lspd/service/LSPSystemServerService.java b/daemon/src/main/java/org/lsposed/lspd/service/LSPSystemServerService.java index e0aac6c5..4ad3166e 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/LSPSystemServerService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/LSPSystemServerService.java @@ -109,6 +109,7 @@ public class LSPSystemServerService extends ILSPSystemServerService.Stub impleme Log.d(TAG, "LSPSystemServerService.onTransact requestApplicationService rejected"); return false; } + case LSPApplicationService.OBFUSCATION_MAP_TRANSACTION_CODE: case LSPApplicationService.DEX_TRANSACTION_CODE: // Proxy LSP dex transaction to Application Binder return ServiceManager.getApplicationService().onTransact(code, data, reply, flags); diff --git a/daemon/src/main/java/org/lsposed/lspd/service/ObfuscationManager.java b/daemon/src/main/java/org/lsposed/lspd/service/ObfuscationManager.java index fa437ec1..4446f236 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/ObfuscationManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ObfuscationManager.java @@ -2,12 +2,12 @@ package org.lsposed.lspd.service; import android.os.SharedMemory; +import java.util.HashMap; + public class ObfuscationManager { // For module dexes static native SharedMemory obfuscateDex(SharedMemory memory); // generates signature - static native String getObfuscatedSignature(); - - static native String getOriginalSignature(); + static native HashMap getSignatures(); } diff --git a/daemon/src/main/jni/obfuscation.cpp b/daemon/src/main/jni/obfuscation.cpp index 1cd14682..58aa37a5 100644 --- a/daemon/src/main/jni/obfuscation.cpp +++ b/daemon/src/main/jni/obfuscation.cpp @@ -39,8 +39,14 @@ using namespace lsplant; namespace { std::mutex init_lock{}; -std::string obfuscated_signature; -const std::string original_signature = "Lde/robv/android/xposed/"; +std::map signatures = { + {"Lde/robv/android/xposed/", ""}, + { "Landroid/app/AndroidApp", ""}, + { "Landroid/content/res/X", ""}, + { "Lorg/lsposed/lspd/core/", ""}, + { "Lorg/lsposed/lspd/nativebridge/", ""}, + { "Lorg/lsposed/lspd/service/", ""}, +}; jclass class_file_descriptor; jmethodID method_file_descriptor_ctor; @@ -73,7 +79,7 @@ void maybeInit(JNIEnv *env) { method_shared_memory_ctor = JNI_GetMethodID(env, class_shared_memory, "", "(Ljava/io/FileDescriptor;)V"); - auto regen = []() { + auto regen = [](std::string_view original_signature) { static auto& chrs = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; @@ -101,40 +107,72 @@ void maybeInit(JNIEnv *env) { return out; }; - obfuscated_signature = regen(); + for (auto &i: signatures) { + i.second = regen(i.first); + LOGD("%s => %s", i.first.c_str(), i.second.c_str()); + } - LOGD("ObfuscationManager.getObfuscatedSignature: %s", obfuscated_signature.c_str()); LOGD("ObfuscationManager init successfully"); inited = true; } -extern "C" -JNIEXPORT jstring JNICALL -Java_org_lsposed_lspd_service_ObfuscationManager_getObfuscatedSignature(JNIEnv *env, [[maybe_unused]] jclass obfuscation_manager) { - maybeInit(env); - static std::string obfuscated_signature_java = to_java(obfuscated_signature); - return env->NewStringUTF(obfuscated_signature_java.c_str()); +// https://stackoverflow.com/questions/4844022/jni-create-hashmap with modifications +jobject stringMapToJavaHashMap(JNIEnv *env, const decltype(signatures)& map) { + jclass mapClass = env->FindClass("java/util/HashMap"); + if(mapClass == nullptr) + return nullptr; + + jmethodID init = env->GetMethodID(mapClass, "", "()V"); + jobject hashMap = env->NewObject(mapClass, init); + jmethodID put = env->GetMethodID(mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + + auto citr = map.begin(); + for( ; citr != map.end(); ++citr) { + jstring keyJava = env->NewStringUTF(citr->first.c_str()); + jstring valueJava = env->NewStringUTF(citr->second.c_str()); + + env->CallObjectMethod(hashMap, put, keyJava, valueJava); + + env->DeleteLocalRef(keyJava); + env->DeleteLocalRef(valueJava); + } + + auto hashMapGobal = static_cast(env->NewGlobalRef(hashMap)); + env->DeleteLocalRef(hashMap); + env->DeleteLocalRef(mapClass); + + return hashMapGobal; } extern "C" -JNIEXPORT jstring JNICALL -Java_org_lsposed_lspd_service_ObfuscationManager_getOriginalSignature(JNIEnv *env, [[maybe_unused]] jclass obfuscation_manager) { - static std::string original_signature_java = to_java(original_signature); - return env->NewStringUTF(original_signature_java.c_str()); +JNIEXPORT jobject JNICALL +Java_org_lsposed_lspd_service_ObfuscationManager_getSignatures(JNIEnv *env, [[maybe_unused]] jclass obfuscation_manager) { + maybeInit(env); + static jobject signatures_jni = nullptr; + if (signatures_jni) return signatures_jni; + decltype(signatures) signatures_java; + for (const auto &i: signatures) { + signatures_java[to_java(i.first)] = to_java(i.second); + } + signatures_jni = stringMapToJavaHashMap(env, signatures_java); + return signatures_jni; } static int obfuscateDex(const void *dex, size_t size) { - const char* new_sig = obfuscated_signature.c_str(); + // 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, original_signature.c_str())); - if (p) { - // NOLINTNEXTLINE bugprone-not-null-terminated-result - memcpy(p, new_sig, strlen(new_sig)); + for (const auto &signature: signatures) { + char* p = const_cast(strstr(s, signature.first.c_str())); + if (p) { + auto new_sig = signature.second.c_str(); + // NOLINTNEXTLINE bugprone-not-null-terminated-result + memcpy(p, new_sig, strlen(new_sig)); + } } } dex::Writer writer(ir); diff --git a/magisk-loader/src/main/jni/api/riru_main.cpp b/magisk-loader/src/main/jni/api/riru_main.cpp index ab26c9b2..af17864f 100644 --- a/magisk-loader/src/main/jni/api/riru_main.cpp +++ b/magisk-loader/src/main/jni/api/riru_main.cpp @@ -24,6 +24,7 @@ #include #include "logging.h" #include "loader.h" +#include "ConfigImpl.h" #include "magisk_loader.h" #include "symbol_cache.h" @@ -42,6 +43,7 @@ namespace lspd { LOGI("onModuleLoaded: version v{} ({})", versionName, versionCode); InitSymbolCache(nullptr); MagiskLoader::Init(); + ConfigImpl::Init(); } void nativeForkAndSpecializePre(JNIEnv *env, jclass, jint *_uid, jint *, diff --git a/magisk-loader/src/main/jni/api/zygisk_main.cpp b/magisk-loader/src/main/jni/api/zygisk_main.cpp index 2ce87d01..0a404e60 100644 --- a/magisk-loader/src/main/jni/api/zygisk_main.cpp +++ b/magisk-loader/src/main/jni/api/zygisk_main.cpp @@ -25,6 +25,7 @@ #include "zygisk.h" #include "logging.h" #include "loader.h" +#include "ConfigImpl.h" #include "magisk_loader.h" #include "symbol_cache.h" @@ -282,6 +283,7 @@ namespace lspd { env_ = env; api_ = api; MagiskLoader::Init(); + ConfigImpl::Init(); auto companion = api->connectCompanion(); if (companion == -1) { diff --git a/magisk-loader/src/main/jni/include/loader.h b/magisk-loader/src/main/jni/include/loader.h index 90838ee3..e6a824e8 100644 --- a/magisk-loader/src/main/jni/include/loader.h +++ b/magisk-loader/src/main/jni/include/loader.h @@ -26,9 +26,6 @@ #include "config.h" namespace lspd { - inline static constexpr auto kEntryClassName = "org.lsposed.lspd.core.Main"_tstr; - inline static constexpr auto kBridgeServiceClassName = "org.lsposed.lspd.service.BridgeService"_tstr; - extern const int apiVersion; extern const char* const moduleName; } diff --git a/magisk-loader/src/main/jni/src/ConfigImpl.h b/magisk-loader/src/main/jni/src/ConfigImpl.h new file mode 100644 index 00000000..e3d5d0c0 --- /dev/null +++ b/magisk-loader/src/main/jni/src/ConfigImpl.h @@ -0,0 +1,43 @@ +/* + * This file is part of LSPosed. + * + * LSPosed is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LSPosed is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LSPosed. If not, see . + * + * Copyright (C) 2022 LSPosed Contributors + */ + +// +// Created by Kotori0 on 2022/4/14. +// + +#ifndef LSPOSED_CONFIGIMPL_H +#define LSPOSED_CONFIGIMPL_H +#include "ConfigBridge.h" +#include "service.h" + +class ConfigImpl: public ConfigBridge { +public: + inline static void Init() { + instance_ = std::make_unique(); + } + + virtual obfuscation_map_t& obfuscation_map() override { return obfuscation_map_; } + virtual void obfuscation_map(obfuscation_map_t m) override { obfuscation_map_ = std::move(m); } + +private: + inline static std::map obfuscation_map_; +}; + + +#endif //LSPOSED_CONFIGIMPL_H diff --git a/magisk-loader/src/main/jni/src/magisk_loader.cpp b/magisk-loader/src/main/jni/src/magisk_loader.cpp index 5dbf2ba2..0d41ef89 100644 --- a/magisk-loader/src/main/jni/src/magisk_loader.cpp +++ b/magisk-loader/src/main/jni/src/magisk_loader.cpp @@ -22,6 +22,7 @@ #include #include +#include "ConfigImpl.h" #include "elf_util.h" #include "loader.h" #include "magisk_loader.h" @@ -73,9 +74,15 @@ namespace lspd { env->DeleteLocalRef(dex_buffer); } + std::string GetEntryClassName() { + const auto &obfs_map = ConfigBridge::GetInstance()->obfuscation_map(); + static auto signature = obfs_map.at("org.lsposed.lspd.core.") + "Main"; + return signature; + } + void MagiskLoader::SetupEntryClass(JNIEnv *env) { if (auto entry_class = FindClassFromLoader(env, GetCurrentClassLoader(), - kEntryClassName)) { + GetEntryClassName())) { entry_class_ = JNI_NewGlobalRef(env, entry_class); } } @@ -104,7 +111,10 @@ namespace lspd { // Call application_binder directly if application binder is available, // or we proxy the request from system server binder - auto [dex_fd, size]= instance->RequestLSPDex(env, application_binder ? application_binder : system_server_binder); + const auto next_binder = std::move(application_binder ? application_binder : system_server_binder); + const auto [dex_fd, size] = instance->RequestLSPDex(env, next_binder); + auto obfs_map = instance->RequestObfuscationMap(env, next_binder); + ConfigBridge::GetInstance()->obfuscation_map(std::move(obfs_map)); LoadDex(env, PreloadedDex(dex_fd, size)); close(dex_fd); instance->HookBridge(*this, env); @@ -196,6 +206,8 @@ namespace lspd { }; InstallInlineHooks(env, initInfo); auto [dex_fd, size] = instance->RequestLSPDex(env, binder); + auto obfs_map = instance->RequestObfuscationMap(env, binder); + ConfigBridge::GetInstance()->obfuscation_map(std::move(obfs_map)); LoadDex(env, PreloadedDex(dex_fd, size)); close(dex_fd); InitHooks(env, initInfo); diff --git a/magisk-loader/src/main/jni/src/service.cpp b/magisk-loader/src/main/jni/src/service.cpp index d7bb7960..c23533d0 100644 --- a/magisk-loader/src/main/jni/src/service.cpp +++ b/magisk-loader/src/main/jni/src/service.cpp @@ -28,6 +28,7 @@ #include "context.h" #include "utils/jni_helper.hpp" #include "symbol_cache.h" +#include "ConfigBridge.h" using namespace lsplant; @@ -108,6 +109,7 @@ namespace lspd { if (auto parcel_class = JNI_FindClass(env, "android/os/Parcel")) { parcel_class_ = JNI_NewGlobalRef(env, parcel_class); } else return; + data_size_method_ = JNI_GetMethodID(env, parcel_class_, "dataSize","()I"); obtain_method_ = JNI_GetStaticMethodID(env, parcel_class_, "obtain", "()Landroid/os/Parcel;"); recycleMethod_ = JNI_GetMethodID(env, parcel_class_, "recycle", "()V"); @@ -119,6 +121,7 @@ namespace lspd { write_strong_binder_method_ = JNI_GetMethodID(env, parcel_class_, "writeStrongBinder", "(Landroid/os/IBinder;)V"); read_exception_method_ = JNI_GetMethodID(env, parcel_class_, "readException", "()V"); + read_int_method_ = JNI_GetMethodID(env, parcel_class_, "readInt", "()I"); read_long_method_ = JNI_GetMethodID(env, parcel_class_, "readLong", "()J"); read_strong_binder_method_ = JNI_GetMethodID(env, parcel_class_, "readStrongBinder", "()Landroid/os/IBinder;"); @@ -144,6 +147,12 @@ namespace lspd { initialized_ = true; } + std::string GetBridgeServiceName() { + const auto &obfs_map = ConfigBridge::GetInstance()->obfuscation_map(); + static auto signature = obfs_map.at("org.lsposed.lspd.service.") + "BridgeService"; + return signature; + } + void Service::HookBridge(const Context &context, JNIEnv *env) { static bool kHooked = false; // This should only be ran once, so unlikely @@ -151,7 +160,7 @@ namespace lspd { if (!initialized_) [[unlikely]] return; kHooked = true; if (auto bridge_service_class = context.FindClassFromCurrentLoader(env, - kBridgeServiceClassName)) + GetBridgeServiceName())) bridge_service_class_ = JNI_NewGlobalRef(env, bridge_service_class); else { LOGE("server class not found"); @@ -284,26 +293,20 @@ namespace lspd { ScopedLocalRef Service::RequestApplicationBinderFromSystemServer(JNIEnv *env, const ScopedLocalRef &system_server_binder) { auto heart_beat_binder = JNI_NewObject(env, binder_class_, binder_ctor_); - auto data = JNI_CallStaticObjectMethod(env, parcel_class_, obtain_method_); - auto reply = JNI_CallStaticObjectMethod(env, parcel_class_, obtain_method_); + Wrapper wrapper{env, this}; - JNI_CallVoidMethod(env, data, write_int_method_, getuid()); - JNI_CallVoidMethod(env, data, write_int_method_, getpid()); - JNI_CallVoidMethod(env, data, write_string_method_, JNI_NewStringUTF(env, "android")); - JNI_CallVoidMethod(env, data, write_strong_binder_method_, heart_beat_binder); + JNI_CallVoidMethod(env, wrapper.data, write_int_method_, getuid()); + JNI_CallVoidMethod(env, wrapper.data, write_int_method_, getpid()); + JNI_CallVoidMethod(env, wrapper.data, write_string_method_, JNI_NewStringUTF(env, "android")); + JNI_CallVoidMethod(env, wrapper.data, write_strong_binder_method_, heart_beat_binder); - auto res = JNI_CallBooleanMethod(env, system_server_binder, transact_method_, - BRIDGE_TRANSACTION_CODE, - data, - reply, 0); + auto res = wrapper.transact(system_server_binder, BRIDGE_TRANSACTION_CODE); ScopedLocalRef app_binder = {env, nullptr}; if (res) { - JNI_CallVoidMethod(env, reply, read_exception_method_); - app_binder = JNI_CallObjectMethod(env, reply, read_strong_binder_method_); + JNI_CallVoidMethod(env, wrapper.reply, read_exception_method_); + app_binder = JNI_CallObjectMethod(env, wrapper.reply, read_strong_binder_method_); } - JNI_CallVoidMethod(env, data, recycleMethod_); - JNI_CallVoidMethod(env, reply, recycleMethod_); if (app_binder) { JNI_NewGlobalRef(env, heart_beat_binder); } @@ -312,23 +315,49 @@ namespace lspd { } 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_, - DEX_TRANSACTION_CODE, - data, - reply, 0); + Wrapper wrapper{env, this}; + bool res = wrapper.transact(binder, DEX_TRANSACTION_CODE); if (!res) { LOGE("Service::RequestLSPDex: transaction failed?"); return {-1, 0}; } - auto parcel_fd = JNI_CallObjectMethod(env, reply, read_file_descriptor_method_); + auto parcel_fd = JNI_CallObjectMethod(env, wrapper.reply, read_file_descriptor_method_); int fd = JNI_CallIntMethod(env, parcel_fd, detach_fd_method_); - auto size = static_cast(JNI_CallLongMethod(env, reply, read_long_method_)); - JNI_CallVoidMethod(env, data, recycleMethod_); - JNI_CallVoidMethod(env, reply, recycleMethod_); - - LOGD("Service::RequestLSPDex fd={}, size={}", fd, size); + auto size = static_cast(JNI_CallLongMethod(env, wrapper.reply, read_long_method_)); + LOGD("fd={}, size={}", fd, size); return {fd, size}; } + + std::map + Service::RequestObfuscationMap(JNIEnv *env, const ScopedLocalRef &binder) { + std::map ret; + Wrapper wrapper{env, this}; + bool res = wrapper.transact(binder, OBFUSCATION_MAP_TRANSACTION_CODE); + + if (!res) { + LOGE("Service::RequestObfuscationMap: transaction failed?"); + return ret; + } + auto size = JNI_CallIntMethod(env, wrapper.reply, read_int_method_); + if (!size || (size & 1) == 1) { + LOGW("Service::RequestObfuscationMap: invalid parcel size"); + } + + auto get_string = [this, &wrapper, &env]() -> std::string { + auto s = JNI_Cast(JNI_CallObjectMethod(env, wrapper.reply, read_string_method_)); + return JUTFString(s); + }; + for (auto i = 0; i < size / 2; i++) { + // DO NOT TOUCH, or value evaluates before key. + auto &&key = get_string(); + ret[key] = get_string(); + } +#ifndef NDEBUG + for (const auto &i: ret) { + LOGD("{} => {}", i.first, i.second); + } +#endif + + return ret; + } } // namespace lspd diff --git a/magisk-loader/src/main/jni/src/service.h b/magisk-loader/src/main/jni/src/service.h index 8eb372d0..a49ee06c 100644 --- a/magisk-loader/src/main/jni/src/service.h +++ b/magisk-loader/src/main/jni/src/service.h @@ -24,6 +24,7 @@ #ifndef LSPOSED_SERVICE_H #define LSPOSED_SERVICE_H +#include #include #include "context.h" @@ -32,6 +33,7 @@ using namespace std::literals::string_view_literals; namespace lspd { class Service { constexpr static jint DEX_TRANSACTION_CODE = 1310096052; + constexpr static jint OBFUSCATION_MAP_TRANSACTION_CODE = 724533732; constexpr static jint BRIDGE_TRANSACTION_CODE = 1598837584; constexpr static auto BRIDGE_SERVICE_DESCRIPTOR = "LSPosed"sv; constexpr static auto BRIDGE_SERVICE_NAME = "activity"sv; @@ -39,6 +41,31 @@ namespace lspd { constexpr static jint BRIDGE_ACTION_GET_BINDER = 2; inline static jint SET_ACTIVITY_CONTROLLER_CODE = -1; + class Wrapper { + public: + Service* service_; + JNIEnv *env_; + lsplant::ScopedLocalRef data; + lsplant::ScopedLocalRef reply; + + Wrapper(JNIEnv *env, Service* service) : + service_(service), + env_(env), + data(lsplant::JNI_CallStaticObjectMethod(env, service->parcel_class_, service->obtain_method_)), + reply(lsplant::JNI_CallStaticObjectMethod(env, service->parcel_class_, service->obtain_method_)) + {} + + inline bool transact(const lsplant::ScopedLocalRef &binder, jint transaction_code) { + return JNI_CallBooleanMethod(env_, binder, service_->transact_method_,transaction_code, + data, reply, 0); + } + + inline ~Wrapper() { + JNI_CallVoidMethod(env_, data, service_->recycleMethod_); + JNI_CallVoidMethod(env_, reply, service_->recycleMethod_); + } + }; + public: inline static Service* instance() { return instance_.get(); @@ -59,6 +86,8 @@ namespace lspd { std::tuple RequestLSPDex(JNIEnv *env, const lsplant::ScopedLocalRef &binder); + std::map RequestObfuscationMap(JNIEnv *env, const lsplant::ScopedLocalRef &binder); + private: inline static std::unique_ptr instance_ = std::make_unique(); bool initialized_ = false; @@ -90,6 +119,7 @@ namespace lspd { jmethodID transact_method_ = nullptr; jclass parcel_class_ = nullptr; + jmethodID data_size_method_ = nullptr; jmethodID obtain_method_ = nullptr; jmethodID recycleMethod_ = nullptr; jmethodID write_interface_token_method_ = nullptr; @@ -99,6 +129,7 @@ namespace lspd { jmethodID read_strong_binder_method_ = nullptr; jmethodID write_strong_binder_method_ = nullptr; jmethodID read_file_descriptor_method_ = nullptr; + jmethodID read_int_method_ = nullptr; jmethodID read_long_method_ = nullptr; jmethodID read_string_method_ = nullptr; diff --git a/services/xposed-service b/services/xposed-service index e183a459..ac9744ab 160000 --- a/services/xposed-service +++ b/services/xposed-service @@ -1 +1 @@ -Subproject commit e183a459a23d8825f495caff30b81d88e56fc65b +Subproject commit ac9744ab71bc899c7954239fadbad605521c4b0c