14: Add JADX decompiler
This commit is contained in:
@@ -3,7 +3,7 @@ package com.bartek.esa.analyser.apk;
|
||||
import com.bartek.esa.analyser.core.Analyser;
|
||||
import com.bartek.esa.core.archetype.Plugin;
|
||||
import com.bartek.esa.core.executor.PluginExecutor;
|
||||
import com.bartek.esa.decompiler.decompiler.Decompiler;
|
||||
import com.bartek.esa.decompiler.archetype.Decompiler;
|
||||
import com.bartek.esa.error.EsaException;
|
||||
import com.bartek.esa.file.cleaner.FileCleaner;
|
||||
import com.bartek.esa.file.matcher.GlobMatcher;
|
||||
@@ -12,11 +12,9 @@ import com.bartek.esa.file.provider.FileProvider;
|
||||
import java.io.File;
|
||||
import java.util.Set;
|
||||
|
||||
public class ApkAnalyser extends Analyser {
|
||||
private static final String ANDROID_MANIFEST_GLOB = "**/" + Decompiler.XML_FILES_DIR + "/AndroidManifest.xml";
|
||||
private static final String JAVA_GLOB = "**/" + Decompiler.JAVA_FILES_DIR + "/**/*.java";
|
||||
private static final String LAYOUT_GLOB = "**/" + Decompiler.XML_FILES_DIR + "/**/layout*/*.xml";
|
||||
import static java.lang.String.format;
|
||||
|
||||
public class ApkAnalyser extends Analyser {
|
||||
private final Decompiler decompiler;
|
||||
private final FileCleaner fileCleaner;
|
||||
private final GlobMatcher globMatcher;
|
||||
@@ -43,17 +41,17 @@ public class ApkAnalyser extends Analyser {
|
||||
|
||||
@Override
|
||||
protected String getAndroidManifestGlob() {
|
||||
return ANDROID_MANIFEST_GLOB;
|
||||
return format("**/%s/AndroidManifest.xml", decompiler.getAndroidManifestFolder());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getJavaGlob() {
|
||||
return JAVA_GLOB;
|
||||
return format("**/%s/**/*.java", decompiler.getJavaSourcesFolder());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLayoutGlob() {
|
||||
return LAYOUT_GLOB;
|
||||
return format("**/%s/layout*/*.xml", decompiler.getResFolder());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,7 +4,7 @@ import com.bartek.esa.analyser.apk.ApkAnalyser;
|
||||
import com.bartek.esa.analyser.source.SourceAnalyser;
|
||||
import com.bartek.esa.core.archetype.Plugin;
|
||||
import com.bartek.esa.core.executor.PluginExecutor;
|
||||
import com.bartek.esa.decompiler.decompiler.Decompiler;
|
||||
import com.bartek.esa.decompiler.archetype.Decompiler;
|
||||
import com.bartek.esa.file.cleaner.FileCleaner;
|
||||
import com.bartek.esa.file.matcher.GlobMatcher;
|
||||
import com.bartek.esa.file.provider.FileProvider;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.bartek.esa.decompiler.archetype;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public interface Decompiler {
|
||||
File decompile(File inputApk, boolean debug);
|
||||
String getAndroidManifestFolder();
|
||||
String getResFolder();
|
||||
String getJavaSourcesFolder();
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.bartek.esa.decompiler.decompiler;
|
||||
|
||||
import com.bartek.esa.decompiler.archetype.Decompiler;
|
||||
import com.bartek.esa.decompiler.process.ProcessExecutor;
|
||||
import com.bartek.esa.file.cleaner.FileCleaner;
|
||||
import com.bartek.esa.file.provider.FileProvider;
|
||||
@@ -10,9 +11,9 @@ import javax.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.util.Set;
|
||||
|
||||
public class Decompiler {
|
||||
public static final String XML_FILES_DIR = "xml";
|
||||
public static final String JAVA_FILES_DIR = "java";
|
||||
public class CfrDecompiler implements Decompiler {
|
||||
private static final String XML_FILES_DIR = "xml";
|
||||
private static final String JAVA_FILES_DIR = "java";
|
||||
|
||||
private static final String APK_UNZIPPED_DIR = "apk_unzipped";
|
||||
private static final String JAR_FILES_DIR = "jar";
|
||||
@@ -23,13 +24,14 @@ public class Decompiler {
|
||||
private final FileCleaner fileCleaner;
|
||||
|
||||
@Inject
|
||||
public Decompiler(FileProvider fileProvider, ProcessExecutor processExecutor1, ZipTool zipTool, FileCleaner fileCleaner) {
|
||||
public CfrDecompiler(FileProvider fileProvider, ProcessExecutor processExecutor1, ZipTool zipTool, FileCleaner fileCleaner) {
|
||||
this.fileProvider = fileProvider;
|
||||
this.processExecutor = processExecutor1;
|
||||
this.zipTool = zipTool;
|
||||
this.fileCleaner = fileCleaner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File decompile(File inputApk, boolean debug) {
|
||||
File tmp = fileProvider.createTemporaryDirectory();
|
||||
File javaDirectory = new File(tmp, JAVA_FILES_DIR);
|
||||
@@ -41,6 +43,21 @@ public class Decompiler {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAndroidManifestFolder() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResFolder() {
|
||||
return XML_FILES_DIR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJavaSourcesFolder() {
|
||||
return JAVA_FILES_DIR;
|
||||
}
|
||||
|
||||
private void decompileJavaFiles(File inputApk, File tmp, File javaDirectory, boolean debug) {
|
||||
File unzippedApkDirectory = new File(tmp, APK_UNZIPPED_DIR);
|
||||
File jarDirectory = new File(tmp, JAR_FILES_DIR);
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.bartek.esa.decompiler.decompiler;
|
||||
|
||||
import com.bartek.esa.decompiler.archetype.Decompiler;
|
||||
import com.bartek.esa.decompiler.process.ProcessExecutor;
|
||||
import com.bartek.esa.file.provider.FileProvider;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.File;
|
||||
|
||||
public class JadxDecompiler implements Decompiler {
|
||||
private static final String RESOURCES_FILES_DIR = "resources";
|
||||
private static final String JAVA_FILES_DIR = "sources";
|
||||
|
||||
private final FileProvider fileProvider;
|
||||
private final ProcessExecutor processExecutor;
|
||||
|
||||
@Inject
|
||||
public JadxDecompiler(FileProvider fileProvider, ProcessExecutor processExecutor) {
|
||||
this.fileProvider = fileProvider;
|
||||
this.processExecutor = processExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File decompile(File inputApk, boolean debug) {
|
||||
File tmp = fileProvider.createTemporaryDirectory();
|
||||
runJadx(inputApk, tmp, debug);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private void runJadx(File inputApk, File tmp, boolean debug) {
|
||||
String[] cmd = {
|
||||
"jadx", inputApk.getAbsolutePath(),
|
||||
"-ds", new File(tmp, JAVA_FILES_DIR).getAbsolutePath(),
|
||||
"-dr", new File(tmp, RESOURCES_FILES_DIR).getAbsolutePath()
|
||||
};
|
||||
processExecutor.execute(cmd, debug);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAndroidManifestFolder() {
|
||||
return RESOURCES_FILES_DIR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResFolder() {
|
||||
return RESOURCES_FILES_DIR + "/res";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJavaSourcesFolder() {
|
||||
return JAVA_FILES_DIR;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
package com.bartek.esa.decompiler.di;
|
||||
|
||||
import com.bartek.esa.decompiler.decompiler.Decompiler;
|
||||
import com.bartek.esa.decompiler.archetype.Decompiler;
|
||||
import com.bartek.esa.decompiler.decompiler.JadxDecompiler;
|
||||
import com.bartek.esa.decompiler.process.ProcessExecutor;
|
||||
import com.bartek.esa.file.cleaner.FileCleaner;
|
||||
import com.bartek.esa.file.provider.FileProvider;
|
||||
import com.bartek.esa.file.zip.ZipTool;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
|
||||
@@ -17,7 +16,7 @@ public class DecompilerModule {
|
||||
}
|
||||
|
||||
@Provides
|
||||
public Decompiler decompiler(FileProvider fileProvider, ProcessExecutor processExecutor, ZipTool zipTool, FileCleaner fileCleaner) {
|
||||
return new Decompiler(fileProvider, processExecutor, zipTool, fileCleaner);
|
||||
public Decompiler decompiler(FileProvider fileProvider, ProcessExecutor processExecutor) {
|
||||
return new JadxDecompiler(fileProvider, processExecutor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ public class ProcessExecutor {
|
||||
.getOrElseThrow(EsaException::new);
|
||||
printStdOutAndStdErrFromProcess(debug, process);
|
||||
waitForProcess(process);
|
||||
checkExitValue(process, command[0]);
|
||||
}
|
||||
|
||||
private void printCommandLine(String[] command, boolean debug) {
|
||||
@@ -31,18 +30,21 @@ public class ProcessExecutor {
|
||||
}
|
||||
|
||||
private void printStdOutAndStdErrFromProcess(boolean debug, Process process) {
|
||||
if(debug) {
|
||||
BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
BufferedReader stderr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
|
||||
String line;
|
||||
try {
|
||||
while ((line = stdout.readLine()) != null) {
|
||||
if (debug) {
|
||||
System.out.println(line);
|
||||
}
|
||||
}
|
||||
|
||||
while ((line = stderr.readLine()) != null) {
|
||||
if (debug) {
|
||||
System.err.println(line);
|
||||
}
|
||||
}
|
||||
|
||||
stdout.close();
|
||||
stderr.close();
|
||||
@@ -50,15 +52,8 @@ public class ProcessExecutor {
|
||||
throw new EsaException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void waitForProcess(Process process) {
|
||||
Try.run(process::waitFor).getOrElseThrow(EsaException::new);
|
||||
}
|
||||
|
||||
private void checkExitValue(Process process, String commandName) {
|
||||
if (process.exitValue() != 0) {
|
||||
throw new EsaException("'" + commandName + "' process has finished with non-zero code. Interrupting...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user