From a2b9e529caf52200c0e9d6c7886a683bd055e1bc Mon Sep 17 00:00:00 2001 From: NkBe Date: Wed, 8 Oct 2025 14:16:03 +0800 Subject: [PATCH] feat: support inject MT Manager DocumentsProvider Co-Authored-By: Hicores --- jar/src/main/assets/provider.dex | Bin 0 -> 9640 bytes manager/src/main/AndroidManifest.xml | 8 ++++ manager/src/main/assets/provider.dex | Bin 0 -> 9640 bytes .../main/java/org/lsposed/lspatch/Patcher.kt | 1 + .../lsposed/lspatch/ui/page/NewPatchScreen.kt | 3 +- .../lspatch/ui/viewmodel/NewPatchViewModel.kt | 7 ++-- .../src/main/res/values-zh-rCN/strings.xml | 2 + .../src/main/res/values-zh-rTW/strings.xml | 2 + manager/src/main/res/values/strings.xml | 2 + .../lspatch/loader/LSPApplication.java | 35 ++++++++++++++++++ .../main/java/org/lsposed/patch/LSPatch.java | 34 +++++++++++++++-- .../org/lsposed/lspatch/share/Constants.java | 3 +- .../lsposed/lspatch/share/PatchConfig.java | 3 ++ 13 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 jar/src/main/assets/provider.dex create mode 100644 manager/src/main/assets/provider.dex diff --git a/jar/src/main/assets/provider.dex b/jar/src/main/assets/provider.dex new file mode 100644 index 0000000000000000000000000000000000000000..ebbbd1a7637af4fc8056f9ded519b429655f1c3b GIT binary patch literal 9640 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 + + + + + + + + diff --git a/manager/src/main/assets/provider.dex b/manager/src/main/assets/provider.dex new file mode 100644 index 0000000000000000000000000000000000000000..ebbbd1a7637af4fc8056f9ded519b429655f1c3b GIT binary patch literal 9640 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 Unit) { } LaunchedEffect(uninstallFirst) { - if (!uninstallFirst && installing == 0) { + if (!uninstallFirst && installing == 0) { + onFinish(LSPPackageManager.STATUS_USER_CANCELLED, "User cancelled") doInstall() } } diff --git a/manager/src/main/java/org/lsposed/lspatch/ui/viewmodel/NewPatchViewModel.kt b/manager/src/main/java/org/lsposed/lspatch/ui/viewmodel/NewPatchViewModel.kt index f0b7107..79c3947 100644 --- a/manager/src/main/java/org/lsposed/lspatch/ui/viewmodel/NewPatchViewModel.kt +++ b/manager/src/main/java/org/lsposed/lspatch/ui/viewmodel/NewPatchViewModel.kt @@ -45,6 +45,7 @@ class NewPatchViewModel : ViewModel() { var overrideVersionCode by mutableStateOf(false) var sigBypassLevel by mutableStateOf(2) var injectDex by mutableStateOf(false) + var injectProvider by mutableStateOf(false) var outputLog by mutableStateOf(true) var embeddedModules = emptyList() @@ -96,9 +97,9 @@ class NewPatchViewModel : ViewModel() { } private fun submitPatch() { - Log.d(TAG, "Submit patch") + Log.d(TAG, "Submit Patch") if (useManager) embeddedModules = emptyList() - val config = PatchConfig(useManager, debuggable, overrideVersionCode, sigBypassLevel, null, null, outputLog, newPackageName) + val config = PatchConfig(useManager, debuggable, overrideVersionCode, sigBypassLevel, null, null, injectProvider, outputLog, newPackageName) patchOptions = Patcher.Options( newPackageName = newPackageName, injectDex = injectDex, @@ -110,7 +111,7 @@ class NewPatchViewModel : ViewModel() { } private suspend fun launchPatch() { - logger.i("Launch patch") + logger.i("Launch Patch") patchState = try { Patcher.patch(logger, patchOptions) PatchState.FINISHED diff --git a/manager/src/main/res/values-zh-rCN/strings.xml b/manager/src/main/res/values-zh-rCN/strings.xml index 9d21c84..2465800 100644 --- a/manager/src/main/res/values-zh-rCN/strings.xml +++ b/manager/src/main/res/values-zh-rCN/strings.xml @@ -65,6 +65,8 @@ 将修补的 App 版本号重写为 1\n这将允许后续降级安装,并且通常来说这不会影响应用实际感知到的版本号 修补新包名 请输入新的包名 + 注入文件提供器 + 注入文件提供器以在没有 Root 权限的情况下管理 data 目录的文件 (来自 MT 管理器) 注入加载器 Dex 对那些需要孤立服务进程的应用程序,譬如说浏览器的渲染引擎,请勾选此选项以确保他们正常运行 日志输出到 Media 目录 diff --git a/manager/src/main/res/values-zh-rTW/strings.xml b/manager/src/main/res/values-zh-rTW/strings.xml index 5c7e7e9..51ab4c5 100644 --- a/manager/src/main/res/values-zh-rTW/strings.xml +++ b/manager/src/main/res/values-zh-rTW/strings.xml @@ -65,6 +65,8 @@ 將打包應用程式的版本編號改成 1\n允許以後降級安裝,一般來說,這不會影響應用程式實際感知的版本編號。 修補新套件名 請輸入新的套件名 + 注入檔案选取器 + 注入檔案选取器以在沒有 Root 權限的情況下管理 data 目錄的檔案(來自 MT 管理器) 注入載入器 Dex 對那些需要孤立服務程序的應用程式,譬如說瀏覽器的渲染引擎,請勾選此選項以確保他們正常執行 日誌輸出到 Media 目錄 diff --git a/manager/src/main/res/values/strings.xml b/manager/src/main/res/values/strings.xml index 24684df..714a4eb 100644 --- a/manager/src/main/res/values/strings.xml +++ b/manager/src/main/res/values/strings.xml @@ -67,6 +67,8 @@ Input a new package for app Override version code Override the patched app\'s version code to 1\nThis allows downgrade installation in the future, and generally this will not affect the version code actually perceived by the application + Inject Files Provider + Inject file providers to manage files in the data directory without root privileges (From MT Manager) Inject loader dex For applications with isolated services, such as the render engines of browsers, please turn on this option to ensure that they work properly. Output Log to Media Directory diff --git a/patch-loader/src/main/java/org/lsposed/lspatch/loader/LSPApplication.java b/patch-loader/src/main/java/org/lsposed/lspatch/loader/LSPApplication.java index 1dc5de8..8b9325c 100644 --- a/patch-loader/src/main/java/org/lsposed/lspatch/loader/LSPApplication.java +++ b/patch-loader/src/main/java/org/lsposed/lspatch/loader/LSPApplication.java @@ -2,6 +2,7 @@ package org.lsposed.lspatch.loader; import static org.lsposed.lspatch.share.Constants.CONFIG_ASSET_PATH; import static org.lsposed.lspatch.share.Constants.ORIGINAL_APK_ASSET_PATH; +import static org.lsposed.lspatch.share.Constants.PROVIDER_DEX_ASSET_PATH; import android.app.ActivityThread; import android.app.LoadedApk; @@ -28,6 +29,7 @@ import org.lsposed.lspd.service.ILSPApplicationService; import java.io.BufferedReader; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -150,6 +152,7 @@ public class LSPApplication { try (ZipFile sourceFile = new ZipFile(appInfo.sourceDir)) { cacheApkPath = originPath.resolve(sourceFile.getEntry(ORIGINAL_APK_ASSET_PATH).getCrc() + ".apk"); } + String sourceFileaa = appInfo.sourceDir; appInfo.sourceDir = cacheApkPath.toString(); appInfo.publicSourceDir = cacheApkPath.toString(); @@ -163,6 +166,20 @@ public class LSPApplication { Files.copy(is, cacheApkPath); } } + Path providerPath = null; + if (config.injectProvider){ + try (ZipFile sourceFile = new ZipFile(sourceFileaa)) { + + providerPath = Paths.get(appInfo.dataDir, "cache/npatch/origin/p_" + sourceFile.getEntry(ORIGINAL_APK_ASSET_PATH).getCrc()+".dex"); + Files.deleteIfExists(providerPath); + try (InputStream is = baseClassLoader.getResourceAsStream(PROVIDER_DEX_ASSET_PATH)) { + Files.copy(is, providerPath); + } + }catch (Exception e){ + Log.e(TAG, "Failed to inject provider:" + Log.getStackTraceString(e)); + } + + } cacheApkPath.toFile().setWritable(false); @@ -170,6 +187,24 @@ public class LSPApplication { mPackages.remove(appInfo.packageName); appLoadedApk = activityThread.getPackageInfoNoCheck(appInfo, compatInfo); + + if (config.injectProvider){ + ClassLoader loader = appLoadedApk.getClassLoader(); + Object dexPathList = XposedHelpers.getObjectField(loader, "pathList"); + Object dexElements = XposedHelpers.getObjectField(dexPathList, "dexElements"); + int length = Array.getLength(dexElements); + Object newElements = Array.newInstance(dexElements.getClass().getComponentType(), length + 1); + System.arraycopy(dexElements, 0, newElements, 0, length); + + DexFile dexFile = new DexFile(providerPath.toString()); + Object element = XposedHelpers.newInstance(XposedHelpers.findClass("dalvik.system.DexPathList$Element",loader), new Class[]{ + DexFile.class + },dexFile); + Array.set(newElements, length, element); + XposedHelpers.setObjectField(dexPathList, "dexElements", newElements); + } + + XposedHelpers.setObjectField(mBoundApplication, "info", appLoadedApk); var activityClientRecordClass = XposedHelpers.findClass("android.app.ActivityThread$ActivityClientRecord", ActivityThread.class.getClassLoader()); diff --git a/patch/src/main/java/org/lsposed/patch/LSPatch.java b/patch/src/main/java/org/lsposed/patch/LSPatch.java index a66f75d..a4d63aa 100644 --- a/patch/src/main/java/org/lsposed/patch/LSPatch.java +++ b/patch/src/main/java/org/lsposed/patch/LSPatch.java @@ -46,6 +46,7 @@ import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; @@ -79,6 +80,9 @@ public class LSPatch { @Parameter(names = {"-f", "--force"}, description = "Force overwrite exists output file") private boolean forceOverwrite = false; + @Parameter(names = {"-p", "--newpackage"}, description = "Patch with new package") + private String newPackageName = ""; + @Parameter(names = {"-d", "--debuggable"}, description = "Set app to be debuggable") private boolean debuggableFlag = false; @@ -88,6 +92,9 @@ public class LSPatch { @Parameter(names = {"--injectdex"}, description = "Inject directly the loder dex file into the original application package") private boolean injectDex = false; + @Parameter(names = {"--provider"}, description = "Inject Provider to manager data files") + private boolean isInjectProvider = false; + @Parameter(names = {"--outputLog"}, description = "Output Log to Media") private boolean outputLog = true; @@ -106,8 +113,7 @@ public class LSPatch { @Parameter(names = {"-m", "--embed"}, description = "Embed provided modules to apk") private List modules = new ArrayList<>(); - @Parameter(names = {"-p", "--newpackage"}, description = "Patch with new package") - private String newPackageName = ""; + private String packageName; private static final String ANDROID_MANIFEST_XML = "AndroidManifest.xml"; private static final HashSet ARCHES = new HashSet<>(Arrays.asList( @@ -247,6 +253,7 @@ public class LSPatch { throw new PatchError("Failed to parse AndroidManifest.xml"); appComponentFactory = pair.appComponentFactory; minSdkVersion = pair.minSdkVersion; + packageName = pair.packageName; logger.d("original appComponentFactory class: " + appComponentFactory); logger.d("original minSdkVersion: " + minSdkVersion); @@ -278,7 +285,7 @@ public class LSPatch { logger.i("Patching apk..."); // modify manifest - final var config = new PatchConfig(useManager, debuggableFlag, overrideVersionCode, sigbypassLevel, originalSignature, appComponentFactory, outputLog, newPackage); + final var config = new PatchConfig(useManager, debuggableFlag, overrideVersionCode, sigbypassLevel, originalSignature, appComponentFactory, isInjectProvider, outputLog, newPackage); final var configBytes = new Gson().toJson(config).getBytes(StandardCharsets.UTF_8); final var metadata = Base64.getEncoder().encodeToString(configBytes); try (var is = new ByteArrayInputStream(modifyManifestFile(manifestEntry.open(), metadata, minSdkVersion, pair.packageName, newPackage, pair.permissions, pair.use_permissions, pair.authorities))) { @@ -310,6 +317,14 @@ public class LSPatch { throw new PatchError("Error when adding dex", e); } + if (isInjectProvider){ + try (var is = getClass().getClassLoader().getResourceAsStream("assets/provider.dex")) { + dstZFile.add("assets/lspatch/provider.dex", is); + } catch (Throwable e) { + throw new PatchError("Error when adding dex", e); + } + } + if (!useManager) { logger.i("Adding loader dex..."); try (var is = getClass().getClassLoader().getResourceAsStream(LOADER_DEX_ASSET_PATH)) { @@ -464,6 +479,17 @@ public class LSPatch { // TODO: replace query_all with queries -> manager if (useManager) property.addUsesPermission("android.permission.QUERY_ALL_PACKAGES"); + if (isInjectProvider){ + HashMap providerMap = new HashMap<>(); + providerMap.put("name","bin.mt.file.content.MTDataFilesProvider"); + providerMap.put("permission","android.permission.MANAGE_DOCUMENTS"); + providerMap.put("exported","true"); + providerMap.put("authorities",packageName + ".MTDataFilesProvider"); + providerMap.put("grantUriPermissions","true"); + + property.addProvider(providerMap,"android.content.action.DOCUMENTS_PROVIDER"); + + } var os = new ByteArrayOutputStream(); (new ManifestEditor(is, os, property)).processManifest(); @@ -472,4 +498,4 @@ public class LSPatch { os.close(); return os.toByteArray(); } -} +} \ No newline at end of file diff --git a/share/java/src/main/java/org/lsposed/lspatch/share/Constants.java b/share/java/src/main/java/org/lsposed/lspatch/share/Constants.java index 9b056b8..e492d97 100644 --- a/share/java/src/main/java/org/lsposed/lspatch/share/Constants.java +++ b/share/java/src/main/java/org/lsposed/lspatch/share/Constants.java @@ -5,13 +5,14 @@ public class Constants { final static public String CONFIG_ASSET_PATH = "assets/lspatch/config.json"; final static public String LOADER_DEX_ASSET_PATH = "assets/lspatch/loader.dex"; final static public String META_LOADER_DEX_ASSET_PATH = "assets/lspatch/metaloader.dex"; + final static public String PROVIDER_DEX_ASSET_PATH = "assets/lspatch/provider.dex"; final static public String ORIGINAL_APK_ASSET_PATH = "assets/lspatch/origin.apk"; final static public String EMBEDDED_MODULES_ASSET_PATH = "assets/lspatch/modules/"; final static public String PATCH_FILE_SUFFIX = "-npatched.apk"; final static public String PROXY_APP_COMPONENT_FACTORY = "org.lsposed.lspatch.metaloader.LSPAppComponentFactoryStub"; final static public String MANAGER_PACKAGE_NAME = "org.lsposed.npatch"; - final static public int MIN_ROLLING_VERSION_CODE = 348; + final static public int MIN_ROLLING_VERSION_CODE = 335; final static public int SIGBYPASS_LV_DISABLE = 0; final static public int SIGBYPASS_LV_PM = 1; diff --git a/share/java/src/main/java/org/lsposed/lspatch/share/PatchConfig.java b/share/java/src/main/java/org/lsposed/lspatch/share/PatchConfig.java index 36816c2..7e171af 100644 --- a/share/java/src/main/java/org/lsposed/lspatch/share/PatchConfig.java +++ b/share/java/src/main/java/org/lsposed/lspatch/share/PatchConfig.java @@ -5,6 +5,7 @@ public class PatchConfig { public final boolean useManager; public final boolean debuggable; public final boolean overrideVersionCode; + public final boolean injectProvider; public final boolean outputLog; public final int sigBypassLevel; public final String originalSignature; @@ -20,6 +21,7 @@ public class PatchConfig { int sigBypassLevel, String originalSignature, String appComponentFactory, + boolean injectProvider, boolean outputLog, String newPackage ) { @@ -30,6 +32,7 @@ public class PatchConfig { this.originalSignature = originalSignature; this.appComponentFactory = appComponentFactory; this.lspConfig = LSPConfig.instance; + this.injectProvider = injectProvider; this.managerPackageName = Constants.MANAGER_PACKAGE_NAME; this.newPackage = newPackage; this.outputLog = outputLog;