Современные информационные технологии/4. Информационная
безопасность
асп. Штеренберг
С.И (к.т.н. Андрианов В.И)
Федеральное
государственное образовательное бюджетное учреждение высшего профессионального
образования "Санкт-Петербургский государственный университет
телекоммуникаций им. проф. М.А. Бонч-Бруевича"
Методика
выбора оптимального способа защиты от копирования в системах UNIX использованием исполнимых файлов.
Федеральное
государственное образовательное бюджетное учреждение высшего профессионального
образования "Санкт-Петербургский государственный университет
телекоммуникаций им. проф. М.А. Бонч-Бруевича"
В статье рассматриваются особенности форматов исполнимых файлов под
операционные системы UNIX и методика выбора наиболее подходящих форматов файлов
для скрытого вложения информации.
В операционной системе
UNIX файл является хранилищем двоичных и символьных данных, хранимых как поток
байтов. В UNIX символьные данные кодируются с помощью кода ASCII, хотя на таких
системах, как мэйнфрейм IBM 390, используется кодировка EBCDIC. Коды ASCII и
EBSDIC отличаются друг от друга, т.е. один и тот же код в них соответствует
разным символам, а один и тот же символ закодирован в них разными кодами. В
разных операционных системах данные хранятся по-разному. Данное обстоятельство
может вызвать проблемы при попытке в одной операционной системе обработать
данные, созданные в другой операционной системе. Необходимы специальные
программы для конвертирования данных из файлов, созданных в одной операционной
системе в файлы другой операционной системы так, чтобы они были пригодны для
обработки.
Файлы содержат разные
типы информации. Например, файл может содержать исходный код программы на С,
COBOL или C++, он может быть текстовым документом с письмом от друга или
исполняемым модулем программы. В UNIX существует несколько "родных"
форматов файлов, которые можно просматривать или копировать, используя команды
системы. Однако некоторые файлы нельзя обработать внутренними командами UNIX.
Например, файлы базы данных для СУБД независимых разработчиков, таких как
Oracle, требуют для обработки специальных программ.
Вложение сообщения в исполняемом
файле - задача более сложная, ведь изменение даже одного бита в файле программы
может сделать ее непригодной к использованию.
Одним из простейших
форматов исполняемых файлов на архитектуре x86 является файл с расширением .COM
(здесь и далее при использовании расширений файлов операционных система
семейства CP/M будет использоваться запись расширения файла в верхнем регистре,
а для операционных систем семейства Unix будет использоваться нижний регистр
для суффикса имени файла). Истоки данного формата файла идут из операционной
системы CP/M для процессора Intel 8080, известной своей широкой популярностью.
Формат файла предполагает использование для создания команд (COM - сокращение
от COMMAND), расширяющий базовую функциональность операционной системы. При
разработке MS-DOS формат .COM сохранился практически без изменения и
обеспечивает совместимость на уровне исходного кода с CP/M. Двоичный формат
специфичен для каждого типа процессора. Формат подразумевает исполнение в
пределах одного сегмента (64Кб), что не позволяло использовать возможности
оперативной памяти в полной мере. Формат .EXE появился в QDOS/86-DOS (позднее
продаваемой под брендом MS-DOS) в 1981 году и был разработан Марком Збиковски
(Mark Zbikowski), о чем свидетельствует сигнатура MZ (или ZM в некоторых старых
версиях редакторов обратных связей) в первых двух байтах файла. В отличие от
формата .COM, где для кода, данных и стека используется один и тот же сегмент,
в формате .EXE были сняты данные ограничения, что делало доступным все адресное
пространство компьютера. Развитие машин класса IBM PC привело к появлению новых
режимов адресации, появлению виртуальной памяти и прочих механизмов, что делало
формат .EXE MZ недостаточно гибким и не приспособленным к реалиям. В частности,
многие производители реализовывали так называемые «оверлеи», что позволяло
осуществлять простейшую подкачку нужных функций в ОЗУ. Плюс, неэффективное
использование повторяющегося исполняемого кода привело к реализации библиотек
динамического связывания, код которых мог использоваться различными процессами
без его дублирования в физической памяти. В итоге формат .EXE был расширен и
были реализованы его более современные версии LX/LE и NE. Формат .EXE NE был
разработан Microsoft для применения в операционной системе OS/2 и оболочки
Windows. Данный формат ориентирован, как и .EXE MZ, на 16-разрядные среды
исполнения. Основная дополнительная функциональность, обеспечиваемая данным
форматом - это поддержка .DLL. С приходом на рынок микропроцессоров 386+
возникла необходимость поддержки 32-разрядного кода, что, естественно, привело
к появлению такого формата, как LE (использовался в оболочках семейства Windows
3.x и операционных систем семейства Windows 9x) и LX (использовался в
операционной системе OS/2). Данные форматы позволили смешивать как 16-битный
код, так и 32-битных. Кроме смешанного кода переходной период также потребовал
реализации такого механизма, как «thunking», что также наложило отпечаток на
данные форматы файлов. При разработке OS/2 NT 3.0 (в последующем - Windows NT
3.51) был разработан формат .EXE PE, который был предназначен для хранения кода
ориентированного на различные аппаратные платформы. В настоящее время данный
формат является основным для семейства операционных систем Windows. В кросс
платформенной OS/2 (OS/2 PPC, Workstation OS) конечным форматом файлы был
принят формат ELF, о котором будет сказано несколько дальше. В мире
операционных систем семейства Unix также наблюдалось развитие форматов
исполняемых файлов. Первый формат, a.out, появился с первой версией UNIX. На
наименование повлияла специфика процесса получения двоичного файла. В отличие
от систем семейства CP/M, для которых всегда была характерна нехватка памяти,
Unix системы позволяли осуществлять полный цикл: компиляция, компиляция,
компоновка. a.out - это сокращение от assembler output. Формат a.out по
структуре похож на форматы .EXE. За свое существование претерпел ряд
модификаций. С появлением разделяемых библиотек формат a.out из-за ряда
ограничений был заменен на формат COFF. Из основных нововведений - это
добавление отладочной информации и относительного виртуального адреса, что
позволило загружать его по произвольному фактическому адресу. Использование
формаьа COFF в Unix системах в настоящее время ограничено, однако формат .EXE
PE является наиболее известным вариантом формата COFF. Формат COFF был принят
не всеми производителями семейства Unix и многие все еще продолжали использовать
a.out. Ситуация изменилась с появлением формата ELF. Достаточно удачное решение
и учет того, что формат не был ориентирован под специфические особенности
определенной архитектуры, он получил широкое распространение. Большинство
современных реализаций Unix и ряд других операционных систем используют именно
его. Существует также "универсальный" формат ELF, содержащий двоичные
образы для большинства различных платформ. Сложно сказать, будет ли формат
FatELF широко использован, но если оглянуться на историю подобный
"многосистемных" форматов, то, скорее всего, FatELF не получит
широкого распространения. Наличие большого числа форматов, накопившихся со
временем, привело к тому, что в конце девяностых годов появилось ряд
исследовательских проектов по разработке некоторого "абстрактного"
формата файлов а также библиотек, предоставляющих единый интерфейс по доступу к
данным любого формата. Причины появление таких инструментов было несколько.
Одна из причин - инструментарий для сред разработки. Например, поддержка
компоновщиком наибольшего числа форматов. Другая причина - необходимость
переноса и запуска двоичных программ на другой аппаратной платформе.
Изначально
Unix поддерживали
множество исполняемых форматов, ожесточенно конкурирующих между собой, но
теперь остался один ELF, ставший стандартом де-факто для Linux и BSD. Для
правки исполняемых файлов Linux необязателен. Достаточно иметь HIEW, запущенный
из-под Windows, или даже MS-DOS. Так что Линукс все-таки желателен, хотя бы в
виде эмулятора - VM Ware, BOCHS или QEMU.
Аббревиатура ELF расшифровывается как
Execution & Linkable Format (формат исполнения и
компоновки). Он состоит в определенном родстве с win32 PE, поэтому у них много
общего. В начале ELF-файла расположен служебный заголовок (ELF-header),
описывающий основные характеристики файла - тип (исполнения или линковки),
архитектура ЦП, виртуальный адрес точки входа, размеры и смещения остальных
заголовков. За ELF-header'ом следует таблица сегментов (program header table),
перечисляющая имеющиеся сегменты и их атрибуты. В формате линковки она
необязательна. Линкер не обращает внимания на сегменты, так как работает
исключительно на уровне секций. Напротив, системный загрузчик, загружающий
исполняемый ELF-файл в память, игнорирует секции и оперирует целыми сегментами.
Ближайший аналог ELF-сегментов - PE-секции, но в PE-файлах секция - это
наименьшая структурная единица, а вот в ELF-файлах сегмент может быть разбит на
один или несколько фрагментов - секций. В частности, типичный кодовый сегмент
состоит из секций .init (процедуры инициализации), .plt (секция связок), .text
(основой код программы) и .finit (процедуры финализации). Секции нужны линкеру
для комбинирования, чтобы он мог отобрать секции с похожими атрибутами и
оптимальным образом растасовать их по сегментам при сборке файла, то есть
«скомбинировать».

Рисунок 1 – Поля заголовка файла elf
В настоящее время ELF постепенно заменяет старые форматы исполняемых файлов и
используется в ПО некоторых телефонов (Siemens, Sony Ericsson, Motorola) и
цифровых видеокамер (Rekam, Olympus). В каждом таком файле имеется заголовок, в
котором точно указан стартовый адрес программы (точка вхождения), для
последующей загрузки в оперативную память и дальнейшего использования. Файлы формата ELF
могут иметь и другие расширения, например, *.o, *.so, *.prx, *.puff. Также файлы с расширением *.elf зачастую используются
в игровых консолях, таких как Sony PlayStation, Nintendo Wii или Dreamcast.
Открыть их можно с помощью соответствующих эмуляторов.
Стандарт формата ELF различает несколько
типов файлов:
·
Перемещаемый
файл — хранит
инструкции и данные, которые могут быть связаны с другими объектными файлами. Результатом такой
связи может быть разделяемый объектный файл или исполняемый файл. К этому типу
относятся объектные файлы статических библиотек.
·
Разделяемый
объектный файл —
также содержит инструкции и данные и может быть связан с другими перемещаемыми
файлами и разделяемыми объектными файлами, в результате чего будет создан новый
объектный файл, либо при запуске программы на выполнение операционная система
может динамически связать его с исполняемым файлом программы, в результате чего
будет создан исполняемый образ программы. В последнем случае речь идет о
разделяемых библиотеках.
·
Исполняемый
файл — содержит
полное описание, позволяющее системе создать образ процесса. В том числе: инструкции,
данные, описание необходимых разделяемых объектных файлов и необходимую
символьную и отладочную информацию.
Cобирать и запускать родные бинарные файлы ELF (и ядро) в системе FreeBSD можно было
несколько раньше, FreeBSD вначале сопротивлялась «проталкиванию» ELF как формата по умолчанию. Почему?
Когда лагерь Linux производил болезненный переход к ELF, у него не было
большого преимущества перед исполняемым форматом a.out,
из-за негибкого, основанного на таблице переходов механизма разделяемых
библиотек, что делало создание разделяемых библиотек очень трудным для
поставщиков и разработчиков. Когда доступные инструменты ELF предоставили решение проблемы разделяемых
библиотек, и появилась некоторая перспектива, цена перехода была признана
допустимой и он был сделан. Механизм разделяемых библиотек FreeBSD близок по
стилю к механизму разделяемых библиотек SunOS™ от Sun, и поэтому очень прост в использовании.
Выводы
Новый набор инструментов GNU (binutils)
поддерживает кросс-компилирование, ELF,
разделяемые библиотеки, C++, расширения и т.д. В дополнение, многие поставщики
выпустили программы в формате ELF и они хорошо подходят для запуска в
FreeBSD.
ELF более
выразителен, чем a.out, позволяет базовой системе быть более
гибкой. ELF лучше поддерживается, и предоставляет
поддержку кросс-компиляторов, что важно для многих людей. ELF может быть немного медленнее, чем a.out,
но замерить это сложно. Есть также множество деталей, отличающихся для этих
двух форматов, в том как они отображают страницы, обрабатывают начальный код, и
т.д. В этом нет ничего очень важного, но они различаются. В настоящее время
поддержка a.out убрана
из ядра GENERIC, и со временем будет убрана из ядра,
как только потребность в запуске старых программ a.out останется в прошлом.
В дополнение ко всему вышесказанному, широкое
применение elf формата делает его особенно
привлекательным для скрытого вложения и прочих стеганографических приемов. Его
схожесте с форматами PE дает
возможность повторять многие операции и делает наибольно удобным для
стегоанализа. Другие, более старые форматы, такие как a.out, признаются не только не эффективными и устаревшими. Формат ELF почти полностью заменил собой
более ранний, так называемый формат a.out, который был далеко не столь
гибок — среди прочих недостатков формат a.out, плохо подходил для
динамического связывания, затрудняя реализацию библиотек совместного
использования. Linux по прежнему сохраняет обработчик двоичных файлов для
формата a.out, но ELF является предпочтительны.
Список используемой литературы:
1)
Эви
Немет, Гарт Снайдер, Трент Хейн, Бэн Уэйли. Unix и Linux: руководство
системного администратора. Как установить и настроить Unix и Linux = Unix and
Linux System Administration Handbook. — 4-е изд. — М.: Вильямс,
2012. — 1312 с.
2)
Роберт
Лав. Ядро
Linux: описание процесса разработки = Linux Kernel Development. — 3-е
изд. — М.: Вильямс, 2012. — 496 с.
3) Ричард Блум, Кристина
Бреснахэн.
Командная строка Linux и сценарии оболочки. Библия пользователя
= Linux Command Line and Shell Scripting Bible. — 2-е изд. —
М.:
Диалектика,
2012. — 784 с
4)
Маттиас
Калле Далхаймер. Запускаем Linux. — М.: Символ-Плюс, 2008. — 992 с.
5)
Колисниченко
Д. Н.
Linux. От новичка к профессионалу. — 2-е изд. — СПб.: БХВ-Петербург,
2010. — 764 с.
6)
Мэтт
Уэлш, Маттиас Калле Далхаймер, Терри Доусон и Лар Кауфман. Запускаем Linux. — 4-е
изд. — СПб-М.: Символ-Плюс, 2004. — 730 с.
7)
эсперанто // Открытые системы. — 1997. —
№ 3.
8)
Красов А.В., Верещагин
А.С., Цветков А.Ю. Аутентификация программного обеспечения при помощи вложения
цифровых водяных знаков в исполняемый код. // М. Телекоммуникации Спецвыпуск
2013, с.27-30