Multiple Dex Support

- CS fixes
 - added decode support for multiple dexes
 - decoded to smali_[dex name]
This commit is contained in:
Connor Tumbleson 2014-08-15 20:24:12 -05:00
parent a7b06f161b
commit 70eaab9971
3 changed files with 101 additions and 40 deletions

View File

@ -30,6 +30,7 @@ import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.logging.*; import java.util.logging.*;
import brut.directory.DirectoryException;
import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.HelpFormatter;
@ -187,6 +188,9 @@ public class Main {
} catch (IOException ex) { } catch (IOException ex) {
System.err.println("Could not modify file. Please ensure you have permission."); System.err.println("Could not modify file. Please ensure you have permission.");
System.exit(1); System.exit(1);
} catch (DirectoryException ex) {
System.err.println("Could not modify internal dex files. Please ensure you have permission.");
System.exit(1);
} }
} }

View File

@ -48,7 +48,8 @@ public class Androlib {
private final AndrolibResources mAndRes = new AndrolibResources(); private final AndrolibResources mAndRes = new AndrolibResources();
protected final ResUnknownFiles mResUnknownFiles = new ResUnknownFiles(); 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); return mAndRes.getResTable(apkFile, true);
} }
@ -57,12 +58,23 @@ public class Androlib {
return mAndRes.getResTable(apkFile, loadMainPkg); 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 { throws AndrolibException {
try { try {
Directory apk = apkFile.getDirectory(); apkFile.getDirectory().copyToDir(outDir, filename);
LOGGER.info("Copying raw classes.dex file...");
apkFile.getDirectory().copyToDir(outDir, "classes.dex");
} catch (DirectoryException ex) { } catch (DirectoryException ex) {
throw new AndrolibException(ex); throw new AndrolibException(ex);
} }
@ -74,7 +86,19 @@ public class Androlib {
File smaliDir = new File(outDir, SMALI_DIRNAME); File smaliDir = new File(outDir, SMALI_DIRNAME);
OS.rmdir(smaliDir); OS.rmdir(smaliDir);
smaliDir.mkdirs(); 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); SmaliDecoder.decode(apkFile, smaliDir, debug, debugLinePrefix, bakdeb, api);
} catch (BrutException ex) { } catch (BrutException ex) {
throw new AndrolibException(ex); throw new AndrolibException(ex);
@ -98,15 +122,14 @@ public class Androlib {
} }
} }
public void decodeManifestFull(ExtFile apkFile, File outDir, public void decodeManifestFull(ExtFile apkFile, File outDir, ResTable resTable)
ResTable resTable) throws AndrolibException { throws AndrolibException {
mAndRes.decodeManifest(resTable, apkFile, outDir); mAndRes.decodeManifest(resTable, apkFile, outDir);
} }
public void decodeResourcesRaw(ExtFile apkFile, File outDir) public void decodeResourcesRaw(ExtFile apkFile, File outDir)
throws AndrolibException { throws AndrolibException {
try { try {
// Directory apk = apkFile.getDirectory();
LOGGER.info("Copying raw resources..."); LOGGER.info("Copying raw resources...");
apkFile.getDirectory().copyToDir(outDir, APK_RESOURCES_FILENAMES); apkFile.getDirectory().copyToDir(outDir, APK_RESOURCES_FILENAMES);
} catch (DirectoryException ex) { } catch (DirectoryException ex) {
@ -114,8 +137,8 @@ public class Androlib {
} }
} }
public void decodeResourcesFull(ExtFile apkFile, File outDir, public void decodeResourcesFull(ExtFile apkFile, File outDir, ResTable resTable)
ResTable resTable) throws AndrolibException { throws AndrolibException {
mAndRes.decode(resTable, apkFile, outDir); mAndRes.decode(resTable, apkFile, outDir);
} }
@ -169,8 +192,8 @@ public class Androlib {
unk.copyToDir(unknownOut,file); unk.copyToDir(unknownOut,file);
try { try {
// ignore encryption // ignore encryption
apkZipFile.getEntry(file.toString()).getGeneralPurposeBit().useEncryption(false); apkZipFile.getEntry(file).getGeneralPurposeBit().useEncryption(false);
invZipFile = apkZipFile.getEntry(file.toString()); invZipFile = apkZipFile.getEntry(file);
// lets record the name of the file, and its compression type // lets record the name of the file, and its compression type
// so that we may re-include it the same way // so that we may re-include it the same way
@ -256,24 +279,23 @@ public class Androlib {
} }
} }
public void build(File appDir, File outFile, public void build(File appDir, File outFile, HashMap<String, Boolean> flags, String aaptPath)
HashMap<String, Boolean> flags, String aaptPath)
throws BrutException { throws BrutException {
build(new ExtFile(appDir), outFile, flags, aaptPath); build(new ExtFile(appDir), outFile, flags, aaptPath);
} }
public void build(ExtFile appDir, File outFile, public void build(ExtFile appDir, File outFile, HashMap<String, Boolean> flags, String aaptPath)
HashMap<String, Boolean> flags, String aaptPath)
throws BrutException { throws BrutException {
LOGGER.info("Using Apktool " + Androlib.getVersion() + " on " + appDir.getName()); LOGGER.info("Using Apktool " + Androlib.getVersion() + " on " + appDir.getName());
mAaptPath = aaptPath; mAaptPath = aaptPath;
Map<String, Object> meta = readMetaFile(appDir); Map<String, Object> meta = readMetaFile(appDir);
Object t1 = meta.get("isFrameworkApk"); Object t1 = meta.get("isFrameworkApk");
flags.put("framework", t1 == null ? false : (Boolean) t1); 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())); : Boolean.valueOf(meta.get("compressionType").toString()));
mAndRes.setSdkInfo((Map<String, String>) meta.get("sdkInfo")); mAndRes.setSdkInfo((Map<String, String>) meta.get("sdkInfo"));
mAndRes.setPackageId((Map<String, String>) meta.get("packageInfo")); mAndRes.setPackageId((Map<String, String>) meta.get("packageInfo"));
mAndRes.setPackageInfo((Map<String, String>) meta.get("packageInfo")); mAndRes.setPackageInfo((Map<String, String>) meta.get("packageInfo"));
@ -287,15 +309,14 @@ public class Androlib {
new File(appDir, APK_DIRNAME).mkdirs(); new File(appDir, APK_DIRNAME).mkdirs();
buildSources(appDir, flags); buildSources(appDir, flags);
buildResources(appDir, flags, buildResources(appDir, flags, (Map<String, Object>) meta.get("usesFramework"));
(Map<String, Object>) meta.get("usesFramework"));
buildLib(appDir, flags); buildLib(appDir, flags);
buildCopyOriginalFiles(appDir, flags); buildCopyOriginalFiles(appDir, flags);
buildApk(appDir, outFile, flags); buildApk(appDir, outFile, flags);
// we must go after the Apk is built, and copy the files in via Zip // 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) // 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<String, Boolean> flags) public void buildSources(File appDir, HashMap<String, Boolean> flags)
@ -362,8 +383,8 @@ public class Androlib {
return true; return true;
} }
public void buildResources(ExtFile appDir, HashMap<String, Boolean> flags, public void buildResources(ExtFile appDir, HashMap<String, Boolean> flags, Map<String, Object> usesFramework)
Map<String, Object> usesFramework) throws BrutException { throws BrutException {
if (!buildResourcesRaw(appDir, flags) if (!buildResourcesRaw(appDir, flags)
&& !buildResourcesFull(appDir, flags, usesFramework) && !buildResourcesFull(appDir, flags, usesFramework)
&& !buildManifest(appDir, flags, usesFramework)) { && !buildManifest(appDir, flags, usesFramework)) {
@ -371,8 +392,8 @@ public class Androlib {
} }
} }
public boolean buildResourcesRaw(ExtFile appDir, public boolean buildResourcesRaw(ExtFile appDir, HashMap<String, Boolean> flags)
HashMap<String, Boolean> flags) throws AndrolibException { throws AndrolibException {
try { try {
if (!new File(appDir, "resources.arsc").exists()) { if (!new File(appDir, "resources.arsc").exists()) {
return false; return false;
@ -394,8 +415,7 @@ public class Androlib {
} }
} }
public boolean buildResourcesFull(File appDir, public boolean buildResourcesFull(File appDir, HashMap<String, Boolean> flags, Map<String, Object> usesFramework)
HashMap<String, Boolean> flags, Map<String, Object> usesFramework)
throws AndrolibException { throws AndrolibException {
try { try {
if (!new File(appDir, "res").exists()) { if (!new File(appDir, "res").exists()) {
@ -440,8 +460,8 @@ public class Androlib {
} }
} }
public boolean buildManifestRaw(ExtFile appDir, public boolean buildManifestRaw(ExtFile appDir, HashMap<String, Boolean> flags)
HashMap<String, Boolean> flags) throws AndrolibException { throws AndrolibException {
try { try {
File apkDir = new File(appDir, APK_DIRNAME); File apkDir = new File(appDir, APK_DIRNAME);
LOGGER.info("Copying raw AndroidManifest.xml..."); LOGGER.info("Copying raw AndroidManifest.xml...");
@ -452,8 +472,7 @@ public class Androlib {
} }
} }
public boolean buildManifest(ExtFile appDir, public boolean buildManifest(ExtFile appDir, HashMap<String, Boolean> flags, Map<String, Object> usesFramework)
HashMap<String, Boolean> flags, Map<String, Object> usesFramework)
throws BrutException { throws BrutException {
try { try {
if (!new File(appDir, "AndroidManifest.xml").exists()) { if (!new File(appDir, "AndroidManifest.xml").exists()) {
@ -519,8 +538,8 @@ public class Androlib {
} }
} }
public void buildCopyOriginalFiles(File appDir, public void buildCopyOriginalFiles(File appDir, HashMap<String, Boolean> flags)
HashMap<String, Boolean> flags) throws AndrolibException { throws AndrolibException {
if (flags.get("copyOriginal")) { if (flags.get("copyOriginal")) {
File originalDir = new File(appDir, "original"); File originalDir = new File(appDir, "original");
if(originalDir.exists()) { if(originalDir.exists()) {

View File

@ -69,7 +69,7 @@ public class ApkDecoder {
mApi = api; mApi = api;
} }
public void decode() throws AndrolibException, IOException { public void decode() throws AndrolibException, IOException, DirectoryException {
File outDir = getOutDir(); File outDir = getOutDir();
if (!mForceDelete && outDir.exists()) { if (!mForceDelete && outDir.exists()) {
@ -134,7 +134,7 @@ public class ApkDecoder {
if (hasSources()) { if (hasSources()) {
switch (mDecodeSources) { switch (mDecodeSources) {
case DECODE_SOURCES_NONE: case DECODE_SOURCES_NONE:
mAndrolib.decodeSourcesRaw(mApkFile, outDir, mDebug); mAndrolib.decodeSourcesRaw(mApkFile, outDir);
break; break;
case DECODE_SOURCES_SMALI: case DECODE_SOURCES_SMALI:
mAndrolib.decodeSourcesSmali(mApkFile, outDir, mDebug, mDebugLinePrefix, mBakDeb, mApi); 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<String> 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.decodeRawFiles(mApkFile, outDir);
mAndrolib.decodeUnknownFiles(mApkFile, outDir, mResTable); mAndrolib.decodeUnknownFiles(mApkFile, outDir, mResTable);
mAndrolib.writeOriginalFiles(mApkFile, outDir); mAndrolib.writeOriginalFiles(mApkFile, outDir);
@ -233,6 +256,23 @@ public class ApkDecoder {
} }
} }
public boolean hasMultipleSources() throws AndrolibException {
try {
Set<String> 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 { public boolean hasManifest() throws AndrolibException {
try { try {
return mApkFile.getDirectory().containsFile("AndroidManifest.xml"); return mApkFile.getDirectory().containsFile("AndroidManifest.xml");
@ -268,10 +308,8 @@ public class ApkDecoder {
meta.put("version", Androlib.getVersion()); meta.put("version", Androlib.getVersion());
meta.put("apkFileName", mApkFile.getName()); meta.put("apkFileName", mApkFile.getName());
if (mDecodeResources != DECODE_RESOURCES_NONE if (mDecodeResources != DECODE_RESOURCES_NONE && (hasManifest() || hasResources())) {
&& (hasManifest() || hasResources())) { meta.put("isFrameworkApk", mAndrolib.isFrameworkApk(getResTable()));
meta.put("isFrameworkApk",
Boolean.valueOf(mAndrolib.isFrameworkApk(getResTable())));
putUsesFramework(meta); putUsesFramework(meta);
putSdkInfo(meta); putSdkInfo(meta);
putPackageInfo(meta); putPackageInfo(meta);