使 C 共享库的逆向工程更加困难的技巧

Posted

技术标签:

【中文标题】使 C 共享库的逆向工程更加困难的技巧【英文标题】:Tips to make reverse engineering a C shared library more difficult 【发布时间】:2012-11-09 21:49:16 【问题描述】:

我对您可以采取的预防措施感兴趣,以使逆向工程 C 共享库变得更加困难

似乎不可能完全预防,但您可以采取一些措施,使其花费更长的时间,从而降低吸引力/成本更高

代码混淆、编译器优化选项、编译器调试标志等(我对 gcc 编译器特别感兴趣)

还对在 $ 或工时等方面对 ~5KLOC C 共享库(.so 大小约为 200kb)进行逆向工程相对困难的任何想法感兴趣。

【问题讨论】:

这个问题更像是“你想隐藏什么?”。 DRM 措施很难隐藏,因为它们归结为 if 语句“如果未获得许可,则警告”。由于庞大的规模和复杂性,实际算法很难进行逆向工程,并且在数月的工作之外可能被视为“无法进行逆向工程”。 您应该问的问题是,“谁真正关心反编译我的代码并尝试对其进行逆向工程?”你会发现答案通常是“没人”。更好的是,你可以尝试所有你想要的,但你不会阻止那些真正想要对你的代码进行逆向工程的人。而是将时间和精力花在改进产品上。 绝对不是代码混淆。 @Hiett 我想我被你的“代码混淆”提到了错误的轨道。您不打算将您的库作为混淆源代码分发,是吗? (如果你这样做了,我会给你一个答案。) @Hiett 如果您只使用非优化编译器,它可能会有所帮助,但它不会比优化编译器做得更糟。事实上,通过降低源代码模式的惯用性,源代码混淆甚至可能阻止优化并使目标代码更容易进行逆向工程。 【参考方案1】:

这些是我知道的一些技巧:

使用 strip--strip-unneeded 选项来删除除重定位所需的符号之外的所有符号(因为我们正在谈论共享库):

strip --strip-unneeded libmylib.so

与标准 libc 的链接静态,这会导致更大的库/二进制文件,这意味着要通过更多代码并且还会混淆,因为将您的函数与库函数分开会更加困难:

gcc -static ...

强制编译器内联小函数,这会将小函数嵌入到您的代码中而不是调用它们,因此几乎无法区分您的代码和标准库代码。

话虽如此,我必须补充一点,我有一个使用上述措施的二进制文件,并且我能够在几个小时内对其进行逆向工程,如果你好奇的话,我首先重建 symtab,并且我不是逆向工程大师。

【讨论】:

【参考方案2】:

- 无需代码混淆(如在 C# 或 Java 中)。

目标代码中不存在您的内部变量和函数的名称。

但是,您导出的函数的名称仍将清晰地显示在共享对象文件中。这听起来很合理。

- 最好使用gcc 优化标志-O2-O3

使用编译器优化,目标代码可以与源代码有很大不同。回到原来的C源代码其实是很困难的。

但是,始终可以在装配级别恢复工程师。通常,并非所有程序都是有价值的。在汇编中对有趣的部分进行逆向工程会比在 C 中对整个程序进行逆向工程更容易。

【讨论】:

嗯......不完全是,但是是的。程序集可以更加结构化,将名称分配给程序或数据的机器代码块。但除此之外,汇编语言与机器码是一一对应的。【参考方案3】:

最常见的反逆转技术的问题在于它们是众所周知的并且有克服它们的工具。当然,剥离符号和混淆是必须的,但这只是隐藏名称/符号。

如果您想让逆向者的工作更加困难,请自己发明一些代码操作。这可能非常简单,例如使用自定义调用约定,但这会使所有反汇编程序无法识别函数的开始和结束。

这些简单的技巧会非常有效,因为没有现成的工具可以将代码还原为原始代码。你看,几乎每一个商业打包器或加密器都已经有了一个一键解包器。

【讨论】:

【参考方案4】:

没那么多。一旦你剥离了调试符号混淆了所有内部符号(不是外部符号,因为库的客户端需要一个符号来链接),你无能为力.由于指令到操作码的 1-1 映射,汇编反汇编非常容易。另一方面,很难理解编译器生成的汇编代码,因为它充满了奇异的优化和效率技巧。

关于这一点,将 GCC 提高到最高优化可能是您可以使用的最佳混淆技巧之一。

考虑到现代计算能力,反汇编本身不会花费那么长时间,并且到那时需要人来破译它。

只是好奇:什么是不进行逆向工程如此重要?保护财务数据等安全的加密和安全性大多是开源的。还是这是一种专有的软件保护?

【讨论】:

和汇编反汇编正在从汇编代码转换为机器代码,反之亦然? 汇编反汇编是从机器代码翻译成汇编源代码。 为什么 - 当然,这一切都归结为非软件工程师设计的官僚繁文缛节 ;-) 我们的目的不是解释原因,而是填写表格和风险评估......【参考方案5】:

将您的代码与 switch/case 混淆(使其非线性)混合。

在编译时使用 C++ 模板加密变量/字符串。可以将整数类型封装在 double 类型中,以使反转更加困难。

在真实代码(jmp x、db 0E8h、x:等)之间插入汇编混淆宏

使用 BOOST ;) 它确实让逆向工程变得很痛苦...... ;)

【讨论】:

以上是关于使 C 共享库的逆向工程更加困难的技巧的主要内容,如果未能解决你的问题,请参考以下文章

在 Strings.xml 与代码中存储字符串是不是会使逆向工程变得更加乏味?

如何对C库进行逆向工程?

我可以使用本机编译作为 Java 混淆吗

MODELSIM 工程和库的区别

GPIO输出—使用固件库点亮LED

Android 中获取某个 dependencies 依赖库的最新版本小技巧