我可以采取哪些步骤来使我的 C++ 应用程序更难逆向工程?

逆向工程 混淆 编译器 C++ 符号 字符串
2021-06-25 01:22:47

如果我正在构建一个 C++ 应用程序并且我想让逆向工程变得更加困难,我可以采取哪些步骤来做到这一点?

  • 编译器的选择会影响这个吗?
  • 编译器标志怎么样,大概高优化级别会有所帮助,那么其他标志呢?
  • 剥离符号是否有帮助而不是使用调试符号进行构建?
  • 我应该加密任何内部数据,例如静态字符串吗?
  • 我还可以采取哪些其他步骤?
1个回答

编译器

编译器的选择对逆向工程代码的难度影响最小。要尽量减少的重要事情都与代码中的信息泄漏有关。您至少要禁用任何运行时类型信息 (RTTI)。类型信息的泄露和虚拟机​​指令集的简单性是CLR和JVM代码更容易逆向工程的原因之一。他们还有一个 JIT,可以对代码进行优化,这可能会降低混淆的强度。混淆基本上与优化相反,许多混淆是通过首先应用优化通道来解决的。

调试信息

我建议您也关闭任何调试信息,即使它今天没有泄漏任何重要的重要信息,但明天可能会泄漏。从调试信息泄漏的信息量因编译器而异,也因二进制格式而异。例如,Microsoft Visual C++ 将所有重要的调试信息保存在外部数据库中,通常以 PDB 的形式。您可能泄漏的最多的是您在构建软件时使用的路径。

字符串

当涉及到字符串时,如果你真的需要它们,你绝对应该加密它们。我的目标是用数字枚举替换所有用于错误跟踪和错误记录的错误。显示二进制文件中当前正在发生的事情的任何类型的信息的字符串需要不可用。如果您加密字符串,它们将被解密。尽量避免它们。

系统 API

另一个重要的信息泄漏来源是系统 API 的导入。您想确保任何具有已知签名的导入函数都隐藏得很好,并且无法使用自动分析找到。因此,来自 LoadLibrary/GetProcAddress 之类的函数指针数组是不可能的。所有对导入函数的调用都需要通过单向函数,并且需要嵌入到一个混淆块中。

标准运行时库

许多人忘记考虑的是标准库泄露的信息,例如 C++ 编译器的运行时。我会完全避免使用它。这是因为大多数有经验的逆向工程师都会为很多标准库准备签名。

混淆

您还应该使用某种严重的混淆来覆盖任何关键代码。现在一些更重、更便宜的混淆是CodeVirtualizer/ThemidaVMProtect请注意,这些软件包有很多缺陷。他们有时会将您的代码转换为与原始代码不同的内容,这可能会导致不稳定。它们还显着降低了混淆代码的速度。慢 10000 倍的因素并不少见。还有一个问题是使用防病毒软件触发更多误报。我建议您使用信誉良好的证书颁发机构对您的软件进行签名。

功能块分离

将代码分离成函数是另一件事,它使对程序进行逆向工程变得更容易。这在函数被混淆时尤其适用,因为它创建了逆向工程师可以推理您的软件的边界。通过这种方式,逆向工程师可以以分而治之的方式解决您的程序。理想情况下,您希望您的软件在一个有效块中,混淆统一应用于整个块。所以减少块的数量,非常慷慨地使用内联并将它们包装在一个好的混淆算法中。编译器可以轻松地进行一些繁重的优化和堆栈排序,这将使块更难逆向工程。

运行

当您隐藏信息时,重要的是在运行时也能很好地隐藏信息。一个称职的逆向工程师会在你的程序运行时检查它的状态。因此,使用加载时解密的静态变量或使用加载时完全解包的打包将导致快速查找。请注意您在堆上分配的内容。所有堆操作都通过 API 调用进行,并且可以轻松地记录到文件中并进行推理。堆栈操作通常更难跟踪,因为它们有多频繁。动态分析与静态分析一样重要。您需要始终了解您的程序状态以及哪些信息位于何处。

反调试

反调试毫无价值。不要花时间在上面。花时间确保您的秘密被很好地隐藏,而不管您的软件是否处于静止状态。

打包加密代码段

我将加密和打包归为同一类别。它们都用于相同的目的,并且都有相同的问题。为了执行代码,CPU 需要看到纯文本。所以你必须在二进制文件中提供密钥。加密和打包代码段的唯一远程有效方法是,如果您在功能边界对它们进行加密和解密,并且只有在进入函数时进行解密,然后在离开函数时才进行重新加密。这将为在运行时转储二进制文件提供一个小障碍,但必须与强大的混淆相结合。

最后

在 IDA 的免费版本之类的东西中研究您的软件。您的目标是确保逆向工程师几乎不可能找到稳定的心理基础。你泄露的信息越少,环境变化越大,学习就越困难。如果您不是经验丰富的逆向工程师,那么设计一些难以逆向工程的东西几乎是不可能的。

如果您正在设计复制保护系统,请做好心理准备。确保你有一个如何处理中断的计划,以及如何确保你的软件的下一个版本增加足够的价值来推动升级。在无法打破的坚实基础上构建您的系统,不要使用某些以我上述方式隐藏的自定义算法来生成您自己的许可证密钥。该系统需要建立在健全的密码基础上,以确保消息的不可伪造性。