在 Java 中混淆游戏

Obfuscate a game in Java

我的情况与此类似...我目前正在 Java 开发一款游戏,我已经采取了几个步骤来保护数据(例如在保存本地文件时使用加密) .然而,朋友推荐我做的一件事是混淆代码,使其变得混乱和不可读,这样如果有人决定打开它——它对他们来说几乎没有用。

我的问题分为几个部分......首先,作为一个普遍的想法,这实际上会降低人们 break/steal/copy 我的游戏的可能性,或者混淆的影响代码可以忽略不计?其次,如果值得这样做 - 是否会对性能产生任何影响?

编辑 - 我主要是想确保代码不会在游戏中作弊,因为客户端的许多文件可能会被操纵以提供不公平的优势。保护实际的二进制文件是我以后必须考虑的一个选项;现在我只是在考虑制作它,这样代码库本身就不能轻易提取和更改。

代码混淆最容易通过专用工具自动完成,例如 Proguard

根据 previous discussion,使用 ProGuard 对代码的性能影响可以忽略不计。

首先,对我写的文字量感到抱歉。

其次,我完全同意answer to the question you linked to:
远离代码流改变 "obfuscators".
(我称它们为 "scramblers",但 English 就是这种情况。)

第三,非常严格地说,纯混淆(如 class 和成员重命名)通常会生成更短的名称(参见 Minecraft 中的 ab、... ) 比你选择的要短,所以因为 class 文件更短,所以加载 classes 可能会稍微快一点,而且因为比较较短的字符串花费的时间更少,所以成员查找会稍微快一点也更快,可能会导致非静态方法调用的性能略有提高。
但是,这种改进很可能可以忽略不计,如果 JVM 执行任何形式的查找缓存,我根本不会期望任何性能改进。
但是,仅 class 和成员重命名,我也不希望性能下降。

至于是否会阻止人们作恶……也许有一点。
非常懒惰的程序员和新手肯定会被吓跑。
然后就看别人破解你的代码能得到多少了。
如果黑客可以通过破解你的游戏(即 speedhack)个人获得一些东西,我想说它发生的可能性比他可以在没有许可证或其他东西的情况下制作 运行 的付费游戏要大得多。
而且还要看代码有多少,需要改动多少。
如果你有大约 25 classes 或更少,我认为对于一个有点高级的开发人员来说,这并不难。
但是Minecraft大小的应用就是另外一回事了。
但以 Minecraft 为例,我最终学会了通过混淆代码找到我的方法,因为每次发布后生成反混淆列表的时间会越来越长,我只想让我的模组保持最新。
大胆声明,对我来说,破解混淆的 java 应用程序并不比破解非混淆的应用程序难多少,而且我当然不是唯一的人。

此外,一些混淆器完全随机选择名称,因此发布更新可能具有完全不同的名称。
有人可能认为这会让黑客退缩,但是一旦您粗略地了解 class 在一个版本中代表什么,您就可以通过搜索字符串轻松地在下一个版本中再次找到 class 和导入 classes 或此类的成员,从那里您可以连接到其他混淆的 classes。
(例如,在 Minecraft 中,我总是从制作管理器开始,因为它有独特的 "###" 字符串,而且由于它大量使用方块和物品,我可以立即从那里找到很多 class。)

但实际上有一件事确实站在你这边:名称冲突。
再次使用 Minecraft,我意识到有些文件无法再次编译 - 不是因为反编译器生成了无效代码,而是因为 a 被用作 class 名称 一个字段名,该字段优先(否则我可以使用 athis.a - 请注意,这仅在您的混淆器删除包并将所有 classes 在顶层!),所以除了反射之外没有其他方法可以引用 class,这就是我在某些情况下最终所做的。在其他情况下(性能是一个问题),我创建了一个 "fake" class 的类型,我可以根据不同的名称进行编译,然后篡改生成的字节码以将名称改回。
因此,尽管仍有可能,但肯定需要付出很多努力。
如果我不得不解决数百次碰撞,我很可能很快就会放弃。

此外,我了解到,至少对于 Oracle 的 Java 实现,版本 6 到 8,字节码中的 "invalid" 名称似乎不是问题,至少对某些人来说不是范围。
在我的一个项目中,我需要在 运行 时间创建字节码,并且我需要生成的 class 包含一个名称不会与 class 可能包含的任何其他方法冲突的方法,所以我的第一个尝试是使用无效字符 (*) 作为它的名称,到目前为止(它已经出现 2 年了)我还没有收到任何关于 JVM 拒绝它的错误报告。
我不知道那里是否有支持无效名称的混淆器,但有了这样的混淆器,您当然可以生成不仅在反编译时看起来很糟糕,而且甚至无法编译的代码。 我想像

Some thing = field.method().whatever.array[index];

变成:

! ? = &.%().+.*[/];

看起来很整洁,不是吗?而且我相信编译器会喜欢它。 *邪恶的笑容*
(但即使它有效,我也不推荐它,因为这不是很好的练习。)

在那个级别,您的代码仍然可以破解,但可能不会比机器代码多很多,所以您应该是安全的。


TL;DR

  • 远离改变代码流的垃圾。
  • 很多 classes = 额外的模糊层。
  • 很多 classes = 名称冲突的可能性更高。
  • 只要奖励够高,总会有人破解的