diff --git a/manager/proguard-rules.pro b/manager/proguard-rules.pro index 41a0a0d..af7b132 100644 --- a/manager/proguard-rules.pro +++ b/manager/proguard-rules.pro @@ -16,6 +16,7 @@ -keep class com.beust.jcommander.** { *; } -keep class org.lsposed.npatch.database.** { *; } +-keep class org.lsposed.npatch.manager.ConfigProvider { *; } -keep class org.lsposed.npatch.Patcher$Options { *; } -keep class org.lsposed.npatch.share.LSPConfig { *; } -keep class org.lsposed.npatch.share.PatchConfig { *; } diff --git a/manager/src/main/AndroidManifest.xml b/manager/src/main/AndroidManifest.xml index 7b5eb1a..888fefc 100644 --- a/manager/src/main/AndroidManifest.xml +++ b/manager/src/main/AndroidManifest.xml @@ -89,5 +89,12 @@ android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> + + + \ No newline at end of file diff --git a/manager/src/main/java/org/lsposed/npatch/manager/ConfigProvider.kt b/manager/src/main/java/org/lsposed/npatch/manager/ConfigProvider.kt new file mode 100644 index 0000000..3b9a232 --- /dev/null +++ b/manager/src/main/java/org/lsposed/npatch/manager/ConfigProvider.kt @@ -0,0 +1,51 @@ +package org.lsposed.npatch.manager + +import android.content.ContentProvider +import android.content.ContentValues +import android.database.Cursor +import android.database.MatrixCursor +import android.net.Uri +import android.util.Log +import kotlinx.coroutines.runBlocking +import org.lsposed.npatch.config.ConfigManager + +class ConfigProvider : ContentProvider() { + + companion object { + const val AUTHORITY = "org.lsposed.npatch.manager.provider.config" + const val TAG = "ConfigProvider" + } + + override fun onCreate(): Boolean = true + + override fun query( + uri: Uri, + projection: Array?, + selection: String?, + selectionArgs: Array?, + sortOrder: String? + ): Cursor? { + val targetPackage = uri.getQueryParameter("package") + if (targetPackage.isNullOrEmpty()) return null + + val modulesList = runBlocking { + try { + // 修正:直接使用 ConfigManager 來獲取該 APP 啟用的模組列表 + ConfigManager.getModulesForApp(targetPackage).map { it.pkgName } + } catch (e: Exception) { + Log.e(TAG, "Database query failed", e) + emptyList() + } + } + + // 返回 Cursor 給被修補的 APP + val cursor = MatrixCursor(arrayOf("packageName")) + modulesList.forEach { cursor.addRow(arrayOf(it)) } + return cursor + } + + override fun getType(uri: Uri): String? = null + override fun insert(uri: Uri, values: ContentValues?): Uri? = null + override fun delete(uri: Uri, selection: String?, selectionArgs: Array?): Int = 0 + override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array?): Int = 0 +} diff --git a/patch-loader/src/main/java/org/lsposed/npatch/service/NeoLocalApplicationService.java b/patch-loader/src/main/java/org/lsposed/npatch/service/NeoLocalApplicationService.java index 0cf2ef5..924dfe8 100644 --- a/patch-loader/src/main/java/org/lsposed/npatch/service/NeoLocalApplicationService.java +++ b/patch-loader/src/main/java/org/lsposed/npatch/service/NeoLocalApplicationService.java @@ -1,12 +1,15 @@ package org.lsposed.npatch.service; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.net.Uri; import android.os.IBinder; -import android.os.RemoteException; import android.os.ParcelFileDescriptor; +import android.os.RemoteException; import android.util.Log; -import org.json.JSONArray; import org.lsposed.npatch.util.ModuleLoader; import org.lsposed.lspd.models.Module; import org.lsposed.lspd.service.ILSPApplicationService; @@ -18,64 +21,55 @@ import java.util.List; public class NeoLocalApplicationService extends ILSPApplicationService.Stub { private static final String TAG = "NPatch"; + private static final String AUTHORITY = "org.lsposed.npatch.manager.provider.config"; + private static final Uri PROVIDER_URI = Uri.parse("content://" + AUTHORITY + "/config"); + private final List cachedModule; public NeoLocalApplicationService(Context context) { cachedModule = Collections.synchronizedList(new ArrayList<>()); - loadModulesFromSharedPreferences(context); + loadModulesFromProvider(context); } - private void loadModulesFromSharedPreferences(Context context) { - var shared = context.getSharedPreferences("npatch", Context.MODE_PRIVATE); + private void loadModulesFromProvider(Context context) { + PackageManager pm = context.getPackageManager(); + String myPackageName = context.getPackageName(); + + Uri queryUri = PROVIDER_URI.buildUpon() + .appendQueryParameter("package", myPackageName) + .build(); + + try (Cursor cursor = context.getContentResolver().query(queryUri, null, null, null, null)) { + if (cursor == null) { + Log.w(TAG, "NeoLocal: Cannot reach Manager Provider."); + return; + } + + while (cursor.moveToNext()) { + int colIndex = cursor.getColumnIndex("packageName"); + if (colIndex != -1) { + loadSingleModule(pm, cursor.getString(colIndex)); + } + } + } catch (Exception e) { + Log.e(TAG, "NeoLocal: Provider query failed", e); + } + } + + private void loadSingleModule(PackageManager pm, String pkgName) { try { - var modulesJsonString = shared.getString("modules", "[]"); - Log.i(TAG, "Loading modules from local SharedPreferences..."); + ApplicationInfo appInfo = pm.getApplicationInfo(pkgName, 0); + Module m = new Module(); + m.packageName = pkgName; + m.apkPath = appInfo.sourceDir; - if (modulesJsonString.equals("{}")) { - modulesJsonString = "[]"; - } - - var mArr = new JSONArray(modulesJsonString); - if (mArr.length() > 0) { - Log.i(TAG, "Found " + mArr.length() + " modules."); - } - - for (int i = 0; i < mArr.length(); i++) { - var mObj = mArr.getJSONObject(i); - var m = new Module(); - - m.packageName = mObj.optString("packageName", null); - var apkPath = mObj.optString("path", null); - - if (m.packageName == null) { - Log.w(TAG, "Module at index " + i + " has no package name, skipping."); - continue; - } - - // 如果路徑為 null 或文件不存在,嘗試從 PackageManager 恢復 - if (apkPath == null || !new File(apkPath).exists()) { - Log.w(TAG, "Module:" + m.packageName + " path not available, attempting reset."); - try { - var info = context.getPackageManager().getApplicationInfo(m.packageName, 0); - m.apkPath = info.sourceDir; - Log.i(TAG, "Module:" + m.packageName + " path reset to " + m.apkPath); - } catch (Exception e) { - Log.e(TAG, "Failed to get ApplicationInfo for module: " + m.packageName, e); - continue; - } - } else { - m.apkPath = apkPath; - } - - if (m.apkPath != null) { - m.file = ModuleLoader.loadModule(m.apkPath); - cachedModule.add(m); - } else { - Log.w(TAG, "Could not load module " + m.packageName + ": final path is null."); - } + if (m.apkPath != null && new File(m.apkPath).exists()) { + m.file = ModuleLoader.loadModule(m.apkPath); + cachedModule.add(m); + Log.i(TAG, "NeoLocal: Loaded module " + pkgName); } } catch (Throwable e) { - Log.e(TAG, "Error loading modules from SharedPreferences.", e); + Log.e(TAG, "NeoLocal: Failed to load " + pkgName, e); } } @@ -90,15 +84,9 @@ public class NeoLocalApplicationService extends ILSPApplicationService.Stub { } @Override - public String getPrefsPath(String packageName) throws RemoteException { - return "/data/data/" + packageName + "/shared_prefs/"; - } - + public String getPrefsPath(String packageName) throws RemoteException { return "/data/data/" + packageName + "/shared_prefs/"; } @Override - public ParcelFileDescriptor requestInjectedManagerBinder(List binder) throws RemoteException { - return null; - } - + public ParcelFileDescriptor requestInjectedManagerBinder(List binder) throws RemoteException { return null; } @Override public IBinder asBinder() { return this; diff --git a/patch-loader/src/main/jni/src/jni/bypass_svc.cpp b/patch-loader/src/main/jni/src/jni/bypass_svc.cpp index f159093..731f471 100644 --- a/patch-loader/src/main/jni/src/jni/bypass_svc.cpp +++ b/patch-loader/src/main/jni/src/jni/bypass_svc.cpp @@ -21,6 +21,11 @@ namespace lspd { // --- 共用結構與變數 --- + // 將此變數移出 #if 區塊,確保 IDE 和編譯器在任何架構下都能識別,避免未定義錯誤。 + static bool g_is_hook_active = false; + +#if defined(__aarch64__) + struct SyscallRequest { long sys_no; long args[6]; @@ -31,7 +36,6 @@ namespace lspd { }; static pthread_t g_trusted_thread; - static bool g_is_hook_active = false; static std::queue g_request_queue; static std::mutex g_queue_mtx; static std::condition_variable g_queue_cv; @@ -53,8 +57,8 @@ namespace lspd { if (req) { // 執行真正的 syscall req->result = syscall(req->sys_no, - req->args[0], req->args[1], req->args[2], - req->args[3], req->args[4], req->args[5]); + req->args[0], req->args[1], req->args[2], + req->args[3], req->args[4], req->args[5]); { std::lock_guard lock(req->mtx); @@ -74,7 +78,6 @@ namespace lspd { SyscallRequest req; // ARM64: 從 regs 讀取 (x8=sys_no, x0-x5=args) - // 直接存取 ARM64 特有的 regs 結構 req.sys_no = ctx->uc_mcontext.regs[8]; for (int i = 0; i < 6; ++i) { req.args[i] = ctx->uc_mcontext.regs[i]; @@ -98,12 +101,17 @@ namespace lspd { ctx->uc_mcontext.regs[0] = req.result; } - // --- JNI 接口層 --- +#endif // 結束 __aarch64__ 專用區塊 + + + // ------------------------------------------------------------------------- + // JNI 接口層 (處理架構差異) + // ------------------------------------------------------------------------- LSP_DEF_NATIVE_METHOD(jboolean, SvcBypass, initSvcHook) { - // 如果已經激活,直接返回成功 if (g_is_hook_active) return JNI_TRUE; +#if defined(__aarch64__) int ret = pthread_create(&g_trusted_thread, nullptr, trusted_thread_loop, nullptr); if (ret != 0) { LOGE("SvcBypass: Failed to create trusted thread"); @@ -122,16 +130,22 @@ namespace lspd { g_is_hook_active = true; LOGI("SvcBypass: Initialized successfully (ARM64)"); return JNI_TRUE; +#else + // x86/x86_64: 僅標記為激活,但不做實際 Hook + g_is_hook_active = true; + LOGI("SvcBypass: Skipped on non-ARM64 architecture"); + return JNI_TRUE; +#endif } LSP_DEF_NATIVE_METHOD(void, SvcBypass, enableSvcRedirect, - jstring path, jstring orig, jstring pkg) { + jstring path, jstring orig, jstring pkg) { if (!g_is_hook_active) { LOGW("SvcBypass: Hook not initialized."); return; } - // ARM64 BPF 規則 +#if defined(__aarch64__) struct sock_filter filter[] = { BPF_STMT(BPF_LD + BPF_W + BPF_ABS, (offsetof(struct seccomp_data, nr))), BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __NR_openat, 0, 1), @@ -154,6 +168,7 @@ namespace lspd { } else { LOGI("SvcBypass: Seccomp filter applied (ARM64)"); } +#endif } LSP_DEF_NATIVE_METHOD(void, SvcBypass, disableSvcRedirect) { @@ -165,7 +180,11 @@ namespace lspd { } LSP_DEF_NATIVE_METHOD(jstring, SvcBypass, getDebugInfo) { +#if defined(__aarch64__) return env->NewStringUTF("SvcBypass: Active (ARM64)"); +#else + return env->NewStringUTF("SvcBypass: Stub (Non-ARM64)"); +#endif } LSP_DEF_NATIVE_METHOD(jint, SvcBypass, getCurrentPid) {