reduce memory allocation && properly close fds
This commit is contained in:
parent
d3b0140230
commit
9760e8d733
|
|
@ -82,7 +82,7 @@ namespace lspd {
|
|||
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 = PreloadedDex(fd, size); // for RAII...
|
||||
|
||||
auto classloader = JNI_FindClass(env, "java/lang/ClassLoader");
|
||||
auto getsyscl_mid = JNI_GetStaticMethodID(
|
||||
|
|
@ -96,7 +96,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_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);
|
||||
|
|
@ -199,7 +199,9 @@ namespace lspd {
|
|||
// Call application_binder directly if application binder is available,
|
||||
// or we proxy the request from system server binder
|
||||
auto dex = instance->RequestLSPDex(env, application_binder ? application_binder : system_server_binder);
|
||||
LoadDex(env, std::get<0>(dex), std::get<1>(dex));
|
||||
auto dex_fd = std::get<0>(dex);
|
||||
LoadDex(env, dex_fd, std::get<1>(dex));
|
||||
close(dex_fd);
|
||||
instance->HookBridge(*this, env);
|
||||
|
||||
if (application_binder) {
|
||||
|
|
@ -264,7 +266,9 @@ namespace lspd {
|
|||
if (binder) {
|
||||
InstallInlineHooks();
|
||||
auto dex = instance->RequestLSPDex(env, binder);
|
||||
LoadDex(env, std::get<0>(dex), std::get<1>(dex));
|
||||
auto dex_fd = std::get<0>(dex);
|
||||
LoadDex(env, dex_fd, std::get<1>(dex));
|
||||
close(dex_fd);
|
||||
obfuscated_signature_ = std::move(std::get<2>(dex));
|
||||
Init(env);
|
||||
LOGD("Done prepare");
|
||||
|
|
|
|||
|
|
@ -110,8 +110,6 @@ namespace lspd {
|
|||
std::size_t size_;
|
||||
};
|
||||
|
||||
PreloadedDex dex_{};
|
||||
|
||||
Context() {}
|
||||
|
||||
void LoadDex(JNIEnv *env, int fd, size_t size);
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ namespace lspd {
|
|||
LOGE("ParcelFileDescriptor not found");
|
||||
return;
|
||||
}
|
||||
get_fd_method = JNI_GetMethodID(env, parcel_file_descriptor_class_, "getFd", "()I");
|
||||
detach_fd_method_ = JNI_GetMethodID(env, parcel_file_descriptor_class_, "detachFd", "()I");
|
||||
|
||||
if (auto dead_object_exception_class = JNI_FindClass(env,
|
||||
"android/os/DeadObjectException")) {
|
||||
|
|
@ -299,8 +299,6 @@ namespace lspd {
|
|||
if (res) {
|
||||
JNI_CallVoidMethod(env, reply, read_exception_method_);
|
||||
app_binder = JNI_CallObjectMethod(env, reply, read_strong_binder_method_);
|
||||
} else {
|
||||
LOGE("Service::RequestSystemServerBinder binder.transact failed?");
|
||||
}
|
||||
JNI_CallVoidMethod(env, data, recycleMethod_);
|
||||
JNI_CallVoidMethod(env, reply, recycleMethod_);
|
||||
|
|
@ -323,7 +321,7 @@ namespace lspd {
|
|||
return {-1, 0, ""};
|
||||
}
|
||||
auto parcel_fd = JNI_CallObjectMethod(env, reply, read_file_descriptor_method_);
|
||||
int fd = JNI_CallIntMethod(env, parcel_fd, get_fd_method);
|
||||
int fd = JNI_CallIntMethod(env, parcel_fd, detach_fd_method_);
|
||||
auto size = JNI_CallLongMethod(env, reply, read_long_method_);
|
||||
auto signature = JNI_CallObjectMethod(env, reply, read_string_method_);
|
||||
JNI_CallVoidMethod(env, data, recycleMethod_);
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ namespace lspd {
|
|||
jmethodID read_string_method_ = nullptr;
|
||||
|
||||
jclass parcel_file_descriptor_class_ = nullptr;
|
||||
jmethodID get_fd_method = nullptr;
|
||||
jmethodID detach_fd_method_ = nullptr;
|
||||
|
||||
jclass deadObjectExceptionClass_ = nullptr;
|
||||
|
||||
|
|
|
|||
|
|
@ -33,24 +33,25 @@
|
|||
#include "slicer/reader.h"
|
||||
#include "slicer/writer.h"
|
||||
#include "config.h"
|
||||
#include "jni_helper.h"
|
||||
#include "obfuscation.h"
|
||||
|
||||
class WA: public dex::Writer::Allocator {
|
||||
std::unordered_map<void*, size_t> allocated_;
|
||||
public:
|
||||
void* Allocate(size_t size) override {
|
||||
auto *mem = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
allocated_[mem] = size;
|
||||
return mem;
|
||||
}
|
||||
void Free(void* ptr) override {
|
||||
munmap(ptr, allocated_[ptr]);
|
||||
allocated_.erase(ptr);
|
||||
}
|
||||
};
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_lsposed_lspd_service_ObfuscationManager_init(JNIEnv *env, jclass ) {
|
||||
LOGD("ObfuscationManager.init");
|
||||
if (auto file_descriptor = JNI_FindClass(env, "java/io/FileDescriptor")) {
|
||||
class_file_descriptor = JNI_NewGlobalRef(env, file_descriptor);
|
||||
} else return;
|
||||
|
||||
static std::string obfuscated_signature;
|
||||
static const std::string old_signature = "Lde/robv/android/xposed";
|
||||
method_file_descriptor_ctor = JNI_GetMethodID(env, class_file_descriptor, "<init>", "(I)V");
|
||||
|
||||
if (auto shared_memory = JNI_FindClass(env, "android/os/SharedMemory")) {
|
||||
class_shared_memory = JNI_NewGlobalRef(env, shared_memory);
|
||||
} else return;
|
||||
|
||||
method_shared_memory_ctor = JNI_GetMethodID(env, class_shared_memory, "<init>", "(Ljava/io/FileDescriptor;)V");
|
||||
LOGD("ObfuscationManager init successfully");
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jstring JNICALL
|
||||
|
|
@ -84,10 +85,9 @@ Java_org_lsposed_lspd_service_ObfuscationManager_getObfuscatedSignature(JNIEnv *
|
|||
return env->NewStringUTF(obfuscated_signature.c_str());
|
||||
}
|
||||
|
||||
using ustring = std::basic_string<uint8_t>;
|
||||
ustring obfuscateDex(void *dex, size_t size) {
|
||||
int obfuscateDex(const void *dex, size_t size) {
|
||||
const char* new_sig = obfuscated_signature.c_str();
|
||||
dex::Reader reader{reinterpret_cast<dex::u1*>(dex), size};
|
||||
dex::Reader reader{reinterpret_cast<const dex::u1*>(dex), size};
|
||||
|
||||
reader.CreateFullIr();
|
||||
auto ir = reader.GetIr();
|
||||
|
|
@ -102,29 +102,16 @@ ustring obfuscateDex(void *dex, size_t size) {
|
|||
|
||||
size_t new_size;
|
||||
WA allocator;
|
||||
auto *p_dex = writer.CreateImage(&allocator, &new_size);
|
||||
ustring new_dex(p_dex, new_size);
|
||||
allocator.Free(p_dex);
|
||||
return new_dex;
|
||||
auto *p_dex = writer.CreateImage(&allocator, &new_size); // allocates memory only once
|
||||
return allocator.GetFd(p_dex);
|
||||
}
|
||||
|
||||
ScopedLocalRef<jobject> new_sharedmem(JNIEnv* env, jint size) {
|
||||
auto clazz = JNI_FindClass(env, "android/os/SharedMemory");
|
||||
auto mid = JNI_GetStaticMethodID(env, clazz, "create", "(Ljava/lang/String;I)Landroid/os/SharedMemory;");
|
||||
auto empty_str = JNI_NewStringUTF(env, "");
|
||||
auto new_mem = JNI_CallStaticObjectMethod(env, clazz, mid, empty_str, static_cast<jint>(size));
|
||||
return new_mem;
|
||||
}
|
||||
|
||||
static jobject lspdDex = nullptr;
|
||||
static std::mutex dex_lock;
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_org_lsposed_lspd_service_ObfuscationManager_preloadDex(JNIEnv *env, jclass ) {
|
||||
Java_org_lsposed_lspd_service_ObfuscationManager_preloadDex(JNIEnv *, jclass ) {
|
||||
using namespace std::string_literals;
|
||||
std::lock_guard lg(dex_lock);
|
||||
if (lspdDex) return ASharedMemory_dupFromJava(env, lspdDex);
|
||||
if (lspdDex != -1) return 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};
|
||||
|
|
@ -147,25 +134,16 @@ Java_org_lsposed_lspd_service_ObfuscationManager_preloadDex(JNIEnv *env, jclass
|
|||
}
|
||||
|
||||
auto new_dex = 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 = JNI_NewGlobalRef(env, 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);
|
||||
if (new_addr == MAP_FAILED) {
|
||||
LOGE("Failed to map new dex to memory?");
|
||||
}
|
||||
memmove(new_addr, new_dex.data(), new_dex.size());
|
||||
|
||||
return new_fd;
|
||||
LOGD("LSPApplicationService::preloadDex: %d, size=%zu", new_dex, ASharedMemory_getSize(new_dex));
|
||||
lspdDex = new_dex;
|
||||
return new_dex;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_org_lsposed_lspd_service_ObfuscationManager_getPreloadedDexSize(JNIEnv *env, jclass ) {
|
||||
if (lspdDex) {
|
||||
auto fd = ASharedMemory_dupFromJava(env, lspdDex);
|
||||
return ASharedMemory_getSize(fd);
|
||||
Java_org_lsposed_lspd_service_ObfuscationManager_getPreloadedDexSize(JNIEnv *, jclass ) {
|
||||
if (lspdDex != -1) {
|
||||
return ASharedMemory_getSize(lspdDex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -176,23 +154,19 @@ Java_org_lsposed_lspd_service_ObfuscationManager_obfuscateDex(JNIEnv *env, jclas
|
|||
jobject memory) {
|
||||
int fd = ASharedMemory_dupFromJava(env, memory);
|
||||
auto size = ASharedMemory_getSize(fd);
|
||||
ustring mem_wrapper;
|
||||
mem_wrapper.resize(size);
|
||||
read(fd, mem_wrapper.data(), size);
|
||||
LOGD("fd=%d, size=%zu", fd, size);
|
||||
|
||||
void *mem = mem_wrapper.data();
|
||||
|
||||
auto new_dex = obfuscateDex(mem, size);
|
||||
|
||||
// create new SharedMem since it cannot be resized
|
||||
auto new_mem = new_sharedmem(env, new_dex.size());
|
||||
int new_fd = ASharedMemory_dupFromJava(env, new_mem.get());
|
||||
|
||||
mem = mmap(nullptr, new_dex.size(), PROT_READ | PROT_WRITE, MAP_SHARED, new_fd, 0);
|
||||
const void* mem = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (mem == MAP_FAILED) {
|
||||
LOGE("Failed to map new dex to memory?");
|
||||
LOGE("old dex map failed?");
|
||||
return nullptr;
|
||||
}
|
||||
memcpy(mem, new_dex.data(), new_dex.size());
|
||||
ASharedMemory_setProt(fd, PROT_READ);
|
||||
return new_mem.release();
|
||||
|
||||
auto new_fd = obfuscateDex(mem, size);
|
||||
|
||||
// construct new shared mem with fd
|
||||
auto java_fd = JNI_NewObject(env, class_file_descriptor, method_file_descriptor_ctor, new_fd);
|
||||
auto java_sm = JNI_NewObject(env, class_shared_memory, method_shared_memory_ctor, java_fd);
|
||||
|
||||
return java_sm.release();
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright (C) 2022 LSPosed Contributors
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include "jni_helper.h"
|
||||
|
||||
static std::string obfuscated_signature;
|
||||
static const std::string old_signature = "Lde/robv/android/xposed";
|
||||
static int lspdDex = -1;
|
||||
static std::mutex dex_lock;
|
||||
|
||||
static jclass class_file_descriptor;
|
||||
static jmethodID method_file_descriptor_ctor;
|
||||
|
||||
static jclass class_shared_memory;
|
||||
static jmethodID method_shared_memory_ctor;
|
||||
|
||||
class WA: public dex::Writer::Allocator {
|
||||
// addr: {size, fd}
|
||||
std::unordered_map<void*, std::pair<size_t, int>> allocated_;
|
||||
public:
|
||||
inline void* Allocate(size_t size) override {
|
||||
auto fd = ASharedMemory_create("", size);
|
||||
auto *mem = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
allocated_[mem] = {size, fd};
|
||||
return mem;
|
||||
}
|
||||
inline void Free(void* ptr) override {
|
||||
auto alloc_data = allocated_.at(ptr);
|
||||
close(alloc_data.second);
|
||||
allocated_.erase(ptr);
|
||||
}
|
||||
inline int GetFd(void* ptr) {
|
||||
auto alloc_data = allocated_.find(ptr);
|
||||
if (alloc_data == allocated_.end()) return -1;
|
||||
return (*alloc_data).second.second;
|
||||
}
|
||||
};
|
||||
|
|
@ -1,3 +1,22 @@
|
|||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright (C) 2021 - 2022 LSPosed Contributors
|
||||
*/
|
||||
|
||||
package org.lsposed.lspd.service;
|
||||
|
||||
import static org.lsposed.lspd.service.ServiceManager.TAG;
|
||||
|
|
@ -296,9 +315,10 @@ public class ConfigFileManager {
|
|||
var byteBuffer = memory.mapReadWrite();
|
||||
Channels.newChannel(in).read(byteBuffer);
|
||||
SharedMemory.unmap(byteBuffer);
|
||||
memory = ObfuscationManager.obfuscateDex(memory);
|
||||
memory.setProtect(OsConstants.PROT_READ);
|
||||
preLoadedDexes.add(memory);
|
||||
var new_memory = ObfuscationManager.obfuscateDex(memory);
|
||||
memory.close();
|
||||
new_memory.setProtect(OsConstants.PROT_READ);
|
||||
preLoadedDexes.add(new_memory);
|
||||
} catch (IOException | ErrnoException e) {
|
||||
Log.w(TAG, "Can not load " + dexFile + " in " + apkFile, e);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ package org.lsposed.lspd.service;
|
|||
import android.os.SharedMemory;
|
||||
|
||||
public class ObfuscationManager {
|
||||
static native void init();
|
||||
|
||||
// For module dexes
|
||||
static native SharedMemory obfuscateDex(SharedMemory memory);
|
||||
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ public class ServiceManager {
|
|||
logcatService.start();
|
||||
|
||||
Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
|
||||
ObfuscationManager.init();
|
||||
ObfuscationManager.getObfuscatedSignature();
|
||||
ObfuscationManager.preloadDex();
|
||||
Looper.prepareMainLooper();
|
||||
|
|
|
|||
Loading…
Reference in New Issue