我对您可以采取的预防措施感兴趣,以使逆向工程 C 共享库更加困难
似乎不可能完全预防,但您可以采取可能使其花费更长的步骤,因此吸引力降低/成本更高
诸如代码混淆、编译器优化选项编译器调试标志等(我会对 gcc 编译器特别感兴趣)
还对逆向工程一个 ~5KLOC C 共享库(.so 大小约为 200kb)的相对难度(以美元或工时等计算)感兴趣。
我对您可以采取的预防措施感兴趣,以使逆向工程 C 共享库更加困难
似乎不可能完全预防,但您可以采取可能使其花费更长的步骤,因此吸引力降低/成本更高
诸如代码混淆、编译器优化选项编译器调试标志等(我会对 gcc 编译器特别感兴趣)
还对逆向工程一个 ~5KLOC C 共享库(.so 大小约为 200kb)的相对难度(以美元或工时等计算)感兴趣。
这些是我知道的一些技巧:
strip
与选项一起使用--strip-unneeded
以删除除重定位所需的符号之外的所有符号(因为我们正在谈论共享库):
strip --strip-unneeded libmylib.so
与标准 libc静态链接,这会导致更大的库/二进制文件,这意味着要通过更多代码并且还会混淆,因为将函数与库函数分开会更加困难:
gcc -static ...
强制编译器内联小函数,这会将小函数嵌入到您的代码中而不是调用它们,因此几乎不可能区分您的代码和标准库代码。
话虽如此,我必须补充一点,我有一个使用上述措施的二进制文件,并且我能够在几个小时内对其进行逆向工程,symtab
如果你好奇的话,我首先重建它,我不是逆向工程大师。
- 不需要代码混淆(如在 C# 或 Java 中)。
目标代码中不存在您的内部变量和函数的名称。
但是,您导出的函数的名称仍将清晰地显示在共享对象文件中。这听起来很合理。
- 最好使用gcc
优化标志-O2
或-O3
.
使用编译器优化,目标代码可以与源代码有很大不同。回到原始的 C 源代码实际上是非常困难的。
但是,始终可以在装配级别恢复工程师。通常,并非所有程序都是有价值的。在汇编中对有趣的部分进行逆向工程比在 C 中对整个程序进行逆向工程会更容易。
最常见的反逆转技术的问题在于它们是众所周知的并且有克服它们的工具。当然,剥离符号和混淆是必须的,但这只是隐藏名称/符号。
如果您想让逆向者的工作更加困难,请自己发明一些代码操作。它可以非常简单,例如使用自定义调用约定,但这会使所有反汇编程序无法识别函数的开始和结束。
这些简单的技巧将非常有效,因为不会有现成的工具可以将代码还原为原始代码。你看,几乎每一个商业打包器或加密器,都已经有了一个一键解包器。
没有那么多。一旦您剥离了调试符号并混淆了所有内部符号(不是外部符号,因为库的客户端需要一个符号来链接),您就无能为力了。由于指令到操作码的 1-1 映射,汇编反汇编非常容易。另一方面,很难理解编译器生成的汇编代码,因为它充满了奇异的优化和效率技巧。
关于这一点,将 GCC 提高到最高优化可能是您可以使用的最佳混淆技巧之一。
考虑到现代计算能力,拆解本身不会花那么长时间,到那时就需要人来破译它。
只是好奇:什么是不进行逆向工程如此重要?确保财务数据安全的加密和安全性大多是开源的。或者这是专有软件保护的东西?
将您的代码与开关/大小写混淆(使其非线性)混合。
在编译时使用 C++ 模板加密变量/字符串。可以将整数类型封装在 double 类型中,以使反转变得更加困难。
在真实代码之间插入汇编混淆宏(jmp x, db 0E8h, x: 等)
使用 BOOST ;) 它确实让逆向工程变得很痛苦...... ;)