From 70eaab997170217fed67ca541c683061c931e09c Mon Sep 17 00:00:00 2001 From: Connor Tumbleson Date: Fri, 15 Aug 2014 20:24:12 -0500 Subject: [PATCH] Multiple Dex Support - CS fixes - added decode support for multiple dexes - decoded to smali_[dex name] --- .../src/main/java/brut/apktool/Main.java | 4 + .../src/main/java/brut/androlib/Androlib.java | 87 +++++++++++-------- .../main/java/brut/androlib/ApkDecoder.java | 50 +++++++++-- 3 files changed, 101 insertions(+), 40 deletions(-) diff --git a/brut.apktool/apktool-cli/src/main/java/brut/apktool/Main.java b/brut.apktool/apktool-cli/src/main/java/brut/apktool/Main.java index 234a44dc..6a3ad6d1 100644 --- a/brut.apktool/apktool-cli/src/main/java/brut/apktool/Main.java +++ b/brut.apktool/apktool-cli/src/main/java/brut/apktool/Main.java @@ -30,6 +30,7 @@ import java.io.IOException; import java.util.HashMap; import java.util.logging.*; +import brut.directory.DirectoryException; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.HelpFormatter; @@ -187,6 +188,9 @@ public class Main { } catch (IOException ex) { System.err.println("Could not modify file. Please ensure you have permission."); System.exit(1); + } catch (DirectoryException ex) { + System.err.println("Could not modify internal dex files. Please ensure you have permission."); + System.exit(1); } } diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/Androlib.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/Androlib.java index 2ab94739..bc8af177 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/Androlib.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/Androlib.java @@ -48,7 +48,8 @@ public class Androlib { private final AndrolibResources mAndRes = new AndrolibResources(); protected final ResUnknownFiles mResUnknownFiles = new ResUnknownFiles(); - public ResTable getResTable(ExtFile apkFile) throws AndrolibException { + public ResTable getResTable(ExtFile apkFile) + throws AndrolibException { return mAndRes.getResTable(apkFile, true); } @@ -57,12 +58,23 @@ public class Androlib { return mAndRes.getResTable(apkFile, loadMainPkg); } - public void decodeSourcesRaw(ExtFile apkFile, File outDir, boolean debug) + public void decodeSourcesRaw(ExtFile apkFile, File outDir) + throws AndrolibException { + LOGGER.info("Copying raw classes.dex file..."); + copySourceRaw(apkFile, outDir, "classes.dex"); + } + + public void decodeNonDefaultSourcesRaw(ExtFile apkFile, File outDir, String filename) + throws AndrolibException { + LOGGER.info("Copying raw " + filename + " file..."); + copySourceRaw(apkFile, outDir, filename); + } + + + public void copySourceRaw(ExtFile apkFile, File outDir, String filename) throws AndrolibException { try { - Directory apk = apkFile.getDirectory(); - LOGGER.info("Copying raw classes.dex file..."); - apkFile.getDirectory().copyToDir(outDir, "classes.dex"); + apkFile.getDirectory().copyToDir(outDir, filename); } catch (DirectoryException ex) { throw new AndrolibException(ex); } @@ -74,7 +86,19 @@ public class Androlib { File smaliDir = new File(outDir, SMALI_DIRNAME); OS.rmdir(smaliDir); smaliDir.mkdirs(); - LOGGER.info("Baksmaling..."); + LOGGER.info("Baksmaling classes.dex..."); + SmaliDecoder.decode(apkFile, smaliDir, debug, debugLinePrefix, bakdeb, api); + } catch (BrutException ex) { + throw new AndrolibException(ex); + } + } + + public void decodeNonDefaultSourcesSmali(File apkFile, File outDir, String filename, boolean debug, + String debugLinePrefix, boolean bakdeb, int api) throws AndrolibException { + try { + File smaliDir = new File(outDir, SMALI_DIRNAME + "_" + filename.substring(0, filename.indexOf("."))); + OS.rmdir(smaliDir); + LOGGER.info("Baksmaling " + filename + "..."); SmaliDecoder.decode(apkFile, smaliDir, debug, debugLinePrefix, bakdeb, api); } catch (BrutException ex) { throw new AndrolibException(ex); @@ -98,15 +122,14 @@ public class Androlib { } } - public void decodeManifestFull(ExtFile apkFile, File outDir, - ResTable resTable) throws AndrolibException { + public void decodeManifestFull(ExtFile apkFile, File outDir, ResTable resTable) + throws AndrolibException { mAndRes.decodeManifest(resTable, apkFile, outDir); } public void decodeResourcesRaw(ExtFile apkFile, File outDir) throws AndrolibException { try { - // Directory apk = apkFile.getDirectory(); LOGGER.info("Copying raw resources..."); apkFile.getDirectory().copyToDir(outDir, APK_RESOURCES_FILENAMES); } catch (DirectoryException ex) { @@ -114,8 +137,8 @@ public class Androlib { } } - public void decodeResourcesFull(ExtFile apkFile, File outDir, - ResTable resTable) throws AndrolibException { + public void decodeResourcesFull(ExtFile apkFile, File outDir, ResTable resTable) + throws AndrolibException { mAndRes.decode(resTable, apkFile, outDir); } @@ -169,8 +192,8 @@ public class Androlib { unk.copyToDir(unknownOut,file); try { // ignore encryption - apkZipFile.getEntry(file.toString()).getGeneralPurposeBit().useEncryption(false); - invZipFile = apkZipFile.getEntry(file.toString()); + apkZipFile.getEntry(file).getGeneralPurposeBit().useEncryption(false); + invZipFile = apkZipFile.getEntry(file); // lets record the name of the file, and its compression type // so that we may re-include it the same way @@ -256,24 +279,23 @@ public class Androlib { } } - public void build(File appDir, File outFile, - HashMap flags, String aaptPath) + public void build(File appDir, File outFile, HashMap flags, String aaptPath) throws BrutException { build(new ExtFile(appDir), outFile, flags, aaptPath); } - public void build(ExtFile appDir, File outFile, - HashMap flags, String aaptPath) + public void build(ExtFile appDir, File outFile, HashMap flags, String aaptPath) throws BrutException { - LOGGER.info("Using Apktool " + Androlib.getVersion() + " on " + appDir.getName()); mAaptPath = aaptPath; Map meta = readMetaFile(appDir); Object t1 = meta.get("isFrameworkApk"); flags.put("framework", t1 == null ? false : (Boolean) t1); - flags.put("compression", meta.get("compressionType") == null ? false + flags.put("compression", meta.get("compressionType") == null + ? false : Boolean.valueOf(meta.get("compressionType").toString())); + mAndRes.setSdkInfo((Map) meta.get("sdkInfo")); mAndRes.setPackageId((Map) meta.get("packageInfo")); mAndRes.setPackageInfo((Map) meta.get("packageInfo")); @@ -287,15 +309,14 @@ public class Androlib { new File(appDir, APK_DIRNAME).mkdirs(); buildSources(appDir, flags); - buildResources(appDir, flags, - (Map) meta.get("usesFramework")); + buildResources(appDir, flags, (Map) meta.get("usesFramework")); buildLib(appDir, flags); buildCopyOriginalFiles(appDir, flags); buildApk(appDir, outFile, flags); // we must go after the Apk is built, and copy the files in via Zip // this is because Aapt won't add files it doesn't know (ex unknown files) - buildUnknownFiles(appDir,outFile,meta); + buildUnknownFiles(appDir, outFile, meta); } public void buildSources(File appDir, HashMap flags) @@ -362,8 +383,8 @@ public class Androlib { return true; } - public void buildResources(ExtFile appDir, HashMap flags, - Map usesFramework) throws BrutException { + public void buildResources(ExtFile appDir, HashMap flags, Map usesFramework) + throws BrutException { if (!buildResourcesRaw(appDir, flags) && !buildResourcesFull(appDir, flags, usesFramework) && !buildManifest(appDir, flags, usesFramework)) { @@ -371,8 +392,8 @@ public class Androlib { } } - public boolean buildResourcesRaw(ExtFile appDir, - HashMap flags) throws AndrolibException { + public boolean buildResourcesRaw(ExtFile appDir, HashMap flags) + throws AndrolibException { try { if (!new File(appDir, "resources.arsc").exists()) { return false; @@ -394,8 +415,7 @@ public class Androlib { } } - public boolean buildResourcesFull(File appDir, - HashMap flags, Map usesFramework) + public boolean buildResourcesFull(File appDir, HashMap flags, Map usesFramework) throws AndrolibException { try { if (!new File(appDir, "res").exists()) { @@ -440,8 +460,8 @@ public class Androlib { } } - public boolean buildManifestRaw(ExtFile appDir, - HashMap flags) throws AndrolibException { + public boolean buildManifestRaw(ExtFile appDir, HashMap flags) + throws AndrolibException { try { File apkDir = new File(appDir, APK_DIRNAME); LOGGER.info("Copying raw AndroidManifest.xml..."); @@ -452,8 +472,7 @@ public class Androlib { } } - public boolean buildManifest(ExtFile appDir, - HashMap flags, Map usesFramework) + public boolean buildManifest(ExtFile appDir, HashMap flags, Map usesFramework) throws BrutException { try { if (!new File(appDir, "AndroidManifest.xml").exists()) { @@ -519,8 +538,8 @@ public class Androlib { } } - public void buildCopyOriginalFiles(File appDir, - HashMap flags) throws AndrolibException { + public void buildCopyOriginalFiles(File appDir, HashMap flags) + throws AndrolibException { if (flags.get("copyOriginal")) { File originalDir = new File(appDir, "original"); if(originalDir.exists()) { diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java index b69bcaab..374bcb9a 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java @@ -69,7 +69,7 @@ public class ApkDecoder { mApi = api; } - public void decode() throws AndrolibException, IOException { + public void decode() throws AndrolibException, IOException, DirectoryException { File outDir = getOutDir(); if (!mForceDelete && outDir.exists()) { @@ -134,7 +134,7 @@ public class ApkDecoder { if (hasSources()) { switch (mDecodeSources) { case DECODE_SOURCES_NONE: - mAndrolib.decodeSourcesRaw(mApkFile, outDir, mDebug); + mAndrolib.decodeSourcesRaw(mApkFile, outDir); break; case DECODE_SOURCES_SMALI: mAndrolib.decodeSourcesSmali(mApkFile, outDir, mDebug, mDebugLinePrefix, mBakDeb, mApi); @@ -145,6 +145,29 @@ public class ApkDecoder { } } + if (hasMultipleSources()) { + // foreach unknown dex file in root, lets disassemble it + Set files = mApkFile.getDirectory().getFiles(true); + for (String file : files) { + if (file.endsWith(".dex")) { + if (! file.equalsIgnoreCase("classes.dex")) { + switch(mDecodeSources) { + case DECODE_SOURCES_NONE: + mAndrolib.decodeNonDefaultSourcesRaw(mApkFile, outDir, file); + break; + case DECODE_SOURCES_SMALI: + mAndrolib.decodeNonDefaultSourcesSmali(mApkFile, outDir, file, mDebug, mDebugLinePrefix, mBakDeb, mApi); + break; + case DECODE_SOURCES_JAVA: + mAndrolib.decodeSourcesJava(mApkFile, outDir, mDebug); + break; + } + } + } + } + + } + mAndrolib.decodeRawFiles(mApkFile, outDir); mAndrolib.decodeUnknownFiles(mApkFile, outDir, mResTable); mAndrolib.writeOriginalFiles(mApkFile, outDir); @@ -233,6 +256,23 @@ public class ApkDecoder { } } + public boolean hasMultipleSources() throws AndrolibException { + try { + Set files = mApkFile.getDirectory().getFiles(true); + for (String file : files) { + if (file.endsWith(".dex")) { + if ( ! file.equalsIgnoreCase("classes.dex")) { + return true; + } + } + } + + return false; + } catch (DirectoryException ex) { + throw new AndrolibException(ex); + } + } + public boolean hasManifest() throws AndrolibException { try { return mApkFile.getDirectory().containsFile("AndroidManifest.xml"); @@ -268,10 +308,8 @@ public class ApkDecoder { meta.put("version", Androlib.getVersion()); meta.put("apkFileName", mApkFile.getName()); - if (mDecodeResources != DECODE_RESOURCES_NONE - && (hasManifest() || hasResources())) { - meta.put("isFrameworkApk", - Boolean.valueOf(mAndrolib.isFrameworkApk(getResTable()))); + if (mDecodeResources != DECODE_RESOURCES_NONE && (hasManifest() || hasResources())) { + meta.put("isFrameworkApk", mAndrolib.isFrameworkApk(getResTable())); putUsesFramework(meta); putSdkInfo(meta); putPackageInfo(meta);