Refine obfuscate (#1679)
This commit is contained in:
parent
ef1439a3f3
commit
5ab4c98fc5
|
|
@ -11,9 +11,6 @@
|
|||
public int getUserId();
|
||||
public android.os.UserHandle getUser();
|
||||
}
|
||||
-keepclasseswithmembers class org.lsposed.lspd.service.ObfuscationManager {
|
||||
static boolean enabled();
|
||||
}
|
||||
-assumenosideeffects class android.util.Log {
|
||||
public static *** v(...);
|
||||
public static *** d(...);
|
||||
|
|
|
|||
|
|
@ -35,16 +35,8 @@
|
|||
#include "slicer/writer.h"
|
||||
#include "obfuscation.h"
|
||||
|
||||
bool obfuscate_enabled(JNIEnv* env, jclass obfuscation_manager) {
|
||||
auto method_enabled = JNI_GetStaticMethodID(env, obfuscation_manager, "enabled", "()Z");
|
||||
auto result = JNI_CallStaticBooleanMethod(env, obfuscation_manager, method_enabled);
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_lsposed_lspd_service_ObfuscationManager_init(JNIEnv *env, jclass obfuscation_manager) {
|
||||
if (!obfuscate_enabled(env, obfuscation_manager)) return;
|
||||
void maybeInit(JNIEnv *env) {
|
||||
if (inited.test_and_set(std::memory_order_acq_rel)) [[likely]] return;
|
||||
LOGD("ObfuscationManager.init");
|
||||
if (auto file_descriptor = JNI_FindClass(env, "java/io/FileDescriptor")) {
|
||||
class_file_descriptor = JNI_NewGlobalRef(env, file_descriptor);
|
||||
|
|
@ -57,14 +49,6 @@ Java_org_lsposed_lspd_service_ObfuscationManager_init(JNIEnv *env, jclass obfusc
|
|||
} 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
|
||||
Java_org_lsposed_lspd_service_ObfuscationManager_getObfuscatedSignature(JNIEnv *env, jclass obfuscation_manager) {
|
||||
if (!obfuscate_enabled(env, obfuscation_manager)) return env->NewStringUTF(old_signature.c_str());
|
||||
if (!obfuscated_signature.empty()) return env->NewStringUTF(obfuscated_signature.c_str());
|
||||
|
||||
auto regen = []() {
|
||||
static auto& chrs = "abcdefghijklmnopqrstuvwxyz"
|
||||
|
|
@ -106,15 +90,22 @@ Java_org_lsposed_lspd_service_ObfuscationManager_getObfuscatedSignature(JNIEnv *
|
|||
return false;
|
||||
};
|
||||
|
||||
do {
|
||||
[[unlikely]] do {
|
||||
obfuscated_signature = regen();
|
||||
} while (contains_keyword(obfuscated_signature));
|
||||
|
||||
LOGD("ObfuscationManager.getObfuscatedSignature: %s", obfuscated_signature.c_str());
|
||||
LOGD("ObfuscationManager init successfully");
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_lsposed_lspd_service_ObfuscationManager_getObfuscatedSignature(JNIEnv *env, [[maybe_unused]] jclass obfuscation_manager) {
|
||||
maybeInit(env);
|
||||
return env->NewStringUTF(obfuscated_signature.c_str());
|
||||
}
|
||||
|
||||
int obfuscateDex(const void *dex, size_t size) {
|
||||
static int obfuscateDex(const void *dex, size_t size) {
|
||||
const char* new_sig = obfuscated_signature.c_str();
|
||||
dex::Reader reader{reinterpret_cast<const dex::u1*>(dex), size};
|
||||
|
||||
|
|
@ -136,63 +127,11 @@ int obfuscateDex(const void *dex, size_t size) {
|
|||
return allocator.GetFd(p_dex);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_org_lsposed_lspd_service_ObfuscationManager_preloadDex(JNIEnv *env, jclass obfuscation_manager) {
|
||||
using namespace std::string_literals;
|
||||
std::lock_guard lg(dex_lock);
|
||||
if (lspdDex != -1) return lspdDex;
|
||||
const std::string dex_path = "framework/lspd.dex";
|
||||
|
||||
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);
|
||||
size_t 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) {
|
||||
PLOGE("Map dex");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int new_dex;
|
||||
if (!obfuscate_enabled(env, obfuscation_manager)) {
|
||||
new_dex = ASharedMemory_create("", size);
|
||||
auto new_addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, new_dex, 0);
|
||||
memcpy(new_addr, addr, size);
|
||||
munmap(new_addr, size);
|
||||
} else {
|
||||
new_dex = obfuscateDex(addr, size);
|
||||
}
|
||||
|
||||
munmap(addr, size);
|
||||
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 *, jclass ) {
|
||||
if (lspdDex != -1) {
|
||||
return ASharedMemory_getSize(lspdDex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobject
|
||||
Java_org_lsposed_lspd_service_ObfuscationManager_obfuscateDex(JNIEnv *env, jclass obfuscation_manager,
|
||||
Java_org_lsposed_lspd_service_ObfuscationManager_obfuscateDex(JNIEnv *env, [[maybe_unused]] jclass obfuscation_manager,
|
||||
jobject memory) {
|
||||
if (!obfuscate_enabled(env, obfuscation_manager)) { return memory; }
|
||||
maybeInit(env);
|
||||
int fd = ASharedMemory_dupFromJava(env, memory);
|
||||
auto size = ASharedMemory_getSize(fd);
|
||||
LOGD("fd=%d, size=%zu", fd, size);
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@
|
|||
|
||||
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 std::atomic_flag inited;
|
||||
|
||||
static jclass class_file_descriptor;
|
||||
static jmethodID method_file_descriptor_ctor;
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ import org.lsposed.lspd.util.Utils;
|
|||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
|
@ -92,6 +93,7 @@ public class ConfigFileManager {
|
|||
private static FileLocker locker = null;
|
||||
private static Resources res = null;
|
||||
private static ParcelFileDescriptor fd = null;
|
||||
private static SharedMemory preloadDex = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
|
|
@ -306,21 +308,28 @@ public class ConfigFileManager {
|
|||
});
|
||||
}
|
||||
|
||||
private static void readDexes(ZipFile apkFile, List<SharedMemory> preLoadedDexes) {
|
||||
int secondary = 2;
|
||||
for (var dexFile = apkFile.getEntry("classes.dex"); dexFile != null;
|
||||
dexFile = apkFile.getEntry("classes" + secondary + ".dex"), secondary++) {
|
||||
try (var in = apkFile.getInputStream(dexFile)) {
|
||||
private static SharedMemory readDex(InputStream in, boolean obfuscate) throws IOException, ErrnoException {
|
||||
var memory = SharedMemory.create(null, in.available());
|
||||
var byteBuffer = memory.mapReadWrite();
|
||||
Channels.newChannel(in).read(byteBuffer);
|
||||
SharedMemory.unmap(byteBuffer);
|
||||
var new_memory = ObfuscationManager.obfuscateDex(memory);
|
||||
if (memory != new_memory) {
|
||||
if (obfuscate) {
|
||||
var newMemory = ObfuscationManager.obfuscateDex(memory);
|
||||
if (memory != newMemory) {
|
||||
memory.close();
|
||||
memory = newMemory;
|
||||
}
|
||||
new_memory.setProtect(OsConstants.PROT_READ);
|
||||
preLoadedDexes.add(new_memory);
|
||||
}
|
||||
memory.setProtect(OsConstants.PROT_READ);
|
||||
return memory;
|
||||
}
|
||||
|
||||
private static void readDexes(ZipFile apkFile, List<SharedMemory> preLoadedDexes, boolean obfuscate) {
|
||||
int secondary = 2;
|
||||
for (var dexFile = apkFile.getEntry("classes.dex"); dexFile != null;
|
||||
dexFile = apkFile.getEntry("classes" + secondary + ".dex"), secondary++) {
|
||||
try (var is = apkFile.getInputStream(dexFile)) {
|
||||
preLoadedDexes.add(readDex(is, obfuscate));
|
||||
} catch (IOException | ErrnoException e) {
|
||||
Log.w(TAG, "Can not load " + dexFile + " in " + apkFile, e);
|
||||
}
|
||||
|
|
@ -344,14 +353,14 @@ public class ConfigFileManager {
|
|||
}
|
||||
|
||||
@Nullable
|
||||
static PreLoadedApk loadModule(String path) {
|
||||
static PreLoadedApk loadModule(String path, boolean obfuscate) {
|
||||
if (path == null) return null;
|
||||
var file = new PreLoadedApk();
|
||||
var preLoadedDexes = new ArrayList<SharedMemory>();
|
||||
var moduleClassNames = new ArrayList<String>(1);
|
||||
var moduleLibraryNames = new ArrayList<String>(1);
|
||||
try (var apkFile = new ZipFile(toGlobalNamespace(path))) {
|
||||
readDexes(apkFile, preLoadedDexes);
|
||||
readDexes(apkFile, preLoadedDexes, obfuscate);
|
||||
readName(apkFile, "assets/xposed_init", moduleClassNames);
|
||||
readName(apkFile, "assets/native_init", moduleLibraryNames);
|
||||
} catch (IOException e) {
|
||||
|
|
@ -382,6 +391,17 @@ public class ConfigFileManager {
|
|||
}
|
||||
}
|
||||
|
||||
synchronized static SharedMemory getPreloadDex(boolean obfuscate) {
|
||||
if (preloadDex == null) {
|
||||
try (var is = new FileInputStream("framework/lspd.dex")) {
|
||||
preloadDex = readDex(is, obfuscate);
|
||||
} catch (Throwable e) {
|
||||
Log.e(TAG, "preload dex", e);
|
||||
}
|
||||
}
|
||||
return preloadDex;
|
||||
}
|
||||
|
||||
private static class FileLocker {
|
||||
private final FileChannel lockChannel;
|
||||
private final FileLock locker;
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ public class ConfigManager {
|
|||
var packageName = cursor.getString(pkgNameIdx);
|
||||
var m = cachedModule.computeIfAbsent(packageName, p -> {
|
||||
var module = new Module();
|
||||
var file = ConfigFileManager.loadModule(path);
|
||||
var file = ConfigFileManager.loadModule(path, dexObfuscate);
|
||||
if (file == null) {
|
||||
Log.w(TAG, "Can not load " + path + ", skip!");
|
||||
return null;
|
||||
|
|
@ -250,6 +250,8 @@ public class ConfigManager {
|
|||
}
|
||||
|
||||
updateManager(false);
|
||||
|
||||
cacheHandler.post(this::getPreloadDex);
|
||||
}
|
||||
|
||||
public synchronized void updateManager(boolean uninstalled) {
|
||||
|
|
@ -271,17 +273,12 @@ public class ConfigManager {
|
|||
}
|
||||
|
||||
static ConfigManager getInstance() {
|
||||
return getInstance(true);
|
||||
}
|
||||
|
||||
static ConfigManager getInstance(boolean needCached) {
|
||||
if (instance == null)
|
||||
instance = new ConfigManager();
|
||||
if (needCached) {
|
||||
boolean needCached;
|
||||
synchronized (instance.cacheHandler) {
|
||||
needCached = instance.lastModuleCacheTime == 0 || instance.lastScopeCacheTime == 0;
|
||||
}
|
||||
}
|
||||
if (needCached) {
|
||||
if (PackageService.isAlive()) {
|
||||
Log.d(TAG, "pm is ready, updating cache");
|
||||
|
|
@ -501,7 +498,7 @@ public class ConfigManager {
|
|||
apkPath = getModuleApkPath(pkgInfo.applicationInfo);
|
||||
if (apkPath == null) obsoleteModules.add(packageName);
|
||||
else obsoletePaths.put(packageName, apkPath);
|
||||
var file = ConfigFileManager.loadModule(apkPath);
|
||||
var file = ConfigFileManager.loadModule(apkPath, dexObfuscate);
|
||||
if (file == null) {
|
||||
Log.w(TAG, "failed to load module " + packageName);
|
||||
obsoleteModules.add(packageName);
|
||||
|
|
@ -882,11 +879,13 @@ public class ConfigManager {
|
|||
|
||||
public void setDexObfuscate(boolean on) {
|
||||
updateModulePrefs("lspd", 0, "config", "enable_dex_obfuscate", on);
|
||||
dexObfuscate = on;
|
||||
}
|
||||
|
||||
public boolean dexObfuscate() {
|
||||
return dexObfuscate;
|
||||
// this is for manager and should not use the cache result
|
||||
boolean dexObfuscate() {
|
||||
Map<String, Object> config = getModulePrefs("lspd", 0, "config");
|
||||
Object bool = config.get("enable_dex_obfuscate");
|
||||
return bool != null && (boolean) bool;
|
||||
}
|
||||
|
||||
public boolean isAddShortcut() {
|
||||
|
|
@ -1057,4 +1056,8 @@ public class ConfigManager {
|
|||
});
|
||||
os.closeEntry();
|
||||
}
|
||||
|
||||
synchronized SharedMemory getPreloadDex() {
|
||||
return ConfigFileManager.getPreloadDex(dexObfuscate);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,13 +26,11 @@ 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;
|
||||
|
|
@ -47,18 +45,13 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
|
|||
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 {
|
||||
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
|
||||
Log.d(TAG, "LSPApplicationService.onTransact: code=" + code);
|
||||
if (code == DEX_TRANSACTION_CODE) {
|
||||
try {
|
||||
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromFd(ObfuscationManager.preloadDex());
|
||||
reply.writeFileDescriptor(pfd.getFileDescriptor());
|
||||
reply.writeLong(ObfuscationManager.getPreloadedDexSize());
|
||||
pfd.close();
|
||||
} catch (IOException ignored) {
|
||||
Log.e(TAG, "LSPApplicationService.onTransact: ParcelFileDescriptor.fromFd failed");
|
||||
return false;
|
||||
}
|
||||
var shm = ConfigManager.getInstance().getPreloadDex();
|
||||
// assume that write only a fd
|
||||
shm.writeToParcel(reply, 0);
|
||||
reply.writeLong(shm.getSize());
|
||||
return true;
|
||||
}
|
||||
return super.onTransact(code, data, reply, flags);
|
||||
|
|
|
|||
|
|
@ -771,12 +771,12 @@ public class LSPManagerService extends ILSPManagerService.Stub {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean getDexObfuscate() throws RemoteException {
|
||||
public boolean getDexObfuscate() {
|
||||
return ConfigManager.getInstance().dexObfuscate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDexObfuscate(boolean enabled) throws RemoteException {
|
||||
public void setDexObfuscate(boolean enabled) {
|
||||
ConfigManager.getInstance().setDexObfuscate(enabled);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,21 +3,9 @@ package org.lsposed.lspd.service;
|
|||
import android.os.SharedMemory;
|
||||
|
||||
public class ObfuscationManager {
|
||||
static boolean enabled() {
|
||||
return ConfigManager.getInstance(false).dexObfuscate();
|
||||
}
|
||||
|
||||
static native void init();
|
||||
|
||||
// For module dexes
|
||||
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();
|
||||
|
||||
// generates signature
|
||||
static native String getObfuscatedSignature();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,9 +98,6 @@ public class ServiceManager {
|
|||
logcatService.start();
|
||||
|
||||
Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
|
||||
ObfuscationManager.init();
|
||||
ObfuscationManager.getObfuscatedSignature();
|
||||
ObfuscationManager.preloadDex();
|
||||
Looper.prepareMainLooper();
|
||||
mainService = new LSPosedService();
|
||||
applicationService = new LSPApplicationService();
|
||||
|
|
|
|||
Loading…
Reference in New Issue