<h2>前言</h2>
<p><strong>Java 反编译</strong>,一听可能觉得高深莫测,其实反编译并不是什么特别高级的操作,Java 对于 Class 字节码文件的生成有着严格的要求,如果你非常熟悉 Java 虚拟机规范,了解 Class 字节码文件中一些字节的作用,那么理解反编译的原理并不是什么问题。<br>
甚至像下面这样的 Class 文件你都能看懂一二。</p>
<p style="text-align: center"><img alt="" src="https://beijingoptbbs.oss-cn-hangzhou.aliyuncs.com/jb/2426819-a39ab928008699f958924cab9c3b36f4.jpg"></p>
<p>一般在逆向研究和代码分析中,反编译用到的比较多。不过在日常开发中,有时候只是简单的看一下所用依赖类的反编译,也是十分重要的。</p>
<p>恰好最近工作中也需要用到 <strong>Java 反编译</strong>,所以这篇文章介绍目前常见的的几种 Java 反编译工具的使用,在文章的最后也会通过<strong>编译速度</strong>、<strong>语法支持</strong>以及<strong>代码可读性</strong>三个维度,对它们<strong>进行测试</strong>,分析几款工具的<strong>优缺点</strong>。</p>
<h2>Procyon</h2>
<p>Github 链接:https://github.com/mstrobel/procyon<br>
<strong>Procyon</strong> 不仅仅是反编译工具,它其实是专注于 Java 代码的生成和分析的一整套的 Java 元编程工具。<br>
主要包括下面几个部分:</p>
<ul>
<li>Core Framework</li>
<li>Reflection Framework</li>
<li>Expressions Framework</li>
<li>Compiler Toolset (Experimental)</li>
<li>Java Decompiler (Experimental)</li>
</ul>
<p>可以看到反编译只是 <strong>Procyon</strong> 的其中一个模块,<strong>Procyon</strong> 原来托管于 bitbucket,后来迁移到了 GitHub,根据 GitHub 的提交记录来看,也有将近两年没有更新了。不过也有依赖 <strong>Procyon</strong> 的其他的开源反编译工具如** decompiler-procyon**,更新频率还是很高的,下面也会选择这个工具进行反编译测试。</p>
<h2>使用 Procyon</h2>
<div class="blockcode">
<pre class="brush:java;">
<!-- 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></pre>
</div>
<p>写一个简单的反编译测试。</p>
<div class="blockcode">
<pre class="brush:java;">
package com.wdbyte.decompiler;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Iterator;
import java.util.List;
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;
/**
* Procyon 反编译测试
*
* @author https://github.com/niumoo
* @date 2021/05/15
*/
public class ProcyonTest {
public static void main(String[] args) throws IOException {
Long time = procyon("decompiler.jar", "procyon_output_jar");
System.out.println(String.format("decompiler time: %dms", time));
}
public static Long procyon(String source,String targetPath) throws IOException {
long start = System.currentTimeMillis();
Path outDir = Paths.get(targetPath);
Path archive = Paths.get(source);
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.toString());
}
System.out.println("Compilation results: " + res.getDecompiledFiles().size() + " succeeded, " + res.getFailures().size() + " failed.");
dec.close();
Long end = System.currentTimeMillis();
return end - start;
}
}</pre>
</div>
<p>Procyon 在反编译时会实时输出反编译文件数量的进度情况,最后还会统计反编译成功和失败的 Class 文件数量。</p>
<blockquote>
<p>....<br>
五月 15, 2021 10:58:28 下午 org.jboss.windup.decompiler.procyon.ProcyonDecompiler$3 call<br>
信息: Decompiling 650 / 783<br>
五月 15, 2021 10:58 |
|