Refine obfuscate (#1679)

This commit is contained in:
LoveSy 2022-02-13 02:47:59 +08:00 committed by GitHub
parent ef1439a3f3
commit 5ab4c98fc5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 79 additions and 142 deletions

View File

@ -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(...);

View File

@ -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"
@ -94,27 +78,34 @@ Java_org_lsposed_lspd_service_ObfuscationManager_getObfuscatedSignature(JNIEnv *
auto contains_keyword = [](std::string_view s) -> bool {
for (const auto &i: {
"abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class",
"continue", "const", "default", "do", "double", "else", "enum", "exports", "extends",
"final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof",
"int", "interface", "long", "module", "native", "new", "package", "private", "protected",
"public", "requires", "return", "short", "static", "strictfp", "super", "switch",
"synchronized", "this", "throw", "throws", "transient", "try", "var", "void", "volatile",
"while"}) {
"abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class",
"continue", "const", "default", "do", "double", "else", "enum", "exports", "extends",
"final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof",
"int", "interface", "long", "module", "native", "new", "package", "private", "protected",
"public", "requires", "return", "short", "static", "strictfp", "super", "switch",
"synchronized", "this", "throw", "throws", "transient", "try", "var", "void", "volatile",
"while"}) {
if (s.find(i) != std::string::npos) return true;
}
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);

View File

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

View File

@ -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) {
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);
if (obfuscate) {
var newMemory = ObfuscationManager.obfuscateDex(memory);
if (memory != newMemory) {
memory.close();
memory = newMemory;
}
}
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 in = apkFile.getInputStream(dexFile)) {
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) {
memory.close();
}
new_memory.setProtect(OsConstants.PROT_READ);
preLoadedDexes.add(new_memory);
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;

View File

@ -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,16 +273,11 @@ public class ConfigManager {
}
static ConfigManager getInstance() {
return getInstance(true);
}
static ConfigManager getInstance(boolean needCached) {
if (instance == null)
instance = new ConfigManager();
if (needCached) {
synchronized (instance.cacheHandler) {
needCached = instance.lastModuleCacheTime == 0 || instance.lastScopeCacheTime == 0;
}
boolean needCached;
synchronized (instance.cacheHandler) {
needCached = instance.lastModuleCacheTime == 0 || instance.lastScopeCacheTime == 0;
}
if (needCached) {
if (PackageService.isAlive()) {
@ -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);
}
}

View File

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

View File

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

View File

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

View File

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