大家好,欢迎来到IT知识分享网。
目录
目标
在spring boot项目中,通过给定的文件地址,将*.jar或*.class反编译为*.java。
方式一:cfr
pom引用
<!-- https://mvnrepository.com/artifact/org.benf/cfr --> <dependency> <groupId>org.benf</groupId> <artifactId>cfr</artifactId> <version>0.151</version> </dependency>
java实现
package com.demo.decompile.cfr; import org.benf.cfr.reader.api.CfrDriver; import org.benf.cfr.reader.util.getopt.OptionsImpl; import org.springframework.util.ResourceUtils; import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.List; / * @Author: huangzh * @Date: 2024/3/5 19:43 / public class CFRDemo {
public static void main(String[] args) throws IOException {
String sourceJar = "D:/xx/xx/xx.jar"; Path sourceJarPath = Paths.get(sourceJar); String sourceJarFileName = sourceJarPath.getFileName().toString().replaceFirst("[.][^.]+$", ""); File file = ResourceUtils.getFile("classpath:"); String relativePath = file.getPath(); String path = relativePath.substring(0, relativePath.lastIndexOf(File.separatorChar)); String outputPath = path + File.separator + "cfr" + File.separator + sourceJarFileName; Long time = cfr(sourceJar, outputPath); System.out.println(String.format("decompiler time: %dms, outputPath: %s", time, outputPath)); } public static Long cfr(String source, String targetPath) throws IOException {
Long start = System.currentTimeMillis(); // source jar List<String> files = new ArrayList<>(); files.add(source); // target dir HashMap<String, String> outputMap = new HashMap<>(); outputMap.put("outputdir", targetPath); OptionsImpl options = new OptionsImpl(outputMap); CfrDriver cfrDriver = new CfrDriver.Builder().withBuiltOptions(options).build(); cfrDriver.analyse(files); Long end = System.currentTimeMillis(); return (end - start); } }
方式二:jd-core
pom引用
<!-- https://mvnrepository.com/artifact/org.jd/jd-core --> <!-- 如果下载不下来,可使用华为镜像:https://repo.huaweicloud.com/repository/maven/org/jd/jd-core/1.1.3/jd-core-1.1.3.pom--> <dependency> <groupId>org.jd</groupId> <artifactId>jd-core</artifactId> <version>1.1.3</version> </dependency>
java实现
package com.demo.decompile.jdcore; import org.jd.core.v1.ClassFileToJavaSourceDecompiler; import org.jd.core.v1.api.loader.Loader; import org.jd.core.v1.api.printer.Printer; import org.springframework.util.ResourceUtils; import org.springframework.util.StringUtils; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Enumeration; import java.util.HashMap; import java.util.jar.JarFile; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; / * @Author: huangzh * @Date: 2024/3/5 10:36 / public class JDCoreDemo {
public static void main(String[] args) throws Exception {
File file = ResourceUtils.getFile("classpath:"); String relativePath = file.getPath(); String path = JDCoreDecompiler.substringBeforeLast(relativePath, File.separator); System.out.println(path); JDCoreDecompiler jdCoreDecompiler = new JDCoreDecompiler(); Long time = jdCoreDecompiler.decompiler("D:\\xx\\xx\\xx.jar", path + File.separator + "JDCore"); System.out.println(String.format("decompiler time: %dms", time)); } } class JDCoreDecompiler{
private ClassFileToJavaSourceDecompiler decompiler = new ClassFileToJavaSourceDecompiler(); // 存放字节码 private HashMap<String,byte[]> classByteMap = new HashMap<>(); / * 注意:没有考虑一个 Java 类编译出多个 Class 文件的情况。 * * @param source * @param target * @return * @throws Exception */ public Long decompiler(String source,String target) throws Exception {
long start = System.currentTimeMillis(); String sourceFileName = substringAfterLast(source, File.separator); String sourcePathName = substringBeforeLast(sourceFileName, "."); target = target + File.separator + sourcePathName; // 解压 archive(source); for (String className : classByteMap.keySet()) {
String path = substringBeforeLast(className, "/"); String name = substringAfterLast(className, "/"); if (contains(name, "$")) {
name = substringAfterLast(name, "$"); } name = StringUtils.replace(name, ".class", ".java"); decompiler.decompile(loader, printer, className); String context = printer.toString(); Path targetPath = Paths.get(target + "/" + path + "/" + name); if (!Files.exists(Paths.get(target + "/" + path))) {
Files.createDirectories(Paths.get(target + "/" + path)); } Files.deleteIfExists(targetPath); Files.createFile(targetPath); Files.write(targetPath, context.getBytes()); } return System.currentTimeMillis() - start; } / * 解压 * @param path * @throws IOException */ private void archive(String path) throws IOException {
try (ZipFile archive = new JarFile(new File(path))) {
Enumeration<? extends ZipEntry> entries = archive.entries(); while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement(); if (!entry.isDirectory()) {
String name = entry.getName(); if (name.endsWith(".class")) {
byte[] bytes = null; try (InputStream stream = archive.getInputStream(entry)) {
bytes = toByteArray(stream); } classByteMap.put(name, bytes); } } } } } private Loader loader = new Loader() {
@Override public byte[] load(String internalName) {
return classByteMap.get(internalName); } @Override public boolean canLoad(String internalName) {
return classByteMap.containsKey(internalName); } }; private Printer printer = new Printer() {
protected static final String TAB = " "; protected static final String NEWLINE = "\n"; protected int indentationCount = 0; protected StringBuilder sb = new StringBuilder(); @Override public String toString() {
String toString = sb.toString(); sb = new StringBuilder(); return toString; } @Override public void start(int maxLineNumber, int majorVersion, int minorVersion) {
} @Override public void end() {
} @Override public void printText(String text) {
sb.append(text); } @Override public void printNumericConstant(String constant) {
sb.append(constant); } @Override public void printStringConstant(String constant, String ownerInternalName) {
sb.append(constant); } @Override public void printKeyword(String keyword) {
sb.append(keyword); } @Override public void printDeclaration(int type, String internalTypeName, String name, String descriptor) {
sb.append(name); } @Override public void printReference(int type, String internalTypeName, String name, String descriptor, String ownerInternalName) {
sb.append(name); } @Override public void indent() {
this.indentationCount++; } @Override public void unindent() {
this.indentationCount--; } @Override public void startLine(int lineNumber) {
for (int i=0; i<indentationCount; i++) sb.append(TAB); } @Override public void endLine() {
sb.append(NEWLINE); } @Override public void extraLine(int count) {
while (count-- > 0) sb.append(NEWLINE); } @Override public void startMarker(int type) {
} @Override public void endMarker(int type) {
} }; / * Represents a failed index search. */ public static final int INDEX_NOT_FOUND = -1; / * The empty String {@code ""}. */ public static final String EMPTY = ""; public static String substringBeforeLast(final String str, final String separator) {
if (isEmpty(str) || isEmpty(separator)) {
return str; } final int pos = str.lastIndexOf(separator); if (pos == INDEX_NOT_FOUND) {
return str; } return str.substring(0, pos); } / * Checks if a CharSequence is empty ("") or null. * @param cs * @return */ public static boolean isEmpty(final CharSequence cs) {
return cs == null || cs.length() == 0; } / * Checks if CharSequence contains a search CharSequence, handling {@code null}. * This method uses {@link String#indexOf(String)} if possible. * @param seq * @param searchSeq * @return */ public static boolean contains(final CharSequence seq, final CharSequence searchSeq) {
if (seq == null || searchSeq == null) {
return false; } return indexOf(seq, searchSeq, 0) >= 0; } / * Used by the indexOf(CharSequence methods) as a green implementation of indexOf. * @param cs * @param searchChar * @param start * @return */ static int indexOf(final CharSequence cs, final CharSequence searchChar, final int start) {
if (cs instanceof String) {
return ((String) cs).indexOf(searchChar.toString(), start); } if (cs instanceof StringBuilder) {
return ((StringBuilder) cs).indexOf(searchChar.toString(), start); } if (cs instanceof StringBuffer) {
return ((StringBuffer) cs).indexOf(searchChar.toString(), start); } return cs.toString().indexOf(searchChar.toString(), start); } / * Gets the substring after the last occurrence of a separator. * The separator is not returned. * @param str * @param separator * @return */ public static String substringAfterLast(final String str, final String separator) {
if (isEmpty(str)) {
return str; } if (isEmpty(separator)) {
return EMPTY; } final int pos = str.lastIndexOf(separator); if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) {
return EMPTY; } return str.substring(pos + separator.length()); } public static byte[] toByteArray(InputStream inputStream) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead); } return outputStream.toByteArray(); } }
方式三:procyon.jar
jar下载
java实现
package com.demo.decompile.procyon; import org.springframework.util.ResourceUtils; import java.io.*; import java.nio.file.Path; import java.nio.file.Paths; / * @Author: huangzh * @Date: 2024/3/7 11:46 / public class ProcyonJarDemo {
public static void main(String[] args) throws FileNotFoundException {
String sourceJar = "D:/xx/xx/xx.jar"; Path sourceJarPath = Paths.get(sourceJar); String sourceJarFileName = sourceJarPath.getFileName().toString().replaceFirst("[.][^.]+$", ""); File file = ResourceUtils.getFile("classpath:"); String relativePath = file.getPath(); String path = relativePath.substring(0, relativePath.lastIndexOf(File.separatorChar)); String outputPath = path + File.separator + "procyon" + File.separator + sourceJarFileName; String[] command = {
"java", "-jar", "src/main/resources/procyon/procyon-decompiler-0.6.0.jar", "-jar", sourceJar, "-o", outputPath }; try {
Process process = new ProcessBuilder(command).start(); InputStream inputStream = process.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); String line; while ((line = reader.readLine()) != null) {
System.out.println("info: " + line); } InputStream inputStreamErr = process.getErrorStream(); BufferedReader readerErr = new BufferedReader(new InputStreamReader(inputStreamErr)); String lineErr; while ((lineErr = readerErr.readLine()) != null) {
System.out.println("error: " + lineErr); } // waiting for command execution to complete int exitCode = process.waitFor(); System.out.println("decompile completed,exit code: " + exitCode); System.out.println("output dir: " + outputPath); } catch (IOException | InterruptedException e) {
e.printStackTrace(); } } }
方式四:procyon
pom引用
<!-- https://mvnrepository.com/artifact/org.jboss.windup.decompiler/decompiler-procyon --> <dependency> <groupId>org.jboss.windup.decompiler</groupId> <artifactId>decompiler-procyon</artifactId> <version>5.1.4.Final</version> </dependency>
java实现
package com.demo.decompile.procyon; import org.jboss.windup.decompiler.api.DecompilationFailure; import org.jboss.windup.decompiler.api.DecompilationListener; import org.jboss.windup.decompiler.api.DecompilationResult; import org.jboss.windup.decompiler.api.Decompiler; import org.jboss.windup.decompiler.procyon.ProcyonDecompiler; import org.springframework.util.ResourceUtils; import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Iterator; import java.util.List; / * @Author: huangzh * @Date: 2024/3/5 18:42 / public class ProcyonDemo {
public static void main(String[] args) throws IOException {
String sourceJar = "D:/xx/xx/xx.jar"; Path sourceJarPath = Paths.get(sourceJar); String sourceJarFileName = sourceJarPath.getFileName().toString().replaceFirst("[.][^.]+$", ""); File file = ResourceUtils.getFile("classpath:"); String relativePath = file.getPath(); String path = relativePath.substring(0, relativePath.lastIndexOf(File.separatorChar)); String outputPath = path + File.separator + "procyon" + File.separator + sourceJarFileName; Long time = procyon(sourceJar, outputPath); System.out.println(String.format("decompiler time: %dms", time)); } / * 解析存在问题,不推荐 * * @param source * @param targetPath * @return * @throws IOException */ public static Long procyon(String source, String targetPath) throws IOException {
long start = System.currentTimeMillis(); Path archive = Paths.get(source); Path outDir = Paths.get(targetPath); Decompiler dec = new ProcyonDecompiler(); DecompilationResult res = dec.decompileArchive(archive, outDir, new DecompilationListener() {
public void decompilationProcessComplete() {
System.out.println("decompilationProcessComplete"); } public void decompilationFailed(List<String> inputPath, String message) {
System.out.println("decompilationFailed"); } public void fileDecompiled(List<String> inputPath, String outputPath) {
} public boolean isCancelled() {
return false; } }); if (!res.getFailures().isEmpty()) {
StringBuilder sb = new StringBuilder(); sb.append("Failed decompilation of " + res.getFailures().size() + " classes: "); Iterator failureIterator = res.getFailures().iterator(); while (failureIterator.hasNext()) {
DecompilationFailure dex = (DecompilationFailure) failureIterator.next(); sb.append(System.lineSeparator() + " ").append(dex.getMessage()); } System.out.println(sb); } System.out.println("Compilation results: " + res.getDecompiledFiles().size() + " succeeded, " + res.getFailures().size() + " failed."); dec.close(); Long end = System.currentTimeMillis(); return end - start; } }
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/109761.html