乐趣区

关于java:面试官如何防止-Java-源码被反编译我竟然答不上来

起源博客:https://www.cnblogs.com/darta…

面试官:如何避免 Java 源码被反编译?我居然答不上来。。

java 作为解释型的语言,其高度形象的个性象征其很容易被反编译,容易被反编译,天然有避免反编译措施存在。明天就拜读了一篇相干的文章,受益匪浅,知彼知己嘛!!

之所以会对 java 的反编译感兴趣,那是因为本人在学习的过程中,经常须要借鉴一下他人的成绩(你懂的 …)。或者反编译他人的代码不怎么道德,这个嘛 ……

废话不多说,注释如下:

罕用的爱护技术

因为 Java 字节码的形象级别较高,因而它们较容易被反编译。本节介绍了几种罕用的办法,用于爱护 Java 字节码不被反编译。通常,这些办法不可能相对避免程序被反编译,而是加大反编译的难度而已,因为这些办法都有本人的应用环境和弱点。

1. 隔离 Java 程序

最简略的办法就是让用户不可能拜访到 Java Class 程序,这种办法是最基本的办法,具体实现有多种形式。例如,开发人员能够将要害的 Java Class 放在服务器端,客户端通过拜访服务器的相干接口来取得服务,而不是间接拜访 Class 文件。

这样黑客就没有方法反编译 Class 文件。

目前,通过接口提供服务的规范和协定也越来越多,例如 HTTP、Web Service、RPC 等。然而有很多利用都不适宜这种保护方式,例如对于单机运行的程序就无奈隔离 Java 程序。这种保护方式见图 1 所示。

2. 对 Class 文件进行加密

为了避免 Class 文件被间接反编译,许多开发人员将一些要害的 Class 文件进行加密,例如对注册码、序列号治理相干的类等。在应用这些被加密的类之前,程序首先须要对这些类进行解密,而后再将这些类装载到 JVM 当中。这些类的解密能够由硬件实现,也能够应用软件实现。

在实现时,开发人员往往通过自定义 ClassLoader 类来实现加密类的装载(留神因为安全性的起因,Applet 不可能反对自定义的 ClassLoader)。自定义的 ClassLoader 首先找到加密的类,而后进行解密,最初将解密后的类装载到 JVM 当中。

在这种保护方式中,自定义的 ClassLoader 是十分要害的类。因为它自身不是被加密的,因而它可能成为黑客最先攻打的指标。如果相干的解密密钥和算法被攻克,那么被加密的类也很容易被解密。这种保护方式示意图见图 2。

3. 转换老本地代码

将程序转换老本地代码也是一种避免反编译的无效办法。因为本地代码往往难以被反编译。开发人员能够抉择将整个利用程序转换老本地代码,也能够抉择要害模块转换。如果仅仅转换要害局部模块,Java 程序在应用这些模块时,须要应用 JNI 技术进行调用。

当然,在应用这种技术爱护 Java 程序的同时,也就义了 Java 的跨平台个性。对于不同的平台,咱们须要保护不同版本的本地代码,这将减轻软件反对和保护的工作。不过对于一些要害的模块,有时这种计划往往是必要的。

为了保障这些本地代码不被批改和代替,通常须要对这些代码进行数字签名。在应用这些本地代码之前,往往须要对这些本地代码进行认证,确保这些代码没有被黑客更改。如果签名查看通过,则调用相干 JNI 办法。这种保护方式示意图见图 3。

            

4、代码混同

代码混同是对 Class 文件进行从新组织和解决,使得解决后的代码与解决前代码实现雷同的性能(语义)。然而混同后的代码很难被反编译,即反编译后得出的代码是十分难懂、艰涩的,因而反编译人员很难得出程序的真正语义。

从实践上来说,黑客如果有足够的工夫,被混同的代码依然可能被破解,甚至目前有些人正在研制反混同的工具。然而从理论状况来看,因为混同技术的多元化倒退,混同实践的成熟,通过混同的 Java 代码还是可能很好地避免反编译。上面咱们会具体介绍混同技术,因为混同是一种爱护 Java 程序的重要技术。图 4 是代码混同的示图。

几种技术的总结

以上几种技术都有不同的应用环境,各自都有本人的弱点,表 1 是相干特点的比拟。

到目前为止,对于 Java 程序的爱护,混同技术还是最根本的爱护办法。Java 混同工具也十分多,包含商业的、收费的、凋谢源代码的。Sun 公司也提供了本人的混同工具。它们大多都是对 Class 文件进行混同解决,也有大量工具首先对源代码进行解决,而后再对 Class 进行解决,这样加大了混同解决的力度。

目前,商业上比拟胜利的混同工具包含 JProof 公司的 1stBarrier 系列、Eastridge 公司的 JShrink 和 4thpass.com 的 SourceGuard 等。次要的混同技术依照混同指标能够进行如下分类,它们别离为符号混同(Lexical Obfuscation)、数据混同(Data Obfuscation)、管制混同(Control Obfuscation)、预防性混同(Prevent Transformation)。

符号混同

在 Class 中存在许多与程序执行自身无关的信息,例如办法名称、变量名称,这些符号的名称往往带有肯定的含意。例如某个办法名为 getKeyLength(),那么这个办法很可能就是用来返回 Key 的长度。符号混同就是将这些信息打乱,把这些信息变成无任何意义的示意,例如将所有的变量从 vairant_001 开始编号;对于所有的办法从 method_001 开始编号。这将对反编译带来肯定的艰难。

对于公有函数、局部变量,通常能够扭转它们的符号,而不影响程序的运行。然而对于一些接口名称、私有函数、成员变量,如果有其它内部模块须要援用这些符号,咱们往往须要保留这些名称,否则内部模块找不到这些名称的办法和变量。因而,少数的混同工具对于符号混同,都提供了丰盛的选项,让用户抉择是否、如何进行符号混同。

数据混同

数据混同是对程序应用的数据进行混同。混同的办法也有多种,次要能够分为扭转数据存储及编码(Store and Encode Transform)、扭转数据拜访(Access Transform)。

扭转数据存储和编码能够打乱程序应用的数据存储形式。例如将一个有 10 个成员的数组,拆开为 10 个变量,并且打乱这些变量的名字;将一个两维数组转化为一个一维数组等。对于一些简单的数据结构,咱们将打乱它的数据结构,例如用多个类代替一个简单的类等。

另外一种形式是扭转数据拜访。例如拜访数组的下标时,咱们能够进行肯定的计算,图 5 就是一个例子。

在实际混同解决中,这两种办法通常是综合应用的,在打乱数据存储的同时,也打乱数据拜访的形式。通过对数据混同,程序的语义变得复杂了,这样增大了反编译的难度。

管制混同

管制混同就是对程序的控制流进行混同,使得程序的控制流更加难以反编译,通常控制流的扭转须要减少一些额定的计算和控制流,因而在性能上会给程序带来肯定的负面影响。有时,须要在程序的性能和混同水平之间进行衡量。管制混同的技术最为简单,技巧也最多。这些技术能够分为如下几类:

减少混同管制通过减少额定的、简单的控制流,能够将程序原来的语义暗藏起来。例如,对于按秩序执行的两个语句 A、B,咱们能够减少一个管制条件,以决定 B 的执行。通过这种形式加大反汇编的难度。然而所有的烦扰管制都不应该影响 B 的执行。图 6 就给出三种形式,为这个例子减少混同管制。

控制流重组重组控制流也是重要的混同办法。例如,程序调用一个办法,在混同后,能够将该办法代码嵌入到调用程序当中。反过来,程序中的一段代码也能够转变为一个函数调用。另外,对于一个循环的控制流,为能够拆分多个循环的控制流,或者将循环转化成一个递归过程。这种办法最为简单,钻研的人员也十分多。

预防性混同

这种混同通常是针对一些专用的反编译器而设计的,一般来说,这些技术利用反编译器的弱点或者 Bug 来设计混同计划。例如,有些反编译器对于 Return 前面的指令不进行反编译,而有些混同计划恰好将代码放在 Return 语句前面。这种混同的有效性对于不同反编译器的作用也不太雷同的。一个好的混同工具,通常会综合应用这些混同技术。

案例剖析

在实际当中,爱护一个大型 Java 程序常常须要综合应用这些办法,而不是繁多应用某一种办法。这是因为每种办法都有其弱点和应用环境。综合应用这些办法使得 Java 程序的爱护更加无效。另外,咱们常常还须要应用其它的相干平安技术,例如平安认证、数字签名、PKI 等。

本文给出的例子是一个 Java 应用程序,它是一个 SCJP(Sun Certificate Java Programmer)的模拟考试软件。该应用程序带有大量的模仿题目,所有的题目都被加密后存储在文件中。因为它所带的题库是该软件的外围局部,所以对于题库的存取和拜访就成为十分外围的类。一旦这些相干的类被反编译,则所有的题库将被破解。当初,咱们来思考如何爱护这些题库及相干的类。

在这个例子中,咱们思考应用综合爱护技术,其中包含本地代码和混同技术。因为该软件次要公布在 Windows 上,因而转换老本地代码后,仅仅须要保护一个版本的本地代码。另外,混同对 Java 程序也是十分无效的,实用于这种独立公布的利用零碎。

在具体的计划中,咱们将程序分为两个局部,一个是由本地代码编写的题库拜访的模块,另外一个是由 Java 开发的其它模块。这样能够更高水平地爱护题目治理模块不被反编译。对于 Java 开发的模块,咱们依然要应用混同技术。该计划的示意图参见图 7。

对于题目治理模块,因为程序次要在 Windows 下应用,所以应用 C ++ 开发题库拜访模块,并且提供了肯定的拜访接口。为了爱护题库拜访的接口,咱们还减少了一个初始化接口,用于每次应用题库拜访接口之前的初始化工作。它的接口次要分为两类:

1. 初始化接口

在应用题库模块之前,咱们必须先调用初始化接口。在调用该接口时,客户端须要提供一个随机数作为参数。题库治理模块和客户端通过这个随机数,按肯定的算法同时生成雷同的 SessionKey,用于加密当前输出和输入的所有数据。

通过这种形式,只有受权 (无效) 的客户端才可能连贯正确的连贯,生成正确的 SessionKey,用于拜访题库信息。非法的客户很难生成正确的 SessionKey,因而无奈取得题库的信息。如果须要建设更高的窃密级别,也能够采纳双向认证技术。

2. 数据拜访接口

认证实现之后,客户端就能够失常的拜访题库数据。然而,输出和输入的数据都是由 SessionKey 所加密的数据。因而,只有正确的题库治理模块才可能应用题库治理模块。图 8 时序图示意了题库治理模块和其它局部的交互过程。

近期热文举荐:

1.1,000+ 道 Java 面试题及答案整顿(2021 最新版)

2. 别在再满屏的 if/ else 了,试试策略模式,真香!!

3. 卧槽!Java 中的 xx ≠ null 是什么新语法?

4.Spring Boot 2.5 重磅公布,光明模式太炸了!

5.《Java 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

退出移动版