关于jvm:如何锁定已编译的Java类以防止反编译?

关于jvm:如何锁定已编译的Java类以防止反编译?

How to lock compiled Java classes to prevent decompilation?

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

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

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

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

还是应该使用本机代码(例如VC ++)构建此类敏感组件,然后通过JNI对其进行调用?


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

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

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

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

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


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


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

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

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

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

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

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


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

怎么办呢?

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


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

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

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


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


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

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

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


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

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


问:如果我加密.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执行我的原始字节码,但没有任何反编译或反向工程的功能,对吧?"

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


推荐阅读