0x00 前言

最近,larry破解的BurpSuite Pro过期了,不久,mxcx放出了一个BurpSuite Pro的无限版,由BurpUnlimited启动,并且开源了BurpUnlimited的源代码,可供分析。

BurpUnlimited可以分为两部分,一是有main函数的larry.lau.BurpLoader及依赖模块,另一部分是有premain函数的mxcx.javaagent及依赖模块,premain函数是Java Instrumentation的入口函数。将BurpUnlimited分为这两部分是显而易见的,因为在BurpUnlimited的readme中,开发者说一种运行BurpUnlimited的方法是

1
java -javaagent:BurpUnlimited.jar -agentpath:lib/libfaketime<osverion> -jar BurpUnlimited.jar

显然,BurpUnlimited能直接运行,说明它有main函数,能作为javaagent加载,说明它又是一个有premain函数的Instrumentation。
在分析这两部分之前,先说一些背景。

0x01 背景

Java Instrumentation允许开发者访问从JVM中加载的类,并且允许对它的字节码做修改,加入我们自己的代码,这些都是在运行时完成的。并且它仍然遵从安全管理器的限制。Java Instrumentation通过-javaagent加载。

在调试Java Instrumentation时,建议使用远程调试,远程调试的命令行参数如下:

1
-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005

在这里,建议将suspend参数设置为y,这样可以保证调试者连接上来之后才开始启动应用,否则在调试代码运行和调试器连接上来之间有时间差,不好控制代码的运行。

0x02 分析

在这里仅分析一下BurpUnlimited对larry的BurpLoader的破解。在larry.lau.BurpLoader中,绝大多数代码是larrylau对BurpSuite Pro的破解,mxcx主要添加了BurpUnlimited.setupValidationEnv();BurpUnlimited.uninstallFakeTime();这两行代码

1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] array) { 
try {
BurpUnlimited.setupValidationEnv();
final String s = BurpLoader.z[3];
//......
StartBurp.main(array);
BurpUnlimited.uninstallFakeTime();
}catch(/*...*/){
//.....
}
}

我们先来看看BurpUnlimited.setupValidationEnv();BurpUnlimited.setupValidationEnv()方法主要做了这么几件事

  • 获取参数,判断是否添加了-javaagent和-agentlib等参数,如果没有添加,说明BurpUnlimited是以双击的方式直接启动的,那么程序构造一个shell命令

    1
    java -javaagent:BurpUnlimited.jar -agentpath:lib/libfaketime<osverion> -jar BurpUnlimited.jar

    运行这个有完整参数的命令重新启动。

  • 利用反射,将JVM的Managed Bean对象里面的jvm成员里面的vmArgs置为[]以绕过BurpSuite中的反调试。
  • 将系统参数faketime.absolute.ms设置为1420045200000,即Thu Jan 01 01:00:00 CST 2015

下面分析一下这个类中几行关键的代码。line118 RuntimeMXBean mxb = ManagementFactory.getRuntimeMXBean();获取当前运行的jvm的managed bean。line120-line152,判断jvm的参数中是否有-javaagent和-agentpath,如果没有,补充完整,运行完整shell命令。line154,

1
StrictPA.setValue(StrictPA.getValue(mxb, "jvm"), "vmArgs", Collections.unmodifiableList(new ArrayList<Object>()));

通过反射,将managed bean中的jvm中的vmArg重置为[],重置之前是jvm的参数是['-javaagent:BurpUnlimited.jar',' -agentpath:lib/libfaketime<osverion>']。重置后可以绕过BurpSuite的反调试。实际上,
在安全管理器没做限定的情况下,反射可以使用setAccessible(true)去除类似于private的访问限制,并且随心所欲的修改受访问限制的变量。而在默认情况下,安全管理器是不启用的。line160-line166,将faketime.absolute.ms设置为2015年,并判断是否成功修改System.currentTimeMillis()的实现。这里使用了faketime项目https://github.com/faketime-java/faketime。

BurpUnlimited.setupValidationEnv();之后就是larrylau的破解,破解完毕之后,调用StartBurp.main(array);启动Burp,之后就调用BurpUnlimited.uninstallFakeTime();将时间改回了真实的时间。代码如下

1
2
StartBurp.main(array);
BurpUnlimited.uninstallFakeTime();

可见BurpSuite仅在启动时对License进行了判断。

下面是分析一下Java Instrumentation,首先,java instrumentation有一个premain函数作为入口,类似于main函数,在这个函数中,可以为Instrumentation添加一个transformer对字节码进行操作。在transformer类中,必须实现transform方法来对字节码进行修改。有时为了安全或者保密,会对字节码加密,必须依赖特定的解密instrumentation才可以被jvm加载。字节码的解密就可以在transform方法中。这个Instrumentation将larry/lau/burp/ui/TestDisclaimerburp/uzd的字节码直接修改成了TestDisclaimerClassuzdClass

1
2
String TestDisclaimerClass = "cafebabe0000003300250a0....20019";
String uzdClass = "cafebabe00000033006f0a0....2003f";

这两个字符串对应的字节码是BurpUnlimited/others/aloneclasses/burp/uzd.javaBurpUnlimited/others/aloneclasses/larry/lau/burp/ui/TestDisclaimer.java的字节码,它替换了原来的larrylau声明
20171206_1.png

和BurpSuite中的License界面

20171206_2.png

0x03 总结

mxcx使用一个java原生agent修改Java API获取的时间,使License在校验时获取的本地时间永远在License过期时间之前,这样,这个License将永远有效,不会过期。

0x04 关于作者

  • c0d3p1ut0s c0d3p1ut0s@gmail.com