feat: allow to load custom input (#1457)
This commit is contained in:
@@ -14,7 +14,7 @@ dependencies {
|
||||
|
||||
testImplementation 'org.apache.commons:commons-lang3:3.12.0'
|
||||
|
||||
testRuntimeOnly(project(':jadx-plugins:jadx-dex-input'))
|
||||
testImplementation(project(':jadx-plugins:jadx-dex-input'))
|
||||
testRuntimeOnly(project(':jadx-plugins:jadx-smali-input'))
|
||||
testRuntimeOnly(project(':jadx-plugins:jadx-java-convert'))
|
||||
testRuntimeOnly(project(':jadx-plugins:jadx-java-input'))
|
||||
|
||||
@@ -13,8 +13,9 @@ public class JadxArgsValidator {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JadxArgsValidator.class);
|
||||
|
||||
public static void validate(JadxArgs args) {
|
||||
checkInputFiles(args);
|
||||
public static void validate(JadxDecompiler jadx) {
|
||||
JadxArgs args = jadx.getArgs();
|
||||
checkInputFiles(jadx, args);
|
||||
validateOutDirs(args);
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
@@ -22,9 +23,9 @@ public class JadxArgsValidator {
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkInputFiles(JadxArgs args) {
|
||||
private static void checkInputFiles(JadxDecompiler jadx, JadxArgs args) {
|
||||
List<File> inputFiles = args.getInputFiles();
|
||||
if (inputFiles.isEmpty()) {
|
||||
if (inputFiles.isEmpty() && jadx.getCustomLoads().isEmpty()) {
|
||||
throw new JadxArgsValidateException("Please specify input file");
|
||||
}
|
||||
for (File inputFile : inputFiles) {
|
||||
@@ -66,19 +67,22 @@ public class JadxArgsValidator {
|
||||
|
||||
@NotNull
|
||||
private static File makeDirFromInput(JadxArgs args) {
|
||||
File outDir;
|
||||
String outDirName;
|
||||
File file = args.getInputFiles().get(0);
|
||||
String name = file.getName();
|
||||
int pos = name.lastIndexOf('.');
|
||||
if (pos != -1) {
|
||||
outDirName = name.substring(0, pos);
|
||||
List<File> inputFiles = args.getInputFiles();
|
||||
if (inputFiles.isEmpty()) {
|
||||
outDirName = JadxArgs.DEFAULT_OUT_DIR;
|
||||
} else {
|
||||
outDirName = name + '-' + JadxArgs.DEFAULT_OUT_DIR;
|
||||
File file = inputFiles.get(0);
|
||||
String name = file.getName();
|
||||
int pos = name.lastIndexOf('.');
|
||||
if (pos != -1) {
|
||||
outDirName = name.substring(0, pos);
|
||||
} else {
|
||||
outDirName = name + '-' + JadxArgs.DEFAULT_OUT_DIR;
|
||||
}
|
||||
}
|
||||
LOG.info("output directory: {}", outDirName);
|
||||
outDir = new File(outDirName);
|
||||
return outDir;
|
||||
return new File(outDirName);
|
||||
}
|
||||
|
||||
private static void checkFile(File file) {
|
||||
|
||||
@@ -98,6 +98,8 @@ public final class JadxDecompiler implements Closeable {
|
||||
|
||||
private final IDecompileScheduler decompileScheduler = new DecompilerScheduler(this);
|
||||
|
||||
private final List<ILoadResult> customLoads = new ArrayList<>();
|
||||
|
||||
public JadxDecompiler() {
|
||||
this(new JadxArgs());
|
||||
}
|
||||
@@ -108,7 +110,7 @@ public final class JadxDecompiler implements Closeable {
|
||||
|
||||
public void load() {
|
||||
reset();
|
||||
JadxArgsValidator.validate(args);
|
||||
JadxArgsValidator.validate(this);
|
||||
LOG.info("loading ...");
|
||||
loadPlugins(args);
|
||||
loadInputFiles();
|
||||
@@ -132,11 +134,20 @@ public final class JadxDecompiler implements Closeable {
|
||||
loadedInputs.add(loadResult);
|
||||
}
|
||||
}
|
||||
loadedInputs.addAll(customLoads);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Loaded using {} inputs plugin in {} ms", loadedInputs.size(), System.currentTimeMillis() - start);
|
||||
}
|
||||
}
|
||||
|
||||
public void addCustomLoad(ILoadResult customLoad) {
|
||||
customLoads.add(customLoad);
|
||||
}
|
||||
|
||||
public List<ILoadResult> getCustomLoads() {
|
||||
return customLoads;
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
root = null;
|
||||
classes = null;
|
||||
|
||||
@@ -57,7 +57,7 @@ public class JadxArgsValidatorOutDirsTest {
|
||||
}
|
||||
|
||||
private void checkOutDirs(String outDir, String srcDir, String resDir) {
|
||||
JadxArgsValidator.validate(args);
|
||||
JadxArgsValidator.validate(new JadxDecompiler(args));
|
||||
LOG.debug("Got dirs: out={}, src={}, res={}", args.getOutDir(), args.getOutDirSrc(), args.getOutDirRes());
|
||||
assertThat(args.getOutDir(), is(toFile(outDir)));
|
||||
assertThat(args.getOutDirSrc(), is(toFile(srcDir)));
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
package jadx.api;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.core.utils.files.FileUtils;
|
||||
import jadx.plugins.input.dex.DexInputPlugin;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
@@ -38,6 +42,20 @@ public class JadxDecompilerTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDirectDexInput() throws IOException {
|
||||
try (JadxDecompiler jadx = new JadxDecompiler();
|
||||
InputStream in = new FileInputStream(getFileFromSampleDir("hello.dex"))) {
|
||||
jadx.addCustomLoad(new DexInputPlugin().loadDexFromInputStream(in, "input"));
|
||||
jadx.load();
|
||||
for (JavaClass cls : jadx.getClasses()) {
|
||||
System.out.println(cls.getCode());
|
||||
}
|
||||
assertThat(jadx.getClasses(), Matchers.hasSize(1));
|
||||
assertThat(jadx.getErrorsCount(), Matchers.is(0));
|
||||
}
|
||||
}
|
||||
|
||||
private static final String TEST_SAMPLES_DIR = "test-samples/";
|
||||
|
||||
public static File getFileFromSampleDir(String fileName) {
|
||||
|
||||
Binary file not shown.
@@ -64,10 +64,7 @@ public class DexFileLoader {
|
||||
if (isStartWithBytes(magic, DexConsts.DEX_FILE_MAGIC) || fileName.endsWith(".dex")) {
|
||||
in.reset();
|
||||
byte[] content = readAllBytes(in);
|
||||
if (options.isVerifyChecksum()) {
|
||||
DexCheckSum.verify(content);
|
||||
}
|
||||
DexReader dexReader = new DexReader(getNextUniqId(), fileName, content);
|
||||
DexReader dexReader = loadDexReader(fileName, content);
|
||||
return Collections.singletonList(dexReader);
|
||||
}
|
||||
if (file != null) {
|
||||
@@ -80,6 +77,13 @@ public class DexFileLoader {
|
||||
}
|
||||
}
|
||||
|
||||
public DexReader loadDexReader(String fileName, byte[] content) {
|
||||
if (options.isVerifyChecksum()) {
|
||||
DexCheckSum.verify(content);
|
||||
}
|
||||
return new DexReader(getNextUniqId(), fileName, content);
|
||||
}
|
||||
|
||||
private List<DexReader> collectDexFromZip(File file) {
|
||||
List<DexReader> result = new ArrayList<>();
|
||||
try {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package jadx.plugins.input.dex;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -13,6 +15,7 @@ import jadx.api.plugins.input.data.ILoadResult;
|
||||
import jadx.api.plugins.input.data.impl.EmptyLoadResult;
|
||||
import jadx.api.plugins.options.JadxPluginOptions;
|
||||
import jadx.api.plugins.options.OptionDescription;
|
||||
import jadx.api.plugins.utils.CommonFileUtils;
|
||||
|
||||
public class DexInputPlugin implements JadxInputPlugin, JadxPluginOptions {
|
||||
public static final String PLUGIN_ID = "dex-input";
|
||||
@@ -38,6 +41,20 @@ public class DexInputPlugin implements JadxInputPlugin, JadxPluginOptions {
|
||||
return new DexLoadResult(dexReaders, closeable);
|
||||
}
|
||||
|
||||
public ILoadResult loadDex(byte[] content, @Nullable String fileName) {
|
||||
String fileLabel = fileName == null ? "input.dex" : fileName;
|
||||
DexReader dexReader = loader.loadDexReader(fileLabel, content);
|
||||
return new DexLoadResult(Collections.singletonList(dexReader), null);
|
||||
}
|
||||
|
||||
public ILoadResult loadDexFromInputStream(InputStream in, @Nullable String fileLabel) {
|
||||
try {
|
||||
return loadDex(CommonFileUtils.loadBytes(in), fileLabel);
|
||||
} catch (Exception e) {
|
||||
throw new DexException("Failed to read input stream", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOptions(Map<String, String> options) {
|
||||
this.options.apply(options);
|
||||
|
||||
@@ -34,7 +34,6 @@ public class DexLoadResult implements ILoadResult {
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
dexReaders.clear();
|
||||
if (closeable != null) {
|
||||
closeable.close();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user