问:如果我加密我的 .class 文件并使用自定义类加载器即时加载和解密它们,这会阻止反编译吗?
A:防止Java 字节码反编译的问题几乎与语言本身一样古老。尽管市场上有一系列混淆工具可供使用,但 Java 新手程序员仍在不断思考新的巧妙方法来保护他们的知识产权。在这期 Java 问答部分中,我消除了一些关于论坛中经常重复讨论的想法的神话。
Java .class 文件可以极其容易地重构为与原始文件非常相似的 Java 源代码,这与 Java 字节码设计目标和权衡取舍有很大关系。除其他外,Java 字节码旨在实现紧凑性、平台独立性、网络移动性以及字节码解释器和 JIT(即时)/HotSpot 动态编译器易于分析。可以说,编译后的 .class 文件如此清楚地表达了程序员的意图,它们比原始源代码更容易分析。
可以做几件事,如果不是为了完全防止反编译,至少要让它变得更加困难。例如,作为编译后的步骤,您可以对 .class 数据进行处理,以使字节码在反编译时更难阅读,或者更难反编译成有效的 Java 代码(或两者兼而有之)。执行极端方法名称重载等技术适用于前者,而操纵控制流以创建无法通过 Java 语法表示的控制结构则适用于后者。更成功的商业混淆器使用这些技术和其他技术的混合。
不幸的是,这两种方法都必须实际更改 JVM 将运行的代码,并且许多用户担心(理所当然地)这种转换可能会给他们的应用程序添加新的错误。此外,方法和字段重命名可能会导致反射调用停止工作。更改实际的类和包名称可能会破坏其他几个 Java API(JNDI(Java 命名和目录接口)、URL 提供程序等)。除了更改名称之外,如果类字节码偏移量和源行号之间的关联发生更改,恢复原始异常堆栈跟踪可能会变得困难。
然后是混淆原始 Java 源代码的选项。但从根本上说,这会导致一系列类似的问题。加密,而不是混淆?
也许上面的内容让你想到,“好吧,如果我在编译后加密我所有的类并在 JVM 中动态解密它们(这可以通过自定义类加载器完成)而不是操作字节码怎么办?然后 JVM 执行我的原始字节码,但没有什么可以反编译或逆向工程,对吧?”
不幸的是,你错了,你认为你是第一个提出这个想法的人,并且认为它确实有效。原因与您的加密方案的强度无关。