diff --git a/core/proguard-rules.pro b/core/proguard-rules.pro index f98ea59b..fc283da2 100644 --- a/core/proguard-rules.pro +++ b/core/proguard-rules.pro @@ -12,7 +12,6 @@ } -keepclasseswithmembers class org.lsposed.lspd.service.BridgeService { public static boolean *(android.os.IBinder, int, long, long, int); - public static android.os.IBinder getApplicationServiceForSystemServer(android.os.IBinder, android.os.IBinder); } -assumenosideeffects class android.util.Log { diff --git a/core/src/main/cpp/main/api/riru_main.cpp b/core/src/main/cpp/main/api/riru_main.cpp index b51f3a40..4404f7a2 100644 --- a/core/src/main/cpp/main/api/riru_main.cpp +++ b/core/src/main/cpp/main/api/riru_main.cpp @@ -43,11 +43,6 @@ namespace lspd { LOGI("onModuleLoaded: version v%s (%d)", versionName, versionCode); InitSymbolCache(nullptr); Context::GetInstance()->Init(); - if constexpr (isDebug) { - Context::GetInstance()->PreLoadDex("/system/" + kDexPath); - } else { - Context::GetInstance()->PreLoadDex(magiskPath + '/' + kDexPath); - } } void nativeForkAndSpecializePre(JNIEnv *env, jclass, jint *_uid, jint *, diff --git a/core/src/main/cpp/main/api/zygisk_main.cpp b/core/src/main/cpp/main/api/zygisk_main.cpp index fba14620..4f5d060b 100644 --- a/core/src/main/cpp/main/api/zygisk_main.cpp +++ b/core/src/main/cpp/main/api/zygisk_main.cpp @@ -290,7 +290,8 @@ namespace lspd { if (int fd = -1, size = 0; (size = read_int(companion)) > 0 && (fd = recv_fd(companion)) != -1) { - Context::GetInstance()->PreLoadDex(fd, size); + // Context::GetInstance()->PreLoadDex(fd, size); + // TODO: remove me close(fd); } else { LOGE("Failed to read dex fd"); @@ -341,8 +342,8 @@ namespace lspd { }; std::tuple InitCompanion() { - LOGI("onModuleLoaded: welcome to LSPosed!"); - LOGI("onModuleLoaded: version v%s (%d)", versionName, versionCode); + LOGI("ZygiskCompanion: welcome to LSPosed!"); + LOGI("ZygiskCompanion: version v%s (%d)", versionName, versionCode); std::string path = "/data/adb/modules/"s + lspd::moduleName + "/" + kDexPath; int dex_fd = open(path.data(), O_RDONLY | O_CLOEXEC); diff --git a/core/src/main/cpp/main/include/jni_helper.h b/core/src/main/cpp/main/include/jni_helper.h index 53909542..5ad77f16 100644 --- a/core/src/main/cpp/main/include/jni_helper.h +++ b/core/src/main/cpp/main/include/jni_helper.h @@ -241,6 +241,18 @@ inline auto JNI_CallObjectMethod(JNIEnv *env, const Object &obj, Args &&... args return JNI_SafeInvoke(env, &JNIEnv::CallObjectMethod, obj, std::forward(args)...); } +template +[[maybe_unused]] +inline auto JNI_CallIntMethod(JNIEnv *env, const Object &obj, Args &&... args) { + return JNI_SafeInvoke(env, &JNIEnv::CallIntMethod, obj, std::forward(args)...); +} + +template +[[maybe_unused]] +inline auto JNI_CallLongMethod(JNIEnv *env, const Object &obj, Args &&... args) { + return JNI_SafeInvoke(env, &JNIEnv::CallLongMethod, obj, std::forward(args)...); +} + template [[maybe_unused]] inline auto JNI_CallVoidMethod(JNIEnv *env, const Object &obj, Args &&...args) { diff --git a/core/src/main/cpp/main/src/context.cpp b/core/src/main/cpp/main/src/context.cpp index d4e56a67..4d40542f 100644 --- a/core/src/main/cpp/main/src/context.cpp +++ b/core/src/main/cpp/main/src/context.cpp @@ -68,60 +68,26 @@ namespace lspd { } Context::PreloadedDex::PreloadedDex(int fd, std::size_t size) { - auto *old = mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0); - auto *addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + LOGD("Context::PreloadedDex::PreloadedDex: fd=%d, size=%zu", fd, size); + auto *addr = mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0); - if (old != MAP_FAILED && addr != MAP_FAILED) { - memmove(addr, old, size); + if (addr != MAP_FAILED) { addr_ = addr; size_ = size; } else { - if (old == MAP_FAILED) LOGE("Old failed"); - if (addr == MAP_FAILED) LOGE("addr failed"); LOGE("Read dex failed: %s", strerror(errno)); } - munmap(old, size); } Context::PreloadedDex::~PreloadedDex() { if (*this) munmap(addr_, size_); } - void Context::ObfuscateDex() { - if (!dex_) [[unlikely]] return; + void Context::LoadDex(JNIEnv *env, int fd, size_t size) { + LOGD("Context::LoadDex: %d", fd); + // map fd to memory. fd should be created with ASharedMemory_create. + dex_ = PreloadedDex(fd, size); // for RAII... - auto dex = Obfuscation::obfuscateDex(dex_.data(), dex_.size()); - // TODO: multiple memory copy prevention - auto *mem = mmap(nullptr, dex.size(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - memmove(mem, dex.data(), dex.size()); - PreloadedDex new_dex(mem, dex.size()); - std::swap(dex_, new_dex); - LOGD("Context::ObfuscateDex: %p, size=%zu", reinterpret_cast(dex_.data()), dex.size()); - } - - void Context::PreLoadDex(int fd, std::size_t size) { - dex_ = PreloadedDex{fd, size}; - ObfuscateDex(); - } - - void Context::PreLoadDex(std::string_view dex_path) { - if (dex_) [[unlikely]] return; - - std::unique_ptr f{fopen(dex_path.data(), "rb"), &fclose}; - - if (!f) { - LOGE("Fail to open dex from %s", dex_path.data()); - return; - } else { - fseek(f.get(), 0, SEEK_END); - auto size = ftell(f.get()); - rewind(f.get()); - PreLoadDex(fileno(f.get()), size); - } - LOGD("Loaded %s with size %zu", dex_path.data(), dex_.size()); - } - - void Context::LoadDex(JNIEnv *env) { auto classloader = JNI_FindClass(env, "java/lang/ClassLoader"); auto getsyscl_mid = JNI_GetStaticMethodID( env, classloader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;"); @@ -134,8 +100,7 @@ namespace lspd { auto initMid = JNI_GetMethodID(env, in_memory_classloader, "", "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V"); auto byte_buffer_class = JNI_FindClass(env, "java/nio/ByteBuffer"); - auto dex = std::move(dex_); - auto dex_buffer = env->NewDirectByteBuffer(dex.data(), dex.size()); + auto dex_buffer = env->NewDirectByteBuffer(dex_.data(), dex_.size()); if (auto my_cl = JNI_NewObject(env, in_memory_classloader, initMid, dex_buffer, sys_classloader)) { inject_class_loader_ = JNI_NewGlobalRef(env, my_cl); @@ -226,9 +191,13 @@ namespace lspd { void Context::OnNativeForkSystemServerPost(JNIEnv *env) { if (!skip_) { - LoadDex(env); - Service::instance()->HookBridge(*this, env); - auto binder = Service::instance()->RequestBinderForSystemServer(env); + auto *instance = Service::instance(); + auto binder = instance->RequestBinderForSystemServer(env); + // TODO: binder could be not available + auto dex = instance->RequestLSPDex(env, binder); + LoadDex(env, std::get<0>(dex), std::get<1>(dex)); + instance->HookBridge(*this, env); + if (binder) { InstallInlineHooks(); Init(env); @@ -284,11 +253,13 @@ namespace lspd { Context::OnNativeForkAndSpecializePost(JNIEnv *env, jstring nice_name, jstring app_data_dir) { const JUTFString process_name(env, nice_name); + auto *instance = Service::instance(); auto binder = skip_ ? ScopedLocalRef{env, nullptr} - : Service::instance()->RequestBinder(env, nice_name); + : instance->RequestBinder(env, nice_name); if (binder) { InstallInlineHooks(); - LoadDex(env); + auto dex = instance->RequestLSPDex(env, binder); + LoadDex(env, std::get<0>(dex), std::get<1>(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 dabc39b0..59ec744b 100644 --- a/core/src/main/cpp/main/src/context.h +++ b/core/src/main/cpp/main/src/context.h @@ -59,10 +59,6 @@ namespace lspd { void OnNativeForkSystemServerPre(JNIEnv *env); - void PreLoadDex(std::string_view dex_paths); - - void PreLoadDex(int fd, std::size_t size); - void Init(); private: @@ -115,11 +111,9 @@ namespace lspd { PreloadedDex dex_{}; - void ObfuscateDex(); - Context() {} - void LoadDex(JNIEnv *env); + void LoadDex(JNIEnv *env, int fd, size_t size); void Init(JNIEnv *env); diff --git a/core/src/main/cpp/main/src/service.cpp b/core/src/main/cpp/main/src/service.cpp index c7883b17..2557010d 100644 --- a/core/src/main/cpp/main/src/service.cpp +++ b/core/src/main/cpp/main/src/service.cpp @@ -117,11 +117,22 @@ 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_long_method_ = JNI_GetMethodID(env, parcel_class_, "readLong", "()J"); read_strong_binder_method_ = JNI_GetMethodID(env, parcel_class_, "readStrongBinder", "()Landroid/os/IBinder;"); + read_file_descriptor_method_ = JNI_GetMethodID(env, parcel_class_, "readFileDescriptor", + "()Landroid/os/ParcelFileDescriptor;"); // createStringArray_ = env->GetMethodID(parcel_class_, "createStringArray", // "()[Ljava/lang/String;"); + if (auto parcel_file_descriptor_class = JNI_FindClass(env, "android/os/ParcelFileDescriptor")) { + parcel_file_descriptor_class_ = JNI_NewGlobalRef(env, parcel_file_descriptor_class); + } else { + LOGE("ParcelFileDescriptor not found"); + return; + } + get_fd_method = JNI_GetMethodID(env, parcel_file_descriptor_class_, "getFd", "()I"); + if (auto dead_object_exception_class = JNI_FindClass(env, "android/os/DeadObjectException")) { deadObjectExceptionClass_ = JNI_NewGlobalRef(env, dead_object_exception_class); @@ -202,6 +213,7 @@ namespace lspd { return {env, nullptr}; } + // TODO: memory leak? auto *bridge_service_name = env->NewStringUTF(BRIDGE_SERVICE_NAME.data()); auto bridge_service = JNI_CallStaticObjectMethod(env, service_manager_class_, get_service_method_, bridge_service_name); @@ -241,10 +253,12 @@ namespace lspd { } ScopedLocalRef Service::RequestBinderForSystemServer(JNIEnv *env) { - if (!initialized_ || !bridge_service_class_) [[unlikely]] { + if (!initialized_) [[unlikely]] { LOGE("Service not initialized"); return {env, nullptr}; } + // Get Binder for LSPSystemServerService. + // The binder itself was inject into system service "serial" auto *bridge_service_name = env->NewStringUTF(SYSTEM_SERVER_BRIDGE_SERVICE_NAME.data()); ScopedLocalRef binder{env, nullptr}; for (int i = 0; i < 3; ++i) { @@ -262,15 +276,55 @@ namespace lspd { LOGW("Fail to get binder for system server"); return {env, nullptr}; } - auto *method = JNI_GetStaticMethodID(env, bridge_service_class_, - "getApplicationServiceForSystemServer", - "(Landroid/os/IBinder;Landroid/os/IBinder;)Landroid/os/IBinder;"); + auto heart_beat_binder = JNI_NewObject(env, binder_class_, binder_ctor_); - auto app_binder = JNI_CallStaticObjectMethod(env, bridge_service_class_, method, binder, - heart_beat_binder); + auto data = JNI_CallStaticObjectMethod(env, parcel_class_, obtain_method_); + auto reply = JNI_CallStaticObjectMethod(env, parcel_class_, obtain_method_); + + JNI_CallVoidMethod(env, data, write_int_method_, getuid()); // data.writeInt(uid) + JNI_CallVoidMethod(env, data, write_int_method_, getpid()); + JNI_CallVoidMethod(env, data, write_string_method_, env->NewStringUTF("android")); + JNI_CallVoidMethod(env, data, write_strong_binder_method_, heart_beat_binder); + + auto res = JNI_CallBooleanMethod(env, binder, transact_method_, + BRIDGE_TRANSACTION_CODE, + data, + reply, 0); + + ScopedLocalRef app_binder = {env, nullptr}; + if (res) { + JNI_CallVoidMethod(env, reply, read_exception_method_); + app_binder = JNI_CallObjectMethod(env, reply, read_strong_binder_method_); + } else { + LOGE("Service::RequestBinderForSystemServer binder.transact failed?"); + } + JNI_CallVoidMethod(env, data, recycleMethod_); + JNI_CallVoidMethod(env, reply, recycleMethod_); if (app_binder) { JNI_NewGlobalRef(env, heart_beat_binder); } + LOGD("Service::RequestBinderForSystemServer app_binder: %p", app_binder.get()); return app_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_, + DEX_TRANSACTION_CODE, + data, + reply, 0); + if (!res) { + LOGE("Service::RequestLSPDex: transaction failed?"); + 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_); + JNI_CallVoidMethod(env, data, recycleMethod_); + JNI_CallVoidMethod(env, reply, recycleMethod_); + + LOGD("Service::RequestLSPDex fd=%d, size=%zu", fd, size); + return {fd, size}; + } } // namespace lspd diff --git a/core/src/main/cpp/main/src/service.h b/core/src/main/cpp/main/src/service.h index 28522ff3..15e6b46d 100644 --- a/core/src/main/cpp/main/src/service.h +++ b/core/src/main/cpp/main/src/service.h @@ -31,6 +31,7 @@ using namespace std::literals::string_view_literals; namespace lspd { class Service { + constexpr static jint DEX_TRANSACTION_CODE = 1310096052; constexpr static jint BRIDGE_TRANSACTION_CODE = 1598837584; constexpr static auto BRIDGE_SERVICE_DESCRIPTOR = "LSPosed"sv; constexpr static auto BRIDGE_SERVICE_NAME = "activity"sv; @@ -54,6 +55,8 @@ namespace lspd { ScopedLocalRef RequestBinderForSystemServer(JNIEnv *env); + std::tuple RequestLSPDex(JNIEnv *env, const ScopedLocalRef &binder); + private: inline static std::unique_ptr instance_ = std::make_unique(); bool initialized_ = false; @@ -93,6 +96,11 @@ namespace lspd { jmethodID read_exception_method_ = nullptr; jmethodID read_strong_binder_method_ = nullptr; jmethodID write_strong_binder_method_ = nullptr; + jmethodID read_file_descriptor_method_ = nullptr; + jmethodID read_long_method_ = nullptr; + + jclass parcel_file_descriptor_class_ = nullptr; + jmethodID get_fd_method = nullptr; jclass deadObjectExceptionClass_ = nullptr; diff --git a/core/src/main/java/org/lsposed/lspd/service/BridgeService.java b/core/src/main/java/org/lsposed/lspd/service/BridgeService.java index f25e1d3b..10ccbb40 100644 --- a/core/src/main/java/org/lsposed/lspd/service/BridgeService.java +++ b/core/src/main/java/org/lsposed/lspd/service/BridgeService.java @@ -214,17 +214,4 @@ public class BridgeService { reply.recycle(); } } - - @SuppressWarnings("unused") - public static IBinder getApplicationServiceForSystemServer(IBinder binder, IBinder heartBeat) { - if (binder == null || heartBeat == null) return null; - try { - var service = ILSPSystemServerService.Stub.asInterface(binder); - var applicationService = service.requestApplicationService(Process.myUid(), Process.myPid(), "android", heartBeat); - if (applicationService != null) return applicationService.asBinder(); - } catch (Throwable e) { - Log.e(TAG, Log.getStackTraceString(e)); - } - return null; - } } diff --git a/daemon/src/main/cpp/Android.mk b/daemon/src/main/cpp/Android.mk index ad54eb5b..04b676e3 100644 --- a/daemon/src/main/cpp/Android.mk +++ b/daemon/src/main/cpp/Android.mk @@ -2,8 +2,8 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := daemon -LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../../core/src/main/cpp/shared/ -LOCAL_SRC_FILES := logcat.cpp obfuscation.cpp ../../../../core/src/main/cpp/shared/Obfuscation.cpp +LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../../core/src/main/cpp/shared/ $(LOCAL_PATH)../../../../core/src/main/cpp/main/include/ +LOCAL_SRC_FILES := logcat.cpp obfuscation.cpp ../../../../core/src/main/cpp/shared/Obfuscation.cpp ../../../../core/src/main/cpp/main/api/config.cpp LOCAL_STATIC_LIBRARIES := cxx dex_builder LOCAL_ALLOW_UNDEFINED_SYMBOLS := true LOCAL_LDLIBS := -llog -landroid diff --git a/daemon/src/main/cpp/obfuscation.cpp b/daemon/src/main/cpp/obfuscation.cpp index 1db6eb65..b09fa067 100644 --- a/daemon/src/main/cpp/obfuscation.cpp +++ b/daemon/src/main/cpp/obfuscation.cpp @@ -12,11 +12,73 @@ #include "slicer/reader.h" #include "slicer/writer.h" #include "Obfuscation.h" -#include +// TODO: BAD +#include "../../../../core/src/main/cpp/main/include/config.h" + +static jobject lspdDex = nullptr; + +jobject new_sharedmem(JNIEnv* env, jint size) { + jclass clazz = env->FindClass("android/os/SharedMemory"); + auto *ref = env->NewGlobalRef(clazz); + jmethodID mid = env->GetStaticMethodID(clazz, "create", "(Ljava/lang/String;I)Landroid/os/SharedMemory;"); + jstring empty_str = env->NewStringUTF(""); + jobject new_mem = env->CallStaticObjectMethod(clazz, mid, empty_str, static_cast(size)); + env->DeleteGlobalRef(ref); + env->DeleteLocalRef(empty_str); + return new_mem; +} + +extern "C" +JNIEXPORT jint JNICALL +Java_org_lsposed_lspd_service_LSPApplicationService_preloadDex(JNIEnv *env, jclass ) { + using namespace std::string_literals; + // TODO: Lock? + if (lspdDex) return ASharedMemory_dupFromJava(env, lspdDex); + std::string dex_path = "/data/adb/modules/"s + lspd::moduleName + "/" + lspd::kDexPath; + + std::unique_ptr f{fopen(dex_path.data(), "rb"), &fclose}; + + if (!f) { + LOGE("Fail to open dex from %s", dex_path.data()); + return -1; + } + fseek(f.get(), 0, SEEK_END); + auto size = ftell(f.get()); + rewind(f.get()); + + LOGD("Loaded %s with size %zu", dex_path.data(), size); + + auto *addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fileno(f.get()), 0); + + if (addr == MAP_FAILED) { + LOGE("Read dex failed: %s", strerror(errno)); + return -1; + } + + auto new_dex = Obfuscation::obfuscateDex(addr, size); + LOGD("LSPApplicationService::preloadDex: %p, size=%zu", new_dex.data(), new_dex.size()); + auto new_mem = new_sharedmem(env, new_dex.size()); + lspdDex = env->NewGlobalRef(new_mem); + auto new_fd = ASharedMemory_dupFromJava(env, lspdDex); + auto new_addr = mmap(nullptr, new_dex.size(), PROT_READ | PROT_WRITE, MAP_SHARED, new_fd, 0); + memmove(new_addr, new_dex.data(), new_dex.size()); + + return new_fd; +} + +extern "C" +JNIEXPORT jlong JNICALL +Java_org_lsposed_lspd_service_LSPApplicationService_getPreloadedDexSize(JNIEnv *env, jclass ) { + if (lspdDex) { + auto fd = ASharedMemory_dupFromJava(env, lspdDex); + return ASharedMemory_getSize(fd); + } + return 0; +} extern "C" JNIEXPORT jobject -Java_org_lsposed_lspd_service_ObfuscationService_obfuscateDex(JNIEnv *env, jclass /*clazz*/, +Java_org_lsposed_lspd_service_LSPApplicationService_obfuscateDex(JNIEnv *env, jclass /*clazz*/, jobject memory) { int fd = ASharedMemory_dupFromJava(env, memory); auto size = ASharedMemory_getSize(fd); @@ -29,16 +91,9 @@ Java_org_lsposed_lspd_service_ObfuscationService_obfuscateDex(JNIEnv *env, jclas auto new_dex = Obfuscation::obfuscateDex(mem, size); // create new SharedMem since it cannot be resized - jclass clazz = env->FindClass("android/os/SharedMemory"); - auto *ref = env->NewGlobalRef(clazz); - jmethodID mid = env->GetStaticMethodID(clazz, "create", "(Ljava/lang/String;I)Landroid/os/SharedMemory;"); - jstring empty_str = env->NewStringUTF(""); - jobject new_mem = env->CallStaticObjectMethod(clazz, mid, empty_str, static_cast(new_dex.size())); + auto new_mem = new_sharedmem(env, new_dex.size()); int new_fd = ASharedMemory_dupFromJava(env, new_mem); - env->DeleteGlobalRef(ref); - env->DeleteLocalRef(empty_str); - mem = mmap(nullptr, new_dex.size(), PROT_READ | PROT_WRITE, MAP_SHARED, new_fd, 0); if (mem == MAP_FAILED) { // LOGE("Failed to map new dex to memory?"); diff --git a/daemon/src/main/java/org/lsposed/lspd/service/BridgeService.java b/daemon/src/main/java/org/lsposed/lspd/service/BridgeService.java index 3249e8a2..6ff22c46 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/BridgeService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/BridgeService.java @@ -16,7 +16,7 @@ import java.util.Map; public class BridgeService { - private static final int TRANSACTION_CODE = ('_' << 24) | ('L' << 16) | ('S' << 8) | 'P'; + static final int TRANSACTION_CODE = ('_' << 24) | ('L' << 16) | ('S' << 8) | 'P'; // 1598837584 private static final String DESCRIPTOR = "LSPosed"; private static final String SERVICE_NAME = "activity"; 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 85a8676f..59d1e136 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 = ObfuscationService.obfuscateDex(memory); + memory = LSPApplicationService.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 aad1668d..3456e991 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/LSPApplicationService.java @@ -23,13 +23,16 @@ import static org.lsposed.lspd.service.ServiceManager.TAG; import android.os.Bundle; import android.os.IBinder; +import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.os.SharedMemory; import android.util.Log; import android.util.Pair; import org.lsposed.lspd.models.Module; +import java.io.IOException; import java.util.Collections; import java.util.List; import java.util.Map; @@ -37,11 +40,30 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; public class LSPApplicationService extends ILSPApplicationService.Stub { + private final static int DEX_TRANSACTION_CODE = 1310096052; // private final static Set> cache = ConcurrentHashMap.newKeySet(); private final static Map handles = new ConcurrentHashMap<>(); private final static Set recipients = ConcurrentHashMap.newKeySet(); + @Override + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws android.os.RemoteException { + Log.i(TAG, "LSPApplicationService.onTransact: code=" + code); + if (code == DEX_TRANSACTION_CODE) { + try { + ParcelFileDescriptor pfd = ParcelFileDescriptor.fromFd(preloadDex()); + reply.writeFileDescriptor(pfd.getFileDescriptor()); + reply.writeLong(getPreloadedDexSize()); + } catch (IOException ignored) { + Log.e(TAG, "LSPApplicationService.onTransact: ParcelFileDescriptor.fromFd failed"); + return false; + } + return true; + } else { + return super.onTransact(code, data, reply, flags); + } + } + public boolean registerHeartBeat(int uid, int pid, IBinder handle) { try { var recipient = new DeathRecipient() { @@ -65,6 +87,14 @@ 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/LSPSystemServerService.java b/daemon/src/main/java/org/lsposed/lspd/service/LSPSystemServerService.java index 7e1ec0a3..61adb82b 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/LSPSystemServerService.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/LSPSystemServerService.java @@ -47,11 +47,15 @@ public class LSPSystemServerService extends ILSPSystemServerService.Stub impleme } public LSPSystemServerService(int maxRetry) { + Log.d(TAG, "LSPSystemServerService::LSPSystemServerService"); requested = -maxRetry; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + // Registers a callback when system is registering an authentic "serial" service + // And we are proxying all requests to that system service var serviceCallback = new IServiceCallback.Stub() { @Override public void onRegistration(String name, IBinder binder) { + Log.d(TAG, "LSPSystemServerService::LSPSystemServerService onRegistration: " + name + " " + binder); if (name.equals(PROXY_SERVICE_NAME) && binder != null && binder != LSPSystemServerService.this) { Log.d(TAG, "Register " + name + " " + binder); originService = binder; @@ -74,6 +78,7 @@ public class LSPSystemServerService extends ILSPSystemServerService.Stub impleme @Override public ILSPApplicationService requestApplicationService(int uid, int pid, String processName, IBinder heartBeat) { + Log.d(TAG, "ILSPApplicationService.requestApplicationService: " + uid + " " + pid + " " + processName + " " + heartBeat); requested = 1; if (ConfigManager.getInstance().shouldSkipSystemServer() || uid != 1000 || heartBeat == null || !"android".equals(processName)) return null; @@ -83,11 +88,30 @@ public class LSPSystemServerService extends ILSPSystemServerService.Stub impleme @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { + Log.i(TAG, "LSPSystemServerService.onTransact: code=" + code); if (originService != null) { return originService.transact(code, data, reply, flags); } - return super.onTransact(code, data, reply, flags); + if (code == BridgeService.TRANSACTION_CODE) { + // request application service with JNI + int uid = data.readInt(); + int pid = data.readInt(); + String processName = data.readString(); + IBinder heartBeat = data.readStrongBinder(); + var service = requestApplicationService(uid, pid, processName, heartBeat); + if (service != null) { + Log.d(TAG, "LSPSystemServerService.onTransact requestApplicationService granted: " + service); + reply.writeNoException(); + reply.writeStrongBinder(service.asBinder()); + return true; + } else { + Log.d(TAG, "LSPSystemServerService.onTransact requestApplicationService rejected"); + return false; + } + } else { + return super.onTransact(code, data, reply, flags); + } } public void linkToDeath() { diff --git a/daemon/src/main/java/org/lsposed/lspd/service/ObfuscationService.java b/daemon/src/main/java/org/lsposed/lspd/service/ObfuscationService.java deleted file mode 100644 index a342056a..00000000 --- a/daemon/src/main/java/org/lsposed/lspd/service/ObfuscationService.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.lsposed.lspd.service; - -import android.os.SharedMemory; - -import java.nio.ByteBuffer; - -public class ObfuscationService { - static native SharedMemory obfuscateDex(SharedMemory memory); -} \ No newline at end of file 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 ab78b0c1..996c4e96 100644 --- a/daemon/src/main/java/org/lsposed/lspd/service/ServiceManager.java +++ b/daemon/src/main/java/org/lsposed/lspd/service/ServiceManager.java @@ -98,6 +98,7 @@ public class ServiceManager { logcatService.start(); Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND); + LSPApplicationService.preloadDex(); Looper.prepareMainLooper(); mainService = new LSPosedService(); applicationService = new LSPApplicationService();