基于Swing 实现反编译 .class
文件和.jar
文件,支持批量反编译
,增加代码编辑和格式化功能,并支持反编译后文件导出保存。
具体功能点:
- 打开 Class 文件:点击
Open Class File
按钮,选择要反编译的 .class 文件。反编译结果将显示在文本区域。 - 打开 Jar 文件:点击
Open Jar File
按钮,选择要反编译的 .class 文件。反编译结果将显示在文本区域。 - 保存反编译文件:点击
Save Decompiled File
按钮,选择保存位置,将反编译后的源代码保存到文件。
引入依赖
<dependencies>
<dependency>
<groupId>org.benf</groupId>
<artifactId>cfr</artifactId>
<version>0.151</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.9</version>
</dependency>
</dependencies>
主框架类
package com.dzy.decompiler;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
/**
* 主框架类,包含反编译器的主要界面
*/
public class MainFrame extends JFrame {
private JTextArea outputArea;
private JButton openClassButton;
private JButton openJarButton;
private JButton saveButton;
public MainFrame() {
setTitle("Class File Decompiler");
setSize(800, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setMinimumSize(new Dimension(600, 400));
initComponents();
setLayout(new BorderLayout());
add(new JScrollPane(outputArea), BorderLayout.CENTER);
add(createButtonPanel(), BorderLayout.NORTH);
}
/**
* 初始化组件
*/
private void initComponents() {
outputArea = new JTextArea();
outputArea.setEditable(true);
openClassButton = new JButton("Open Class File");
openJarButton = new JButton("Open JAR File");
saveButton = new JButton("Save Decompiled File");
// 设置按钮动作监听器
openClassButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
int result = fileChooser.showOpenDialog(MainFrame.this);
if (result == JFileChooser.APPROVE_OPTION) {
File selectedFile = fileChooser.getSelectedFile();
String decompiledCode = Decompiler.decompileClassFile(selectedFile);
outputArea.setText(decompiledCode);
}
}
});
openJarButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
int result = fileChooser.showOpenDialog(MainFrame.this);
if (result == JFileChooser.APPROVE_OPTION) {
File selectedFile = fileChooser.getSelectedFile();
String decompiledCode = Decompiler.decompileJarFile(selectedFile);
outputArea.setText(decompiledCode);
}
}
});
saveButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
int result = fileChooser.showSaveDialog(MainFrame.this);
if (result == JFileChooser.APPROVE_OPTION) {
File saveFile = fileChooser.getSelectedFile();
Decompiler.saveDecompiledFile(saveFile, outputArea.getText());
}
}
});
}
/**
* 创建按钮面板
* @return JPanel 包含所有操作按钮
*/
private JPanel createButtonPanel() {
JPanel panel = new JPanel();
panel.add(openClassButton);
panel.add(openJarButton);
panel.add(saveButton);
return panel;
}
/**
* 主方法,启动应用程序
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new MainFrame().setVisible(true);
}
});
}
}
反编译工具类
package com.dzy.decompiler;
import org.benf.cfr.reader.Main;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* 反编译工具类
*/
public class Decompiler {
/**
* 反编译 class 文件
* @param classFile 要反编译的 class 文件
* @return 反编译后的源代码
*/
public static String decompileClassFile(File classFile) {
if (classFile == null || !classFile.exists()) {
return "Invalid class file.";
}
List<String> options = new ArrayList<>();
options.add(classFile.getAbsolutePath());
options.add("--outputdir");
options.add("temp"); // 临时目录存储反编译结果
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(outputStream);
PrintStream originalOut = System.out;
System.setOut(printStream);
try {
Main.main(options.toArray(new String[0]));
} finally {
System.setOut(originalOut);
}
return outputStream.toString();
}
/**
* 反编译 jar 文件
* @param jarFile 要反编译的 jar 文件
* @return 反编译后的源代码
*/
public static String decompileJarFile(File jarFile) {
if (jarFile == null || !jarFile.exists()) {
return "Invalid JAR file.";
}
StringBuilder result = new StringBuilder();
try (ZipFile zipFile = new ZipFile(jarFile)) {
zipFile.stream()
.filter(entry -> entry.getName().endsWith(".class"))
.forEach(entry -> {
try {
InputStream is = zipFile.getInputStream(entry);
File tempClassFile = File.createTempFile("temp", ".class");
Files.copy(is, tempClassFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
String decompiledCode = decompileClassFile(tempClassFile);
result.append(decompiledCode).append("\n\n");
} catch (IOException e) {
e.printStackTrace();
}
});
} catch (IOException e) {
e.printStackTrace();
}
return result.toString();
}
/**
* 将反编译后的源代码保存到文件
* @param file 要保存的文件
* @param content 源代码内容
*/
public static void saveDecompiledFile(File file, String content) {
try {
Files.write(file.toPath(), content.getBytes(), StandardOpenOption.CREATE);
} catch (IOException e) {
e.printStackTrace();
}
}
}
JSON 格式化工具类
package com.dzy.decompiler;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
/**
* JSON 格式化工具类
*/
public class JsonFormatter {
/**
* 格式化JSON字符串
* @param json 输入的JSON字符串
* @return 格式化后的JSON字符串
*/
public static String formatJson(String json) {
try {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
Object jsonObj = gson.fromJson(json, Object.class);
return gson.toJson(jsonObj);
} catch (JsonSyntaxException e) {
return "Invalid JSON: " + e.getMessage();
}
}
}