0×01 Java反编译工具
Java反编译提供了在线的反汇编方式,同时也给出几款反编译工具作为参考,罗列如下:
1. Procyon
https://bitbucket.org/mstrobel/procyon/wiki/Java%20Decompiler
2. CFR
http://www.benf.org/other/cfr/
3. JD
http://jd.benow.ca/
4. Fernflower
https://github.com/fesh0r/fernflower
5. JAD(非开源)
http://www.javadecompilers.com/jad
0×02 反编译BurpLoader
在Mac为了方便,我直接使用Jd-gui来载入Burploader.jar,但是很显然的能看到已经经过了混淆了。转换成字节码打开,如下:
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
|
// Original Bytecode:
//
// 0: bipush 12
// 2: anewarray Ljava/lang/String;
// 5: dup
// 6: iconst_0
// 7: ldc “/u0002/u001bW/tY/u0002/”
// 9: jsr 216
// 12: aastore
// 13: dup
// 14: iconst_1
// 15: ldc “2C/fBN/u0016Y/nV/u001c/u0007FER/u000f/b”
// 17: jsr 216
// 20: aastore
// 21: dup
// 22: iconst_2
// 23: ldc “/u0004^/u0017A@5_/u0004C/u001a$^/u0017A”
// 25: jsr 216
// 28: aastore
// 29: dup
// 30: iconst_3
// 31: ldc “*e/f///f/u0013X”
// 33: jsr 216
// 36: aastore
// 37: dup
// 38: iconst_4
// 39: ldc “/u000bJ/f_”
// 41: jsr 216
// 44: aastore
// 45: dup
// 46: iconst_5
// 47: ldc “II/u0010C/u001e”
// 49: jsr 216
|
根据乌云Drops的资料来看,混淆的算法依旧没变是Zelix KlassMaster(http://www.zelix.com/klassmaster/index.html),这个提问中同时提到了一些其他的 混淆器(http://stackoverflow.com/questions/13098606/decompiler-bytecode-and- obfuscators)。在参考链接Defcon的议题中也提到了这个混淆器的特征。我们这里用DirtyJoe(http://dirty- joe.com/)来帮反混出ZKM加密的字符串信息,使用其的Py脚本(http://dirty-joe.com/help /python_scripting.php)。
打开DirtyJoe载入Burploader.class(先解压Burploader.jar),然后宣导Method的标签栏,中间有两项没有名字 的函数clinit,往下找可以找到ZKM的加密Key.然后在Constant Pool中找到加密过的常量的值,右键选择Run Python Script,载入ZKM的解密脚本,并修正Py代码中的Key值,则可以解出加密串的内容,如图所示:
依次解出加密串,并尝试还原程序流程。我们来对比一下目前能下载到且没有混淆过的BurpLoader的代码(http://pan.baidu.com/share/link?shareid=442575&uk=2466540631),删减部分常量:
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
|
package larry.lau;
import burp.StartBurp;
import java.lang.reflect.Field;
import java.util.prefs.Preferences;
import javax.swing.JOptionPane;
public class BurpLoader
{
public static final String readme1 = “——————————————”;
public static final String readme2 = “ x ”;
public static final String readme3 = “ x “;
public static final String readme4 = “ x ”;
public static final String readme5 = “ x “;
public static final String readme6 = “ x”;
public static final String readme7 = “ larry_lau@163.com “;
public static final String readme0 = “——————————————”;
private static final String[] strData = {
“a”,
“b”,
“c”,
“d”,
“e”,
“f”,
“g”,
“h” };
private static final String[] clzzData = { “burp.ecc”, “burp.voc”, “burp.jfc”,
“burp.gtc”, “burp.zi”, “burp.q4c”, “burp.pid”, “burp.y0b” };
private static final String[] fieldData = { “b”, “b”, “c”, “c”, “c”, “b”, “c”, “c” };
private static final String tip = “This program can not be used for commercial purposes!”;
private static final String errortip = “This program can only run with burpsuite_pro_v1.5.01.jar”;
private static final String[] keys = { “license1″, “uG4NTkffOhFN/on7RT1nbw==” };
private static final String[] vals = {
“like base64 string”,
“like base64 string” };
public static void main(String[] args)
{
try
{
int ret = JOptionPane.showOptionDialog(null, “This program can not be used for commercial purposes!”, “BurpLoader by larry_lau@163.com”,
0, 2, null, new String[] { “I Accept”, “I Decline” }, null);
if (ret == 0)
{
for (int i = 0; i < clzzData.length; i++)
{
Class<?> clzz = Class.forName(clzzData[i]);
Field field = clzz.getDeclaredField(fieldData[i]);
field.setAccessible(true);
field.set(null, strData[i]);
}
Preferences prefs = Preferences.userNodeForPackage(StartBurp.class);
for (int i = 0; i < keys.length; i++)
{
String v = prefs.get(keys[i], null);
if (!vals[i].equals(v)) {
prefs.put(keys[i], vals[i]);
}
}
StartBurp.main(args);
}
}
catch (Exception e)
{
JOptionPane.showMessageDialog(null, “This program can only run with burpsuite_pro_v1.5.01.jar”, “BurpLoader by larry_lau@163.com”,
0);
}
}
}
|
再来对比我们混淆过的,且解出了字符串的版本(这里是1.6.37的Burp)。
0×03 BurpLoader源码分析
经过对比,整理出差不多的反汇编后的代码:
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
|
//
// Decompiled by Procyon v0.5.30
//
package larry.lau;
import java.lang.reflect.Field;
import java.io.InputStream;
import java.security.CodeSource;
import java.awt.HeadlessException;
import java.awt.GraphicsEnvironment;
import java.util.prefs.Preferences;
import java.awt.Component;
import javax.swing.JOptionPane;
import java.security.MessageDigest;
import javax.swing.UIManager;
public class BurpLoader
{
public static final String readme0 = “Burp Suite is an integrated platform for performing security testing of web applications. “;
public static final String readme1 = “If you like it, please try Free edition or <b>buy</b> Pro edition.”;
public static final String readme2 = “This loader is Free and CAN NOT be used for Commercial purposes!”;
public static final String readme3 = “If you bought it somewhere else, you should take action against the seller.”;
public static final String readme4 = “No exploiting and no malware in my code. Shaby is boring!”;
public static final String readme5 = “Usage:”;
public static final String readme6 = “1. you need a burpsuite_pro jar file.”;
public static final String readme7 = “2. add burpsuite_pro jar into classpath then run burploader”;
public static final String readme8 = “<ul><li>java -jar BurpLoader.jar</li>”;
public static final String readme9 = “<li>java -cp BurpLoader.jar;burpsuite_pro.jar larry.lau.BurpLoader</li>”;
public static final String readme10 = “<li>java -cp BurpLoader.jar:burpsuite_pro.jar larry.lau.BurpLoader</li></ul>”;
public static final String readme11 = “3. To Support headless mode, add -Djava.awt.headless=true into jvm arguments.”;
public static final String readme12 = “4. Any suggestions, let me know.”;
private static final String[] a; //stringdata 对应解密出密文的那一大堆
private static final String[] b = {“llc” , “frb” , “dfd” ,“zud” ,“bdf”, “uxh”, “a7b” , “u6b” }; //classname数组
private static final String[] c = {}; //fileddata数组
private static final String[] d = {“license1″, “uG4NTkffOhFN/on7RT1nbw==”}; // keys数组
private static final String[] e = {“pQwzPmoS+nV4oph/ti7SdybjoUB9IWHt0BGBVS1kycSvYAn2zh0uJq9gCfbOHS4mrpBSDMCrw+Aw6t2wCDaKXMJoXejEZIvQifD7ev/ieLttU9OZmtQxiQvOezD/tIy96RrqBxRJQqO1M+cHUq0emgxViBsoFVklsQmr6ayz0rTcwz9sXYvE9N4LvQ7thuRKMaO49TJR+9sjImBql1kBGTOHsJCETT5Mh62lIzXUYnpKhnWi1IjmSYXhhQnHSrTJtPMnN4lc0W36TPXlqWE7KmcGSWrjNiEWMVJ8ez1jIk2J5kSD3dV3gokc2tAm3MeslXO39AhD3RCbXV4SzJNb9A==”,“CONSTANT_String : 6Oxo0eZXXJNgBSjf5x9U7CXRqLnEIQaqNhLHKcSKbabe//W7jgdzbDMQor2PE44WeyvBtJFh848jEZys6bvlyLN70lJi5wqkoXe+BtrTnpS3Y9+9ygkcaUleLj7/UPie18gUNblikWyctTG/IKCPKGPZSe4JuPclh3HH9FAcd4shrJmrcAhJYCTYOFO3bqxs0kIhcZKUBUJ/DG//UIFceegfGVijiBeM9K4xbR+HfxTIg49Pqa1JTNcoWqjeq1xewqd8Ovqt+J9Zrsn7XC1zy8XyK6U65vHBA6HY/h/2Li7sxatMzfGX8m8L3hiAx7eOKBBtFJj/8VnuVggQZodIPna6xhrBBIcA1YLrQ3EXxXDLlO5yVM/S+B7oFgYMgMd4″}; // values数组
public static boolean f;
public static boolean g;
private static final String[] z = { “d0287d85d288c2af116e0d60878a8a24″ , “This program can only run with burpsuite_pro_v1.6.37.jar”, “burp.StartBurp”, “LNimbus” , “main”, “/burp”, “md5″, “BurpLoader by larry_lau”, “larry.lau.javax.swing.plaf.nimbus.NimbusLookAndFeel”,
“burpsuite_pro_v1.6.37.jar was corrupted!” , “burp.” , “%02x”};
static {} //error
public static void main(final String[] array) {
final boolean g = BurpLoader.g;
try {
try {
final String s = BurpLoader.z[8];
Class.forName(s); //实例化一个字符串为名称的类 http://blog.csdn.net/kaiwii/article/details/7405761
UIManager.installLookAndFeel(BurpLoader.z[3], s); //Swing用来设置外观与风格的相关函数
}
catch (ClassNotFoundException ex8) {}
final Class<?> forName = Class.forName(BurpLoader.z[2]); //找不到那个外观类就实例化 burp.StartBurp 既BurpSuite的启动类
//用md5验证了啥东西
try {
MessageDigest messageDigest = null;
Label_0086_Outer:
while (true) {
final CodeSource codeSource = forName.getProtectionDomain().getCodeSource(); //取CodeSource,一般配合getLocation使用取Jar包中的路径
final MessageDigest instance = MessageDigest.getInstance(BurpLoader.z[6]); //动态获取加密算法,这里是md5
final InputStream openStream = codeSource.getLocation().openStream(); //OpenStream()打开流以读取当前生成提供程序对象的虚拟路径。
final byte[] array2 = new byte[1024];
int read = 0;
while (true) {
while (true) {
Label_0094: {
try {
if (!g) {
break Label_0094;
}
}
catch (ClassNotFoundException ex) {
throw ex;
}
messageDigest.update(array2, 0, read); //// // array2是输入字符串转换得到的字节数组
}
if ((read = openStream.read(array2)) > 0) {
continue Label_0086_Outer;
}
break;
}
openStream.close();
messageDigest = instance;
if (!g) {
break;
}
continue;
}
}
StringBuffer sb = null;
Label_0178_Outer:
while (true) {
final byte[] digest = messageDigest.digest(); //生成md5
sb = new StringBuffer();
int n = 0;
while (true) {
while (true) {
Label_0181: {
try {
if (!g) {
break Label_0181;
}
//sb.append(String.format(BurpLoader.z[11], digest[n] & 0xFF)); 优化
sb.append(String.format(“%02x”, digest[n] & 0xFF)) //准备输出md5?
}
catch (ClassNotFoundException ex2) {
throw ex2;
}
++n;
}
if (n < digest.length) {
continue Label_0178_Outer;
}
break;
}
if (!g) {
break;
}
continue;
}
}
int equals = 0;
/*
用于确认版本
~>>> md5 burpsuite_pro_v1.6.37.jar
MD5 (burpsuite_pro_v1.6.37.jar) = d0287d85d288c2af116e0d60878a8a24
*/
Label_0245: {
Label_0219: {
int n2;
try {
n2 = (equals = (BurpLoader.z[0].equals(sb.toString()) ? 1 : 0)); // 比较md5的值
if (g) {
break Label_0245;
}
if (n2 == 0) {
break Label_0219;
}
break Label_0219;
}
catch (ClassNotFoundException ex3) {
throw ex3;
}
try {
if (n2 == 0) {
JOptionPane.showMessageDialog(null, BurpLoader.z[9], BurpLoader.z[7], 0); //弹出提示版本不符或者被修改
System.exit(-1);
}
}
catch (ClassNotFoundException ex4) {
throw ex4;
}
}
equals = 0;
}
/*
利用反射机制修改BurpSuite类相关信息,对于未混淆版本的Burploader和解密出的字符串可以重构前面的定义
*/
int n3 = equals; //0
while (true) {
Label_0316: {
if (!g) {
break Label_0316;
}
//final Field declaredField = Class.forName(BurpLoader.z[10] + BurpLoader.b[n3]).getDeclaredField(BurpLoader.c[n3]); 优化
//通过反射机制获取类相关的属性或去修改它 http://my.oschina.net/swords/blog/117357
//从 burp.xxx 的类中取变量,可以用jd-gui反编译去看,取对应类中的第一个Strinig变量
final Field declaredField = Class.forName(“burp.b_classarray”).getDeclaredField(BurpLoader.c[n3]);
declaredField.setAccessible(true);
declaredField.set(null, BurpLoader.a[n3]); //插入stringdata
++n3;
}
if (n3 < BurpLoader.b.length) {
continue;
}
break;
}
Preferences preferences = null;
Label_0352_Outer:
while (true) {
//保存用户偏好,Windows是注册表,Linux是Home目录下的文件
final Preferences node = Preferences.userRoot().node(BurpLoader.z[5]); //node(“/burp”)
int n4 = 0;
while (true) {
while (true) {
Label_0398: {
try {
if (!g) {
break Label_0398;
}
}
catch (ClassNotFoundException ex5) {
throw ex5;
}
//比较一些偏好设定,这里其实是key和values的比较
/*
String v = prefs.get(keys[i], null);
if (!vals[i].equals(v)) {
prefs.put(keys[i], vals[i]);
}
*/
if (!BurpLoader.e[n4].equals(preferences.get(BurpLoader.d[n4], null))) {
node.put(BurpLoader.d[n4], BurpLoader.e[n4]);
}
++n4;
}
if (n4 < BurpLoader.d.length) {
continue Label_0352_Outer;
}
break;
}
preferences = node;
if (!g) {
break;
}
continue;
}
}
preferences.flush();
//反射调用 StartBurp.main(args);
forName.getDeclaredMethod(BurpLoader.z[4], String[].class).invoke(null, array); // z4 = main
}
catch (Throwable t) {
t.printStackTrace();
int headless = GraphicsEnvironment.isHeadless() ? 1 : 0; //测试当前是否为图形环境
Label_0504: {
int n5 = 0;
Label_0503: {
try {
n5 = headless;
if (g) {
break Label_0504;
}
if (n5 != 0) {
break Label_0503;
}
}
catch (ClassNotFoundException ex6) {
throw ex6;
}
try {
GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); //取默认图形环境
}
catch (HeadlessException ex9) {
headless = 1;
}
catch (InternalError internalError) {
headless = 1;
}
}
try {
if (n5 != 0) {
System.err.println(BurpLoader.z[1]);
if (!g) {
return;
}
}
}
catch (ClassNotFoundException ex7) {
throw ex7;
}
}
//JOptionPane.showMessageDialog(null, BurpLoader.z[1], BurpLoader.z[7], 0); 弹出提示框
JOptionPane.showMessageDialog(null, “This program can only run with burpsuite_pro_v1.6.37.jar”, “Powered by XXX”, 0);
}
}
catch (ClassNotFoundException ex10) {
System.exit(-1);
}
}
}
|
从以上代码可以看出,BurpLoader的新版本破解BurpSuite的方式依旧没有发生改变,还是通过反射机制修改相关Burp类的成员变量 值来固定检测环境,同时写入Key来实现的。只不过比之前的版本,多了通过md5等方式来判断要启动的Burp主体是否是对应的版本。
0×04 使坏
原谅用了这么一个2B的小标题,Raphael Mudge牛曾在自己的Blog上写过(http://blog.cobaltstrike.com/2013/09/05/how-to-crack- cobalt-strike-and-backdoor-it/)如何破解自己的产品并加后门。事实上在BurpLoader中加上一点dirty code也是很容易的,然后再各大论坛或者某F传播出去也是能收获一批灰阔的,显而易见的例子是(http://it.rising.com.cn /dongtai/18192.html),堪比二十世纪出头灰阔圈子中各大XX联盟和XX技术小组了。最后感谢乌云Drops带来的好文章,多学习多实 践,有机会也去感受一把逆向Burp。
Copyright © hongdaChiaki. All Rights Reserved. 鸿大千秋 版权所有
联系方式:
地址: 深圳市南山区招商街道沿山社区沿山路43号创业壹号大楼A栋107室
邮箱:service@hongdaqianqiu.com
备案号:粤ICP备15078875号