如何从已编译的二进制文件中删除字符串(.so)

Sté*_*ane 15 linux android gcc compilation android-ndk

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

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

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

jch*_*chl 25

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

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

有两种主要方法可以告知编译器哪些函数是私有的.

  1. 标记私人功能static.显然,这仅适用于单个编译单元中仅需要的函数,但对于某些库,此技术可能就足够了.

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

如果你有一个功能:

int foo(int a, int b);
Run Code Online (Sandbox Code Playgroud)

然后隐藏标记的语法是:

int foo(int a, int b) __attribute__((visibility("hidden")));
Run Code Online (Sandbox Code Playgroud)

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

int foo(int a, int b) __attribute__((visibility("default")));
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅此文档,该文档是有关此主题的绝佳信息来源.


Tim*_*ost 7

有一些商业混淆器可以实现这一目标.基本上,他们在旅途中重写所有符号.像这样的东西:

void foo()
Run Code Online (Sandbox Code Playgroud)

void EEhj_y33() // usually much, much longer and clobbered
Run Code Online (Sandbox Code Playgroud)

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

他们中的大多数都是通过扫描你的代码库,建立一个字典,然后在输出中用乱码混乱代替符号名称,然后可以照常编译.

我不建议使用它们,但它们可用.简单地模糊有意义的符号名称并不会阻止那些决心发现你的图书馆/程序如何工作的人.此外,您无法对跟踪系统调用的人员执行任何操作.真的,重点是什么?有人认为这有助于让"随意的观察者"陷入困境,我认为有人跑步ltrace strace并且strings通常不是偶然的.

除非你的意思是字符串文字,而不是符号?关于它们没有什么可以做的,除非你以加密的格式存储文字,你编码在使用之前必须解密.这不仅仅是一种浪费,而是一种令人生畏的浪费,它不会带来任何好处.