├── .gitignore ├── README.md ├── image └── example.gif ├── pom.xml └── src └── main ├── java ├── UI │ ├── ChangeZ_Tool.form │ ├── ChangeZ_Tool.java │ └── JavaSource.java └── Util │ └── JavaUtil.java └── resources └── META-INF └── MANIFEST.MF /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | /target/ 26 | /out/ 27 | /.idea/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Java内存马分析辅助工具 2 | 3 | 目的是快速完成重复性的工作,内存马编写测试分析总离不开下面三部分的互相转换 4 | 5 | java源码 <--> class字节码 <--> base64编码 6 | 7 | 其中java编译为class需要对应环境依赖,工具不考虑做,剩下的就是class字节码和base64互转,以及base64直接查看java源码。 8 | 9 | 通过base64保存class文件和直接查看java源码的功能。 10 | 11 | ### 使用方法 12 | 13 | ```bash 14 | java -jar GuiTool-1.0.jar 15 | ``` 16 | 17 | ### 待办 18 | - [x] base64保存class文件 19 | - [x] base64直接查看java源码 20 | - [ ] 上传class转化为base64 21 | - [ ] ... 22 | 23 | 24 | ![](image/example.gif) 25 | 26 | ### 参考链接 27 | https://github.com/java-decompiler/jd-core -------------------------------------------------------------------------------- /image/example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YPS233/JavaGuiTool/189bba1741e18e21cc8a301917fb1cfd3e9e322f/image/example.gif -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.example 8 | GuiTool 9 | 0.1 10 | 11 | 12 | 13 | 14 | io.github.skylot 15 | jadx-core 16 | 1.4.2 17 | 18 | 19 | 20 | io.github.skylot 21 | jadx-java-input 22 | 1.4.2 23 | 24 | 25 | 26 | 27 | 28 | google 29 | google Public Repositories 30 | https://maven.google.com/ 31 | 32 | 33 | 34 | 35 | 8 36 | 8 37 | 38 | 39 | 40 | 41 | 42 | org.apache.maven.plugins 43 | maven-assembly-plugin 44 | 45 | 46 | package 47 | 48 | single 49 | 50 | 51 | 52 | 53 | 54 | UI.ChangeZ_Tool 55 | 56 | 57 | 58 | 59 | jar-with-dependencies 60 | 61 | false 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /src/main/java/UI/ChangeZ_Tool.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 |
75 | -------------------------------------------------------------------------------- /src/main/java/UI/ChangeZ_Tool.java: -------------------------------------------------------------------------------- 1 | package UI; 2 | 3 | import Util.JavaUtil; 4 | 5 | import javax.swing.*; 6 | import java.awt.event.ActionEvent; 7 | import java.awt.event.ActionListener; 8 | import java.io.File; 9 | import java.io.FileOutputStream; 10 | import java.io.IOException; 11 | import java.util.*; 12 | 13 | public class ChangeZ_Tool { 14 | private JTextArea textAreaBase64; 15 | private JButton Button_toclass; 16 | private JPanel root; 17 | private JButton button_tojava; 18 | 19 | public ChangeZ_Tool() { 20 | textAreaBase64.setLineWrap(true); //激活自动换行功能 21 | textAreaBase64.setWrapStyleWord(true); // 激活断行不断字功能 22 | 23 | Button_toclass.addActionListener(new ActionListener() { 24 | @Override 25 | public void actionPerformed(ActionEvent e) { 26 | String base64Data = textAreaBase64.getText(); 27 | System.out.println(base64Data); 28 | byte[] b = Base64.getDecoder().decode(base64Data); 29 | 30 | JFileChooser chooser = new JFileChooser(); 31 | chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); 32 | int returnVal = chooser.showOpenDialog(Button_toclass); 33 | if (returnVal == JFileChooser.APPROVE_OPTION) { //如果符合文件类型 34 | 35 | String dirPath = chooser.getSelectedFile().getAbsolutePath(); //获取绝对路径 36 | String filepath = dirPath + File.separator + "res.class"; 37 | System.out.println(filepath); 38 | File saveFile = new File(filepath); 39 | try { 40 | FileOutputStream fos = new FileOutputStream(saveFile); 41 | fos.write(b); 42 | fos.flush(); 43 | fos.close(); 44 | JOptionPane.showMessageDialog(root, "保存成功,路径为:" + filepath); 45 | 46 | }catch (IOException exception){ 47 | exception.printStackTrace(); 48 | } 49 | 50 | System.out.println("You chose to open this file: " + chooser.getSelectedFile().getName()); //输出相对路径 51 | }else { 52 | System.out.println("not a dir path"); 53 | } 54 | 55 | 56 | 57 | } 58 | }); 59 | button_tojava.addActionListener(new ActionListener() { 60 | @Override 61 | public void actionPerformed(ActionEvent e) { 62 | String base64Data = textAreaBase64.getText(); 63 | Map javaMap = null; 64 | try { 65 | javaMap = JavaUtil.base64Tojava(base64Data); 66 | }catch (IllegalArgumentException ei){ 67 | JOptionPane.showMessageDialog(null, "非法的base64字符串", "错误", JOptionPane.INFORMATION_MESSAGE); 68 | 69 | } 70 | catch (IOException ex) { 71 | throw new RuntimeException(ex); 72 | } 73 | 74 | JavaSource js = new JavaSource(javaMap); 75 | 76 | } 77 | }); 78 | } 79 | 80 | 81 | public static void main(String[] args) { 82 | JFrame frame = new JFrame("ChangeZ_Tool"); 83 | frame.setContentPane(new ChangeZ_Tool().root); 84 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 85 | frame.setSize(600,400); 86 | //frame.pack(); 87 | frame.setVisible(true); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/UI/JavaSource.java: -------------------------------------------------------------------------------- 1 | package UI; 2 | 3 | import javax.swing.*; 4 | import javax.swing.event.ListSelectionEvent; 5 | import javax.swing.event.ListSelectionListener; 6 | import java.awt.*; 7 | import java.awt.event.MouseEvent; 8 | import java.awt.event.MouseListener; 9 | import java.util.ArrayList; 10 | import java.util.Map; 11 | import java.util.Vector; 12 | 13 | public class JavaSource implements MouseListener { 14 | 15 | Vector leftData; 16 | Vector rightData; 17 | JList left; 18 | 19 | JTextPane right; 20 | JScrollPane leftPanel, rightPanel; 21 | 22 | Map data; 23 | 24 | public JavaSource(Map data) throws HeadlessException { 25 | 26 | this.data = data; 27 | 28 | ArrayList keys = new ArrayList<>(); 29 | for(String s: data.keySet()){ 30 | keys.add(s); 31 | } 32 | 33 | 34 | JDialog frame = new JDialog(); 35 | frame.setTitle("Java Source Code"); 36 | frame.setVisible(true); 37 | frame.setSize(800,600); 38 | 39 | leftData = new Vector<>(keys); 40 | left = new JList<>(leftData); 41 | leftPanel = new JScrollPane(left); 42 | 43 | rightData = new Vector<>(); 44 | right = new JTextPane(); 45 | rightPanel = new JScrollPane(right); 46 | 47 | frame.setLayout(new GridLayout(1, 4)); 48 | frame.add(leftPanel); 49 | frame.add(rightPanel); 50 | 51 | left.addListSelectionListener(new ListSelectionListener() { 52 | @Override 53 | public void valueChanged(ListSelectionEvent e) { 54 | // 获取所有被选中的选项索引 55 | int[] indices = left.getSelectedIndices(); 56 | // 获取选项数据的 ListModel 57 | ListModel listModel = left.getModel(); 58 | 59 | String currentSelect = null; 60 | // 输出选中的选项 61 | for (int index : indices) { 62 | currentSelect = listModel.getElementAt(index); 63 | // System.out.println("选中: " + index + " = " + listModel.getElementAt(index)); 64 | } 65 | // System.out.println(data.get(currentSelect)); 66 | String showCode = data.get(currentSelect); 67 | // left.setListData(data.get(currentSelect)); 68 | right.setText(showCode); 69 | } 70 | }); 71 | 72 | 73 | } 74 | 75 | @Override 76 | public void mouseClicked(MouseEvent e) { 77 | 78 | } 79 | 80 | private void doubleClick(MouseEvent e) { 81 | 82 | } 83 | 84 | @Override 85 | public void mousePressed(MouseEvent e) { 86 | 87 | } 88 | 89 | @Override 90 | public void mouseReleased(MouseEvent e) { 91 | 92 | } 93 | 94 | @Override 95 | public void mouseEntered(MouseEvent e) { 96 | 97 | } 98 | 99 | @Override 100 | public void mouseExited(MouseEvent e) { 101 | 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/Util/JavaUtil.java: -------------------------------------------------------------------------------- 1 | package Util; 2 | 3 | import jadx.api.JadxArgs; 4 | import jadx.api.JadxDecompiler; 5 | 6 | import javax.swing.*; 7 | import java.io.*; 8 | import java.nio.file.Paths; 9 | import java.util.*; 10 | import java.nio.file.Files; 11 | 12 | 13 | public class JavaUtil { 14 | public static Map base64Tojava(String base64Data) throws IOException { 15 | byte[] b = Base64.getDecoder().decode(base64Data); 16 | String tempPath = System.getProperty("java.io.tmpdir"); 17 | String outputPath = tempPath + "output/"; 18 | writeFile(tempPath + "temp.class", b); 19 | System.out.println(outputPath); 20 | 21 | JadxArgs jadxArgs = new JadxArgs(); 22 | jadxArgs.setInputFile(new File(tempPath + "temp.class")); 23 | jadxArgs.setOutDir(new File(outputPath)); 24 | try (JadxDecompiler jadx = new JadxDecompiler(jadxArgs)) { 25 | jadx.load(); 26 | jadx.save(); 27 | } catch (Exception e) { 28 | JOptionPane.showMessageDialog(null, "反编译失败", "错误", JOptionPane.INFORMATION_MESSAGE); 29 | e.printStackTrace(); 30 | } 31 | List fileList = new ArrayList<>(); 32 | findJava(new File(outputPath), fileList); 33 | 34 | HashMap map = new HashMap(); 35 | getJava(fileList, map); 36 | 37 | // delete temp dir 38 | deleteDirectory(new File(outputPath)); 39 | return map; 40 | } 41 | 42 | 43 | public static void writeFile(String filepath, byte[] content) throws IOException { 44 | File f = new File(filepath); 45 | FileOutputStream fos = new FileOutputStream(f); 46 | fos.write(content); 47 | fos.close(); 48 | } 49 | 50 | public static void findJava(File outputFile, List fileList) { 51 | File[] files = outputFile.listFiles(); 52 | for (File i : files) { 53 | if (i.isDirectory()) { 54 | findJava(i, fileList); 55 | } 56 | if (i.isFile()) { 57 | if (i.getName().endsWith(".java")) {//判断名 58 | fileList.add(i); 59 | } 60 | } 61 | 62 | } 63 | } 64 | 65 | public static void getJava(List Files, HashMap map) throws IOException { 66 | for(File f: Files){ 67 | String content = getContent(f.getPath()); 68 | map.put(f.getName(),content); 69 | } 70 | } 71 | 72 | public static String getContent(String filePath) throws IOException { 73 | BufferedReader reader = new BufferedReader(new FileReader(filePath)); 74 | StringBuilder stringBuilder = new StringBuilder(); 75 | String line = null; 76 | String ls = System.getProperty("line.separator"); 77 | while ((line = reader.readLine()) != null) { 78 | stringBuilder.append(line); 79 | stringBuilder.append(ls); 80 | } 81 | 82 | stringBuilder.deleteCharAt(stringBuilder.length() - 1); 83 | reader.close(); 84 | 85 | String content = stringBuilder.toString(); 86 | return content; 87 | } 88 | 89 | public static void deleteDirectory(File directory) { 90 | 91 | //文件是否为目录 92 | if(directory.isDirectory()) { 93 | File[] files = directory.listFiles(); 94 | 95 | //如果目录包含任何文件 96 | if(files != null) { 97 | for(File file : files) { 98 | 99 | //如果子目录为非空,则进行递归调用 100 | deleteDirectory(file); 101 | } 102 | } 103 | } 104 | directory.delete(); 105 | } 106 | 107 | public static void main(String[] args) throws IOException { 108 | String base64data = "yv66vgAAADQAZgoAFQA1CgA2ADcHADgKAAMAOQgAOgoACAA7CAA8BwA9BwA+CgAIAD8KAEAAQQcAQggAQwkARABFCgBGAEcKAAkASAoAQABJBwBKCgAVAEsHAEwHAE0BAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEANExvcmcvc3UxOC9tZW1zaGVsbC90ZXN0L2dsYXNzZmlzaC9UZXN0R3JpenpseUZpbHRlcjsBAApoYW5kbGVSZWFkAQBmKExvcmcvZ2xhc3NmaXNoL2dyaXp6bHkvZmlsdGVyY2hhaW4vRmlsdGVyQ2hhaW5Db250ZXh0OylMb3JnL2dsYXNzZmlzaC9ncml6emx5L2ZpbHRlcmNoYWluL05leHRBY3Rpb247AQABYwEAEUxqYXZhL2xhbmcvQ2xhc3M7AQABbQEAGkxqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7AQADY3R4AQA2TG9yZy9nbGFzc2Zpc2gvZ3JpenpseS9maWx0ZXJjaGFpbi9GaWx0ZXJDaGFpbkNvbnRleHQ7AQAKY29ubmVjdGlvbgEANkxvcmcvZ2xhc3NmaXNoL2dyaXp6bHkvbmlvL3RyYW5zcG9ydC9UQ1BOSU9Db25uZWN0aW9uOwEAB2NoYW5uZWwBACVMamF2YS9uaW8vY2hhbm5lbHMvU2VsZWN0YWJsZUNoYW5uZWw7AQAWTG9jYWxWYXJpYWJsZVR5cGVUYWJsZQEAFExqYXZhL2xhbmcvQ2xhc3M8Kj47AQANU3RhY2tNYXBUYWJsZQcATAcATgcAOAcATwcASgEACkV4Y2VwdGlvbnMHAFABAApTb3VyY2VGaWxlAQAWVGVzdEdyaXp6bHlGaWx0ZXIuamF2YQwAFgAXBwBODABRAFIBADRvcmcvZ2xhc3NmaXNoL2dyaXp6bHkvbmlvL3RyYW5zcG9ydC9UQ1BOSU9Db25uZWN0aW9uDABTAFQBABxzdW4ubmlvLmNoLlNvY2tldENoYW5uZWxJbXBsDABVAFYBAAV3cml0ZQEAD2phdmEvbGFuZy9DbGFzcwEAE2phdmEvbmlvL0J5dGVCdWZmZXIMAFcAWAcAWQwAWgBbAQAQamF2YS9sYW5nL09iamVjdAEAGUhUVFAvMS4xIDIwMCBPSyBzdTE4IHl5ZHMHAFwMAF0AXgcAXwwAYABhDABiAGMMAGQAZQEAE2phdmEvbGFuZy9FeGNlcHRpb24MAB0AHgEAMm9yZy9zdTE4L21lbXNoZWxsL3Rlc3QvZ2xhc3NmaXNoL1Rlc3RHcml6emx5RmlsdGVyAQAsb3JnL2dsYXNzZmlzaC9ncml6emx5L2ZpbHRlcmNoYWluL0Jhc2VGaWx0ZXIBADRvcmcvZ2xhc3NmaXNoL2dyaXp6bHkvZmlsdGVyY2hhaW4vRmlsdGVyQ2hhaW5Db250ZXh0AQAjamF2YS9uaW8vY2hhbm5lbHMvU2VsZWN0YWJsZUNoYW5uZWwBABNqYXZhL2lvL0lPRXhjZXB0aW9uAQAMZ2V0Q2xvc2VhYmxlAQAjKClMb3JnL2dsYXNzZmlzaC9ncml6emx5L0Nsb3NlYWJsZTsBAApnZXRDaGFubmVsAQAnKClMamF2YS9uaW8vY2hhbm5lbHMvU2VsZWN0YWJsZUNoYW5uZWw7AQAHZm9yTmFtZQEAJShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9DbGFzczsBABFnZXREZWNsYXJlZE1ldGhvZAEAQChMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzczspTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBABhqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2QBAA1zZXRBY2Nlc3NpYmxlAQAEKFopVgEAIWphdmEvbmlvL2NoYXJzZXQvU3RhbmRhcmRDaGFyc2V0cwEABVVURl84AQAaTGphdmEvbmlvL2NoYXJzZXQvQ2hhcnNldDsBABBqYXZhL2xhbmcvU3RyaW5nAQAIZ2V0Qnl0ZXMBAB4oTGphdmEvbmlvL2NoYXJzZXQvQ2hhcnNldDspW0IBAAR3cmFwAQAZKFtCKUxqYXZhL25pby9CeXRlQnVmZmVyOwEABmludm9rZQEAOShMamF2YS9sYW5nL09iamVjdDtbTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwAhABQAFQAAAAAAAgABABYAFwABABgAAAAvAAEAAQAAAAUqtwABsQAAAAIAGQAAAAYAAQAAABMAGgAAAAwAAQAAAAUAGwAcAAAAAQAdAB4AAgAYAAABBQAHAAYAAABQK7YAAsAAA00stgAEThIFuAAGOgQZBBIHBL0ACFkDEglTtgAKOgUZBQS2AAsZBS0EvQAMWQMSDbIADrYAD7gAEFO2ABFXpwAFOgQqK7cAE7AAAQANAEUASAASAAQAGQAAACYACQAAABcACAAYAA0AGwAUABwAJgAdACwAHgBFACIASAAgAEoAIwAaAAAAPgAGABQAMQAfACAABAAmAB8AIQAiAAUAAABQABsAHAAAAAAAUAAjACQAAQAIAEgAJQAmAAIADQBDACcAKAADACkAAAAMAAEAFAAxAB8AKgAEACsAAAAZAAL/AEgABAcALAcALQcALgcALwABBwAwAQAxAAAABAABADIAAQAzAAAAAgA0"; 109 | Map m = base64Tojava(base64data); 110 | System.out.println(m); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: UI.ChangeZ_Tool 3 | 4 | --------------------------------------------------------------------------------