说要混淆Burp插件,可能有些小伙伴会说:

A:混淆干嘛,大家都这么忙,谁有时间看你的烂代码!

B:现在都鼓励开源,你这么做有悖于开源精神。

……

me:这和开源精神没有冲突,我的理解里,真正的开源精神应该是从内心出发的,而不是受“开源人士”的舆论压力,这是道德绑架。更不能因为大家开源,所以我也开源,为了开源而开源没有意义。况且本文仅仅研究混淆这门技术的原理和魅力!

C:把不开源说得这么清新脱俗,NB!

me:被你发现了,哈哈

0x01 Burp插件混淆规则

混淆不能一键化,java程序中有apk,有桌面引用程序,有web程序,有jar库。需要根据各自代码的特点来制定混淆规则。burp的插件,第一它不算应用,因为它没有main函数,第二它被burp调用,但又不算是库。倒是很像是介于两者之间,所以相对来说比较特殊。自然混淆时有些特殊……

  • 首选不能混淆掉burp这个包名,因为burp默认会读burp包下的BurpExtender。如果BurpExtender在其他包下,它会报错说找不到该入口类。
  • 不能混淆掉burp包下的BurpExtender这个类,因为这是burp调用插件的入口。
  • 不能混淆Burp包下引入的接口,因为接口是共同遵守的规范。
代码混淆工具
  • ProGuard
  • allatori

0x02 使用ProGuard混淆

混淆的本质就使程序的可读性变差,而通常程序的包名类名方法名和属性名都是遵守见名知意。所以我们反其道而行,先来生成令人眼傻傻分不清的混淆字典吧(坏笑脸)。ProGurd会根据我们的混淆字典,替换掉程序中令人易懂的名称!

混淆对象 元素 例子
包名 o,0 00000o0oo0
类名 l,i ililiillii
方法名和属性名 l,1 1l11111lll

编写了一个py脚本来快速生成字典(obf_dic_creater.py)

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
#coding=utf-8
import random
#author:c0ny1
package_str = "o0"
class_str = "li"
field_method_str = "l1"
def create_obf_str(str,length):
obf_str = ""
for i in range(length):
j = random.randrange(0,len(str))
obf_str+=str[j]
print obf_str
return obf_str
def create_obf_dic(str,filename,length,num):
f = open(filename,"a")
for n in range(num):
obf_str = create_obf_str(str,length)
f.write(obf_str)
f.write('\n')
f.close()
if __name__ == '__main__':
create_obf_dic(package_str,"package_dic.txt",10,500)
create_obf_dic(class_str,"class_dic.txt",10,500)
create_obf_dic(field_method_str,"field_method_dic.txt",10,500)

生成字典

我们使用ProGuard的配置文件语法来描述burp插件混淆规则部分分析好的规则,内容如下

XXEHelper.pro

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-injars Test.jar #要混淆的插件
-outjars Obf.jar #混淆成功后导出的文件
#添加依赖的jar
-libraryjars <java.home>/lib/rt.jar
-dontshrink #不压缩
-dontoptimize #不优化
-obfuscationdictionary package_dic.txt #方法和属性名混淆字典
-classobfuscationdictionary class_dic.txt #类名混淆字典
-packageobfuscationdictionary package_dic.txt #包名混淆字典
-overloadaggressively #深度重载混淆
-useuniqueclassmembernames #使用大小写混合类名
-keeppackagenames burp # 不混淆burp这个包名
-flattenpackagehierarchy me.gv7 #将混淆的包放在me.gv7这个父包
-keep,allowshrinking class burp.* { #不混淆burp.*下的class
public <fields>; #不混淆public属性
public <methods>; #不混淆public方法
}

注意:在编写混淆配置文件时,需要用-libraryjars引入我们的插件依赖的jar。jar引入不全的话会导致ProGuard混淆失败。如果混淆失败,ProGuard会提示我们所缺少的类,我们可以根据该类名去以下网址搜索到对应jar,下载并引入后重新混淆即可。这个过程会很枯燥,要有耐心哦!该例子插件没有依赖外部jar,故只引入rt.jar即可。

大家可以以我这个配置文件为模板,根据具体情况来修改相关路径,和参数值,来混淆自己的burp插件!

最后我们运行ProGuargui>ProGuard>Load configuration...>选择XXEHelper.pro>Process>Process!

ProGuargui混淆成功

ProGuard混淆前

ProGuard混淆后

经过测试混淆后插件可以正常运行。

0x03 使用allatori混淆

不过ProGuard的混淆效果个人感觉不是特别好,公司大神推荐allatori这款商业混淆器。

allaroi目录结构

由于官方程序的目录结构比较深,为了方便研究复制核心文件,简洁目录格式为如下:

allaroi目录结构

根据以上我们burp混淆的规则,重新编写config.xml为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<config>
<input>
<jar in="xxe-helper 0.1.jar" out="xxe-helper-obf.jar"/>
</input>
<classpath basedir="library-jars">
<jar name="*.jar"/>
</classpath>
<keep-names>
<class template="class burp.*">
<field template="public *"/>
<method template="public *(*)"/>
</class>
<class template="interface burp.*">
</class>
</keep-names>
<property name="log-file" value="log.xml"/>
</config>

修改RunAllatori.bat代码为:

1
2
java -Xms128m -Xmx512m -jar allatori\allatori.jar config.xml
pause

修改Clean.bat代码为:

1
2
3
del log.xml
del *obf.jar
pause

最后运行RunAllitori.bat

运行RunAllitori.bat

大家可以发现红框标出的是混淆器提示我们有些类没有找到,这些类时插件包含的jar所依赖的jar,大家可以根据提示的缺的包名,用上面说过的搜jar方法,把它们下载并引入进来。不过我们不引入它们也是可以混淆的,但混淆的强度会弱一些。

不懂编写config.xml的小伙伴,可以去阅读一下官方文档

下面我们对比一下混淆前后的效果!

插件混淆前代码反编译

插件混淆后代码反编译

经过测试插件混淆后,可以运行。

0x04 总结

混淆和编码有大关系,比如设计包名时,应该将我们插件的核心代码单独放一个包里,不要一股脑都放在burp。这样的话最后不好写混淆规则。对于方法和属性得访问属性(public,protected,private),要深思熟虑。这样不但程序更规范,写混淆规则也会简单些。

如果插件引用的jar比较多,使用ProGuard来混淆是比较麻烦的。因为依赖的外部jar也会依赖其他jar,你需要将它们都引入才行!我自己目前也没有好的解决方法。例子中的插件没有引用外部jar,所以混淆容易一些。allori不存在这个问题,只引入依赖jar就行。

最后大家可以在我研究的基础上去,看看如何设置使得混淆效果更加好。如有新发现,欢迎留言交流。

参考文章

ProGuard代码混淆技术详解

ProGuard 最全混淆规则说明

ProGuard工具 jar包混淆问题总结

allatori混淆技术总结

Allatori Java Obfuscator - Documentation