[core] send LSP main dex through binder
This commit is contained in:
parent
30d1c1b551
commit
4d5a4dcb27
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 *,
|
||||
|
|
|
|||
|
|
@ -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<SharedMem, SharedMem> 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);
|
||||
|
|
|
|||
|
|
@ -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)...);
|
||||
}
|
||||
|
||||
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>
|
||||
[[maybe_unused]]
|
||||
inline auto JNI_CallVoidMethod(JNIEnv *env, const Object &obj, Args &&...args) {
|
||||
|
|
|
|||
|
|
@ -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::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 getsyscl_mid = JNI_GetStaticMethodID(
|
||||
env, classloader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
|
||||
|
|
@ -134,8 +100,7 @@ namespace lspd {
|
|||
auto initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>",
|
||||
"(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<jobject>{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",
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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<jobject> 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<jobject> 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<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) {
|
||||
JNI_NewGlobalRef(env, heart_beat_binder);
|
||||
}
|
||||
LOGD("Service::RequestBinderForSystemServer app_binder: %p", app_binder.get());
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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<jobject> RequestBinderForSystemServer(JNIEnv *env);
|
||||
|
||||
std::tuple<int, size_t> RequestLSPDex(JNIEnv *env, const ScopedLocalRef<jobject> &binder);
|
||||
|
||||
private:
|
||||
inline static std::unique_ptr<Service> instance_ = std::make_unique<Service>();
|
||||
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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -12,11 +12,73 @@
|
|||
#include "slicer/reader.h"
|
||||
#include "slicer/writer.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"
|
||||
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<jint>(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?");
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
// <uid, pid>
|
||||
private final static Set<Pair<Integer, Integer>> cache = ConcurrentHashMap.newKeySet();
|
||||
private final static Map<Integer, IBinder> handles = new ConcurrentHashMap<>();
|
||||
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) {
|
||||
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<Module> getModulesList(String processName) throws RemoteException {
|
||||
ensureRegistered();
|
||||
|
|
|
|||
|
|
@ -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,12 +88,31 @@ 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);
|
||||
}
|
||||
|
||||
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() {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Reference in New Issue