[core] send LSP main dex through binder

This commit is contained in:
kotori0 2022-02-01 22:05:18 +08:00 committed by LoveSy
parent 30d1c1b551
commit 4d5a4dcb27
17 changed files with 229 additions and 107 deletions

View File

@ -12,7 +12,6 @@
} }
-keepclasseswithmembers class org.lsposed.lspd.service.BridgeService { -keepclasseswithmembers class org.lsposed.lspd.service.BridgeService {
public static boolean *(android.os.IBinder, int, long, long, int); 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 { -assumenosideeffects class android.util.Log {

View File

@ -43,11 +43,6 @@ namespace lspd {
LOGI("onModuleLoaded: version v%s (%d)", versionName, versionCode); LOGI("onModuleLoaded: version v%s (%d)", versionName, versionCode);
InitSymbolCache(nullptr); InitSymbolCache(nullptr);
Context::GetInstance()->Init(); 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 *, void nativeForkAndSpecializePre(JNIEnv *env, jclass, jint *_uid, jint *,

View File

@ -290,7 +290,8 @@ namespace lspd {
if (int fd = -1, size = 0; (size = read_int(companion)) > 0 && if (int fd = -1, size = 0; (size = read_int(companion)) > 0 &&
(fd = recv_fd(companion)) != -1) { (fd = recv_fd(companion)) != -1) {
Context::GetInstance()->PreLoadDex(fd, size); // Context::GetInstance()->PreLoadDex(fd, size);
// TODO: remove me
close(fd); close(fd);
} else { } else {
LOGE("Failed to read dex fd"); LOGE("Failed to read dex fd");
@ -341,8 +342,8 @@ namespace lspd {
}; };
std::tuple<SharedMem, SharedMem> InitCompanion() { std::tuple<SharedMem, SharedMem> InitCompanion() {
LOGI("onModuleLoaded: welcome to LSPosed!"); LOGI("ZygiskCompanion: welcome to LSPosed!");
LOGI("onModuleLoaded: version v%s (%d)", versionName, versionCode); LOGI("ZygiskCompanion: version v%s (%d)", versionName, versionCode);
std::string path = "/data/adb/modules/"s + lspd::moduleName + "/" + kDexPath; std::string path = "/data/adb/modules/"s + lspd::moduleName + "/" + kDexPath;
int dex_fd = open(path.data(), O_RDONLY | O_CLOEXEC); int dex_fd = open(path.data(), O_RDONLY | O_CLOEXEC);

View File

@ -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>(args)...); return JNI_SafeInvoke(env, &JNIEnv::CallObjectMethod, obj, std::forward<Args>(args)...);
} }
template<ScopeOrObject Object, typename ...Args>
[[maybe_unused]]
inline auto JNI_CallIntMethod(JNIEnv *env, const Object &obj, Args &&... args) {
return JNI_SafeInvoke(env, &JNIEnv::CallIntMethod, obj, std::forward<Args>(args)...);
}
template<ScopeOrObject Object, typename ...Args>
[[maybe_unused]]
inline auto JNI_CallLongMethod(JNIEnv *env, const Object &obj, Args &&... args) {
return JNI_SafeInvoke(env, &JNIEnv::CallLongMethod, obj, std::forward<Args>(args)...);
}
template<ScopeOrObject Object, typename ...Args> template<ScopeOrObject Object, typename ...Args>
[[maybe_unused]] [[maybe_unused]]
inline auto JNI_CallVoidMethod(JNIEnv *env, const Object &obj, Args &&...args) { inline auto JNI_CallVoidMethod(JNIEnv *env, const Object &obj, Args &&...args) {

View File

@ -68,60 +68,26 @@ namespace lspd {
} }
Context::PreloadedDex::PreloadedDex(int fd, std::size_t size) { Context::PreloadedDex::PreloadedDex(int fd, std::size_t size) {
auto *old = mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0); LOGD("Context::PreloadedDex::PreloadedDex: fd=%d, size=%zu", fd, size);
auto *addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); auto *addr = mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0);
if (old != MAP_FAILED && addr != MAP_FAILED) { if (addr != MAP_FAILED) {
memmove(addr, old, size);
addr_ = addr; addr_ = addr;
size_ = size; size_ = size;
} else { } else {
if (old == MAP_FAILED) LOGE("Old failed");
if (addr == MAP_FAILED) LOGE("addr failed");
LOGE("Read dex failed: %s", strerror(errno)); LOGE("Read dex failed: %s", strerror(errno));
} }
munmap(old, size);
} }
Context::PreloadedDex::~PreloadedDex() { Context::PreloadedDex::~PreloadedDex() {
if (*this) munmap(addr_, size_); if (*this) munmap(addr_, size_);
} }
void Context::ObfuscateDex() { void Context::LoadDex(JNIEnv *env, int fd, size_t size) {
if (!dex_) [[unlikely]] return; 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::u1*>(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<FILE, decltype(&fclose)> 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 classloader = JNI_FindClass(env, "java/lang/ClassLoader");
auto getsyscl_mid = JNI_GetStaticMethodID( auto getsyscl_mid = JNI_GetStaticMethodID(
env, classloader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;"); env, classloader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
@ -134,8 +100,7 @@ namespace lspd {
auto initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>", auto initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>",
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V"); "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
auto byte_buffer_class = JNI_FindClass(env, "java/nio/ByteBuffer"); 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, if (auto my_cl = JNI_NewObject(env, in_memory_classloader, initMid,
dex_buffer, sys_classloader)) { dex_buffer, sys_classloader)) {
inject_class_loader_ = JNI_NewGlobalRef(env, my_cl); inject_class_loader_ = JNI_NewGlobalRef(env, my_cl);
@ -226,9 +191,13 @@ namespace lspd {
void void
Context::OnNativeForkSystemServerPost(JNIEnv *env) { Context::OnNativeForkSystemServerPost(JNIEnv *env) {
if (!skip_) { if (!skip_) {
LoadDex(env); auto *instance = Service::instance();
Service::instance()->HookBridge(*this, env); auto binder = instance->RequestBinderForSystemServer(env);
auto binder = Service::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) { if (binder) {
InstallInlineHooks(); InstallInlineHooks();
Init(env); Init(env);
@ -284,11 +253,13 @@ namespace lspd {
Context::OnNativeForkAndSpecializePost(JNIEnv *env, jstring nice_name, Context::OnNativeForkAndSpecializePost(JNIEnv *env, jstring nice_name,
jstring app_data_dir) { jstring app_data_dir) {
const JUTFString process_name(env, nice_name); const JUTFString process_name(env, nice_name);
auto *instance = Service::instance();
auto binder = skip_ ? ScopedLocalRef<jobject>{env, nullptr} auto binder = skip_ ? ScopedLocalRef<jobject>{env, nullptr}
: Service::instance()->RequestBinder(env, nice_name); : instance->RequestBinder(env, nice_name);
if (binder) { if (binder) {
InstallInlineHooks(); InstallInlineHooks();
LoadDex(env); auto dex = instance->RequestLSPDex(env, binder);
LoadDex(env, std::get<0>(dex), std::get<1>(dex));
Init(env); Init(env);
LOGD("Done prepare"); LOGD("Done prepare");
FindAndCall(env, "forkAndSpecializePost", FindAndCall(env, "forkAndSpecializePost",

View File

@ -59,10 +59,6 @@ namespace lspd {
void OnNativeForkSystemServerPre(JNIEnv *env); void OnNativeForkSystemServerPre(JNIEnv *env);
void PreLoadDex(std::string_view dex_paths);
void PreLoadDex(int fd, std::size_t size);
void Init(); void Init();
private: private:
@ -115,11 +111,9 @@ namespace lspd {
PreloadedDex dex_{}; PreloadedDex dex_{};
void ObfuscateDex();
Context() {} Context() {}
void LoadDex(JNIEnv *env); void LoadDex(JNIEnv *env, int fd, size_t size);
void Init(JNIEnv *env); void Init(JNIEnv *env);

View File

@ -117,11 +117,22 @@ namespace lspd {
write_strong_binder_method_ = JNI_GetMethodID(env, parcel_class_, "writeStrongBinder", write_strong_binder_method_ = JNI_GetMethodID(env, parcel_class_, "writeStrongBinder",
"(Landroid/os/IBinder;)V"); "(Landroid/os/IBinder;)V");
read_exception_method_ = JNI_GetMethodID(env, parcel_class_, "readException", "()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", read_strong_binder_method_ = JNI_GetMethodID(env, parcel_class_, "readStrongBinder",
"()Landroid/os/IBinder;"); "()Landroid/os/IBinder;");
read_file_descriptor_method_ = JNI_GetMethodID(env, parcel_class_, "readFileDescriptor",
"()Landroid/os/ParcelFileDescriptor;");
// createStringArray_ = env->GetMethodID(parcel_class_, "createStringArray", // createStringArray_ = env->GetMethodID(parcel_class_, "createStringArray",
// "()[Ljava/lang/String;"); // "()[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, if (auto dead_object_exception_class = JNI_FindClass(env,
"android/os/DeadObjectException")) { "android/os/DeadObjectException")) {
deadObjectExceptionClass_ = JNI_NewGlobalRef(env, dead_object_exception_class); deadObjectExceptionClass_ = JNI_NewGlobalRef(env, dead_object_exception_class);
@ -202,6 +213,7 @@ namespace lspd {
return {env, nullptr}; return {env, nullptr};
} }
// TODO: memory leak?
auto *bridge_service_name = env->NewStringUTF(BRIDGE_SERVICE_NAME.data()); auto *bridge_service_name = env->NewStringUTF(BRIDGE_SERVICE_NAME.data());
auto bridge_service = JNI_CallStaticObjectMethod(env, service_manager_class_, auto bridge_service = JNI_CallStaticObjectMethod(env, service_manager_class_,
get_service_method_, bridge_service_name); get_service_method_, bridge_service_name);
@ -241,10 +253,12 @@ namespace lspd {
} }
ScopedLocalRef<jobject> Service::RequestBinderForSystemServer(JNIEnv *env) { ScopedLocalRef<jobject> Service::RequestBinderForSystemServer(JNIEnv *env) {
if (!initialized_ || !bridge_service_class_) [[unlikely]] { if (!initialized_) [[unlikely]] {
LOGE("Service not initialized"); LOGE("Service not initialized");
return {env, nullptr}; 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()); auto *bridge_service_name = env->NewStringUTF(SYSTEM_SERVER_BRIDGE_SERVICE_NAME.data());
ScopedLocalRef<jobject> binder{env, nullptr}; ScopedLocalRef<jobject> binder{env, nullptr};
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
@ -262,15 +276,55 @@ namespace lspd {
LOGW("Fail to get binder for system server"); LOGW("Fail to get binder for system server");
return {env, nullptr}; 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 heart_beat_binder = JNI_NewObject(env, binder_class_, binder_ctor_);
auto app_binder = JNI_CallStaticObjectMethod(env, bridge_service_class_, method, binder, auto data = JNI_CallStaticObjectMethod(env, parcel_class_, obtain_method_);
heart_beat_binder); 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<jobject> 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) { if (app_binder) {
JNI_NewGlobalRef(env, heart_beat_binder); JNI_NewGlobalRef(env, heart_beat_binder);
} }
LOGD("Service::RequestBinderForSystemServer app_binder: %p", app_binder.get());
return app_binder; return app_binder;
} }
std::tuple<int, size_t> Service::RequestLSPDex(JNIEnv *env, const ScopedLocalRef<jobject> &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 } // namespace lspd

View File

@ -31,6 +31,7 @@ using namespace std::literals::string_view_literals;
namespace lspd { namespace lspd {
class Service { class Service {
constexpr static jint DEX_TRANSACTION_CODE = 1310096052;
constexpr static jint BRIDGE_TRANSACTION_CODE = 1598837584; constexpr static jint BRIDGE_TRANSACTION_CODE = 1598837584;
constexpr static auto BRIDGE_SERVICE_DESCRIPTOR = "LSPosed"sv; constexpr static auto BRIDGE_SERVICE_DESCRIPTOR = "LSPosed"sv;
constexpr static auto BRIDGE_SERVICE_NAME = "activity"sv; constexpr static auto BRIDGE_SERVICE_NAME = "activity"sv;
@ -54,6 +55,8 @@ namespace lspd {
ScopedLocalRef<jobject> RequestBinderForSystemServer(JNIEnv *env); ScopedLocalRef<jobject> RequestBinderForSystemServer(JNIEnv *env);
std::tuple<int, size_t> RequestLSPDex(JNIEnv *env, const ScopedLocalRef<jobject> &binder);
private: private:
inline static std::unique_ptr<Service> instance_ = std::make_unique<Service>(); inline static std::unique_ptr<Service> instance_ = std::make_unique<Service>();
bool initialized_ = false; bool initialized_ = false;
@ -93,6 +96,11 @@ namespace lspd {
jmethodID read_exception_method_ = nullptr; jmethodID read_exception_method_ = nullptr;
jmethodID read_strong_binder_method_ = nullptr; jmethodID read_strong_binder_method_ = nullptr;
jmethodID write_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; jclass deadObjectExceptionClass_ = nullptr;

View File

@ -214,17 +214,4 @@ public class BridgeService {
reply.recycle(); 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;
}
} }

View File

@ -2,8 +2,8 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE := daemon LOCAL_MODULE := daemon
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../../core/src/main/cpp/shared/ 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 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_STATIC_LIBRARIES := cxx dex_builder
LOCAL_ALLOW_UNDEFINED_SYMBOLS := true LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
LOCAL_LDLIBS := -llog -landroid LOCAL_LDLIBS := -llog -landroid

View File

@ -12,11 +12,73 @@
#include "slicer/reader.h" #include "slicer/reader.h"
#include "slicer/writer.h" #include "slicer/writer.h"
#include "Obfuscation.h" #include "Obfuscation.h"
#include <jni.h> // 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<jint>(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<FILE, decltype(&fclose)> 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" extern "C"
JNIEXPORT jobject 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) { jobject memory) {
int fd = ASharedMemory_dupFromJava(env, memory); int fd = ASharedMemory_dupFromJava(env, memory);
auto size = ASharedMemory_getSize(fd); 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); auto new_dex = Obfuscation::obfuscateDex(mem, size);
// create new SharedMem since it cannot be resized // create new SharedMem since it cannot be resized
jclass clazz = env->FindClass("android/os/SharedMemory"); auto new_mem = new_sharedmem(env, new_dex.size());
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<jint>(new_dex.size()));
int new_fd = ASharedMemory_dupFromJava(env, new_mem); 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); mem = mmap(nullptr, new_dex.size(), PROT_READ | PROT_WRITE, MAP_SHARED, new_fd, 0);
if (mem == MAP_FAILED) { if (mem == MAP_FAILED) {
// LOGE("Failed to map new dex to memory?"); // LOGE("Failed to map new dex to memory?");

View File

@ -16,7 +16,7 @@ import java.util.Map;
public class BridgeService { 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 DESCRIPTOR = "LSPosed";
private static final String SERVICE_NAME = "activity"; private static final String SERVICE_NAME = "activity";

View File

@ -296,7 +296,7 @@ public class ConfigFileManager {
var byteBuffer = memory.mapReadWrite(); var byteBuffer = memory.mapReadWrite();
Channels.newChannel(in).read(byteBuffer); Channels.newChannel(in).read(byteBuffer);
SharedMemory.unmap(byteBuffer); SharedMemory.unmap(byteBuffer);
memory = ObfuscationService.obfuscateDex(memory); memory = LSPApplicationService.obfuscateDex(memory);
memory.setProtect(OsConstants.PROT_READ); memory.setProtect(OsConstants.PROT_READ);
preLoadedDexes.add(memory); preLoadedDexes.add(memory);
} catch (IOException | ErrnoException e) { } catch (IOException | ErrnoException e) {

View File

@ -23,13 +23,16 @@ import static org.lsposed.lspd.service.ServiceManager.TAG;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.os.Parcel;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.SharedMemory;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
import org.lsposed.lspd.models.Module; import org.lsposed.lspd.models.Module;
import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -37,11 +40,30 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
public class LSPApplicationService extends ILSPApplicationService.Stub { public class LSPApplicationService extends ILSPApplicationService.Stub {
private final static int DEX_TRANSACTION_CODE = 1310096052;
// <uid, pid> // <uid, pid>
private final static Set<Pair<Integer, Integer>> cache = ConcurrentHashMap.newKeySet(); private final static Set<Pair<Integer, Integer>> cache = ConcurrentHashMap.newKeySet();
private final static Map<Integer, IBinder> handles = new ConcurrentHashMap<>(); private final static Map<Integer, IBinder> handles = new ConcurrentHashMap<>();
private final static Set<IBinder.DeathRecipient> recipients = ConcurrentHashMap.newKeySet(); private final static Set<IBinder.DeathRecipient> 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) { public boolean registerHeartBeat(int uid, int pid, IBinder handle) {
try { try {
var recipient = new DeathRecipient() { 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 @Override
public List<Module> getModulesList(String processName) throws RemoteException { public List<Module> getModulesList(String processName) throws RemoteException {
ensureRegistered(); ensureRegistered();

View File

@ -47,11 +47,15 @@ public class LSPSystemServerService extends ILSPSystemServerService.Stub impleme
} }
public LSPSystemServerService(int maxRetry) { public LSPSystemServerService(int maxRetry) {
Log.d(TAG, "LSPSystemServerService::LSPSystemServerService");
requested = -maxRetry; requested = -maxRetry;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { 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() { var serviceCallback = new IServiceCallback.Stub() {
@Override @Override
public void onRegistration(String name, IBinder binder) { 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) { if (name.equals(PROXY_SERVICE_NAME) && binder != null && binder != LSPSystemServerService.this) {
Log.d(TAG, "Register " + name + " " + binder); Log.d(TAG, "Register " + name + " " + binder);
originService = binder; originService = binder;
@ -74,6 +78,7 @@ public class LSPSystemServerService extends ILSPSystemServerService.Stub impleme
@Override @Override
public ILSPApplicationService requestApplicationService(int uid, int pid, String processName, IBinder heartBeat) { public ILSPApplicationService requestApplicationService(int uid, int pid, String processName, IBinder heartBeat) {
Log.d(TAG, "ILSPApplicationService.requestApplicationService: " + uid + " " + pid + " " + processName + " " + heartBeat);
requested = 1; requested = 1;
if (ConfigManager.getInstance().shouldSkipSystemServer() || uid != 1000 || heartBeat == null || !"android".equals(processName)) if (ConfigManager.getInstance().shouldSkipSystemServer() || uid != 1000 || heartBeat == null || !"android".equals(processName))
return null; return null;
@ -83,11 +88,30 @@ public class LSPSystemServerService extends ILSPSystemServerService.Stub impleme
@Override @Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
Log.i(TAG, "LSPSystemServerService.onTransact: code=" + code);
if (originService != null) { if (originService != null) {
return originService.transact(code, data, reply, flags); 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() { public void linkToDeath() {

View File

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

View File

@ -98,6 +98,7 @@ public class ServiceManager {
logcatService.start(); logcatService.start();
Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND); Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
LSPApplicationService.preloadDex();
Looper.prepareMainLooper(); Looper.prepareMainLooper();
mainService = new LSPosedService(); mainService = new LSPosedService();
applicationService = new LSPApplicationService(); applicationService = new LSPApplicationService();