mirror of
https://github.com/revanced/Apktool.git
synced 2024-12-12 05:47:46 +01:00
Multiple Dex Support
- CS fixes - added decode support for multiple dexes - decoded to smali_[dex name]
This commit is contained in:
parent
a7b06f161b
commit
70eaab9971
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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()) {
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user