BurpUnlimited分析
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
11public 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
2StartBurp.main(array);
BurpUnlimited.uninstallFakeTime();
可见BurpSuite仅在启动时对License进行了判断。
下面是分析一下Java Instrumentation,首先,java instrumentation有一个premain函数作为入口,类似于main函数,在这个函数中,可以为Instrumentation添加一个transformer
对字节码进行操作。在transformer类中,必须实现transform
方法来对字节码进行修改。这个Instrumentation将larry/lau/burp/ui/TestDisclaimer
和burp/uzd
的字节码直接修改成了TestDisclaimerClass
和uzdClass
1
2String TestDisclaimerClass = "cafebabe0000003300250a0....20019";
String uzdClass = "cafebabe00000033006f0a0....2003f";
这两个字符串对应的字节码是BurpUnlimited/others/aloneclasses/burp/uzd.java
和BurpUnlimited/others/aloneclasses/larry/lau/burp/ui/TestDisclaimer.java
的字节码,它替换了原来的larrylau声明
和BurpSuite中的License界面
0x03 总结
mxcx使用一个java原生agent修改Java API获取的时间,使License在校验时获取的本地时间永远在License过期时间之前,这样,这个License将永远有效,不会过期。
0x04 关于作者
- c0d3p1ut0s
c0d3p1ut0s@gmail.com