混淆应用程序是否存在潜在问题?

3

我正在构建一个Spring MVC Web应用程序。

我计划使用Hibernate。

我对混淆等方面没有太多经验。

混淆应用程序的潜在缺点是什么?

我知道可能存在调试应用程序和恢复丢失源代码的问题。

实际运行应用程序是否会有任何已知问题?会引入错误吗?

由于这是我寻求一般指导的领域,请随时提出我应该注意的任何问题。

5个回答

8

很惊讶没有人提到速度 - 通常,代码越难懂=运行速度越慢。


[编辑] 我不敢相信这个答案得到了-2。这是一个正确的答案。

缩短标识符和删除未使用的方法会减小文件大小,但对运行速度没有任何影响(除了减少加载时间的几个纳秒)。与此同时,程序的大部分混淆来自于添加的代码:

  • 将1个方法拆分成5个;交错方法;合并类 [聚合变换]
  • 将1个算术表达式分裂成10个;混淆控制流程 [计算变换]
  • 添加一些无用的代码块 [不透明谓词]

这些都是常见的混淆技术,会导致程序运行更慢。


1
你从哪里得到这个想法的?如果说混淆可以缩短标识符并删除未使用的类/方法,那么它就是一种优化。 - rsp
(@Raja,我在添加评论时没有给你点踩。)我遇到的几个混淆器实际上进行了优化。我猜想,在混淆过程中添加垃圾代码的混淆器是需要注意的,就像你所说的那样。 - rsp

8

当然,使用代码混淆器可能会带来一些潜在的性能/维护问题,但是一个好的代码混淆器至少可以帮助你解决其中的一些问题。以下是需要注意的事项:

  • 明显的问题:如果你的代码通过反射调用方法或动态加载类,那么这可能会失败,因为类/方法名称已经被混淆;一个好的代码混淆器将允许你选择不混淆的类/方法名称以解决这个问题;
  • 如果你的应用程序不是同时编译的,则可能会出现类似的问题;
  • 如果它直接处理字节码级别,那么混淆器可以创建Java编译器原则上无法创建的代码(例如,它可以插入任意GOTO指令,而从Java中只能作为循环的一部分创建)- 这可能有点理论,但如果我要编写JVM,则会优化Java编译器可以创建的字节码序列的性能,而不是不能创建的字节码序列......
  • 如果混淆器明显改变了方法中的字节码数量,或以某种方式更改了给定方法/代码块是否满足某些JVM优化的阈值(例如,“内联方法,字节码少于X”),则混淆器可能会对性能造成其他微妙的影响。

但是,正如你所看到的,这些影响有些微妙和理论- 因此,在混淆之后,你需要对你的应用程序进行大量的实测,就像你对任何其他重要更改一样。

你还应该小心不要假设混淆可以隐藏你想要隐藏的代码/算法(如果这是你的意图) - 使用反编译器查看结果混淆过的类的内容。


4
您可能需要查看这里的一些评论,以决定是否进行混淆: https://stackoverflow.com/questions/1988451/net-obfuscation 您可能想表达为什么要混淆。在我看来,最好的原因主要是拥有更小的应用程序,因为您可以摆脱在项目中未使用的类,同时进行混淆。
只要您不使用反射,并且假设您可以找到某些内容(例如私有方法),我从未见过引入错误的情况,因为它们的名称将被更改。

“InternalsVisibleToAttribute”也是混淆漏洞的丰富来源。我也曾经看到过激进的混淆使得在Mono上无法使用程序集的情况。 - itowlson

1
最大的问题在于混淆程序通常保证不改变其目标程序的行为。在某些情况下,这很难实现--例如,想象一下一个通过反射从字符串数组检查特定私有字段值的程序。混淆器可能无法确定该字符串也需要相应地更新,结果就会出现运行时意外访问错误。
更糟糕的是,程序的行为微妙地改变可能并不明显--那么你可能根本不知道有问题,直到你的客户先发现并感到不满。
一般来说,专业级别的混淆产品足够复杂,可以捕获一些问题并防止它们发生,但最终覆盖所有问题可能是具有挑战性的。最好的方法是对混淆结果进行单元测试,并确保所有预期的行为仍然成立。

你能推荐一些免费的专业级编程软件吗? - mrblah

0

一个免费的 obfuscator 是 Babel,你可能想要试试。它被设计用于命令行(像许多其他的 obfuscators 一样),有一个 Reflector addin 可以为你提供 UI。

当涉及到混淆时,你真的需要分析你的目标是什么。在你的情况下 - 如果你有一个 web 应用程序(mvc),你计划将其作为可下载的应用程序出售吗?(如果不是,并且你将源代码保留在你的 web 服务器上,那么你不需要它)。

你可以查看组件并选择只混淆某些部分...而不是整个应用程序。一般来说,当你在开发后尝试添加混淆时,ASP.Net 应用程序很容易崩溃,因为使用了大量反射。

几乎以上提到的所有内容都是正确的...这完全取决于你打开多少功能来使你的代码难以逆向:

成员重命名(字段/方法/事件/属性)是最常见的操作之一(有不同的方式:从将方法从GetId()更改为a()到不可读的字符和命名空间的删除)。顺便说一句:这通常会破坏反射。你的程序集文件可能会变得更小,因为使用了较小的字符串。
字符串加密:这使得在您的代码中使用静态字符串时更难逆向操作。顺便说一句:这与重命名配对使用时将使调试重命名问题更加困难......因此,您可能需要在解决问题后再开启它。这还需要添加解密代码,在IL中使用该字符串之前进行解密。
代码混淆...这就是BlueRaja所指的。它使您的代码看起来像意大利面条代码-使其更难以被人理解。CLR不喜欢这个......它不能像往常那样轻松地优化事物,而且由于用于此选项的IL重写,您的最终代码很可能会处理得更慢,因为某些内容没有被内联。顺便说一句:这个选项确实提高了反向工程源代码所需的门槛,但可能会带来性能损失。
删除未使用的代码。一些模糊器为您提供了修剪发现未使用的任何代码的选项。如果您有很多死代码,则可以使程序集变小...但这只是模糊器提供的免费福利。

我的建议是只有在你知道为什么要使用它并且以此为设计目标时才使用它...不要在完成代码后尝试添加它(我曾经这样做过,不好玩)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接