如何锁定已编译的 Java 类以防止反编译?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/49379/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to lock compiled Java classes to prevent decompilation?
提问by jatanp
How do I lock compiled Java classes to prevent decompilation?
如何锁定已编译的 Java 类以防止反编译?
I know this must be very well discussed topic on the Internet, but I could not come to any conclusion after referring them.
我知道这一定是互联网上讨论得很好的话题,但在参考之后我无法得出任何结论。
Many people do suggest obfuscator, but they just do renaming of classes, methods, and fields with tough-to-remember character sequences but what about sensitive constant values?
许多人确实建议使用混淆器,但他们只是用难以记住的字符序列重命名类、方法和字段,但是敏感的常量值呢?
For example, you have developed the encryption and decryption component based on a password based encryption technique. Now in this case, any average Java person can use JADto decompile the class file and easily retrieve the password value (defined as constant) as well as saltand in turn can decrypt the data by writing small independent program!
例如,您开发了基于密码加密技术的加密和解密组件。现在在这种情况下,任何普通的 Java 人都可以使用JAD反编译类文件,轻松检索密码值(定义为常量)和盐,进而可以通过编写独立的小程序来解密数据!
Or should such sensitive components be built in native code (for example, VC++) and call them via JNI?
还是应该将此类敏感组件构建在本机代码(例如 VC++)中并通过JNI调用它们?
采纳答案by Roland Tepp
Some of the more advanced Java bytecode obfuscators do much more than just class name mangling. Zelix KlassMaster, for example, can also scramble your code flow in a way that makes it really hard to follow and works as an excellent code optimizer...
一些更高级的 Java 字节码混淆器所做的不仅仅是类名修改。例如,Zelix KlassMaster还可以打乱您的代码流,使其很难遵循并作为出色的代码优化器工作......
Also many of the obfuscators are also able to scramble your string constants and remove unused code.
此外,许多混淆器还能够打乱您的字符串常量并删除未使用的代码。
Another possible solution (not necessarily excluding the obfuscation) is to use encrypted JAR filesand a custom classloader that does the decryption (preferably using native runtime library).
另一种可能的解决方案(不一定排除混淆)是使用加密的 JAR 文件和进行解密的自定义类加载器(最好使用本机运行时库)。
Third (and possibly offering the strongest protection) is to use native ahead of time compilers like GCCor Excelsior JET, for example, that compile your Java code directly to a platform specific native binary.
第三个(可能提供最强大的保护)是使用像GCC或Excelsior JET这样的本地提前编译器,例如,将您的 Java 代码直接编译为特定于平台的本地二进制文件。
In any case You've got to remember that as the saying goes in Estonian "Locks are for animals". Meaning that every bit of code is available (loaded into memory) during the runtime and given enough skill, determination and motivation, people can and will decompile, unscramble and hack your code... Your job is simply to make the process as uncomfortable as you can and still keep the thing working...
无论如何,您必须记住,正如爱沙尼亚语中所说的“锁是为动物准备的”。这意味着在运行时每一段代码都是可用的(加载到内存中),并给予足够的技能、决心和动力,人们可以并且将会反编译、解读和破解你的代码......你的工作只是让这个过程变得像你可以并且仍然保持工作......
回答by Daren Thomas
No matter what you do, it can be 'decompiled'. Heck, you can just disassemble it. Or look at a memory dump to find your constants. You see, the computer needs to know them, so your code will need to too.
无论你做什么,它都可以被“反编译”。哎呀,你可以把它拆开。或者查看内存转储以找到您的常量。你看,计算机需要知道它们,所以你的代码也需要知道。
What to do about this?
怎么办?
Try not to ship the key as a hardcoded constant in your code: Keep it as a per-user setting. Make the user responsible for looking after that key.
尽量不要在代码中将密钥作为硬编码常量发送:将其作为每个用户的设置。让用户负责保管该密钥。
回答by Daren Thomas
Disclaimer: I am not a security expert.
免责声明:我不是安全专家。
This sounds like a bad idea: You are letting someone encrypt stuff with a 'hidden' key that you give him. I don't think this can be made secure.
这听起来像是个坏主意:您让某人使用您提供给他的“隐藏”密钥来加密内容。我不认为这可以确保安全。
Maybe asymmetrical keys could work:
也许非对称密钥可以工作:
- deploy an encrypted license with a public key to decrypt
- let the customer create a new license and send it to you for encryption
- send a new license back to the client.
- 使用公钥部署加密许可证以进行解密
- 让客户创建一个新的许可证并将其发送给您进行加密
- 将新许可证发送回客户端。
I'm not sure, but I believe the client can actually encrypt the license key with the public key you gave him. You can then decrypt it with your private key and re-encrypt as well.
我不确定,但我相信客户实际上可以使用您提供给他的公钥来加密许可证密钥。然后你可以用你的私钥解密它并重新加密。
You could keep a separate public/private key pair per customer to make sure you actually are getting stuff from the right customer - now youare responsible for the keys...
您可以为每个客户保留一个单独的公钥/私钥对,以确保您确实从正确的客户那里获得了东西-现在您负责密钥...
回答by Stu Thompson
@jatanp: or better yet, they can decompile, remove the licensing code, and recompile. With Java, I don't really think there is a proper, hack-proof solution to this problem. Not even an evil little dongle could prevent this with Java.
@jatanp:或者更好的是,他们可以反编译、删除许可代码并重新编译。对于 Java,我真的不认为有一个适当的、防黑客的解决方案来解决这个问题。使用 Java,即使是一个邪恶的小加密狗也无法阻止这一点。
My own biz managers worry about this, and I think too much. But then again, we sell our application into large corporates who tend to abide by licensing conditions--generally a safe environment thanks to the bean counters and lawyers. The act of decompiling itself can be illegal if your license is written correctly.
我自己的业务经理担心这个,我想太多了。但话又说回来,我们将我们的应用程序出售给倾向于遵守许可条件的大公司——由于豆子柜台和律师,通常是一个安全的环境。如果您的许可证编写正确,反编译本身的行为可能是非法的。
So, I have to ask, do you reallyneed hardened protection like you are seeking for your application? What does your customer base look like? (Corporates? Or the teenage gamer masses, where this would be more of an issue?)
所以,我不得不问,您真的需要像您正在为您的应用程序寻求的强化保护吗?您的客户群是什么样的?(企业?还是青少年玩家群体,这会是一个更大的问题吗?)
回答by Erlend Halvorsen
As long as they have access to both the encrypted data and the software that decrypts it, there is basically no way you can make this completely secure. Ways this has been solved before is to use some form of external black box to handle encryption/decryption, like dongles, remote authentication servers, etc. But even then, given that the user has full access to their own system, this only makes things difficult, not impossible -unless you can tie your product directly to the functionality stored in the "black box", as, say, online gaming servers.
只要他们可以访问加密数据和解密数据的软件,基本上就没有办法让它完全安全。以前解决这个问题的方法是使用某种形式的外部黑匣子来处理加密/解密,如加密狗、远程身份验证服务器等。但即便如此,鉴于用户可以完全访问自己的系统,这只会使事情变得困难,并非不可能 - 除非您可以将您的产品直接与存储在“黑匣子”中的功能相关联,例如在线游戏服务器。
回答by hakan
If you're looking for a licensing solution, you can check out the TrueLicense API. It's based on the use of asymmetrical keys. However, it doesn't mean your application cannot be cracked. Every application can be cracked with enough effort. What really important is, as Stu answered, figuring out how strong protection you need.
如果您正在寻找许可解决方案,您可以查看TrueLicense API。它基于非对称密钥的使用。但是,这并不意味着您的应用程序无法破解。每个应用程序都可以通过足够的努力来破解。正如Stu 回答的那样,真正重要的是弄清楚您需要多强的保护。
回答by Telcontar
I don't think there exists any effective offline antipiracy method. The videogame industry has tried to find that many times and their programs has always been cracked. The only solution is that the program must be run online connected with your servers, so that you can verify the lincense key, and that there is only one active connecion by the licensee at a time. This is how World of Warcraftor Diabloworks. Even tough there are private servers developed for them to bypass the security.
我认为不存在任何有效的离线反盗版方法。电子游戏行业已经多次尝试发现,他们的程序总是被破解。唯一的解决方案是该程序必须与您的服务器连接在线运行,以便您可以验证 lincense 密钥,并且被许可人一次只有一个活动连接。这就是魔兽世界或暗黑破坏神的运作方式。甚至还有为他们开发的私人服务器来绕过安全性。
Having said that, I don't believe that mid/large corporations use illegal copied software, because the cost of the license for them is minimal (perhaps, I don't know how much you are goig to charge for your program) compared to the cost of a trial version.
话虽如此,我不相信大中型公司使用非法复制的软件,因为与它们相比,它们的许可证成本是最低的(也许,我不知道你要为你的程序收取多少费用)试用版的费用。
回答by Yury Bendersky
You can use byte-code encryption with no fear.
您可以无所畏惧地使用字节码加密。
The fact is that the cited above paper “Cracking Java byte-code encryption” contains a logic fallacy. The main claim of the paper is before running all classes must be decrypted and passed to the ClassLoader.defineClass(...)
method. But this is not true.
事实是,上面引用的论文“破解 Java 字节码加密”包含一个逻辑谬误。该论文的主要主张是在运行所有类之前必须解密并传递给ClassLoader.defineClass(...)
方法。但是这是错误的。
The assumption missed here is provided that they are running in authentic, or standard, java run-time environment. Nothing can oblige the protected java app not only to launch these classes but even decrypt and pass them to ClassLoader
. In other words, if you are in standard JRE you can't intercept defineClass(...)
method because the standard java has no API for this purpose, and if you use modified JRE with patched ClassLoader
or any other “hacker trick” you can't do it because protected java app will not work at all, and therefore you will have nothing to intercept. And absolutely doesn't matter which “patch finder” is used or which trick is used by hackers. These technical details are a quite different story.
此处忽略的假设是,它们在真实或标准的 Java 运行时环境中运行。没有什么可以迫使受保护的 Java 应用程序不仅启动这些类,而且甚至解密它们并将它们传递给ClassLoader
. 换句话说,如果你在标准 JRE 中你不能拦截defineClass(...)
方法,因为标准 java 没有用于这个目的的 API,如果你使用带有补丁ClassLoader
或任何其他“黑客技巧”的修改后的 JRE,你不能这样做,因为受保护java 应用程序根本无法运行,因此您将无法拦截任何内容。使用哪种“补丁查找器”或黑客使用哪种技巧完全无关紧要。这些技术细节是一个完全不同的故事。
回答by S Harish Morampudi
Q: If I encrypt my .class files and use a custom classloader to load and decrypt them on the fly, will this prevent decompilation?
问:如果我加密我的 .class 文件并使用自定义类加载器动态加载和解密它们,这会阻止反编译吗?
A: The problem of preventing Java byte-code decompilation is almost as old the language itself. Despite a range of obfuscation tools available on the market, novice Java programmers continue to think of new and clever ways to protect their intellectual property. In this Java Q&A installment, I dispel some myths around an idea frequently rehashed in discussion forums.
答:阻止 Java 字节码反编译的问题几乎与语言本身一样古老。尽管市场上有一系列混淆工具可用,但 Java 新手程序员仍在继续思考新的、聪明的方法来保护他们的知识产权。在本期 Java 问答中,我消除了围绕讨论论坛中经常重复的想法的一些神话。
The extreme ease with which Java .class files can be reconstructed into Java sources that closely resemble the originals has a lot to do with Java byte-code design goals and trade-offs. Among other things, Java byte code was designed for compactness, platform independence, network mobility, and ease of analysis by byte-code interpreters and JIT (just-in-time)/HotSpot dynamic compilers. Arguably, the compiled .class files express the programmer's intent so clearly they could be easier to analyze than the original source code.
Java .class 文件可以极其轻松地重构为与原始文件非常相似的 Java 源代码,这与 Java 字节码设计目标和权衡有很大关系。除其他外,Java 字节码旨在实现紧凑性、平台独立性、网络移动性以及字节码解释器和 JIT(即时)/HotSpot 动态编译器的易于分析。可以说,编译后的 .class 文件非常清楚地表达了程序员的意图,它们比原始源代码更容易分析。
Several things can be done, if not to prevent decompilation completely, at least to make it more difficult. For example, as a post-compilation step you could massage the .class data to make the byte code either harder to read when decompiled or harder to decompile into valid Java code (or both). Techniques like performing extreme method name overloading work well for the former, and manipulating control flow to create control structures not possible to represent through Java syntax work well for the latter. The more successful commercial obfuscators use a mix of these and other techniques.
有几件事可以做,如果不是为了完全防止反编译,至少是让它变得更加困难。例如,作为编译后步骤,您可以修改 .class 数据,使字节码在反编译时更难阅读,或者更难反编译为有效的 Java 代码(或两者兼有)。诸如执行极端方法名称重载之类的技术对前者很有效,而操纵控制流以创建无法通过 Java 语法表示的控制结构对后者很有效。更成功的商业混淆器混合使用这些技术和其他技术。
Unfortunately, both approaches must actually change the code the JVM will run, and many users are afraid (rightfully so) that this transformation may add new bugs to their applications. Furthermore, method and field renaming can cause reflection calls to stop working. Changing actual class and package names can break several other Java APIs (JNDI (Java Naming and Directory Interface), URL providers, etc.). In addition to altered names, if the association between class byte-code offsets and source line numbers is altered, recovering the original exception stack traces could become difficult.
不幸的是,这两种方法实际上都必须更改 JVM 将运行的代码,而且许多用户担心(理所当然地)这种转换可能会给他们的应用程序添加新的错误。此外,方法和字段重命名会导致反射调用停止工作。更改实际的类和包名称可能会破坏其他几个 Java API(JNDI(Java 命名和目录接口)、URL 提供程序等)。除了更改名称之外,如果类字节码偏移量和源代码行号之间的关联发生更改,则恢复原始异常堆栈跟踪可能会变得困难。
Then there is the option of obfuscating the original Java source code. But fundamentally this causes a similar set of problems. Encrypt, not obfuscate?
然后是混淆原始 Java 源代码的选项。但从根本上说,这会导致一系列类似的问题。加密,而不是混淆?
Perhaps the above has made you think, "Well, what if instead of manipulating byte code I encrypt all my classes after compilation and decrypt them on the fly inside the JVM (which can be done with a custom classloader)? Then the JVM executes my original byte code and yet there is nothing to decompile or reverse engineer, right?"
也许上面的内容让您想到,“好吧,如果我在编译后加密所有类并在 JVM 内部动态解密它们,而不是操作字节码会怎样?然后 JVM 执行我的原始字节码,但没有什么可以反编译或逆向工程,对吧?”
Unfortunately, you would be wrong, both in thinking that you were the first to come up with this idea and in thinking that it actually works. And the reason has nothing to do with the strength of your encryption scheme.
不幸的是,您会错误地认为您是第一个提出这个想法的人,并且认为它确实有效。原因与您的加密方案的强度无关。