fix: load .class files

This commit is contained in:
Skylot
2020-08-10 12:20:42 +01:00
parent 13609a5c44
commit 444ea9ec7e
6 changed files with 101 additions and 14 deletions
@@ -1,40 +1,86 @@
package jadx.plugins.input.javaconvert;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.objectweb.asm.ClassReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.api.plugins.utils.ZipSecurity;
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);
}
}
}
processJars(input, result);
processClassFiles(input, result);
return result;
}
private static boolean isJavaFile(Path path) {
String fileName = path.getFileName().toString();
return fileName.endsWith(".jar")
|| fileName.endsWith(".class");
private static void processJars(List<Path> input, ConvertResult result) {
PathMatcher jarMatcher = FileSystems.getDefault().getPathMatcher("glob:**.jar");
input.stream()
.filter(path -> Files.isRegularFile(path, LinkOption.NOFOLLOW_LINKS))
.filter(jarMatcher::matches)
.forEach(path -> {
try {
convertJar(result, path);
} catch (Exception e) {
LOG.error("Failed to convert file: " + path.toAbsolutePath(), e);
}
});
}
private static void convert(ConvertResult result, Path path) throws Exception {
private static void processClassFiles(List<Path> input, ConvertResult result) {
PathMatcher jarMatcher = FileSystems.getDefault().getPathMatcher("glob:**.class");
List<Path> clsFiles = input.stream()
.filter(path -> Files.isRegularFile(path, LinkOption.NOFOLLOW_LINKS))
.filter(jarMatcher::matches)
.collect(Collectors.toList());
if (clsFiles.isEmpty()) {
return;
}
try {
Path jarFile = Files.createTempFile("jadx-", ".jar");
try (JarOutputStream jo = new JarOutputStream(Files.newOutputStream(jarFile))) {
for (Path file : clsFiles) {
String clsName = getNameFromClassFile(file);
if (clsName == null || !ZipSecurity.isValidZipEntryName(clsName)) {
throw new IOException("Can't read class name from file: " + file);
}
addFileToJar(jo, file, clsName + ".class");
}
}
result.addTempPath(jarFile);
LOG.debug("Packed class files {} into jar {}", clsFiles, jarFile);
convertJar(result, jarFile);
} catch (Exception e) {
LOG.error("Error process class files", e);
}
}
public static String getNameFromClassFile(Path file) throws IOException {
try (InputStream in = Files.newInputStream(file)) {
ClassReader classReader = new ClassReader(in);
return classReader.getClassName();
}
}
private static void convertJar(ConvertResult result, Path path) throws Exception {
Path tempDirectory = Files.createTempDirectory("jadx-");
result.addTempPath(tempDirectory);
@@ -45,10 +91,34 @@ public class JavaConvertLoader {
}
private static List<Path> collectFilesInDir(Path tempDirectory) throws IOException {
PathMatcher dexMatcher = FileSystems.getDefault().getPathMatcher("glob:**.dex");
try (Stream<Path> pathStream = Files.walk(tempDirectory, 1)) {
return pathStream
.filter(p -> Files.isRegularFile(p, LinkOption.NOFOLLOW_LINKS))
.filter(dexMatcher::matches)
.collect(Collectors.toList());
}
}
public static void addFileToJar(JarOutputStream jar, Path source, String entryName) throws IOException {
try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(source))) {
JarEntry entry = new JarEntry(entryName);
entry.setTime(Files.getLastModifiedTime(source, LinkOption.NOFOLLOW_LINKS).toMillis());
jar.putNextEntry(entry);
copyStream(in, jar);
jar.closeEntry();
}
}
public static void copyStream(InputStream input, OutputStream output) throws IOException {
byte[] buffer = new byte[8 * 1024];
while (true) {
int count = input.read(buffer);
if (count == -1) {
break;
}
output.write(buffer, 0, count);
}
}
}