Make embedded module so loadable
This commit is contained in:
parent
4e3e2a8637
commit
1ced48aa49
|
|
@ -191,14 +191,15 @@ public class LSPApplication extends ApplicationServiceClient {
|
|||
HashSet<String> disabled_modules = new HashSet<>();
|
||||
try {
|
||||
for (var name : context.getAssets().list("modules")) {
|
||||
String modulePath = context.getCacheDir() + "/lspatch/" + name + "/";
|
||||
String packageName = name.substring(0, name.length() - 4);
|
||||
String modulePath = context.getCacheDir() + "/lspatch/" + packageName + "/";
|
||||
String cacheApkPath;
|
||||
try (ZipFile sourceFile = new ZipFile(context.getApplicationInfo().sourceDir)) {
|
||||
cacheApkPath = modulePath + sourceFile.getEntry("assets/modules/" + name).getCrc();
|
||||
}
|
||||
|
||||
if (!Files.exists(Paths.get(cacheApkPath))) {
|
||||
Log.i(TAG, "extract module apk: " + name);
|
||||
Log.i(TAG, "extract module apk: " + packageName);
|
||||
FileUtils.deleteFolderIfExists(Paths.get(modulePath));
|
||||
Files.createDirectories(Paths.get(modulePath));
|
||||
try (var is = context.getAssets().open("modules/" + name)) {
|
||||
|
|
@ -206,10 +207,10 @@ public class LSPApplication extends ApplicationServiceClient {
|
|||
}
|
||||
}
|
||||
|
||||
embedded_modules.add(name);
|
||||
embedded_modules.add(packageName);
|
||||
var module = new Module();
|
||||
module.apkPath = cacheApkPath;
|
||||
module.packageName = name;
|
||||
module.packageName = packageName;
|
||||
LSPApplication.modules.add(module);
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ public class LSPApplicationStub extends Application {
|
|||
vmInstructionSet.setAccessible(true);
|
||||
|
||||
String arch = (String) vmInstructionSet.invoke(getRuntime.invoke(null));
|
||||
String path = LSPApplicationStub.class.getClassLoader().getResource("assets/lib/" + arch + "/liblspd.so").getPath().substring(5);
|
||||
String path = LSPApplicationStub.class.getClassLoader().getResource("assets/lib/lspd/" + arch + "/liblspd.so").getPath().substring(5);
|
||||
System.load(path);
|
||||
} catch (Throwable e) {
|
||||
Log.e("LSPatch", "load lspd error", e);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package org.lsposed.patch;
|
||||
|
||||
import com.android.apksig.internal.util.Pair;
|
||||
import com.android.tools.build.apkzlib.sign.SigningExtension;
|
||||
import com.android.tools.build.apkzlib.sign.SigningOptions;
|
||||
import com.android.tools.build.apkzlib.zip.AlignmentRules;
|
||||
|
|
@ -99,7 +100,7 @@ public class LSPatch {
|
|||
|
||||
private static final ZFileOptions Z_FILE_OPTIONS = new ZFileOptions().setAlignmentRule(AlignmentRules.compose(
|
||||
AlignmentRules.constantForSuffix(".so", 4096),
|
||||
AlignmentRules.constantForSuffix(ORIGINAL_APK_ASSET_PATH, 4096)
|
||||
AlignmentRules.constantForSuffix(".bin", 4096)
|
||||
));
|
||||
|
||||
private static JCommander jCommander;
|
||||
|
|
@ -223,7 +224,7 @@ public class LSPatch {
|
|||
// copy so and dex files into the unzipped apk
|
||||
// do not put liblspd.so into apk!lib because x86 native bridge causes crash
|
||||
for (String arch : APK_LIB_PATH_ARRAY) {
|
||||
String entryName = "assets/lib/" + arch + "/liblspd.so";
|
||||
String entryName = "assets/lib/lspd/" + arch + "/liblspd.so";
|
||||
try (var is = getClass().getClassLoader().getResourceAsStream("assets/so/" + (arch.equals("arm") ? "armeabi-v7a" : (arch.equals("arm64") ? "arm64-v8a" : arch)) + "/liblspd.so")) {
|
||||
dstZFile.add(entryName, is, false); // no compress for so
|
||||
} catch (Throwable e) {
|
||||
|
|
@ -256,7 +257,7 @@ public class LSPatch {
|
|||
throw new PatchError("Error when saving signature bypass level: " + e);
|
||||
}
|
||||
|
||||
embedModules(dstZFile);
|
||||
var embedded = embedModules(dstZFile);
|
||||
|
||||
dstZFile.realign();
|
||||
|
||||
|
|
@ -274,9 +275,22 @@ public class LSPatch {
|
|||
if (name.equals("AndroidManifest.xml")) continue;
|
||||
if (name.startsWith("META-INF/CERT")) continue;
|
||||
if (name.equals("META-INF/MANIFEST.MF")) continue;
|
||||
nestedZip.addFileLink(name);
|
||||
nestedZip.addFileLink(name, name);
|
||||
}
|
||||
nestedZipLink.nestedZips.add(nestedZip);
|
||||
|
||||
for (var pair : embedded) {
|
||||
ZFile moduleZFile = ZFile.openReadOnly(pair.getFirst());
|
||||
StoredEntry moduleEntry = dstZFile.get("assets/modules/" + pair.getSecond() + ".bin");
|
||||
nestedZip = new NestedZip(moduleZFile, moduleEntry);
|
||||
for (var nestedEntry : moduleZFile.entries()) {
|
||||
var name = nestedEntry.getCentralDirectoryHeader().getName();
|
||||
if (name.startsWith("lib/"))
|
||||
nestedZip.addFileLink(name, "assets/lib/" + pair.getSecond() + name.substring(3));
|
||||
}
|
||||
nestedZipLink.nestedZips.add(nestedZip);
|
||||
}
|
||||
|
||||
dstZFile.addZFileExtension(nestedZipLink);
|
||||
|
||||
// sign apk
|
||||
|
|
@ -308,8 +322,9 @@ public class LSPatch {
|
|||
}
|
||||
}
|
||||
|
||||
private void embedModules(ZFile zFile) {
|
||||
private List<Pair<File, String>> embedModules(ZFile zFile) {
|
||||
System.out.println("Embedding modules...");
|
||||
List<Pair<File, String>> list = new ArrayList<>();
|
||||
for (var module : modules) {
|
||||
var file = new File(module);
|
||||
if (!file.exists()) {
|
||||
|
|
@ -339,13 +354,15 @@ public class LSPatch {
|
|||
}
|
||||
if (triple != null) {
|
||||
try (var is = new FileInputStream(file)) {
|
||||
zFile.add("assets/modules/" + triple.packageName, is);
|
||||
var entryName = "assets/modules/" + triple.packageName + ".bin";
|
||||
zFile.add(entryName, is, false);
|
||||
list.add(Pair.of(file, triple.packageName));
|
||||
} catch (Throwable e) {
|
||||
System.err.println("Embed " + triple.packageName + " with error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private byte[] modifyManifestFile(InputStream is) throws IOException {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
package org.lsposed.patch.util;
|
||||
|
||||
import com.android.apksig.internal.util.Pair;
|
||||
import com.android.tools.build.apkzlib.utils.IOExceptionRunnable;
|
||||
import com.android.tools.build.apkzlib.zip.CentralDirectoryHeader;
|
||||
import com.android.tools.build.apkzlib.zip.EncodeUtils;
|
||||
import com.android.tools.build.apkzlib.zip.StoredEntry;
|
||||
import com.android.tools.build.apkzlib.zip.ZFile;
|
||||
import com.android.tools.build.apkzlib.zip.ZFileExtension;
|
||||
|
|
@ -15,7 +17,7 @@ import java.util.Set;
|
|||
|
||||
public class NestedZipLink extends ZFileExtension {
|
||||
public static class NestedZip {
|
||||
final Set<String> links;
|
||||
final Set<Pair<String, String>> links;
|
||||
final ZFile zip;
|
||||
final StoredEntry entry;
|
||||
|
||||
|
|
@ -25,8 +27,8 @@ public class NestedZipLink extends ZFileExtension {
|
|||
this.links = new HashSet<>();
|
||||
}
|
||||
|
||||
public void addFileLink(String name) {
|
||||
links.add(name);
|
||||
public void addFileLink(String srcName, String dstName) {
|
||||
links.add(Pair.of(srcName, dstName));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -71,9 +73,10 @@ public class NestedZipLink extends ZFileExtension {
|
|||
|
||||
Field field_cdh_file = CentralDirectoryHeader.class.getDeclaredField("file");
|
||||
field_cdh_file.setAccessible(true);
|
||||
|
||||
Field field_offset = CentralDirectoryHeader.class.getDeclaredField("offset");
|
||||
field_offset.setAccessible(true);
|
||||
Field field_cdh_encodedFileName = CentralDirectoryHeader.class.getDeclaredField("encodedFileName");
|
||||
field_cdh_encodedFileName.setAccessible(true);
|
||||
Field field_cdh_offset = CentralDirectoryHeader.class.getDeclaredField("offset");
|
||||
field_cdh_offset.setAccessible(true);
|
||||
|
||||
Method makeFree = Class.forName("com.android.tools.build.apkzlib.zip.FileUseMapEntry")
|
||||
.getDeclaredMethod("makeUsed", long.class, long.class, Object.class);
|
||||
|
|
@ -89,17 +92,29 @@ public class NestedZipLink extends ZFileExtension {
|
|||
for (var nestedZip : nestedZips) {
|
||||
long nestedZipOffset = nestedZip.entry.getCentralDirectoryHeader().getOffset();
|
||||
for (var link : nestedZip.links) {
|
||||
var entry = nestedZip.zip.get(link);
|
||||
var entry = nestedZip.zip.get(link.getFirst());
|
||||
if (entry == null) throw new IOException("Entry " + link + " does not exist in nested zip");
|
||||
CentralDirectoryHeader cdh = entry.getCentralDirectoryHeader();
|
||||
field_entry_file.set(entry, zFile);
|
||||
field_cdh_file.set(cdh, zFile);
|
||||
field_offset.set(cdh, nestedZipOffset + cdh.getOffset() + nestedZip.entry.getLocalHeaderSize());
|
||||
field_cdh_encodedFileName.set(cdh, encodeFileName(link.getSecond()));
|
||||
field_cdh_offset.set(cdh, nestedZipOffset + cdh.getOffset() + nestedZip.entry.getLocalHeaderSize());
|
||||
var newFileUseMapEntry = makeFree.invoke(null, 0, 1, entry);
|
||||
entries.put(link, newFileUseMapEntry);
|
||||
entries.put(link.getSecond(), newFileUseMapEntry);
|
||||
}
|
||||
}
|
||||
computeCentralDirectory.invoke(zFile);
|
||||
computeEocd.invoke(zFile);
|
||||
}
|
||||
|
||||
private byte[] encodeFileName(String name) throws Exception {
|
||||
Class<?> GPFlags = Class.forName("com.android.tools.build.apkzlib.zip.GPFlags");
|
||||
Method make = GPFlags.getDeclaredMethod("make", boolean.class);
|
||||
make.setAccessible(true);
|
||||
Method encode = EncodeUtils.class.getDeclaredMethod("encode", String.class, GPFlags);
|
||||
|
||||
boolean encodeWithUtf8 = !EncodeUtils.canAsciiEncode(name);
|
||||
var flags = make.invoke(null, encodeWithUtf8);
|
||||
return (byte[]) encode.invoke(null, name, flags);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue