Java字节码的base64转Java源码小工具
在做java内存马相关分析和开发的时候,免不了总是要base64,字节码和java源码各种来回转化,每次都手动操作很麻烦,写个工具自动化把字节码的base64转化为java源码。
其实反向从java源码到base64字符串也有需求,但是涉及到编译以及依赖,所以只需要classtobase64即可,比较简单。
实现
反编译器
这个步骤涉及到了反编译,需要找一个反编译的库,java反编译用的最多的就是jd-core和jadx两个。
分析了一下发现jd-core使用比较简单,但是jd-core是针对于jar包实现的,反编译时传入的class名是一个internalName,也就是org/apache/jsp/ccc.class
这样带有包路径的类名,或者干脆是一个jar包全部反编译,参考jd-core。
但是我的需求是只有一个base64,也就是一个class文件,不知道具体的类名和包名,需要反编译器反编译后告诉我类名,因此不太合适。
所以选择了jadx,使用方法参考Use jadx as a library
其中第二步是要在pom.xml
中添加谷歌仓库来加载aapt的依赖,如下:
<repositories>
<repository>
<id>google</id>
<name>google Public Repositories</name>
<url>https://maven.google.com/</url>
</repository>
</repositories>
第三步中需要按照要反编译的输入类型选择对应插件,这里说的添加插件就是把对应的依赖添加到pom.xml
中,我需要反编译class,使用jadx-java-input
,所以依赖如下:
<!-- https://mvnrepository.com/artifact/io.github.skylot/jadx-core -->
<dependency>
<groupId>io.github.skylot</groupId>
<artifactId>jadx-core</artifactId>
<version>1.4.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.github.skylot/jadx-java-input -->
<dependency>
<groupId>io.github.skylot</groupId>
<artifactId>jadx-java-input</artifactId>
<version>1.4.2</version>
</dependency>
完成后即可参考链接中的代码反编译
最终代码
考虑到方便使用,可以写一个图形界面,也可以用springboot打包一个web使用html写页面,这里写一个工具类,界面部分自由发挥。
jadx在使用的时候需要选择输入的class和结构输出目录,没有提供直接用字节码作为输入的接口(废话,人家是命令行工具),也没必要看源码去改了,用一个目录过度一下,这里选系统的temp目录:
String tempPath = System.getProperty("java.io.tmpdir")+File.separator;
思路是先把base64解码得到字节码写到临时class文件中,用jadx反编译,结果保存到${temp}/output/
,再遍历这个目录找到所有java文件取出类名和内容返回。
效果:
源码:
import jadx.api.JadxArgs;
import jadx.api.JadxDecompiler;
import java.io.*;
import java.util.*;
public class JavaUtil {
public static Map base64Tojava(String base64Data) throws IOException {
byte[] b = Base64.getDecoder().decode(base64Data);
String tempPath = System.getProperty("java.io.tmpdir")+File.separator;
String outputPath = tempPath + "output/";
writeFile(tempPath + "temp.class", b);
JadxArgs jadxArgs = new JadxArgs();
jadxArgs.setInputFile(new File(tempPath + "temp.class"));
jadxArgs.setOutDir(new File(outputPath));
try (JadxDecompiler jadx = new JadxDecompiler(jadxArgs)) {
jadx.load();
jadx.save();
} catch (Exception e) {
e.printStackTrace();
}
List<File> fileList = new ArrayList<>();
findJava(new File(outputPath), fileList);
HashMap map = new HashMap();
getJava(fileList, map);
return map;
}
public static void writeFile(String filepath, byte[] content) throws IOException {
File f = new File(filepath);
FileOutputStream fos = new FileOutputStream(f);
fos.write(content);
fos.close();
}
public static void findJava(File outputFile, List<File> fileList) {
File[] files = outputFile.listFiles();
for (File i : files) {
if (i.isDirectory()) {
findJava(i, fileList);
}
if (i.isFile()) {
if (i.getName().endsWith(".java")) {//判断名
fileList.add(i);
}
}
}
}
public static void getJava(List<File> Files, HashMap map) throws IOException {
for(File f: Files){
String content = getContent(f.getPath());
map.put(f.getName(),content);
}
}
public static String getContent(String filePath) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(filePath));
StringBuilder stringBuilder = new StringBuilder();
String line = null;
String ls = System.getProperty("line.separator");
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
stringBuilder.append(ls);
}
stringBuilder.deleteCharAt(stringBuilder.length() - 1);
reader.close();
String content = stringBuilder.toString();
return content;
}
public static void main(String[] args) throws IOException {
String base64data = "yv66vgAAADQAZg......";
Map m = base64Tojava(base64data);
System.out.println(m.get("TestGrizzlyFilter.java"));
}