Try to fix x86 crash caused by native bridge

This commit is contained in:
Nullptr 2021-08-08 21:47:05 +08:00
parent a104684126
commit 258e10337d
4 changed files with 39 additions and 80 deletions

View File

@ -1,36 +0,0 @@
package org.lsposed.lspatch.appstub;
import android.app.Application;
import android.content.Context;
import java.io.ByteArrayOutputStream;
public class LSPApplicationStub extends Application {
private static byte[] dex = null;
static {
try (var is = LSPApplicationStub.class.getClassLoader().getResourceAsStream("assets/lsp");
var os = new ByteArrayOutputStream()) {
byte[] buffer = new byte[8192];
int n;
while (-1 != (n = is.read(buffer))) {
os.write(buffer, 0, n);
}
dex = os.toByteArray();
} catch (Throwable e) {
android.util.Log.e("LSPatch", "load dex error", e);
}
System.loadLibrary("lspd");
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
}
}

View File

@ -28,6 +28,7 @@ public class LSPAppComponentFactoryStub extends AppComponentFactory {
private static final String ORIGINAL_APP_COMPONENT_FACTORY_ASSET_PATH = "assets/original_app_component_factory.ini"; private static final String ORIGINAL_APP_COMPONENT_FACTORY_ASSET_PATH = "assets/original_app_component_factory.ini";
private ClassLoader appClassLoader = null; private ClassLoader appClassLoader = null;
private ClassLoader lspClassLoader = null;
private ClassLoader baseClassLoader = null; private ClassLoader baseClassLoader = null;
private AppComponentFactory originalAppComponentFactory = null; private AppComponentFactory originalAppComponentFactory = null;
@ -37,8 +38,7 @@ public class LSPAppComponentFactoryStub extends AppComponentFactory {
**/ **/
private void initOriginalAppComponentFactory(ApplicationInfo aInfo) { private void initOriginalAppComponentFactory(ApplicationInfo aInfo) {
final String cacheApkPath = aInfo.dataDir + "/cache/origin_apk.bin"; final String cacheApkPath = aInfo.dataDir + "/cache/origin_apk.bin";
final String originalAppComponentFactoryClass = final String originalAppComponentFactoryClass = FileUtils.readTextFromInputStream(baseClassLoader.getResourceAsStream(ORIGINAL_APP_COMPONENT_FACTORY_ASSET_PATH));
FileUtils.readTextFromInputStream(baseClassLoader.getResourceAsStream(ORIGINAL_APP_COMPONENT_FACTORY_ASSET_PATH));
try { try {
try (InputStream inputStream = baseClassLoader.getResourceAsStream(ORIGINAL_APK_ASSET_PATH)) { try (InputStream inputStream = baseClassLoader.getResourceAsStream(ORIGINAL_APK_ASSET_PATH)) {
@ -46,10 +46,15 @@ public class LSPAppComponentFactoryStub extends AppComponentFactory {
} catch (FileAlreadyExistsException ignored) { } catch (FileAlreadyExistsException ignored) {
} }
appClassLoader = new PathClassLoader(cacheApkPath, aInfo.nativeLibraryDir, baseClassLoader.getParent()); appClassLoader = new PathClassLoader(cacheApkPath, aInfo.nativeLibraryDir, baseClassLoader.getParent());
if (originalAppComponentFactoryClass == null || originalAppComponentFactoryClass.isEmpty())
originalAppComponentFactory = new AppComponentFactory(); try {
else
originalAppComponentFactory = (AppComponentFactory) appClassLoader.loadClass(originalAppComponentFactoryClass).newInstance(); originalAppComponentFactory = (AppComponentFactory) appClassLoader.loadClass(originalAppComponentFactoryClass).newInstance();
} catch (ClassNotFoundException | NullPointerException ignored) {
if (originalAppComponentFactoryClass != null && !originalAppComponentFactoryClass.isEmpty())
Log.w(TAG, "Original AppComponentFactory not found");
originalAppComponentFactory = new AppComponentFactory();
}
Log.d(TAG, "Instantiate original AppComponentFactory: " + originalAppComponentFactory); Log.d(TAG, "Instantiate original AppComponentFactory: " + originalAppComponentFactory);
} catch (Throwable e) { } catch (Throwable e) {
Log.e(TAG, "initOriginalAppComponentFactory", e); Log.e(TAG, "initOriginalAppComponentFactory", e);
@ -59,6 +64,9 @@ public class LSPAppComponentFactoryStub extends AppComponentFactory {
@Override @Override
public ClassLoader instantiateClassLoader(ClassLoader cl, ApplicationInfo aInfo) { public ClassLoader instantiateClassLoader(ClassLoader cl, ApplicationInfo aInfo) {
baseClassLoader = cl; baseClassLoader = cl;
var apkPath = baseClassLoader.getResource("AndroidManifest.xml").getPath();
apkPath = apkPath.substring(5, apkPath.lastIndexOf('!'));
lspClassLoader = new PathClassLoader(apkPath, null, null);
initOriginalAppComponentFactory(aInfo); initOriginalAppComponentFactory(aInfo);
Log.d(TAG, "baseClassLoader is " + baseClassLoader); Log.d(TAG, "baseClassLoader is " + baseClassLoader);
Log.d(TAG, "appClassLoader is " + appClassLoader); Log.d(TAG, "appClassLoader is " + appClassLoader);
@ -67,7 +75,7 @@ public class LSPAppComponentFactoryStub extends AppComponentFactory {
@Override @Override
public Application instantiateApplication(ClassLoader cl, String className) throws IllegalAccessException, InstantiationException, ClassNotFoundException { public Application instantiateApplication(ClassLoader cl, String className) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
baseClassLoader.loadClass(PROXY_APPLICATION).newInstance(); lspClassLoader.loadClass(PROXY_APPLICATION).newInstance();
return originalAppComponentFactory.instantiateApplication(cl, className); return originalAppComponentFactory.instantiateApplication(cl, className);
} }

View File

@ -1,10 +1,15 @@
package org.lsposed.lspatch.appstub; package org.lsposed.lspatch.appstub;
import android.annotation.SuppressLint;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import android.util.Log;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.InputStreamReader;
@SuppressLint("UnsafeDynamicallyLoadedCode")
public class LSPApplicationStub extends Application { public class LSPApplicationStub extends Application {
private static byte[] dex = null; private static byte[] dex = null;
@ -19,9 +24,16 @@ public class LSPApplicationStub extends Application {
} }
dex = os.toByteArray(); dex = os.toByteArray();
} catch (Throwable e) { } catch (Throwable e) {
android.util.Log.e("LSPatch", "load dex error", e); Log.e("LSPatch", "load dex error", e);
}
try (var br = new BufferedReader(new InputStreamReader(Runtime.getRuntime().exec("getprop ro.product.cpu.abi").getInputStream()))) {
String arch = br.readLine();
String path = LSPApplicationStub.class.getClassLoader().getResource("assets/lib/" + arch + "/liblspd.so").getPath().substring(5);
System.load(path);
} catch (Throwable e) {
Log.e("LSPatch", "load lspd error", e);
} }
System.loadLibrary("lspd");
} }
@Override @Override

View File

@ -32,7 +32,6 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.jar.JarFile; import java.util.jar.JarFile;
public class LSPatch { public class LSPatch {
@ -97,6 +96,12 @@ public class LSPatch {
"x86_64" "x86_64"
)); ));
private static final ZFileOptions Z_FILE_OPTIONS = new ZFileOptions().setAlignmentRule(AlignmentRules.compose(
AlignmentRules.constantForSuffix(".so", 4096),
AlignmentRules.constantForSuffix(RESOURCES_ARSC, 4),
AlignmentRules.constantForSuffix(ORIGINAL_APK_ASSET_PATH, 4096)
));
private static JCommander jCommander; private static JCommander jCommander;
public static void main(String... args) throws IOException { public static void main(String... args) throws IOException {
@ -154,14 +159,7 @@ public class LSPatch {
System.out.println("Parsing original apk..."); System.out.println("Parsing original apk...");
final ZFileOptions zFileOptions = new ZFileOptions(); try (ZFile zFile = ZFile.openReadWrite(tmpApk, Z_FILE_OPTIONS)) {
final var alignmentRule = AlignmentRules.compose(
AlignmentRules.constantForSuffix(RESOURCES_ARSC, 4),
AlignmentRules.constantForSuffix(ORIGINAL_APK_ASSET_PATH, 4096)
);
zFileOptions.setAlignmentRule(alignmentRule);
try (ZFile zFile = ZFile.openReadWrite(tmpApk, zFileOptions)) {
// copy origin apk to assets // copy origin apk to assets
zFile.add(ORIGINAL_APK_ASSET_PATH, new FileInputStream(srcApkFile), false); zFile.add(ORIGINAL_APK_ASSET_PATH, new FileInputStream(srcApkFile), false);
@ -225,36 +223,13 @@ public class LSPatch {
throw new PatchError("Error when saving application name: " + e); throw new PatchError("Error when saving application name: " + e);
} }
// copy so and dex files into the unzipped apk
Set<String> apkArchs = new HashSet<>();
if (verbose)
System.out.println("Search target apk library arch..");
for (StoredEntry storedEntry : zFile.entries()) {
var name = storedEntry.getCentralDirectoryHeader().getName();
if (name.startsWith("lib/") && name.length() >= 5) {
var arch = name.substring(4, name.indexOf('/', 5));
apkArchs.add(arch);
}
}
if (apkArchs.isEmpty()) {
apkArchs.addAll(APK_LIB_PATH_ARRAY);
}
apkArchs.removeIf((arch) -> {
if (!APK_LIB_PATH_ARRAY.contains(arch) && !arch.equals("armeabi")) {
System.err.println("Warning: unsupported arch " + arch + ". Skipping...");
return true;
}
return false;
});
if (verbose) if (verbose)
System.out.println("Adding native lib.."); System.out.println("Adding native lib..");
for (String arch : apkArchs) { // copy so and dex files into the unzipped apk
// lib/armeabi-v7a -> armeabi-v7a // do not put liblspd.so into apk!lib because x86 native bridge causes crash
String entryName = "lib/" + arch + "/liblspd.so"; for (String arch : APK_LIB_PATH_ARRAY) {
String entryName = "assets/lib/" + arch + "/liblspd.so";
try (var is = getClass().getClassLoader().getResourceAsStream("assets/so/" + (arch.equals("armeabi") ? "armeabi-v7a" : arch) + "/liblspd.so")) { try (var is = getClass().getClassLoader().getResourceAsStream("assets/so/" + (arch.equals("armeabi") ? "armeabi-v7a" : arch) + "/liblspd.so")) {
zFile.add(entryName, is, false); // no compress for so zFile.add(entryName, is, false); // no compress for so
} catch (Throwable e) { } catch (Throwable e) {