我们可以完全对 java 字节码的源代码进行逆向工程吗?为什么在 Java 中允许使用此功能以及 Java 反编译器对混淆器的成功程度如何。?
4 回答
我知道这个问题很老,但我一直在寻找可靠的答案,直到我一无所获。因此,在这篇文章中,我总结了我为混淆 J2EE JAR 所做的一些努力。看来,到 2014 年(撰写本文时)已经没有多少选择了。如果您稍后阅读此评论,那么事情可能已经改变或修复。当我想到为什么时,我开始感觉到整个混淆工作给人一种虚假的安全感。不要误会我的意思。它确实增加了一定程度的安全性,但没有我希望的那么多。我将尝试对我发现的解释自己的内容进行预览。我的建议是个人的,其他人可能不同意。
因此,首先:Java 中的混淆是获取字节码并使其可读性降低(当然使用反编译器)同时保持其原始功能的过程。我们能做什么,Java 作为一个interperter,必须保持其字节码暴露。您运行混淆器作为一种安全措施,以防类文件落入坏人之手。混淆的结果是一个反向映射文件和一个带有混淆类的 JAR。反向映射文件当然用于执行堆栈跟踪读取(也称为重新跟踪)或将字节码恢复为其原始形状。混淆类的运行时性能影响不应超过 10%(但这实际上取决于您在代码中执行的操作)。
但是有一个很大的“但是”。混淆会扰乱您的代码,但不会使其免受黑客攻击。请记住,您只是在争取时间,而坚定的黑客会找到一种方法将您的字节码逆向工程到其纯算法中。
恕我直言:隐藏一段敏感代码的最佳方法是将其淹没在一堆无意义的代码中。
一些黑客会尝试修改您的字节码(通过代码注入)以帮助他们实现目标。一些混淆器提供额外级别的 JAR 强化,使其更难修改。
反混淆器和反编译器:我最喜欢的 Java 反编译器是 JD-GUI。然而,当谈到去混淆器时,我发现市场相当空虚。大多数工具都要求您提供提示(使用什么混淆工具来加密源 JAR),但它们都没有真正提供结果(其中一些工具甚至在尝试解密 JAR 时崩溃)。它们是维护成本低的开源项目。我什至找不到一个付费的应用程序来做一个像样的去混淆。如果你知道的话,请赐教。
免费解决方案
有一些开源的、免费的混淆器,它们通常只是简单地重命名类/方法名称,使其成为一个字母方法(即从 printUsage(String params) 到 a(String p) )。正如这里所暗示的,他们甚至可能会剥离调试信息以使其更加困难。(调试信息保存在每个 Java 方法字节码的末尾,包含:行号、变量名等)。这是一项不错的工作,但是具有调试器的经验丰富的 Java 开发人员可以很容易地推断出每个参数的用途,同时进行很少的实时运行。ProGuard 是不错的开源混淆器之一,但还有更多工具。然而,如果你真的是安全狂热者,你可能会想要更强大的东西。更强需要更多功能(和更多资金),这导致我们进入下一个项目:
付费解决方案
虽然免费产品可能只会更改类方法名称,但付费产品通常会提供更多功能:
代码/流混淆:这将改变方法代码并注入空循环/死代码/混淆开关表等。其中一些甚至可能会打乱异常表的内容。混淆强度通常决定输出大小。注意:关于代码混淆:我在评论中故意避开了细节。我看到和分析的一些字节码暴露了他们的混淆方法,我希望保护他们的 IP。我确实对谁使用更好的算法有意见。如果您想知道,请与我联系。
类/方法重命名:这是显而易见的,我们在免费混淆中讨论过它。一些产品将重命名类名,然后递归搜索该类的反射用法并修复它们。付费产品甚至可以为相同的目的重命名 Spring /Wink 配置文件(在反射中重命名)。字符串加密:对于代码中“像这样”的每个字符串,它会将其加密到某种程度并将密钥保存在某处(在类常量表/静态块/新方法或任何其他方式中)。
调试信息:剥离部分或加扰。其中许多将删除行号信息。班级
强化:各种方法,例如在类/方法的开头注入一些签名方案,确保外人无法轻易修改 JAR 并运行它。对于 Android 或小程序来说不太重要,因为它们中的大多数都经过数字签名。有些会结合硬化和水印来跟踪盗版。但我们都知道,软件的反盗版方法注定会被黑。数十年来,游戏行业一直深受其害,直到基于网络的订阅出现。
由于这里的大多数产品都处理 Java ,因此其中一些提供了 Android 集成。这意味着它不仅会混淆 Java (dalvik) 代码,还会操纵 Android 的清单文件和资源。有些提供反调试:删除 android 应用程序中的调试标志。
不错的 GUI 应用程序,用于配置各种选项,并可能对给定的日志文件进行重新发送。UI 通常用于生成配置文件。使用这样的文件,您以后可以多次重新播放混淆,甚至从命令行。
增量构建支持 - 这对于经常发布产品更新/修复的大型团体很有用。您可以告诉混淆器保留旧的“混淆”结果并随机混淆仅“新”代码流。这样,您可以确保对您的方法签名的影响最小。如果没有这个标志,JAR 上的每个混淆循环都会产生不同的输出,因为大多数好的工具在它们的算法中都使用了某种程度的随机性。
CLI 和分布式构建。当您独自工作时,运行混淆器并不是什么大问题。您需要将混淆器配置为您的相关选项并运行它。但是,在企业中,当将混淆器集成到构建脚本中时,情况会有所不同。还有另一个复杂程度:构建引擎任务(如 ant/maven)和许可证管理。好消息是我测试的所有混淆器都有命令行 API。在分布式构建环境中,有构建机器的集群/池来支持构建的并发需求。集群是动态的和虚拟的,机器会上升或下降,具体取决于各种条件。一些混淆产品基于 cpuID 许可证文件或主机名。这会给构建团队的集成带来相当大的挑战。有些人更喜欢本地浮动许可证服务器。有些可能需要公共许可证服务器(但是:并非所有构建农场都可以访问公共互联网)。有些提供多站点许可证(我认为这是最好的)。
有些提供代码优化 - 代数等价和删除死代码。它很好,但我相信今天的 JDK 在优化字节码方面做得很好。确实,死代码使您可下载的更大,但以今天的带宽,它不是问题。我也想相信在今天的软件中 20:80 拇指规则仍然适用。在任何应用程序中,20% 都可能是死代码。
那么我尝试过的球员是谁?
Zelix.com 的 KlassMaster - 业内最古老的公司之一。然而,他们每年发布 3-4 个版本,提供可靠的产品。这已经持续了几十年(自 1997 年以来)。Zelix 提供良好的电子邮件支持,并及时回复了我所有的电子邮件。他们有一个很好的 GUI 客户端来混淆 JAR 或创建配置文件以供将来混淆。它简单而流畅。这里没什么特别的。他们为所有标志提供了易于阅读的在线文档。它们支持引擎应该混淆的“排除”和“包含”正则表达式。我最喜欢他们的过程的一点是,它还在异常表中添加了“噪音”。它使方法异常处理变得更加混乱。它们的流混淆器强度非常好,可以在 3 个可能的级别(轻、中和激进)之间进行配置。我喜欢的另一个功能是它们为调试信息剥离(在线行号或在线局部变量或两者)提供的微调。Klass Master 不提供任何专用的 Android 标志或防篡改方法。他们的许可模型非常简单:将一个文本文件放置在 KlassMaster 主 JAR 附近。它们还支持增量混淆。
来自secureTeam.net 的JFuscator:虽然secureTeam 也有一个.Net 工具,但我关注的是他们的Java 工具功能。他们的(基于 Swing 的)GUI 工具看起来不错,但在尝试最简单的混淆任务时它会崩溃。错误始终相同:读取“/opt/sun-jdk1.7.0_55/jre\lib\rt.jar”时出错。原因:''/opt/sun-jdk1.7.0_55/jre\lib\rt.jar':没有这样的文件或目录'。现在,我当然在 /opt/sun-jdk1.7.0_55/jre 中安装了我的 Java。你可以想象他们根本没想到 linux 的反斜杠结构。我通过电子邮件联系了secureTeam.net 支持,解决了“路径”的小问题。他们问我是否是 linux 用户,在我回答我是后,他们从未回复我的电子邮件。我也试过他们的网站在线聊天:没反应。所以我停止了测试。如果没有进一步的结果,我无法检查混淆的字节码质量。
GuartIt4J(来自 Arxan.com):Arxan 在移动环境中是相当可靠的播放器,因此他们提供了 Android 混淆器,这当然适用于 Java。它们拥有最灵活的引擎之一。它们提供代码混淆、字符串加密等您可以定义代码混淆的复杂性。它只是一个整数。越高 - 你的方法越长。当然,你必须小心不要超过每个类 JVM 64KB 的限制……正如我之前所说,隐藏敏感代码的最佳策略之一不是对其进行加密,而是将其注入大量垃圾中。这正是 GuardIt 所做的。它也可以像方法异常表一样爆炸。我设法在其异常表中创建了一个包含 100 个异常的方法(预混淆器是 5 个)。他们错过了什么:他们的重新跟踪程序不是提供的主 JAR 的一部分。尽管如此,他们还是很友好地向我发送了一个示例 Java 程序,该程序在给定反向映射文件和日志的情况下执行重新跟踪。它们不支持增量混淆,也没有关于调试信息的灵活性。调试信息剥离要么全有,要么全无。观察输出 JAR,你会看到大量注入的条件和跳跃。请记住,爆炸式的班级规模会对性能造成影响。在某些方法中,我测量了在应用长混淆(这些方法中没有 I/O)时几乎 50% 的性能损失。所以推断代码是有代价的。(从 400 个操作码 - 我在混淆后增加到 2200 个操作码)。JD-GUI ,我的反编译器无法打开此类并崩溃(IndexOutOfBoundException)。他们还提供完整的类加密。这意味着该类是用一些对称密钥加密的,这需要一个特殊的(或自定义编写的)类加载器才能在内存中打开它。这是一种防篡改机制以及隐藏代码。请记住,如果没有类加载器的帮助,JVM 就无法运行该类。它是一个不错的功能,但密钥和引导加载程序 JAR 可能在那里。如果他得到了加密的 JAR,黑客最终会得到他的手并解密这些类。然而,这是普通黑客需要克服的另一层障碍。我不喜欢这里的许可证文件策略:绑定到 CPUid 或需要安装浮动许可证服务器。请记住,如果没有类加载器的帮助,JVM 就无法运行该类。它是一个不错的功能,但密钥和引导加载程序 JAR 可能在那里。如果他得到了加密的 JAR,黑客最终会得到他的手并解密这些类。然而,这是普通黑客需要克服的另一层障碍。我不喜欢这里的许可证文件策略:绑定到 CPUid 或需要安装浮动许可证服务器。请记住,如果没有类加载器的帮助,JVM 就无法运行该类。它是一个不错的功能,但密钥和引导加载程序 JAR 可能在那里。如果他得到了加密的 JAR,黑客最终会得到他的手并解密这些类。然而,这是普通黑客需要克服的另一层障碍。我不喜欢这里的许可证文件策略:绑定到 CPUid 或需要安装浮动许可证服务器。
SecureIt(由 Allatori.com 提供):SecureIt 提供所有通用代码混淆、字符串加密、重命名等。除了标准的混淆方法之外,他们还提供了某种水印,这是一种防篡改/盗版方法。他们支持 Android 和 JavaME(现在谁在使用 ME?!)。它们支持增量混淆。关于配置 SecureIt 需要注意的一件事:它都是命令行。这次没有 GUI 工具。就个人而言,我不介意命令行工具,只要它们带有良好的文档即可。幸运的是,他们有一个非常好的文档和一个丰富的 API,如果你愿意,可以调整许多标志。您可以使用他们的工具(也是命令行)重新跟踪。他们不能混淆异常表。我没有检查他们的许可机制。
DashO(由 Preemptive.com 提供):DashO 混淆器可能会被认为是您可以获得的最佳 UI 工具(用于创建配置)。与 SecureIt 一样,它们对异常表进行了混淆,但它们具有所有其他必需的功能(以及 CLI、Spring 框架和 gradle/ant 集成,甚至还有一个 eclipse 插件)。好吧,他们确实记录了一个 try-catch 混淆器(与异常表混淆器相同),但这只是对引擎的推荐。当我尝试它时,它对异常表没有影响。正如我所说,GUI 工具非常棒,并且嵌入了重新跟踪。他们还提供某种应用程序签名和水印作为防篡改/盗版机制。DashO 提供了出色的 Android 集成,并在他们的产品中结合了分析上传的大门。您实际上可以跟踪您的应用程序。将崩溃日志上传器和报告代码注入您的 JAR。然而,这不是混淆的范围——这是一个完全不同的代码注入产品。他们有很好的支持。在线和电话。他们的许可计划基于每月订阅或一次性购买付款。和别人有点不同。他们使用浮动许可证服务器来支持大型环境。
我希望这个能有一点帮助..
我们可以完全对 java 字节码的源代码进行逆向工程吗?
不完全是,因为源代码的某些方面,例如空格、局部变量名和注释,并没有保存在字节码中。否则,是的——虽然你不能得到完全相同的源代码,但你几乎总能得到至少可以编译回相同字节码的东西。
为什么 Java 允许使用此功能
与其说是“允许”,不如说是“不阻止”。它并没有被阻止,因为这样做是不可能的——代码必须是可运行的才能有用;如果代码是可运行的,那么它是可分析的;如果它是可分析的,那么通过充分的分析,它可以转换回源。
java反编译器对混淆器有多成功?
不是特别的。我见过的大多数混淆器(尤其是 ProGuard)在删除有意义的函数和类名方面主要是有效的;通常不会尝试混淆逻辑本身。
这些天你可以从二进制文件中获取源代码。Java的字节码得到的源代码虽然可读性更强,但经过混淆处理会使其略显不可读。并不是说只有 Java 可以逆向工程为代码。即使是现在的 C/C++(带有 IDA Pro 的 Hexrays 插件)也可以反编译为源代码。混淆器会使它难以阅读,但并非不可能。没有什么可以从聪明而有能力的逆向工程师手中拯救你的程序。:)。
祝你好运。
我们可以完全对 java 字节码的源代码进行逆向工程吗?
java 类文件基于规范,因此任何人都可以读入它。像JD-GUI这样的工具会很容易地撕入你的源代码。它本身不是一个“功能”。虽然不可能进行 100% 的逆向工程,但您的大部分代码都可以进行逆向工程。
java反编译器对混淆器有多成功?
依靠。混淆器的目的是删除任何有意义的名称,并尝试在代码中引入混淆而不影响性能。大多数开发人员都擅长自己混淆代码 :) Pro-guard 非常擅长混淆。