refactor: use own dex parser instead deprecated dx lib
This commit is contained in:
+67
@@ -0,0 +1,67 @@
|
||||
package jadx.plugins.input.javaconvert;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ConvertResult {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ConvertResult.class);
|
||||
|
||||
private final List<Path> converted = new ArrayList<>();
|
||||
private final List<Path> tmpPaths = new ArrayList<>();
|
||||
|
||||
public List<Path> getConverted() {
|
||||
return converted;
|
||||
}
|
||||
|
||||
public void addConvertedFiles(List<Path> paths) {
|
||||
converted.addAll(paths);
|
||||
}
|
||||
|
||||
public void addTempPath(Path path) {
|
||||
tmpPaths.add(path);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return converted.isEmpty();
|
||||
}
|
||||
|
||||
public void deleteTemp() {
|
||||
for (Path tmpPath : tmpPaths) {
|
||||
try {
|
||||
delete(tmpPath);
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Failed to delete temp path: {}", tmpPath, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
private static void delete(Path path) throws IOException {
|
||||
if (Files.isRegularFile(path)) {
|
||||
Files.delete(path);
|
||||
return;
|
||||
}
|
||||
if (Files.isDirectory(path)) {
|
||||
try (Stream<Path> pathStream = Files.walk(path)) {
|
||||
pathStream
|
||||
.sorted(Comparator.reverseOrder())
|
||||
.map(Path::toFile)
|
||||
.forEach(File::delete);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ConvertResult{converted=" + converted + ", tmpPaths=" + tmpPaths + '}';
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package jadx.plugins.input.javaconvert;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.android.tools.r8.CompilationFailedException;
|
||||
import com.android.tools.r8.CompilationMode;
|
||||
import com.android.tools.r8.D8;
|
||||
import com.android.tools.r8.D8Command;
|
||||
import com.android.tools.r8.Diagnostic;
|
||||
import com.android.tools.r8.DiagnosticsHandler;
|
||||
import com.android.tools.r8.OutputMode;
|
||||
|
||||
public class D8Converter {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(D8Converter.class);
|
||||
|
||||
public static void run(Path path, Path tempDirectory) throws CompilationFailedException {
|
||||
D8Command d8Command = D8Command.builder(new LogHandler())
|
||||
.addProgramFiles(path)
|
||||
.setOutput(tempDirectory, OutputMode.DexIndexed)
|
||||
.setMode(CompilationMode.DEBUG)
|
||||
.setMinApiLevel(30)
|
||||
.setIntermediate(true)
|
||||
.setEnableDesugaring(false)
|
||||
.build();
|
||||
D8.run(d8Command);
|
||||
}
|
||||
|
||||
private static class LogHandler implements DiagnosticsHandler {
|
||||
@Override
|
||||
public void error(Diagnostic diagnostic) {
|
||||
LOG.error("D8 error: {}", format(diagnostic));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warning(Diagnostic diagnostic) {
|
||||
LOG.warn("D8 warning: {}", format(diagnostic));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Diagnostic diagnostic) {
|
||||
LOG.info("D8 info: {}", format(diagnostic));
|
||||
}
|
||||
|
||||
public static String format(Diagnostic diagnostic) {
|
||||
return diagnostic.getDiagnosticMessage()
|
||||
+ ", origin: " + diagnostic.getOrigin()
|
||||
+ ", position: " + diagnostic.getPosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package jadx.plugins.input.javaconvert;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import com.android.dx.command.dexer.DxContext;
|
||||
import com.android.dx.command.dexer.Main;
|
||||
|
||||
public class DxConverter {
|
||||
private static final String CHARSET_NAME = "UTF-8";
|
||||
|
||||
private static class DxArgs extends com.android.dx.command.dexer.Main.Arguments {
|
||||
public DxArgs(DxContext context, String dexDir, String[] input) {
|
||||
super(context);
|
||||
outName = dexDir;
|
||||
fileNames = input;
|
||||
jarOutput = false;
|
||||
multiDex = true;
|
||||
|
||||
optimize = true;
|
||||
localInfo = true;
|
||||
coreLibrary = true;
|
||||
|
||||
debug = true;
|
||||
warnings = true;
|
||||
minSdkVersion = 28;
|
||||
}
|
||||
}
|
||||
|
||||
public static void run(Path path, Path tempDirectory) {
|
||||
int result;
|
||||
String dxErrors;
|
||||
try (ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ByteArrayOutputStream errOut = new ByteArrayOutputStream()) {
|
||||
DxContext context = new DxContext(out, errOut);
|
||||
DxArgs args = new DxArgs(
|
||||
context,
|
||||
tempDirectory.toAbsolutePath().toString(),
|
||||
new String[] { path.toAbsolutePath().toString() });
|
||||
result = new Main(context).runDx(args);
|
||||
dxErrors = errOut.toString(CHARSET_NAME);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("dx exception: " + e.getMessage(), e);
|
||||
}
|
||||
if (result != 0) {
|
||||
throw new RuntimeException("Java to dex conversion error, code: " + result + "\n errors: " + dxErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package jadx.plugins.input.javaconvert;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class JavaConvertLoader {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JavaConvertLoader.class);
|
||||
|
||||
public static ConvertResult process(List<Path> input) {
|
||||
ConvertResult result = new ConvertResult();
|
||||
for (Path path : input) {
|
||||
if (isJavaFile(path)) {
|
||||
try {
|
||||
convert(result, path);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to convert file: " + path.toAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean isJavaFile(Path path) {
|
||||
String fileName = path.getFileName().toString();
|
||||
return fileName.endsWith(".jar")
|
||||
|| fileName.endsWith(".class");
|
||||
}
|
||||
|
||||
private static void convert(ConvertResult result, Path path) throws Exception {
|
||||
Path tempDirectory = Files.createTempDirectory("jadx-");
|
||||
result.addTempPath(tempDirectory);
|
||||
|
||||
// D8Converter.run(path, tempDirectory);
|
||||
DxConverter.run(path, tempDirectory);
|
||||
|
||||
LOG.debug("Converted to dex: {}", path.toAbsolutePath());
|
||||
result.addConvertedFiles(collectFilesInDir(tempDirectory));
|
||||
}
|
||||
|
||||
private static List<Path> collectFilesInDir(Path tempDirectory) throws IOException {
|
||||
try (Stream<Path> pathStream = Files.walk(tempDirectory)) {
|
||||
return pathStream.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package jadx.plugins.input.javaconvert;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import jadx.api.plugins.JadxPluginInfo;
|
||||
import jadx.api.plugins.input.JadxInputPlugin;
|
||||
import jadx.api.plugins.input.data.ILoadResult;
|
||||
import jadx.api.plugins.input.data.impl.EmptyLoadResult;
|
||||
import jadx.plugins.input.dex.DexFileLoader;
|
||||
import jadx.plugins.input.dex.DexLoadResult;
|
||||
import jadx.plugins.input.dex.DexReader;
|
||||
|
||||
public class JavaConvertPlugin implements JadxInputPlugin {
|
||||
|
||||
@Override
|
||||
public JadxPluginInfo getPluginInfo() {
|
||||
return new JadxPluginInfo("java-convert", "JavaConvert", "Convert .jar and .class files to dex");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ILoadResult loadFiles(List<Path> input) {
|
||||
ConvertResult result = JavaConvertLoader.process(input);
|
||||
if (result.isEmpty()) {
|
||||
result.deleteTemp();
|
||||
return EmptyLoadResult.INSTANCE;
|
||||
}
|
||||
List<DexReader> dexReaders = DexFileLoader.collectDexFiles(result.getConverted());
|
||||
return new DexLoadResult(dexReaders) {
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
result.deleteTemp();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
jadx.plugins.input.javaconvert.JavaConvertPlugin
|
||||
Reference in New Issue
Block a user