Allow uers to chose if inject loader dex (#19)

If we always inject loader dex, then modules with third party libraries might fail to find library classes since the default class loader is alway used before the the loader of the module package.

Therefore, it is better to treat packages with isolated services as special cases.
This commit is contained in:
xihan123 2024-11-21 02:38:48 +08:00 committed by GitHub
parent 7c153f6491
commit b83152323a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 38 additions and 10 deletions

2
core

@ -1 +1 @@
Subproject commit 1db3217d2e7b0986b0ad1f0e7581601c759a39c0 Subproject commit 6575c443f09693244a72e5cd5dcf41f6cba0f9a2

View File

@ -11,10 +11,12 @@ import org.lsposed.lspatch.share.PatchConfig
import org.lsposed.patch.LSPatch import org.lsposed.patch.LSPatch
import org.lsposed.patch.util.Logger import org.lsposed.patch.util.Logger
import java.io.IOException import java.io.IOException
import java.util.Collections.addAll
object Patcher { object Patcher {
class Options( class Options(
private val injectDex: Boolean,
private val config: PatchConfig, private val config: PatchConfig,
private val apkPaths: List<String>, private val apkPaths: List<String>,
private val embeddedModules: List<String>? private val embeddedModules: List<String>?
@ -31,6 +33,7 @@ object Patcher {
embeddedModules?.forEach { embeddedModules?.forEach {
add("-m"); add(it) add("-m"); add(it)
} }
if(injectDex) add("--injectdex")
if (!MyKeyStore.useDefault) { if (!MyKeyStore.useDefault) {
addAll(arrayOf("-k", MyKeyStore.file.path, Configs.keyStorePassword, Configs.keyStoreAlias, Configs.keyStoreAliasPassword)) addAll(arrayOf("-k", MyKeyStore.file.path, Configs.keyStorePassword, Configs.keyStoreAlias, Configs.keyStoreAliasPassword))
} }

View File

@ -337,6 +337,15 @@ private fun PatchOptionsBody(modifier: Modifier, onAddEmbed: () -> Unit) {
title = stringResource(R.string.patch_override_version_code), title = stringResource(R.string.patch_override_version_code),
desc = stringResource(R.string.patch_override_version_code_desc) desc = stringResource(R.string.patch_override_version_code_desc)
) )
SettingsCheckBox(
modifier = Modifier.clickable { viewModel.injectDex = !viewModel.injectDex },
checked = viewModel.injectDex,
icon = Icons.Outlined.Code,
title = stringResource(R.string.patch_inject_dex),
desc = stringResource(R.string.patch_inject_dex_desc)
)
var bypassExpanded by remember { mutableStateOf(false) } var bypassExpanded by remember { mutableStateOf(false) }
AnywhereDropdown( AnywhereDropdown(
expanded = bypassExpanded, expanded = bypassExpanded,

View File

@ -38,6 +38,7 @@ class NewPatchViewModel : ViewModel() {
var debuggable by mutableStateOf(false) var debuggable by mutableStateOf(false)
var overrideVersionCode by mutableStateOf(false) var overrideVersionCode by mutableStateOf(false)
var sigBypassLevel by mutableStateOf(2) var sigBypassLevel by mutableStateOf(2)
var injectDex by mutableStateOf(false)
var embeddedModules = emptyList<AppInfo>() var embeddedModules = emptyList<AppInfo>()
lateinit var patchApp: AppInfo lateinit var patchApp: AppInfo
@ -90,6 +91,7 @@ class NewPatchViewModel : ViewModel() {
Log.d(TAG, "Submit patch") Log.d(TAG, "Submit patch")
if (useManager) embeddedModules = emptyList() if (useManager) embeddedModules = emptyList()
patchOptions = Patcher.Options( patchOptions = Patcher.Options(
injectDex = injectDex,
config = PatchConfig(useManager, debuggable, overrideVersionCode, sigBypassLevel, null, null), config = PatchConfig(useManager, debuggable, overrideVersionCode, sigBypassLevel, null, null),
apkPaths = listOf(patchApp.app.sourceDir) + (patchApp.app.splitSourceDirs ?: emptyArray()), apkPaths = listOf(patchApp.app.sourceDir) + (patchApp.app.splitSourceDirs ?: emptyArray()),
embeddedModules = embeddedModules.flatMap { listOf(it.app.sourceDir) + (it.app.splitSourceDirs ?: emptyArray()) } embeddedModules = embeddedModules.flatMap { listOf(it.app.sourceDir) + (it.app.splitSourceDirs ?: emptyArray()) }

View File

@ -117,7 +117,7 @@ class AppManageViewModel : ViewModel() {
} }
} }
} }
Patcher.patch(logger, Patcher.Options(config, patchPaths, embeddedModulePaths)) Patcher.patch(logger, Patcher.Options(false, config, patchPaths, embeddedModulePaths))
val (status, message) = LSPPackageManager.install() val (status, message) = LSPPackageManager.install()
if (status != PackageInstaller.STATUS_SUCCESS) throw RuntimeException(message) if (status != PackageInstaller.STATUS_SUCCESS) throw RuntimeException(message)
} }

View File

@ -86,4 +86,6 @@
<string name="settings_keystore_wrong_alias">别名错误</string> <string name="settings_keystore_wrong_alias">别名错误</string>
<string name="settings_keystore_wrong_alias_password">别名密码错误</string> <string name="settings_keystore_wrong_alias_password">别名密码错误</string>
<string name="settings_detail_patch_logs">详细修补日志</string> <string name="settings_detail_patch_logs">详细修补日志</string>
<string name="patch_inject_dex">注入加载器 Dex</string>
<string name="patch_inject_dex_desc">对那些需要孤立服务进程的应用程序,譬如说浏览器的渲染引擎,请勾选此选项以确保他们正常运行</string>
</resources> </resources>

View File

@ -86,4 +86,6 @@
<string name="settings_keystore_wrong_alias">別名錯誤</string> <string name="settings_keystore_wrong_alias">別名錯誤</string>
<string name="settings_keystore_wrong_alias_password">別名密碼錯誤</string> <string name="settings_keystore_wrong_alias_password">別名密碼錯誤</string>
<string name="settings_detail_patch_logs">詳細打包日誌</string> <string name="settings_detail_patch_logs">詳細打包日誌</string>
<string name="patch_inject_dex">注入加載器 Dex</string>
<string name="patch_inject_dex_desc">對那些需要孤立服務進程的應用程序,譬如說瀏覽器的渲染引擎,請勾選此選項以確保他們正常運行</string>
</resources> </resources>

View File

@ -90,4 +90,6 @@
<string name="settings_keystore_wrong_alias">Wrong alias name</string> <string name="settings_keystore_wrong_alias">Wrong alias name</string>
<string name="settings_keystore_wrong_alias_password">Wrong alias password</string> <string name="settings_keystore_wrong_alias_password">Wrong alias password</string>
<string name="settings_detail_patch_logs">Detail patch logs</string> <string name="settings_detail_patch_logs">Detail patch logs</string>
<string name="patch_inject_dex">Inject loader dex</string>
<string name="patch_inject_dex_desc">For applications with isolated services, such as the render engines of browsers, please turn on this option to ensure that they work properly.</string>
</resources> </resources>

View File

@ -46,7 +46,6 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class LSPatch { public class LSPatch {
@ -79,6 +78,9 @@ public class LSPatch {
@Parameter(names = {"-l", "--sigbypasslv"}, description = "Signature bypass level. 0 (disable), 1 (pm), 2 (pm+openat). default 0") @Parameter(names = {"-l", "--sigbypasslv"}, description = "Signature bypass level. 0 (disable), 1 (pm), 2 (pm+openat). default 0")
private int sigbypassLevel = 0; private int sigbypassLevel = 0;
@Parameter(names = {"--injectdex"}, description = "Inject directly the loder dex file into the original application package")
private boolean injectDex = false;
@Parameter(names = {"-k", "--keystore"}, arity = 4, description = "Set custom signature keystore. Followed by 4 arguments: keystore path, keystore password, keystore alias, keystore alias password") @Parameter(names = {"-k", "--keystore"}, arity = 4, description = "Set custom signature keystore. Followed by 4 arguments: keystore path, keystore password, keystore alias, keystore alias password")
private List<String> keystoreArgs = Arrays.asList(null, "123456", "key0", "123456"); private List<String> keystoreArgs = Arrays.asList(null, "123456", "key0", "123456");
@ -208,7 +210,7 @@ public class LSPatch {
String originalSignature = null; String originalSignature = null;
if (sigbypassLevel > 0) { if (sigbypassLevel > 0) {
originalSignature = ApkSignatureHelper.getApkSignInfo(srcApkFile.getAbsolutePath()); originalSignature = ApkSignatureHelper.getApkSignInfo(srcApkFile.getAbsolutePath());
if (originalSignature == null || originalSignature.isEmpty()) { if (originalSignature == null || originalSignature.isEmpty()) {
throw new PatchError("get original signature failed"); throw new PatchError("get original signature failed");
} }
@ -239,7 +241,8 @@ public class LSPatch {
for (StoredEntry entry : srcZFile.entries()) { for (StoredEntry entry : srcZFile.entries()) {
String name = entry.getCentralDirectoryHeader().getName(); String name = entry.getCentralDirectoryHeader().getName();
if (dstZFile.get(name) != null) continue; if (dstZFile.get(name) != null) continue;
if (name.startsWith("META-INF") && (name.endsWith(".SF") || name.endsWith(".MF") || name.endsWith(".RSA"))) continue; if (name.startsWith("META-INF") && (name.endsWith(".SF") || name.endsWith(".MF") || name.endsWith(".RSA")))
continue;
srcZFile.addFileLink(name, name); srcZFile.addFileLink(name, name);
} }
return; return;
@ -266,11 +269,15 @@ public class LSPatch {
logger.i("Adding metaloader dex..."); logger.i("Adding metaloader dex...");
try (var is = getClass().getClassLoader().getResourceAsStream(Constants.META_LOADER_DEX_ASSET_PATH)) { try (var is = getClass().getClassLoader().getResourceAsStream(Constants.META_LOADER_DEX_ASSET_PATH)) {
var dexCount = srcZFile.entries().stream().filter(entry -> { if (!injectDex) {
var name = entry.getCentralDirectoryHeader().getName(); dstZFile.add("classes.dex", is);
return name.startsWith("classes") && name.endsWith(".dex"); } else {
}).collect(Collectors.toList()).size() + 1; var dexCount = srcZFile.entries().stream().filter(entry -> {
dstZFile.add("classes" + dexCount + ".dex", is); var name = entry.getCentralDirectoryHeader().getName();
return name.startsWith("classes") && name.endsWith(".dex");
}).collect(Collectors.toList()).size() + 1;
dstZFile.add("classes" + dexCount + ".dex", is);
}
} catch (Throwable e) { } catch (Throwable e) {
throw new PatchError("Error when adding dex", e); throw new PatchError("Error when adding dex", e);
} }
@ -307,6 +314,7 @@ public class LSPatch {
for (StoredEntry entry : srcZFile.entries()) { for (StoredEntry entry : srcZFile.entries()) {
String name = entry.getCentralDirectoryHeader().getName(); String name = entry.getCentralDirectoryHeader().getName();
if (dstZFile.get(name) != null) continue; if (dstZFile.get(name) != null) continue;
if (!injectDex && name.startsWith("classes") && name.endsWith(".dex")) continue;
if (name.equals("AndroidManifest.xml")) continue; if (name.equals("AndroidManifest.xml")) continue;
if (name.startsWith("META-INF") && (name.endsWith(".SF") || name.endsWith(".MF") || name.endsWith(".RSA"))) continue; if (name.startsWith("META-INF") && (name.endsWith(".SF") || name.endsWith(".MF") || name.endsWith(".RSA"))) continue;
srcZFile.addFileLink(name, name); srcZFile.addFileLink(name, name);