龙空技术网

网安加·百家讲坛 | 肖文棣:Java加壳,脱壳与实践

网安加社区 78

前言:

如今咱们对“jadxgui反编译教程”可能比较重视,我们都想要分析一些“jadxgui反编译教程”的相关知识。那么小编也在网络上网罗了一些有关“jadxgui反编译教程””的相关文章,希望朋友们能喜欢,姐妹们一起来了解一下吧!

作者简介:肖文棣,OWASP中国广东分会负责人、网安加社区特聘专家,现任某外企安全架构师,负责应用安全设计、管理和评审等工作。

最近由于业务的需要,我对Java的加壳和反加壳等技术进行了一些研究,现在就和大家分享一下我的研究成果。

Java字节码

众所周知,Java程序编译的时候,最终生成的是字节码,然后以JVM将字节码转换为机器码。

Java字节码(Java bytecode)是Java虚拟机(JVM)执行的一种虚拟指令格式。它是Java源代码经过虚拟机编译器编译后产生的文件,这些文件具有.class扩展名。字节码是一种中间码,它比机器码更抽象,需要直译器转译后才能成为机器码的中间代码。这些字节码指令由JVM解释为对应系统可运行的机器指令,从而实现Java程序的跨平台执行。

字节码文件由十六进制值组成,而JVM以两个十六进制值为一组,即以字节为单位进行读取,这也是其被称为“字节码”的原因。字节码文件包含了程序执行所需的所有信息,包括类、方法、字段、字节码指令等。JVM通过加载、验证、解释(或即时编译)这些字节码指令来执行Java程序。

字节码的存在实现了JVM和编程语言的解耦,意味着非Java语言也可以运行在JVM之上,并可将其对应的源程序编译成字节码。这也是Java“一次编写,到处运行”理念的基础。

Java字节码是一种基于堆栈的语言,这意味着临时变量存储在堆栈中,而不是存储在寄存器中。这个就是字节码的例子:

这个是使用JDK自带的工具Javap进行反编译的效果,具体命令如下:

Javap -v -p “Class的名字”

通过这个简单的工具,很容易就获取源代码的信息,比如源文件的名称,Main函数的超类信息以及函数的具体内容。

Java加壳

为了避免使用简单的Javap就可以还原源代码,我们就要对生成的字节码进行混淆,或者称为加壳。Java加壳,即对Java字节码进行加密或混淆,使得未经授权的用户难以理解或修改代码。

业界常用的Java加壳有下面几种:

1.字节码加密:通过对Java字节码进行加密,使得字节码文件无法直接通过常规的反编译工具进行阅读。加密方式可以是简单的XOR加密、AES加密等。

2.代码混淆:通过改变类名、方法名、变量名等标识符,以及调整代码结构,使得反编译后的代码难以阅读和理解。混淆工具通常会使用一系列算法,如字符串加密、控制流混淆等,以增加反编译的难度。

3.资源加密:除了字节码本身,Java应用程序中的资源文件(如图片、音频等)也可以进行加密,以增加破解者的破解难度。

4.动态加载:通过动态加载加密后的字节码,使得应用程序在运行时才能解密和执行代码,进一步增加安全性。

加壳的流程如下图:

实践中,我们可以考虑工具,比如ProGuard。

ProGuard是一个用于Java应用程序优化的工具,它可以缩小、优化和混淆Java字节码。ProGuard通过移除未使用的代码、重命名类和方法等方式,使得反编译后的代码难以阅读和理解。

项目地址是:

它提供GUI工具,使用相当简单,但是我实际测试的效果一般,使用一些反加壳的逆向工具很容易被破解。

Java脱壳和逆向

有攻必有防,有矛必有盾。上面有对Java进行加壳,那么就一定会有对Java进行脱壳的过程。Java脱壳,即解密和恢复加壳后的Java字节码,以便进行正常的反编译和执行。

脱壳的原理与加壳的原理相反:

1.字节码解密:根据加壳时使用的加密算法,对加密后的字节码进行解密,还原为原始的字节码文件。

2.代码还原:对混淆后的代码进行还原,恢复原始的类名、方法名、变量名等标识符,以及代码结构,使得反编译后的代码易于阅读和理解。

3.资源解密:对加密的资源文件进行解密,以便应用程序能够正常使用这些资源。

4.动态加载处理:对于使用动态加载技术的加壳程序,需要处理动态加载的逻辑,以便在脱壳后能够正确加载和执行字节码。

Java脱壳也有相关的工具,这里推荐两个工具:

Jd-gui

Jd-gui是一个基于图形界面的Java反编译器,它可以直接打开加密的Java字节码文件,并显示反编译后的代码。虽然它不能直接解密加密的字节码,但对于混淆后的代码,Jd-gui仍然能够提供一个相对清晰的阅读界面。

项目地址是:

Jadx-gui

Jadx是用于从Android Dex和Apk文件生成Java源代码的命令行和Gui工具,也支持普通的Jar文件翻译为Java源代码的工具。

项目地址是:

根据我的实践经验,Jd-gui更加轻量级,使用的资源比较少。Jadx-gui虽然使用的资源比较多,但是反编译的效果更好。我在工作中就遇到使用Jd-gui不能有效反编译,但是使用Jadx-gui就可以顺利反编译的情况,所以实际应用中推荐两个同时使用。

实践总结

Java的加壳工具在实际测试中并不是非常理想的,开源的Java加壳工具也不是非常多。在实际应用中,Java加壳一般和授权管理一起使用,只有得到授权码的用户才能使用Java程序,Java代码运行的时候需要指定一个Agent才能运行,同时考虑Java加壳和Java授权管理的需求,最好考虑商业工具,比如国内的Virbox和Bitanswer,实际上由于这个市场比较小,可以选择的供应商并不是非常多。

如果要使用Spring框架的程序,混淆加壳就更加困难,因为Spring需要有特定的加载器进行加载,对混淆和加壳有限制。根据我现在的测试,Virbox和Bitanswer都没有对函数名以及参数列表进行处理,都要保持原有的形式,否则加壳后可能系统不能正常运行。

根据这两家的白皮书,它们的原理有所不同。

Bitanswer据称是Java程序混淆加壳处理后,在程序运行的时候,会把Java程序脱壳并运行在内存中,Java程序运行过程中是字节码运行了。这个时候的风险可能是通过Dump内存将字节码保存为Class文件,然后使用逆向工具进行破解。

Virbox据说用的是另外的思路,Java程序混淆加壳运行时,会根据系统的逐段处理,而不是一次加载到内存中,这个时候从内存中还原字节码的难度就更高了。

业界也有大佬表示,Java程序的混淆加壳不真正靠谱,Java程序还是可以还原的,所以大家的实际使用过程中还是要谨慎考虑。

在我的实际测试中,针对简单的Helloworld这样的单一Jar包,使用Virbox和Bitanswer都可以很好满足要求,这个时候使用Jd-gui和Jadx-gui都不能很好地还原代码。

但是对于Spring框架生成的Jar包,这种Jar包都有多层嵌套,无论Virbox和Bitanswer的处理都不是非常理想,不能真正识别出所有文件进行加密,这是一个比较大的隐患。此时用Jd-gui感觉代码被混淆加密了,但是用Jadx-gui却可以打开,看到源代码,这也是推荐Jd-gui和Jadx-gui同使用的原因。

Java除了考虑混淆加密后,还要考虑Java的反射特性,要防止用户虽然不能完整看到Java的源代码,但是可以利用反射对Java进行操作,间接避开混淆加密的特性。这个也是有案例的。

另外,Java的加壳混淆有两个场景,一个Apk的加固场景,相对比较成熟,有相关的认证标准。另外一个是Jar的混淆加壳场景,受众比较少,没有相关的标准,供应商也没有提供足够证据证明它们的Jar的混淆加壳的强度,也很难完全测试是否可以被破解,这个在实际应用中也要注意。

没有绝对的安全,也没有绝对的保险,大家只能衡量破解的难度以及风险。有朋友建议说将加密后的Jar包放到众包平台上进行悬赏破解,这也是一种好的思路。也可以考虑找专业的黑客进行尝试破解,但是企业在考虑将Jar包放到外网就要考虑这些风险,而且这些风险可能是无解的。

标签: #jadxgui反编译教程