如何锁定已编译的Java类以防止反编译?


96

如何锁定已编译的Java类以防止反编译?

我知道这个话题必须在Internet上进行充分讨论,但是在引用它们之后我无法得出任何结论。

许多人确实建议使用混淆器,但是他们只是使用难以记住的字符序列来重命名类,方法和字段,但是敏感的常数值又如何呢?

例如,您已经基于基于密码的加密技术开发了加密和解密组件。现在,在这种情况下,任何普通的Java人士都可以使用JAD来反编译类文件,并轻松检索密码值(定义为常量)以及salt,然后可以通过编写小型独立程序来解密数据!

还是应该以本机代码(例如VC ++)构建此类敏感组件并通过以下方式调用它们 JNI


即使反汇编的本机代码对于某些人来说还是相当可读的,您可能还必须使用一些混淆器或手工汇编使其不明显(使用优化编译的通用C ++足够可读)。在用户设备上运行的任何代码都可以被拦截。尽管这种拦截的成本/技能要求可能很高,例如,闯入智能卡“防篡改”芯片代码并不是一件容易的事,只有使用顶级设备和技能才能做到。有了Java类,我不会太在意,您可以对它们进行足够的加密以使脚本孩子们离开,而不是更多。
Ped7g

Answers:


96

一些更高级的Java字节码混淆器所做的不仅是类名处理。Zelix KlassMaster例如,还可以使您的代码流混乱,使其很难遵循,并且可以作为出色的代码优化器...

此外,许多混淆器还可以对字符串常量进行加扰并删除未使用的代码。

另一种可能的解决方案(不一定排除混淆)是使用加密的JAR文件和进行解密的自定义类加载器(最好使用本机运行时库)。

第三(可能提供最强大的保护)是使用本机提前编译器,例如GCCExcelsior JET,这些编译器将Java代码直接编译为平台特定的本地二进制文件。

无论如何,您都必须记住爱沙尼亚语中的俗语:“锁是为动物而设的”。意味着在运行时可以使用所有代码,并将其加载到内存中,并且只要有足够的技能,决心和动力,人们就可以并且将对代码进行反编译,解密和黑化……您的工作就是使过程变得不那么舒服。您可以并且仍然使事情正常进行...


13
+1是“锁是动物的”。我猜这里合适的术语是脚本小子。
锑2013年

您的意思是GCJ,它已经死了。
罗恩侯爵,

1
Componio jar文件加密也无效。请改用JarProtector
J.Profi '17

16

只要他们能够访问加密的数据和解密数据的软件,基本上就没有办法确保其完全安全。以前解决此问题的方法是使用某种形式的外部黑匣子来处理加密/解密,例如加密狗,远程身份验证服务器等。但是即使如此,由于用户可以完全访问自己的系统,所以这只能使事情变得简单。困难,并非没有可能-除非您可以将产品直接与在线游戏服务器之类的“黑匣子”中存储的功能绑定在一起。


13

免责声明:我不是安全专家。

这听起来像是个坏主意:您要让某人使用您提供给他的“隐藏”密钥来加密内容。我认为这不能保证安全。

也许非对称密钥可以工作:

  • 部署带有公共密钥的加密许可证以解密
  • 让客户创建新许可证并将其发送给您进行加密
  • 将新许可证发送回客户端。

我不确定,但是我相信客户端实际上可以使用您提供给他的公共密钥来加密许可证密钥。然后,您可以使用私钥对其进行解密并重新进行加密。

您可以为每个客户保留一个单独的公钥/私钥对,以确保您实际上是从合适的客户那里得到的东西-现在要负责密钥...


2
我以前使用过这种技术,并且效果很好。但是,从攻击角度来看,第一种方法是仅修改执行许可证检查的代码并将其删除。您可以采取一些措施来使此攻击向量更难,但是如果您让攻击者控制硬件,那么注定要失败的是有适当动机和技能的攻击者。实际上,目标只是让大多数诚实的人保持诚实。
Jim Rush

12

无论您做什么,都可以对其进行“反编译”。哎呀,你可以拆开它。或者查看内存转储以查找常量。您会看到,计算机需要了解它们,因此您的代码也需要知道它们。

怎么办呢?

尽量不要将密钥作为代码中的硬编码常量发送:将其保留为每个用户的设置。让用户负责该密钥。


6

@jatanp:或者更好的是,它们可以反编译,删除许可代码并重新编译。使用Java,我真的不认为有解决此问题的适当的,防黑客攻击的解决方案。甚至没有邪恶的小软件狗也无法使用Java阻止这种情况。

我自己的业务经理对此很担心,我想得太多了。但是话又说回来,我们将我们的应用程序出售给倾向于遵守许可条件的大型公司,这通常是一个安全的环境,这要归功于bean柜台和律师。如果正确编写了许可证,则反编译本身就是非法的。

因此,我不得不问,您是否真的像您在寻找自己的应用程序一样需要加强保护?您的客户群是什么样的?(公司?还是十几岁的游戏玩家群,这在哪里更成问题?)


事实上,有一个正确的,下锅证明的解决方案,顺便说一句看起来像一个加密狗: excelsior-usa.com/blog/excelsior-jet/...
梅德列斯科夫

@DmitryLeskov可能是“抗黑客攻击的”。但这对任何想要使用该代码的人来说都是一个障碍。最终,字节码必须在未加密的主机平台上运行。句号
斯图·汤普森

您尚未阅读我链接到的帖子。字节码将转换为加密狗的CPU代码并进行加密。当最终用户运行受保护的应用程序时,该加密的代码将传输到“加密狗”。加密狗解密并在其CPU上运行。
德米特里·莱斯科夫

2
企业青少年游戏玩家。
odiszapc

3

如果您正在寻找许可解决方案,则可以查看TrueLicense API。它基于非对称密钥的使用。但是,这并不意味着您的应用程序无法被破解。可以通过足够的努力来破解每个应用程序。正如Stu回答的那样,真正重要的是弄清楚您需要多大的保护。


2

我认为没有任何有效的离线反盗版方法。电子游戏行业试图找到很多次,并且他们的程序始终被破解。唯一的解决方案是,该程序必须与服务器在线连接运行,以便您可以验证lincense密钥,并且被许可方一次只能进行一次活动连接。这就是《魔兽世界》或《暗黑破坏神》运作方式。甚至更艰难的是,有专门为它们开发的专用服务器可以绕过安全性。

话虽如此,我不相信大中型企业会使用非法复制的软件,因为与之相比,它们的许可证成本极低(也许,我不知道您要为程序收取多少费用)试用版的费用。


2

您可以放心使用字节码加密。

事实是,上面引用的论文“破解Java字节码加密”包含逻辑谬误。本文的主要主张是在运行所有类之前必须将其解密并传递给ClassLoader.defineClass(...)方法。但是这是错误的。

如果它们在真实的或标准的Java运行时环境中运行,则会错过此处的假设。受保护的Java应用程序不仅没有义务启动这些类,甚至解密并将它们传递给ClassLoader。换句话说,如果您使用的是标准JRE,则无法拦截defineClass(...)方法,因为标准Java没有为此目的而使用的API;如果您使用带有修补程序ClassLoader或任何其他“黑客把戏”的经过修改的JRE,则不能这样做,因为受保护Java应用程序根本无法工作,因此您将无法进行拦截。而且,使用哪个“补丁查找程序”或黑客使用哪种技巧绝对不重要。这些技术细节是完全不同的故事。


您打算如何精确检测修补的JVM?无论如何,所有这些都会使事情变得更加困难。
锑2013年

您能否在应用启动器中找到对defineClass()的调用?进行该调用时,无论如何都必须提交一个解密字节数组。这不是原始来源可能泄漏的另一点吗?
2013年

4
我真的不同意这个答案。对我来说,这听起来像是“问题:找到Pi的最简单方法是什么?答案:取2 * Pi并除以2。” 我不同意这个想法,但是您能提供更多细节吗?例如,您是否希望主程序用纯Java编写?这包括寻找修改的代码吗?
Patrick M

-1

问:如果我加密.class文件并使用自定义的类加载器即时加载和解密文件,是否可以防止反编译?

答:防止Java字节码反编译的问题几乎与语言本身一样古老。尽管市场上有许多模糊处理工具,但是Java新手程序员仍然在考虑保护知识产权的新颖巧妙方法。在本期Java Q&A文章中,我消除了关于经常在讨论论坛中重新出现的一个想法的一些神话。

Java .class文件可以非常容易地重构为与原始文件非常相似的Java源代码,这与Java字节码的设计目标和权衡关系很大。除其他外,Java字节码旨在通过字节码解释器和JIT(即时)/ HotSpot动态编译器实现紧凑性,平台独立性,网络移动性和易于分析的目的。可以说,已编译的.class文件非常清楚地表达了程序员的意图,与原始源代码相比,它们可能更易于分析。

如果不能完全防止反编译,至少可以增加反编译的难度,可以做几件事。例如,作为编译后的步骤,您可以对.class数据进行处理,以使字节码在反编译时更难以阅读,或者更难于反编译为有效的Java代码(或两者)。诸如执行极端方法名称重载之类的技术对于前者而言效果很好,而操纵控制流以创建不可能通过Java语法表示的控件结构则对后者而言效果很好。比较成功的商业混淆器将这些技术与其他技术结合使用。

不幸的是,这两种方法实际上都必须更改JVM将运行的代码,许多用户担心(理应如此)这种转换可能会在其应用程序中添加新的错误。此外,方法和字段重命名可能导致反射调用停止工作。更改实际的类和程序包名称可能会破坏其他几种Java API(JNDI(Java命名和目录接口),URL提供程序等)。除了更改名称之外,如果更改了类字节码偏移量和源行号之间的关联,则恢复原始异常堆栈跟踪可能会变得困难。

然后可以选择混淆原始Java源代码。但是从根本上讲,这会引起一系列类似的问题。加密,而不是混淆?

也许上面的内容使您想到:“好吧,如果我不处理字节码,而是在编译后对我的所有类进行加密,然后在JVM中对其进行动态解密(可以通过自定义类加载器完成),那该怎么办?然后JVM执行我的原始字节码,却没有反编译或反向工程的功能,对吧?”

不幸的是,您既会认为自己是第一个提出此想法的人,又会认为它确实有效,这是错误的。原因与加密方案的强度无关。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.