Commit f8d57d92 authored by Skylot's avatar Skylot

core: decompile '.class' files

parent ebbe6db3
......@@ -20,7 +20,7 @@ import com.beust.jcommander.ParameterException;
public final class JadxCLIArgs implements IJadxArgs {
@Parameter(description = "<input file> (.dex, .apk or .jar)")
@Parameter(description = "<input file> (.dex, .apk, .jar or .class)")
protected List<String> files;
@Parameter(names = {"-d", "--output-dir"}, description = "output directory")
......
......@@ -2,6 +2,7 @@ ext.jadxClasspath = 'clsp-data/android-4.3.jar'
dependencies {
compile files('lib/dx-1.8.jar')
compile 'org.ow2.asm:asm:5.0.3'
runtime files(jadxClasspath)
}
......
package jadx.core.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import org.objectweb.asm.ClassReader;
public class AsmUtils {
private AsmUtils() {
}
public static String getNameFromClassFile(File file) throws IOException {
FileInputStream in = new FileInputStream(file);
ClassReader classReader = new ClassReader(in);
return classReader.getClassName();
}
}
package jadx.core.utils.files;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
public class FileUtils {
private FileUtils() {
}
public static void addFileToJar(JarOutputStream jar, File source, String entryName) throws IOException {
BufferedInputStream in = null;
try {
JarEntry entry = new JarEntry(entryName);
entry.setTime(source.lastModified());
jar.putNextEntry(entry);
in = new BufferedInputStream(new FileInputStream(source));
byte[] buffer = new byte[8192];
while (true) {
int count = in.read(buffer);
if (count == -1) {
break;
}
jar.write(buffer, 0, count);
}
jar.closeEntry();
} finally {
if (in != null) {
in.close();
}
}
}
}
package jadx.core.utils.files;
import jadx.core.utils.AsmUtils;
import jadx.core.utils.exceptions.DecodeException;
import jadx.core.utils.exceptions.JadxException;
import jadx.core.utils.exceptions.JadxRuntimeException;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
......@@ -35,37 +37,44 @@ public class InputFile {
if (fileName.endsWith(".dex")) {
return new Dex(file);
}
if (fileName.endsWith(".class")) {
return loadFromClassFile(file);
}
if (fileName.endsWith(".apk")) {
byte[] data = openDexFromZip(file);
if (data == null) {
throw new JadxRuntimeException("File 'classes.dex' not found in file: " + file);
Dex dex = loadFromZip(file);
if (dex == null) {
throw new IOException("File 'classes.dex' not found in file: " + file);
}
return new Dex(data);
return dex;
}
if (fileName.endsWith(".jar")) {
// check if jar contains 'classes.dex'
byte[] data = openDexFromZip(file);
if (data != null) {
return new Dex(data);
}
try {
LOG.info("converting to dex: {} ...", fileName);
JavaToDex j2d = new JavaToDex();
byte[] ba = j2d.convert(file.getAbsolutePath());
if (ba.length == 0) {
throw new JadxException(j2d.isError() ? j2d.getDxErrors() : "Empty dx output");
} else if (j2d.isError()) {
LOG.warn("dx message: " + j2d.getDxErrors());
}
return new Dex(ba);
} catch (Throwable e) {
throw new DecodeException("java class to dex conversion error:\n " + e.getMessage(), e);
Dex dex = loadFromZip(file);
if (dex != null) {
return dex;
}
return loadFromJar(file);
}
throw new DecodeException("Unsupported input file format: " + file);
}
private byte[] openDexFromZip(File file) throws IOException {
private static Dex loadFromJar(File jarFile) throws DecodeException {
try {
LOG.info("converting to dex: {} ...", jarFile.getName());
JavaToDex j2d = new JavaToDex();
byte[] ba = j2d.convert(jarFile.getAbsolutePath());
if (ba.length == 0) {
throw new JadxException(j2d.isError() ? j2d.getDxErrors() : "Empty dx output");
} else if (j2d.isError()) {
LOG.warn("dx message: " + j2d.getDxErrors());
}
return new Dex(ba);
} catch (Throwable e) {
throw new DecodeException("java class to dex conversion error:\n " + e.getMessage(), e);
}
}
private static Dex loadFromZip(File file) throws IOException {
ZipFile zf = new ZipFile(file);
ZipEntry dex = zf.getEntry("classes.dex");
if (dex == null) {
......@@ -87,7 +96,19 @@ public class InputFile {
}
zf.close();
}
return bytesOut.toByteArray();
return new Dex(bytesOut.toByteArray());
}
private static Dex loadFromClassFile(File file) throws IOException, DecodeException {
File outFile = File.createTempFile("jadx-tmp-", System.nanoTime() + ".jar");
outFile.deleteOnExit();
FileOutputStream out = new FileOutputStream(outFile);
JarOutputStream jo = new JarOutputStream(out);
String clsName = AsmUtils.getNameFromClassFile(file);
FileUtils.addFileToJar(jo, file, clsName + ".class");
jo.close();
out.close();
return loadFromJar(outFile);
}
public File getFile() {
......
......@@ -7,17 +7,15 @@ import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.visitors.DepthTraversal;
import jadx.core.dex.visitors.IDexTreeVisitor;
import jadx.core.utils.files.FileUtils;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import static org.hamcrest.CoreMatchers.containsString;
......@@ -94,7 +92,7 @@ public abstract class InternalJadxTest extends TestUtils {
File temp = File.createTempFile("jadx-tmp-", System.nanoTime() + ".jar");
JarOutputStream jo = new JarOutputStream(new FileOutputStream(temp));
for (File file : list) {
add(file, path + "/" + file.getName(), jo);
FileUtils.addFileToJar(jo, file, path + "/" + file.getName());
}
jo.close();
if (deleteTmpJar) {
......@@ -127,29 +125,6 @@ public abstract class InternalJadxTest extends TestUtils {
return list;
}
private void add(File source, String entryName, JarOutputStream target) throws IOException {
BufferedInputStream in = null;
try {
JarEntry entry = new JarEntry(entryName);
entry.setTime(source.lastModified());
target.putNextEntry(entry);
in = new BufferedInputStream(new FileInputStream(source));
byte[] buffer = new byte[1024];
while (true) {
int count = in.read(buffer);
if (count == -1) {
break;
}
target.write(buffer, 0, count);
}
target.closeEntry();
} finally {
if (in != null) {
in.close();
}
}
}
// Use only for debug purpose
@Deprecated
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment