未验证 提交 1832f2ae 编写于 作者: S Skylot

feat: allow to load custom input (#1457)

上级 1ec127c3
...@@ -14,7 +14,7 @@ dependencies { ...@@ -14,7 +14,7 @@ dependencies {
testImplementation 'org.apache.commons:commons-lang3:3.12.0' 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-smali-input'))
testRuntimeOnly(project(':jadx-plugins:jadx-java-convert')) testRuntimeOnly(project(':jadx-plugins:jadx-java-convert'))
testRuntimeOnly(project(':jadx-plugins:jadx-java-input')) testRuntimeOnly(project(':jadx-plugins:jadx-java-input'))
......
...@@ -13,8 +13,9 @@ public class JadxArgsValidator { ...@@ -13,8 +13,9 @@ public class JadxArgsValidator {
private static final Logger LOG = LoggerFactory.getLogger(JadxArgsValidator.class); private static final Logger LOG = LoggerFactory.getLogger(JadxArgsValidator.class);
public static void validate(JadxArgs args) { public static void validate(JadxDecompiler jadx) {
checkInputFiles(args); JadxArgs args = jadx.getArgs();
checkInputFiles(jadx, args);
validateOutDirs(args); validateOutDirs(args);
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
...@@ -22,9 +23,9 @@ public class JadxArgsValidator { ...@@ -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(); List<File> inputFiles = args.getInputFiles();
if (inputFiles.isEmpty()) { if (inputFiles.isEmpty() && jadx.getCustomLoads().isEmpty()) {
throw new JadxArgsValidateException("Please specify input file"); throw new JadxArgsValidateException("Please specify input file");
} }
for (File inputFile : inputFiles) { for (File inputFile : inputFiles) {
...@@ -66,19 +67,22 @@ public class JadxArgsValidator { ...@@ -66,19 +67,22 @@ public class JadxArgsValidator {
@NotNull @NotNull
private static File makeDirFromInput(JadxArgs args) { private static File makeDirFromInput(JadxArgs args) {
File outDir;
String outDirName; String outDirName;
File file = args.getInputFiles().get(0); List<File> inputFiles = args.getInputFiles();
String name = file.getName(); if (inputFiles.isEmpty()) {
int pos = name.lastIndexOf('.'); outDirName = JadxArgs.DEFAULT_OUT_DIR;
if (pos != -1) {
outDirName = name.substring(0, pos);
} else { } 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); LOG.info("output directory: {}", outDirName);
outDir = new File(outDirName); return new File(outDirName);
return outDir;
} }
private static void checkFile(File file) { private static void checkFile(File file) {
......
...@@ -98,6 +98,8 @@ public final class JadxDecompiler implements Closeable { ...@@ -98,6 +98,8 @@ public final class JadxDecompiler implements Closeable {
private final IDecompileScheduler decompileScheduler = new DecompilerScheduler(this); private final IDecompileScheduler decompileScheduler = new DecompilerScheduler(this);
private final List<ILoadResult> customLoads = new ArrayList<>();
public JadxDecompiler() { public JadxDecompiler() {
this(new JadxArgs()); this(new JadxArgs());
} }
...@@ -108,7 +110,7 @@ public final class JadxDecompiler implements Closeable { ...@@ -108,7 +110,7 @@ public final class JadxDecompiler implements Closeable {
public void load() { public void load() {
reset(); reset();
JadxArgsValidator.validate(args); JadxArgsValidator.validate(this);
LOG.info("loading ..."); LOG.info("loading ...");
loadPlugins(args); loadPlugins(args);
loadInputFiles(); loadInputFiles();
...@@ -132,11 +134,20 @@ public final class JadxDecompiler implements Closeable { ...@@ -132,11 +134,20 @@ public final class JadxDecompiler implements Closeable {
loadedInputs.add(loadResult); loadedInputs.add(loadResult);
} }
} }
loadedInputs.addAll(customLoads);
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("Loaded using {} inputs plugin in {} ms", loadedInputs.size(), System.currentTimeMillis() - start); 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() { private void reset() {
root = null; root = null;
classes = null; classes = null;
......
...@@ -57,7 +57,7 @@ public class JadxArgsValidatorOutDirsTest { ...@@ -57,7 +57,7 @@ public class JadxArgsValidatorOutDirsTest {
} }
private void checkOutDirs(String outDir, String srcDir, String resDir) { 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()); LOG.debug("Got dirs: out={}, src={}, res={}", args.getOutDir(), args.getOutDirSrc(), args.getOutDirRes());
assertThat(args.getOutDir(), is(toFile(outDir))); assertThat(args.getOutDir(), is(toFile(outDir)));
assertThat(args.getOutDirSrc(), is(toFile(srcDir))); assertThat(args.getOutDirSrc(), is(toFile(srcDir)));
......
package jadx.api; package jadx.api;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL; import java.net.URL;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import jadx.core.utils.files.FileUtils; import jadx.core.utils.files.FileUtils;
import jadx.plugins.input.dex.DexInputPlugin;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.notNullValue;
...@@ -38,6 +42,20 @@ public class JadxDecompilerTest { ...@@ -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/"; private static final String TEST_SAMPLES_DIR = "test-samples/";
public static File getFileFromSampleDir(String fileName) { public static File getFileFromSampleDir(String fileName) {
......
...@@ -64,10 +64,7 @@ public class DexFileLoader { ...@@ -64,10 +64,7 @@ public class DexFileLoader {
if (isStartWithBytes(magic, DexConsts.DEX_FILE_MAGIC) || fileName.endsWith(".dex")) { if (isStartWithBytes(magic, DexConsts.DEX_FILE_MAGIC) || fileName.endsWith(".dex")) {
in.reset(); in.reset();
byte[] content = readAllBytes(in); byte[] content = readAllBytes(in);
if (options.isVerifyChecksum()) { DexReader dexReader = loadDexReader(fileName, content);
DexCheckSum.verify(content);
}
DexReader dexReader = new DexReader(getNextUniqId(), fileName, content);
return Collections.singletonList(dexReader); return Collections.singletonList(dexReader);
} }
if (file != null) { if (file != null) {
...@@ -80,6 +77,13 @@ public class DexFileLoader { ...@@ -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) { private List<DexReader> collectDexFromZip(File file) {
List<DexReader> result = new ArrayList<>(); List<DexReader> result = new ArrayList<>();
try { try {
......
package jadx.plugins.input.dex; package jadx.plugins.input.dex;
import java.io.Closeable; import java.io.Closeable;
import java.io.InputStream;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -13,6 +15,7 @@ import jadx.api.plugins.input.data.ILoadResult; ...@@ -13,6 +15,7 @@ import jadx.api.plugins.input.data.ILoadResult;
import jadx.api.plugins.input.data.impl.EmptyLoadResult; import jadx.api.plugins.input.data.impl.EmptyLoadResult;
import jadx.api.plugins.options.JadxPluginOptions; import jadx.api.plugins.options.JadxPluginOptions;
import jadx.api.plugins.options.OptionDescription; import jadx.api.plugins.options.OptionDescription;
import jadx.api.plugins.utils.CommonFileUtils;
public class DexInputPlugin implements JadxInputPlugin, JadxPluginOptions { public class DexInputPlugin implements JadxInputPlugin, JadxPluginOptions {
public static final String PLUGIN_ID = "dex-input"; public static final String PLUGIN_ID = "dex-input";
...@@ -38,6 +41,20 @@ public class DexInputPlugin implements JadxInputPlugin, JadxPluginOptions { ...@@ -38,6 +41,20 @@ public class DexInputPlugin implements JadxInputPlugin, JadxPluginOptions {
return new DexLoadResult(dexReaders, closeable); 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 @Override
public void setOptions(Map<String, String> options) { public void setOptions(Map<String, String> options) {
this.options.apply(options); this.options.apply(options);
......
...@@ -34,7 +34,6 @@ public class DexLoadResult implements ILoadResult { ...@@ -34,7 +34,6 @@ public class DexLoadResult implements ILoadResult {
@Override @Override
public void close() throws IOException { public void close() throws IOException {
dexReaders.clear();
if (closeable != null) { if (closeable != null) {
closeable.close(); closeable.close();
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册