Java类编译与反编译基础

在渗透测试的时候需要审计的代码通常是class文件或者jar包,那么我们应该如何审计呢?让我们先来学习一下什么是Java源码和字节码。

1. Java类编译与反编译基础

简单的说Java源码就是未经编译的.java文件,我们可以很轻松的阅读其中的代码逻辑,而字节码.class文件则是.java文件经过编译之后产生的字节码文件,因为.class文件是编译后的二进制文件所以我们是无法直接阅读的,只能通过反编译工具将二进制文件转换成java代码或者ASM代码

示例代码Test.java:

  1. /**
  2. * @author yz
  3. */
  4. public class Test {
  5. public static void hello() {
  6. System.out.println("Hello~");
  7. }
  8. public void world() {
  9. System.out.println("World!");
  10. }
  11. public static void main(String[] args) {
  12. hello();
  13. }
  14. }

Test.java编译执行流程:

image-20200919110424641

Test.java 源码、字节码

4

由于class文件的可读性较差,通常我们需要使用Java反编译工具来反编译代码。我们通常会使用到JD-GUIIDEA Fernflower插件Bytecode-ViewerFernflowerJADJBEJEB 等工具来反编译class。

其中JD-GUI可能是目前反编译中使用的最多的工具了,但是个人觉得JD-GUI的反编译能力远不如经过IDEA(IDEA应该是使用的改版后的Fernflower),因为IDEA默认支持对jarclass的反编译,所以我个人强烈推荐使用IDEA来反编译class代码。

当然,反编译工具很多时候也不是万能的,JD-GUI经常遇到无法反编译或反编译过程中程序直接崩溃的情况,遇到这类情况我们通常可以使用IDEA反编译试试,如果IDEA也无法反编译可以使用JBE来加载class文件读取程序的字节码,如果JBE仍无法读取类信息还可以使用JDK自带的javap命令来读取class类字节码,如果上诉所有的方法都无法反编译,那么恐怕是这个类本身就存在无法编译问题要么可能就是类文件被加密处理过。可能你会说java编译的class不是说不可以加密吗?没错,这里所说的加密其实是为了保护编译后的class代码不可反编译,通过实现自定义ClassLoaderloadClass加密后的类方式而已,这种加密方式曾在实战中也有遇到。

2. 反编译整个Jar技巧

通常我们在某些特殊的场景下拿到的只是jar文件,那么我们应该如何反编译整个jar包的class文件呢?

2.1. Fernflower

Fernflower可以很轻松的实现jar的完整反编译,执行如下命令即可: java -jar fernflower.jar jarToDecompile.jar decomp/ 其中jarToDecompile.jar是需要反编译的jar文件,decomp是反编译后的class文件所存放的目录。需要注意的是Fernflower如遇无法反编译的情况可能会生成空的java文件!

2.2. JD-GUI

JD-GUI是一个带GUI的反编译工具,在JD-GUI的菜单中点击File—>Save All Sources即可反编译jar。

2.3. IDEA

IDEA默认就支持jar包反编译,同时还支持class文件名(⇧⌘F)、类方法名称(⇧⌘O)搜索。

2.4. Bytecode-Viewer

FernFlower提供了GUI版本Bytecode-Viewer,Bytecode-Viewer提供了直接反编译的classjarzipapkdex功能,直接拖拽jar就可以直接对整个jar进行反编译了。

4.1

2.5. Find命令

find命令并不能支持Java反编译,但是find命令可以非常方便的搜索经过编译后的二进制文件中的内容,所以有的时候使用find命令通常是最简单实用的,直接解压jar包然后使用find命令搜索: find ./ -type f -name "*.class" |xargs grep XXXX 即可搞定。

2.6 使用Find命令和Fernflower实现批量反编译jar

当我们只有项目war包且源码经过打包后发布到WEB-INF/lib的情况下,我们不得不去找出待审计源码的具体jar文件并反编译。遇到这种情况我们可以巧妙的使用find命令来反编译所有目标的jar包。

这里以jcms的一个非常老版本为例,jcms最终给客户部署的war包中源码并不是在WEB-INF/classes目录下,而是将整个jcms系统按模块打包成了多个jar包放在了WEB-INF/lib目录下。我们可以通过搜索com.hanweb包名称来找出所有jar中包含了jcms的文件并通过Fernflower来反编译。

  1. java -jar /Users/yz/Desktop/javaweb-decomplier/javaweb-decomplier.jar -dgs=1 $(find /Users/yz/Desktop/jcms/WEB-INF/lib/ -type f -name "*.jar" |xargs grep "com.hanweb" |awk '{print $3}') /Users/yz/jcms-decomplier

执行上面的命令后会在jcms-decomplier目录下看到所有的jar已经被Fernflower反编译了。

4.2

依赖的jar: javaweb-decomplierIntellij java-decompiler

3. IntelliJ IDEA 推荐

IntelliJ IDEAJetbrains出品的一款非常强大的Java IDE,IDEA提供了强大的代码搜索、近乎完美的反编译、动态调试等功能可以最大程度的辅助我们代码审计。

不可以否认,与IDEA相比虽然Eclipse和Netbeans也有与之类似的功能,但是在真正的实战体验中个人更倾向于使用IDEA,虽然曾经的我也是一个重度Eclipse开发者。