| ||||||||||||||||
| ||||||||||||||||
| ||||||||||||||||
|
Как сделать Linux программы меньше Данный опус описывает два способа уменьшения размера ELF программ под Линух, однако эти способы не специфичны для Линукса, и работают также под FreeBSD (возможно, они будут работать и под некоторыми другими Unixes на платформе Intel x86). Предисловие В наши дни почти никто не задумывается о размере программ. И это очень печальное последствие монополии Микрософт - вместо того, чтобы думать об эффективном использовании имеющегося оборудования, эти парни пишут всё более прожорливые (но вовсе не всё более лучшие) монстрообразные программы, вынуждая конечных пользователей каждый год покупать всё более новые компьютеры (более мощные и дорогие). Меня уже давно тошнит писать программы под "операционные системы" этой фирмы - да и глупо заниматься оптимизацией программ для платформы, которая предназначена исключительно для того, чтобы заставить пользователя купить более мощную машину. Так что мы будем рассматривать альтернативные платформы - Linux & FreeBSD. Поэтому Вы должны иметь машину с установленным на ней одним из этих дистрибутивов. На этом требования и заканчиваются. Nasm improvements В самом деле, один из самых простых способов уменьшить размеры программы - писать её на ассемблере. Я лично считаю одним из лучших ассемблеров под Unixes на платформе x86 Nasm, взять можно на . Однако при создании ELF-файлов (самый распространённый формат исполнимых файлов под Unix) он вставляет в каждый объектный файл секцию с комментариями, что данный файл был произведён Nasmом версии такой-то. Но ведь я и так знаю это ! Зачем мне нужна в каждом объектном файле такая секция ? Кроме того, содержимое всех этих секции аккумулируется при линковке в секции комментариев исполнимого файла ! В общем, я "доработал" файл outelf.c из версии 0.98 (последняя на сегодняшний момент), отвечающий за генерацию объектных файлов в ELF формате, так что теперь туда не помещается секция с комментариями. Я надеюсь, парни из команды разработчиков Nasmа на меня не сильно за это обидятся - мы и так знаем, что их продукт лучший, а теперь он стал даже ещё лучше - он генерирует файлы меньшего размера ! Но если Вам всё-таки нравится иметь строку с copyrights, вы можете закомментировать строчку #define RP_NO_COMMENT и всё будет как раньше. #define RP_ONLY_GLOBAL то перед записью ELF объектника будет перестроена таблица символов (и строковая
таблица) чтобы не включать в себя локальные символы.
Написание Linux kernel modules на ассемблере Что-то нигде в Сети я ещё не видел документации, описывающей, как создавать
kernel modules не с помощью ассемблера, а целиком на ассемблере - вообще без
использования компилятора C (правда, нам потребуется линковщик). Тем не менее
я обнаружил, что это вполне возможно. Для проверки был написан (на Nasmе) абсолютно
бесполезный модуль, который умеет только сообщать о факте своей загрузки и
выгрузки. Чтобы пересобрать его для Вашей версии кернела, Вам потребуется
найти в файле заголовков /usr/include/linux/version-up.h значение
макроса UTS_RELEASE (версия кернела) и вписать его в определение
константы kern_ver моего файла a.asm. Собственно, в этом нехитром
действии и кроется причина отсутствия модулей кернела, написанных целиком на
ассемблере - все файлы заголовков, определяющих структуры и функции кернела,
расcчитаны на использование языка C (хотя мне попадалась пара экспериментальных
модулей, написанных на C++). Полностью отсутствует инфраструктура, необходимая
для полноценного использования ассемблера. ELF compact Хм, а как быть с уже скомпилированными исполнимыми файлами ? Действительно ли
ELF файлы не содержат ничего лишнего ? На изучение этого вопроса я потратил
около двух недель (в основном просматривая исходный код загрузчика ELF файлов
на исполнение в Linux кернеле и ELF interpretorа). И в результате выяснились очень
интересные вещи. ELF формат имеет два типа секций - одни обычные, используемые
линковщиком и иже с ним, а другие - так называемые программные, т.е. которые
используются кернелом при загрузке файла на исполнение. Более того, если, скажем,
для объектных файлов и разделяемых библиотек необходимы первые (символьные) - по
достаточно очевидным причинам, ведь эти файлы предназначены для их дальнейшей
обработки (линковка или динамическая загрузка), то для обычных исполнимых
файлов необходимы ТОЛЬКО программные секции. Ни код запуска ELFов, ни ELF interpretor
в своей работе не используют символьных секций ! Тем не менее, линковщик честно
помещает их в каждый генерируемый файл. Это цель для приложения усилий номер раз. Неочевидные следствия Оказалось, что, несмотря на то, что выходные файлы отлично запускаются и работают, и вообще кернел не испытывает каких-либо неудобств от ампутации мусора, ни отладчик gdb, ни утилиты из binutils не могут жить без символьных секций и отказываются иметь с такими файлами дело. Т.е. совершенно непроизвольно на свет появился также простейший ELF protector (насколько я знаю, первый в своём роде - по крайней мере ни я, ни те люди, которым я дал эту программу для тестирования, ничего аналогичного под Linux не знают). Это тем более иронично, что до этого я в основном ломал программы под Linux/Unix ! Краткий перечень сломанного прилагается (IMHO, далеко не полный - что-то с памятью в последнее время стало совсем плохо - весна, однако...):
И вот на старости лет угораздило написать защиту. Впрочем, я не совсем болен на голову, и уже на следующий день нашёл способ, как загружать такие "оптимизированные" исполнимые файлы в IDA Pro - я написал для них свой loader. Он грузит такие файлы правильно - т.е. не так как описано в спецификации ELF формата, а так, как это делает Linux кернел. Но ! когда я обратился к Гильфанову на предмет получить исходные коды его загрузчика ELFов, в ответ мне было сказано, что "папуасам и хакерам никогда я исходные коды не дам, даже не проси !" Так что
Я же планирую написать несколько более усложнённый вариант настоящей защиты под Linux (кто же лучше крякера сможет это сделать ?), возможно с применением модулей в кернеле и есть ещё пара идей (пока не скажу) - в общем, что-то вроде VBoxа под Linux... Критикам Когда Вы будете источать праведные вопли о том, что якобы тоже самое, что и ELF compact, умеют делать утилиты из пакета binutils, перечитайте ещё раз предыдущую главу, где написано чёрным по белому русскими буквами - что утилиты из binutils не умеют общаться с выходными файлами ELF compactа. Даже если быть полным ламером, но мыслить логически - как утилиты binutils могут так исправить файлы, что потом сами не смогут с ними работать ? Кроме того, настоятельно рекомендую почитать документацию на ELF - возможно, Вы наконец поймёте разницу между символьными и программными секциями... Ссылки
Жалобы и предложения можно отправлять автору по адресу .
На глупые вопросы типа "Что такое FreeBSD ?" или
"где мне взять что-либо из описанного в этой статье ?" я не отвечаю.
Если же Вы нашли bug, имеете конструктивные идеи или уверены в
моей неправоте - всегда открыт к общению. Также большая просьба - не присылайте
мне десятимегабайтных (притом несжатых) файлов в качестве доказательства чего бы
то ни было. #include <std_disclaim.h> |
|
|
| ||||||||||||||||
|