Как удалить строки из скомпилированного двоичного файла (.so) - PullRequest
15 голосов
/ 20 мая 2010

Как удалить строки из / обфусцировать скомпилированный двоичный файл? Цель состоит в том, чтобы люди не читали названия функций / методов внутри.

Это динамическая библиотека (.so), скомпилированная из кода C ++ для Android с помощью инструментов NDK (включая GCC)

Я компилирую с -O3 и уже использую arm-eabi-strip -g mylib.so для удаления символов отладки, но когда я делаю strings mylib.so, все имена функций / методов по-прежнему читаемы.

Ответы [ 4 ]

25 голосов
/ 02 июня 2010

Эти строки находятся в динамической таблице символов , которая используется при загрузке библиотеки во время выполнения. 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")));

Подробнее см. в этом документе , который является отличным источником информации по этому вопросу.

7 голосов
/ 20 мая 2010

Есть несколько коммерческих обфускаторов , которые выполняют это. По сути, они переписывают все символы на ходу. Примерно так:

void foo()

становится

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

Имена переменных также обрабатываются так же, как и члены структур / союзов (в зависимости от того, какой уровень запутанности вы установили).

Большинство из них работают, сканируя вашу кодовую базу, создавая словарь, затем подставляя искаженные путаницы именам символов в выводе, который затем может быть скомпилирован как обычно.

Я не рекомендую использовать их, но они доступны. Простое запутывание значимых имен символов не остановит кого-то, кто полон решимости узнать, как работает ваша библиотека / программа. Кроме того, вы не сможете ничего делать с кем-то, кто отслеживает системные вызовы. Действительно, какой смысл? Некоторые утверждают, что это помогает держать «случайного наблюдателя» в страхе, я утверждаю, что кто-то, работающий с ltrace strace и strings, обычно не случайен.

Если вы не имеете в виду строковые литералы , а не символов ? С ними ничего не поделаешь, если только вы не храните литералы в зашифрованном формате, который вы должны расшифровать перед использованием. Это не просто отходы, а вопиющие отходы, которые не приносят никакой пользы.

3 голосов
/ 11 июля 2010

Предполагая, что вы правильно указываете скрытую видимость 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 или более позднюю версию, так как она там исправлена.

0 голосов
/ 20 мая 2010

Они неизбежны. Эти строки являются средством, с помощью которого загрузчик связывает общие библиотеки во время выполнения.

...