【问题标题】:How to remove strings from a compiled binary (.so)如何从已编译的二进制文件 (.so) 中删除字符串
【发布时间】:2011-02-21 19:01:02
【问题描述】:

如何从已编译的二进制文件中删除/混淆字符串?目的是避免让人们阅读里面的函数/方法的名称。

它是使用 NDK 工具(包括 GCC)从 C++ 代码为 Android 编译的动态库 (.so)

我使用-O3 编译并且已经使用arm-eabi-strip -g mylib.so 删除调试符号,但是当我使用strings mylib.so 时,所有函数/方法的名称仍然可读。

【问题讨论】:

    标签: android linux gcc compilation android-ndk


    【解决方案1】:

    假设您正确地为所有源文件指定了对 g++ 的隐藏可见性(正如其他海报所建议的那样),您可能会遇到这个 GCC 错误: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38643

    尝试转储二进制文件中出现的符号 (readelf -Wa mylib.so | c++filt | less);如果您在解组后只看到 vtable 和 VTT 符号,那么 gcc 错误可能是您的问题。

    编辑:如果可以,请尝试 GCC 4.4.0 或更高版本,因为它似乎已修复。

    【讨论】:

    • -fvisibility=hidden 在 GCC (V4.4.0) + arm-eabi-strip -s 工作。谢谢
    【解决方案2】:

    这些字符串在动态符号表中,当库在运行时加载时使用。 readelf -p .dynstr mylib.so 将显示这些条目。

    strip -g 将删除调试符号,但它不能从动态符号表中删除条目,因为在运行时可能需要这些条目。您的问题是您在动态符号表中有永远不会从库外部调用的函数的条目。除非您告诉它,否则编译器/链接器无法知道哪些函数构成外部 API 的一部分(因此需要动态符号表中的条目)以及哪些函数是您的库私有的(因此不需要在动态符号表),所以它只是为所有非静态函数创建动态符号表条目。

    您可以通过两种主要方式通知编译器哪些函数是私有的。

    1. 标记私有函数static。显然,这仅适用于仅在单个编译单元中需要的函数,尽管对于某些库而言,这种技术可能就足够了。

    2. 使用 gcc 的“可见性”属性将函数标记为可见或隐藏。您有两个选择:将所有私有函数标记为隐藏,或者使用-fvisibility=hidden 编译器选项将默认可见性更改为隐藏,并将所有公共函数标记为可见。后者可能是您的最佳选择,因为这意味着您不必担心意外添加功能而忘记将其标记为隐藏。

    如果你有一个函数:

    int foo(int a, int b);
    

    然后将其标记为隐藏的语法是:

    int foo(int a, int b) __attribute__((visibility("hidden")));
    

    将其标记为可见的语法是:

    int foo(int a, int b) __attribute__((visibility("default")));
    

    有关详细信息,请参阅this document,这是有关此主题的极好信息来源。

    【讨论】:

    • 很好的答案!我需要测试一下......操作方法也很棒,但是读起来很长。非常感谢!
    【解决方案3】:

    有一些commercial obfuscators 可以做到这一点。基本上,他们会在旅途中重新编写所有符号。像这样的:

    void foo()
    

    变成

    void EEhj_y33() // usually much, much longer and clobbered
    

    变量名称也被给予相同的处理,结构/联合的成员也是如此(取决于您设置的混淆级别)。

    它们中的大多数通过扫描您的代码库、建立字典然后用乱码替换输出中的符号名称来工作,然后可以照常编译。

    我不建议使用它们,但它们是可用的。简单地混淆有意义的符号名称​​不会阻止那些决心发现你的库/程序如何工作的人。此外,您将无法对跟踪系统调用的人做任何事情。真的,有什么意义?有人争辩说,这有助于阻止“随意观察者”,我认为运行ltrace stracestrings 的人通常绝不是随便的。

    除非你的意思是 string literals ,而不是 symbols ?您对它们无能为力,除非您以加密格式存储文字,您的代码在使用之前必须对其进行解密。这不仅是一种浪费,而且是一种令人震惊的浪费,没有任何好处。

    【讨论】:

    • 谢谢!混淆总比没有好;我的代码主要由复杂的算法组成,它们的实现和调整,在某种程度上被函数的名称所泄露,使得软件的价值很大。另一方面,让系统调用可识别不是问题。
    【解决方案4】:

    它们是不可避免的。这些字符串是加载程序在运行时链接共享库的方式。

    【讨论】:

    • 我说的不是访问库的导出函数,而是内部函数。是否不可避免地要展示它们?
    • 啊,那你的arm-eabi-gcc 命令行让我很困惑。 -g 选项通常添加调试符号。
    • 抱歉打错了,不是gcc,而是strip...让我更正一下。
    猜你喜欢
    • 2021-11-03
    • 1970-01-01
    • 2017-12-22
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 2013-12-18
    • 2018-02-19
    • 1970-01-01
    相关资源
    最近更新 更多