From c87f7ffa148d627a14ed3767c52c53e9c427433b Mon Sep 17 00:00:00 2001 From: LoveSy Date: Sat, 19 Jun 2021 13:54:43 +0800 Subject: [PATCH] Merge so and dex into jar --- .github/workflows/main.yml | 4 +- app/build.gradle | 6 +- appstub/build.gradle | 6 +- .../lspatch/appstub/LSPApplicationStub.java | 2 +- patch/build.gradle | 9 +- .../main/java/org/lsposed/patch/LSPatch.java | 129 +++++++++--------- 6 files changed, 84 insertions(+), 72 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e06e581..1f8dd74 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -35,7 +35,7 @@ jobs: uses: actions/upload-artifact@v2 with: name: lspatch-debug - path: out/ + path: out/lspatch.jar - name: Build Release run: ./gradlew buildRelease @@ -43,4 +43,4 @@ jobs: uses: actions/upload-artifact@v2 with: name: lspatch-release - path: out/ + path: out/lspatch.jar diff --git a/app/build.gradle b/app/build.gradle index 6301479..9667815 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -51,14 +51,14 @@ android { dependsOn("assemble$buildType") def dexFilePath = "$buildDir/intermediates/dex/${variantLowered}/mergeDex${buildType}/classes.dex" from dexFilePath - rename "(.*).dex", "lsploader.dex" - into "$rootProject.projectDir/out/list-assets" + rename "classes.dex", "lsp.dex" + into "$rootProject.projectDir/out/dexes" } task "copySo$buildType"(type: Copy) { dependsOn("assemble$buildType") from "$buildDir/intermediates/merged_native_libs/${variantLowered}/out/lib" - into "$rootProject.projectDir/out/list-so" + into "$rootProject.projectDir/out/so" } task "copy$buildType"() { diff --git a/appstub/build.gradle b/appstub/build.gradle index 0e33a57..a24c6f9 100644 --- a/appstub/build.gradle +++ b/appstub/build.gradle @@ -35,8 +35,8 @@ android { dependsOn("assemble$buildType") def dexFilePath = "$buildDir/intermediates/dex/${variantLowered}/mergeDex${buildType}/classes.dex" from dexFilePath - rename "(.*).dex", "classes-${version_name}.dex" - into "$rootProject.projectDir/out/list-dex" + rename "classes.dex", "loader.dex" + into "$rootProject.projectDir/out/dexes" } task "copy$buildType"() { @@ -52,4 +52,4 @@ android { dependencies { implementation project(':share') compileOnly project(":hiddenapi-stubs") -} \ No newline at end of file +} diff --git a/appstub/src/main/java/org/lsposed/lspatch/appstub/LSPApplicationStub.java b/appstub/src/main/java/org/lsposed/lspatch/appstub/LSPApplicationStub.java index 46c55eb..6ea482f 100644 --- a/appstub/src/main/java/org/lsposed/lspatch/appstub/LSPApplicationStub.java +++ b/appstub/src/main/java/org/lsposed/lspatch/appstub/LSPApplicationStub.java @@ -26,7 +26,7 @@ public class LSPApplicationStub extends Application { throw new IllegalStateException("create context err"); } else { - try (InputStream inputStream = context.getAssets().open("lsploader.dex"); + try (InputStream inputStream = context.getAssets().open("lsp.dex"); ByteArrayOutputStream buffer = new ByteArrayOutputStream()) { int nRead; diff --git a/patch/build.gradle b/patch/build.gradle index 5d84c1c..6e9807f 100644 --- a/patch/build.gradle +++ b/patch/build.gradle @@ -34,6 +34,13 @@ jar { } from fileTree(dir: 'src/main', includes: ['assets/**']) + into("assets/dex") { + from fileTree(dir: "$rootProject.projectDir/out/dexes") + } + + into("assets/so") { + from fileTree(dir: "$rootProject.projectDir/out/so") + } exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.MF', 'META-INF/*.txt' } @@ -48,4 +55,4 @@ sourceSets.main.resources { "src/main/java", ]; include "**/*.*" -} \ No newline at end of file +} diff --git a/patch/src/main/java/org/lsposed/patch/LSPatch.java b/patch/src/main/java/org/lsposed/patch/LSPatch.java index 2735f1c..cda1fc9 100644 --- a/patch/src/main/java/org/lsposed/patch/LSPatch.java +++ b/patch/src/main/java/org/lsposed/patch/LSPatch.java @@ -26,7 +26,9 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -44,8 +46,8 @@ public class LSPatch { @Parameter(names = {"-h", "--help"}, help = true, order = 0, description = "Print this message") private boolean help = false; - @Parameter(names = {"-o", "--output"}, description = "Output apk file") - private String outputPath; + @Parameter(names = {"-o", "--output"}, description = "Output directory") + private String outputPath = "."; @Parameter(names = {"-f", "--force"}, description = "Force overwrite exists output file") private boolean forceOverwrite = false; @@ -77,13 +79,13 @@ public class LSPatch { private static final String SIGNATURE_INFO_ASSET_PATH = "assets/original_signature_info.ini"; private static final String ORIGIN_APK_ASSET_PATH = "assets/origin_apk.bin"; private static final String ANDROID_MANIFEST_XML = "AndroidManifest.xml"; - private static final String[] APK_LIB_PATH_ARRAY = { - "lib/armeabi-v7a", - "lib/armeabi", - "lib/arm64-v8a", - "lib/x86", - "lib/x86_64" - }; + private static final HashSet APK_LIB_PATH_ARRAY = new HashSet<>(Arrays.asList( +// "armeabi", + "armeabi-v7a", + "arm64-v8a", + "x86", + "x86_64" + )); private static JCommander jCommander; @@ -109,14 +111,25 @@ public class LSPatch { jCommander.usage(); return; } + for (var apk : apkPaths) { File srcApkFile = new File(apk).getAbsoluteFile(); - System.out.println("Processing " + srcApkFile); - patch(srcApkFile); + + String apkFileName = srcApkFile.getName(); + + var outputDir = new File(outputPath); + outputDir.mkdirs(); + + File outputFile = new File(outputDir, String.format("%s-lv%s-xposed-signed.apk", FilenameUtils.getBaseName(apkFileName), sigbypassLevel)).getAbsoluteFile(); + + if (outputFile.exists() && !forceOverwrite) + throw new PatchError(outputPath + " exists. Use --force to overwrite"); + System.out.println("Processing " + srcApkFile + " -> " + outputFile); + patch(srcApkFile, outputFile); } } - public void patch(File srcApkFile) throws PatchError, IOException { + public void patch(File srcApkFile, File outputFile) throws PatchError, IOException { if (!srcApkFile.exists()) throw new PatchError("The source apk file does not exit. Please provide a correct path."); @@ -129,16 +142,6 @@ public class LSPatch { System.out.println("apk path: " + srcApkFile); } - String apkFileName = srcApkFile.getName(); - - if (outputPath == null || outputPath.length() == 0) { - outputPath = String.format("%s-lv%s-xposed-signed.apk", FilenameUtils.getBaseName(apkFileName), sigbypassLevel); - } - - File outputFile = new File(outputPath); - if (outputFile.exists() && !forceOverwrite) - throw new PatchError(outputPath + " exists. Use --force to overwrite"); - System.out.println("Copying to tmp apk..."); FileUtils.copyFile(srcApkFile, tmpApk); @@ -155,7 +158,7 @@ public class LSPatch { System.out.println("Original signature\n" + originalSignature); try (var is = new ByteArrayInputStream(originalSignature.getBytes(StandardCharsets.UTF_8))) { zFile.add(SIGNATURE_INFO_ASSET_PATH, is); - } catch (IOException e) { + } catch (Throwable e) { throw new PatchError("Error when saving signature: " + e); } @@ -183,14 +186,14 @@ public class LSPatch { // modify manifest try (var is = new ByteArrayInputStream(modifyManifestFile(manifestEntry.open()))) { zFile.add(APPLICATION_NAME_ASSET_PATH, is); - } catch (IOException e) { + } catch (Throwable e) { throw new PatchError("Error when modifying manifest: " + e); } // save original main application name to asset file even its empty try (var is = new ByteArrayInputStream(applicationName.getBytes(StandardCharsets.UTF_8))) { zFile.add(APPLICATION_NAME_ASSET_PATH, is); - } catch (IOException e) { + } catch (Throwable e) { throw new PatchError("Error when saving signature: " + e); } @@ -198,45 +201,50 @@ public class LSPatch { Set apkArchs = new HashSet<>(); if (verbose) - System.out.println("search target apk library arch.."); + System.out.println("Search target apk library arch.."); for (StoredEntry storedEntry : zFile.entries()) { - for (String arch : APK_LIB_PATH_ARRAY) { - if (storedEntry.getCentralDirectoryHeader().getName().startsWith(arch)) { - apkArchs.add(arch); - } + var name = storedEntry.getCentralDirectoryHeader().getName(); + if (name.startsWith("lib/")) { + var arch = name.substring(4, name.indexOf('/', 5)); + apkArchs.add(arch); } } if (apkArchs.isEmpty()) { - apkArchs.add(APK_LIB_PATH_ARRAY[0]); + apkArchs.addAll(APK_LIB_PATH_ARRAY); } + apkArchs.removeIf((arch) -> { + if (!APK_LIB_PATH_ARRAY.contains(arch)) { + System.err.println("Warning: unsupported arch " + arch + ". Skipping..."); + return true; + } + return false; + }); + if (verbose) + System.out.println("Adding native lib.."); + for (String arch : apkArchs) { // lib/armeabi-v7a -> armeabi-v7a - String justArch = arch.substring(arch.indexOf('/')); - File sod = new File("list-so", justArch); - File[] files = sod.listFiles(); - if (files == null) { - System.err.println("Warning: No so file has been copied in " + sod.getPath()); - continue; - } - for (File file : files) { - zFile.add(arch + "/" + file.getName(), new FileInputStream(file)); - if (verbose) - System.out.println("add " + file.getPath()); + String entryName = "lib/" + arch + "/liblspd.so"; + try (var is = getClass().getClassLoader().getResourceAsStream("assets/so/" + arch + "/liblspd.so")) { + zFile.add(entryName, is); + } catch (Throwable e) { + throw new PatchError("Error when adding native lib: " + e); } + if (verbose) + System.out.println("added " + entryName); } - // copy all dex files in list-dex - File[] files = new File("list-dex").listFiles(); - if (files == null || files.length == 0) { - System.err.println("Warning: No dex file has been copied"); - return; - } - for (File file : files) { + if (verbose) + System.out.println("Adding dex.."); + + try (var is = getClass().getClassLoader().getResourceAsStream("assets/dex/loader.dex")) { String copiedDexFileName = "classes" + (dexFileCount + 1) + ".dex"; - zFile.add(copiedDexFileName, new FileInputStream(file)); + zFile.add(copiedDexFileName, is); dexFileCount++; + } catch (Throwable e) { + throw new PatchError("Error when add dex: " + e); } // copy origin apk to assets @@ -245,22 +253,16 @@ public class LSPatch { zFile.add(ORIGIN_APK_ASSET_PATH, new FileInputStream(srcApkFile)); } - File[] listAssets = new File("list-assets").listFiles(); - if (listAssets == null || listAssets.length == 0) { - System.err.println("Warning: No assets file copyied"); - } else { - for (File f : listAssets) { - if (f.isDirectory()) { - throw new PatchError("unsupported directory in assets"); - } - zFile.add("assets/" + f.getName(), new FileInputStream(f)); - } + try (var is = getClass().getClassLoader().getResourceAsStream("assets/dex/lsp.dex")) { + zFile.add("assets/lsp.dex", is); + } catch (Throwable e) { + throw new PatchError("Error when add assets: " + e); } // save lspatch config to asset.. try (var is = new ByteArrayInputStream("42".getBytes(StandardCharsets.UTF_8))) { zFile.add("assets/" + Constants.CONFIG_NAME_SIGBYPASSLV + sigbypassLevel, is); - } catch (IOException e) { + } catch (Throwable e) { throw new PatchError("Error when saving signature: " + e); } @@ -272,7 +274,10 @@ public class LSPatch { System.out.println("Done. Output APK: " + outputFile.getAbsolutePath()); } finally { - FileUtils.deleteDirectory(workingDir); + try { + FileUtils.deleteDirectory(workingDir); + } catch (Throwable ignored) { + } } }