如何锁定已编译的Java类以防止反编译?
我知道这必须是互联网上讨论得很好的主题,但在提到它之后我无法得出任何结论。
许多人确实建议使用混淆器,但他们只是使用难以记忆的字符序列重命名类,方法和字段,但是敏感的常量值呢?
例如,您已基于基于密码的加密技术开发了加密和解密组件。现在在这种情况下,任何普通的Java人员都可以使用JAD来反编译该类文件,并轻松检索密码值(定义为常量)以及salt,然后通过编写小写来解密数据独立计划!
或者是否应该使用本机代码(例如VC ++)构建此类敏感组件并通过JNI调用它们?
答案 0 :(得分:92)
一些更高级的Java字节码混淆器不仅仅是类名称修改。例如,Zelix KlassMaster也可以以一种非常难以理解的方式扰乱您的代码流,并作为优秀的代码优化器工作......
许多混淆器也能够加扰你的字符串常量并删除未使用的代码。
另一种可能的解决方案(不一定排除混淆)是使用encrypted JAR files和执行解密的自定义类加载器(最好使用本机运行时库)。
第三(并且可能提供最强大的保护)是使用原生的提前编译器,例如GCC或Excelsior JET,将Java代码直接编译为特定于平台的本机二进制文件。 / p>
无论如何你必须记住爱沙尼亚语中的谚语“锁定动物”。这意味着在运行期间每一段代码都可用(加载到内存中)并且给予足够的技能,决心和动力,人们可以并且将会反编译,解读和破解您的代码......您的工作只是让过程变得不舒服你可以并且仍然保持工作......
答案 1 :(得分:16)
只要他们可以访问加密数据和解密它的软件,基本上没有办法让你完全安全。之前已经解决的方法是使用某种形式的外部黑匣子来处理加密/解密,例如加密狗,远程认证服务器等。但即便如此,鉴于用户可以完全访问他们自己的系统,这只能做事情困难,并非不可能 - 除非您将产品直接绑定到“黑匣子”中存储的功能,例如在线游戏服务器。
答案 2 :(得分:12)
免责声明:我不是安全专家。
这听起来像个坏主意:你让某人用你给他的“隐藏”密钥来加密东西。我不认为这可以保证安全。
也许非对称键可以起作用:
我不确定,但我相信客户端实际上可以使用您提供的公钥加密许可证密钥。然后,您可以使用私钥对其进行解密并重新加密。
您可以为每个客户保留一个单独的公钥/私钥对,以确保您确实从正确的客户那里获得了东西 - 现在您负责密钥......
答案 3 :(得分:10)
无论你做什么,都可以'反编译'。哎呀,你可以把它拆开。或者查看内存转储以查找常量。你看,计算机需要知道它们,所以你的代码也需要。
该怎么办?
尽量不要将密钥作为代码中的硬编码常量发送:将其保留为每用户设置。让用户负责管理该密钥。
答案 4 :(得分:5)
@jatanp:或者更好的是,他们可以反编译,删除许可代码并重新编译。使用Java,我并不认为这个问题有一个适当的,防黑客的解决方案。即使是一个邪恶的小加密狗也不能用Java阻止它。
我自己的商业经理担心这一点,我想太多了。但话说回来,我们将我们的应用程序出售给那些倾向于遵守许可条件的大型企业 - 通常是一个安全的环境,这要归功于豆类柜台和律师。如果您的许可证写得正确,则反编译的行为可能是非法的。
所以,我不得不问,你真的需要强化保护,就像你正在寻找你的申请一样吗?您的客户群是什么样的? (企业?还是十几岁的玩家群众,这会更成为一个问题?)
答案 5 :(得分:3)
如果您正在寻找许可解决方案,可以查看TrueLicense API。它基于非对称键的使用。但是,这并不意味着您的应用程序无法破解。每个应用程序都可以通过足够的努真正重要的是,Stu answered,找出你需要多么强大的保护。
答案 6 :(得分:2)
我认为没有任何有效的离线反盗版方法。视频游戏行业试图发现很多次,他们的程序一直被破解。唯一的解决方案是程序必须与您的服务器联机运行,以便您可以验证lincense密钥,并且被许可方一次只有一个活动连接。这就是World of Warcraft或Diablo的工作原理。即使很难,也有为他们开发的私人服务器绕过安全。
话虽如此,我不相信中/大公司使用非法复制的软件,因为他们的许可费用很少(也许,我不知道你为你的程序收取多少费用) )与试用版的成本相比。
答案 7 :(得分:2)
您可以毫不畏惧地使用字节码加密。
事实是上面引用的论文“破解Java字节码加密”包含一个逻辑谬误。该论文的主要论点是在运行之前,所有类必须被解密并传递给ClassLoader.defineClass(...)
方法。但是这是错误的。
这里假设的假设是,前提是它们在真实的或标准的java运行时环境中运行。没有什么可以迫使受保护的Java应用程序不仅要启动这些类,还要解密并将它们传递给ClassLoader
。换句话说,如果您使用标准JRE,则无法拦截defineClass(...)
方法,因为标准java没有用于此目的的API,并且如果您使用已修补的ClassLoader
或任何其他“黑客”的修改后的JRE诀窍“你不能这样做,因为受保护的Java应用程序根本不起作用,因此你将无法拦截。无论使用哪种“补丁查找器”或黑客使用哪种技巧都无关紧要。这些技术细节是一个完全不同的故事。
答案 8 :(得分:0)
问:如果我加密我的.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执行我的原始字节代码,但没有任何反编译或反向工程,对吧?“
不幸的是,你认为自己是第一个提出这个想法的人并且认为它确实有效,你就错了。原因与加密方案的强度无关。