如何从编译的二进制文件(.so)中删除string

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

它是一个dynamic库(.so),由Android的C ++代码和NDK工具(包括GCC)编译而成,

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

Solutions Collecting From Web of "如何从编译的二进制文件(.so)中删除string"

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

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

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

  1. 将私有函数标记为static 。 显然,这只适用于单个编译单元中需要的函数,但对于某些库,这种技术可能就足够了。

  2. 使用gcc“visibility”属性将函数标记为可见或隐藏。 有两种选择:将所有私有函数标记为隐藏,或使用-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"))); 

有关更多详细信息,请参阅此文档 ,这是有关此主题的绝佳资讯来源。

有一些商业混淆器可以实现这一点。 基本上,他们重新编写了所有的移动符号。 像这样的东西:

 void foo() 

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

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

他们大多数是通过扫描你的代码库,建立一个字典,然后用乱码替换输出中的符号名称,然后像往常一样编译。

我不推荐使用它们,但它们是可用的。 简单地混淆有意义的符号名称不会阻止某个决心发现您的图书馆/程序如何工作的人。 另外,你不能对跟踪系统调用的人做任何事情。 真的,有什么意义? 有人认为,它有助于保持“随便的观察者”的ltrace ,我认为有人运行ltrace stracestrings通常是什么都不休闲。

除非你的意思是字符串文字 ,而不是符号 ? 没有什么可以对他们做的,除非你存储文字的加密格式,你编码之前必须解密使用。 这不仅仅是一种浪费,而且是一种毫无益处的浪费。

假设你正确地为g ++指定了所有源文件的隐藏可见性(正如其他海报推荐的那样),你可能会碰到这个GCC bug: http : //gcc.gnu.org/bugzilla/show_bug的CGI?ID = 38643

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

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

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