Аннотация: Управление памятью в Windows. Обзор структуры исполняемых файлов в формате Portable Executable (PE). Пример генерации PE-файла.
Формат исполняемых файлов
Исполняемый файл ( executable file ) — это файл , который может быть загружен в память загрузчиком операционной системы и затем исполнен. В операционной системе Windows исполняемые файлы, как правило, имеют расширения «.exe» и «.dll». Расширение «.exe» имеют программы, которые могут быть непосредственно запущены пользователем. Расширение «.dll» имеют так называемые динамически связываемые библиотеки ( dynamic link libraries). Эти библиотеки экспортируют функции, используемые другими программами.
Для того чтобы загрузчик операционной системы мог правильно загрузить исполняемый файл в память , содержимое этого файла должно соответствовать принятому в данной операционной системе формату исполняемых файлов. В разных операционных системах в разное время существовало и до сих пор существует множество различных форматов. В этой главе мы рассмотрим формат Portable Executable (PE). Формат PE — это основной формат для хранения исполняемых файлов в операционной системе Windows . Сборки . NET тоже хранятся в этом формате.
ВСЁ о расширениях файлов в Windows 7, 8.1, 10, 11 | Экспорт / Импорт расширений
Кроме того, формат PE может использоваться для представления объектных файлов . Объектные файлы служат для организации раздельной компиляции программы. Смысл раздельной компиляции заключается в том, что части программы (модули) компилируются независимо в объектные файлы , которые затем связываются компоновщиком в один исполняемый файл .
А теперь — немного истории. Формат PE был создан разработчиками Windows NT. До этого в операционной системе Windows использовались форматы New Executable (NE) и Linear Executable (LE) для представления исполняемых файлов, а для хранения объектных файлов использовался Object Module Format (OMF). Формат NE предназначался для 16-разрядных приложений Windows , а формат LE, изначально разработанный для OS/2 , был уже 32-разрядным.
Возникает вопрос: почему разработчики Windows NT решили отказаться от существующих форматов? Ответ становится очевидным, если обратить внимание на то, что большая часть команды, работавшей над созданием Windows NT, ранее работала в Digital Equipment Corporation. Они занимались в DEC разработкой инструментария для операционной системы VAX / VMS , и у них уже были навыки и готовый код для работы с исполняемыми файлами, представленными в формате Common Object File Format ( COFF ). Соответственно, формат COFF в слегка модифицированном виде был перенесен в Windows NT и получил название PE.
В «. NET Framework Glossary » сказано, что PE — это реализация Microsoft формата COFF . В то же время в [5] утверждается, что PE — это формат исполняемых файлов, а COFF — это формат объектных файлов . Вообще, мы можем наблюдать путаницу в документации Microsoft относительно названия формата. В некоторых местах они называют его COFF , а в некоторых — PE.
35 — Как маскируют расширение файла .exe на любое другое (pdf, png и т.д.)
Правда, можно заметить, что в новых текстах название COFF используется все меньше и меньше. Более того, формат PE постоянно эволюционирует. Например, несколько лет назад в Microsoft отказались от хранения отладочной информации внутри исполняемого файла, и поэтому теперь многие поля в структурах формата COFF просто не используются. Кроме того, формат COFF — 32-разрядный, а последняя редакция формата PE (она называется PE32+) может использоваться на 64-разрядных аппаратных платформах. Поэтому, видимо, дело идет к тому, что название COFF вообще перестанут использовать.
Интересно отметить, что исполняемые файлы в устаревших форматах NE и LE до сих пор поддерживаются Windows . Исполняемые файлы в формате NE можно запускать под управлением NTVDM (NT Virtual DOS Machine), а формат LE используется для виртуальных драйверов устройств ( VxD ).
Почему в названии формата PE присутствует слово » portable » («переносимый»)? Дело в том, что Windows NT была реализована не только для платформы Intel x86 , но и для платформ MIPS R4000, DEC Alpha и PowerPC . И во всех реализациях для хранения исполняемых файлов использовался формат PE. При этом речь не шла о достижении двоичной совместимости между этими платформами, то есть exe- файл , предназначенный для выполнения на платформе Intel x86 , нельзя было запустить на PowerPC . Важно понимать, что переносимость формата еще не означает переносимость исполняемых файлов, записанных в этом формате. Формат PE переносим в том смысле, что он слабо зависит от типа процессора и поэтому подходит для разных платформ (в том числе и для платформы . NET ).
Далее в этой главе мы не будем затрагивать 64-разрядный вариант формата PE, потому что в настоящее время сборки . NET хранятся в прежнем 32-разрядном формате. Однако отметим, что 64-разрядный PE очень слабо отличается от 32-разрядного. Основное отличие касается разрядности полей структур PE-файла.
Источник: intuit.ru
Исполняемые файлы имеют расширение какого типа? Наиболее распространенные
Многие пользователи компьютерных систем наверняка в той или иной степени сталкивались с понятием исполняемого файла программы. Исполняемые файлы не всегда, но довольно часто имеют расширение EXE, которое является общепринятым для операционных систем семейства Windows. Чтобы немного прояснить вопрос, связанный с расширениями, мы рассмотрим общую информацию об этих объектах, а также рассмотрим некоторые типы основных расширений.
Чем исполняемые файлы отличаются от других объектов
Исполняемые файлы: структура
Что же касается построения исполняемых файлов, то они должны содержать заголовки (предполагаемое выполнение инструкций, параметры и форматы кода) и непосредственно сами инструкции (исходные, машинные или байт-коды). В некоторых случаях в структуру могут быть включены данные для отладки, описания окружения, требования к операционной системе, списки соответствующих библиотек, звук, графика, изображения, иконки ярлыков и тому подобное. Многие из вас наверняка обращали внимание на то, что в большинстве своем у каждого такого файла в операционной системе изначально имеется иконка.
Принцип работы
Несмотря на то, что исполняемые файлы могут иметь расширение различных типов, работают они по одному принципу. Исполняемый файл при запуске загружается в память компьютера. При этом осуществляется настройка окружения и инициализация, подтягиваются дополнительные библиотеки, если их использование предусмотрено программой. Также на данном этапе происходит настройка некоторых дополнительных операций и само исполнение инструкций теми методами, которые прописаны непосредственно в файле.
Исполняемые файлы программ: какое расширение они имеют?
Теперь перейдем к рассмотрению вопроса, связанного с расширениями. Разумеется, совершенно все типы рассмотреть не получится, это займет очень много времени. Мы отметим только наиболее распространенные и популярные варианты. Итак, расширение задается в зависимости от типа содержимого.
Так, например, в операционной системе типа Windows наиболее распространенные исполняемые файлы обладают расширением EXE. Это относится ко всем программам, которые рассчитаны на работу в среде данных операционных систем. Такие объекты содержат в себе машинные коды. Файлы BIN являются очень похожими. Пакетные файлы типа CMD, BAT и COM являются еще одним типом исполняемых файлов.
Первый тип в данном случае является пакетным файлом Windows. Файлы второго и третьего типа относятся к операционным системам семейства DOS. Многие из вас вероятно уже встречали файлы типа MSI иMSU. Это может быть установщик обновлений системы, или родной инсталлятор операционной системы Windows. Отдельную категорию файлов составляют макросы и скрипты.
Это файлы с расширениями JSE, JS, SCR,VBE, VBS, VB. Часто также встречаются файлы JAD иJAR, которые предназначены для установки приложений в мобильные устройства или использование в среде JAVA. В своем содержании такие объекты имеют уже не машинные коды, а коды виртуальных машин.
Какое расширение имеют исполняемые файлы в различных ОС?
Если внимательно посмотреть, то можно заметить, что в некоторых ОС встречаются довольно специфичные компоненты. Так, например, в операционной системе Windows имеется специальная категория исполняемых файлов. Вообще, в любой операционной системе можно найти как стандартные, так и специальные компоненты. Однако имеются и некоторые общие форматы, например, HTA, исполняемый документ HTML.
Они работают практически везде вне зависимости от используемого типа операционной системы. Что же касается других типов систем, то, например, в «маках» исполняемые файлы обладают расширением APP для программ и PKG для дистрибутивов. В операционных системах семейства Linux дело обстоит немного иначе.
Проблема заключается в том, что в таких операционных системах понятие расширения вообще отсутствует. Можно распознать исполняемый файл по атрибутам, например, системный, скрытый, только для чтения и т.д. В результате проблема изменения расширения для запуска или прочтения искомого файла пропадает.
Впрочем, в любой операционной системе даже на мобильных устройствах можно найти огромное число объектов данного типа. Не нужно далеко ходить. В той же операционной системе семейства Android исполняемый файл установщика имеет расширение APK. В яблочных устройствах исполняемые файлы имеют расширение IPA.
Заключение
Подведем итог нашего небольшого обзора о расширении исполняемых файлов. Упор в данном случае делался в основном на объекты, которые присутствуют в операционных системах семейства Windows. Остальные операционные системы были затронуты только вскользь для общего развития. Как уже стало ясно, разнообразие исполняемых файлов очень велико. Невозможно привести какую-то сводную таблицу с указанием совершенно всех типов расширений. Поэтому в данной статье мы ограничились только наиболее распространенными форматами
Похожие статьи:
- MiniTool Partition Wizard. Скачать бесплатно
- Подключение телефонов через Nokia Suite
- MathType. Скачать бесплатно
- Секреты установки сторонних программ на Windows 7: отключение антивируса
- GIGABYTE OC Guru 2 — программа для разгона видеокарт
Источник: computerologia.ru
Анатомия эльфов. Разбираемся с внутренним устройством ELF-файлов
Если в мире Windows исполняемые файлы представлены в формате Portable Executable (PE), то в Linux эта роль отведена файлам в формате Executable and Linkable Format (ELF). Сегодня мы заглянем внутрь таких файлов, немного поисследуем их структуру и узнаем, как они устроены.
Сразу отмечу, что в отличие от Windows в Linux от расширения файла не зависит практически ничего (за совсем небольшим исключением). Тип и формат файла определяется его внутренним содержимым и наличием тех или иных атрибутов, поэтому файлы в формате Executable and Linkable Format могут иметь любое расширение.
Что нам понадобится
Вообще, можно позавидовать людям, обитающим в мире Linux, — как правило, в системе «из коробки» идет большое число утилит и программ, которые в Windows необходимо где‑то искать и устанавливать дополнительно, да еще и не всегда бесплатно. В нашем случае для анализа ELF-файлов в Linux присутствует вполне состоятельный арсенал встроенных средств и утилит:
- readelf — с помощью этой утилиты можно практически полностью просматривать все потаенные места ELF-файлов в удобочитаемом виде;
- hexdump — простой просмотрщик файлов в шестнадцатеричном представлении (конечно, до hiew из мира Windows ему далеко, но, во‑первых, он присутствует в системе по умолчанию, а во‑вторых, делает это совершенно бесплатно);
- strings — с помощью этой известной утилиты можно увидеть имена всех импортируемых (или экспортируемых) функций, а также библиотек, из которых эти функции импортированы, названия секций и еще много чего интересного;
- ldd — позволяет выводить имена разделяемых библиотек, из которых импортируются те или иные функции, используемые исследуемой программой;
- nm — может показывать таблицу имен из состава отладочной информации, которая добавляется в ELF-файлы при их компиляции (эта отладочная информация с помощью команды strip может быть удалена из файла, и в этом случае утилита nm ничем не поможет);
- objdump — способна вывести информацию и содержимое всех элементов исследуемого файла, в том числе и в дизассемблированном виде.
Часть перечисленного (кроме hexdump и ldd) входит в состав пакета GNU Binutils. Если этого пакета в твоей системе нет, его легко установить. К примеру, в Ubuntu это выглядит следующим образом:
sudo apt install binutils
В принципе, имея все перечисленное, можно уже приступать к анализу и исследованию ELF-файлов без привлечения дополнительных средств. Для большего удобства и наглядности можно добавить к нашему инструментарию известный в кругах реверс‑инженеров дизассемблер IDA в версии Freeware (этой версии для наших целей будет более чем достаточно, хотя никто не запрещает воспользоваться версиями Home или Pro, если есть возможность за них заплатить).
Также неплохо было бы использовать вместо hexdump что‑то поудобнее, например 010 Editor или wxHex Editor. Первый hex-редактор — достойная альтернатива Hiew для Linux (в том числе и благодаря возможности использовать в нем большое количество шаблонов для различных типов файлов, среди них и шаблон для парсинга ELF-файлов). Однако он небесплатный (стоимость лицензии начинается с 49,95 доллара, при этом есть 30-дневный триальный период).
Говоря о дополнительных инструментах, которые облегчают анализ ELF-файлов, нельзя не упомянуть Python-пакет lief. Используя этот пакет, можно писать Python-скрипты для анализа и модификации не только ELF-файлов, но и файлов PE и MachO. Скачать и установить этот пакет получится традиционным для Python-пакетов способом:
pip install lief
Подопытные экземпляры
В Linux (да и во многих других современных UNIX-подобных операционных системах) формат ELF используется в нескольких типах файлов.
- Исполняемый файл — содержит все необходимое для создания системой образа процесса и запуска этого процесса. В общем случае это инструкции и данные. Также в файле может присутствовать описание необходимых разделяемых объектных файлов, а также символьная и отладочная информация. Исполняемый файл может быть позиционно зависимым (в этом случае он грузится всегда по одному и тому же адресу, для 32-разрядных программ обычно это 0x8048000 , для 64-разрядных — 0x400000 ) и позиционно независимым исполняемым файлом (PIE — Position Independent Execution или PIC — Position Independent Code). В этом случае адрес загрузки файла может меняться при каждой загрузке. При построении позиционно независимого исполняемого файла используются такие же принципы, как и при построении разделяемых объектных файлов.
- Перемещаемый файл — содержит инструкции и данные, при этом они могут быть статически связаны с другими объектными файлами, в результате чего получается разделяемый объектный или исполняемый файл. К этому типу относятся объектные файлы статических библиотек (как правило, для статических библиотек имя начинается с lib и применяется расширение *. a ), однако, как мы уже говорили, расширение в Linux практически ничего не определяет. В случае статических библиотек это просто дань традиции, а работоспособность библиотеки будет обеспечена с любым именем и любым расширением.
- Разделяемый объектный файл — содержит инструкции и данные, может быть связан с другими перемещаемыми файлами или разделяемыми объектными файлами, в результате чего будет создан новый объектный файл. Такие файлы могут выполнять функции разделяемых библиотек (по аналогии с DLL-библиотеками Windows). При этом в момент запуска программы на выполнение операционная система динамически связывает эту разделяемую библиотеку с исполняемым файлом программы, и создается исполняемый образ приложения. Опять же традиционно разделяемые библиотеки имеют расширение *. so (от английского Shared Object).
- Файл дампа памяти — файл, который содержит образ памяти того или иного процесса на момент его завершения. В определенных ситуациях ядро может создавать файл с образом памяти аварийно завершившегося процесса. Этот файл также создается в формате ELF, однако мы о такого рода файлах говорить не будем, поскольку задача исследования дампов и содержимого памяти достаточно объемна и требует отдельной статьи.
Для наших изысканий нам желательно иметь все возможные варианты исполняемых файлов из перечисленных выше, чем мы сейчас и займемся.
Делаем исполняемые файлы
Не будем выдумывать что‑то сверхоригинальное, а остановимся на классическом хелловорлде на С:
int main ( int argc , char * argv [] ) <
printf ( «Hello world» ) ;
Компилировать это дело мы будем с помощью GCC. Современные версии Linux, как правило, 64-разрядные, и входящие в их состав по умолчанию средства разработки (в том числе и компилятор GCC) генерируют 64-разрядные приложения. Мы в своих исследованиях не будем отдельно вникать в 32-разрядные ELF-файлы (по большому счету отличий от 64-разрядных ELF-файлов в них не очень много) и основные усилия сосредоточим именно на 64-разрядных версиях программ. Если у тебя возникнет желание поэкспериментировать с 32-разрядными файлами, то при компиляции в GCC нужно добавить опцию -m32 , при этом, возможно, потребуется установить библиотеку gcc-multilib. Сделать это можно примерно вот так:
sudo apt- get install gcc- multilib
Итак, назовем наш хелловорлд example. c (кстати, здесь как раз один из немногих случаев, когда в Linux расширение имеет значение) и начнем с исполняемого позиционно зависимого кода:
gcc -no-pie example. c -o example_ no_ pie
Как ты уже догадался, опция -no-pie как раз и говорит компилятору собрать не позиционно независимый код.
Вообще, если говорить правильно, то GCC — это не совсем компилятор. Это комплексная утилита, которая в зависимости от расширения входного файла и опций вызывает нужный компилятор или компоновщик с соответствующими входными данными. Причем из С или другого высокоуровневого языка сначала исходник транслируется в ассемблерный код, а уже затем все это окончательно преобразуется в объектный код и собирается в нужный нам ELF-файл.
В целом можно выделить четыре этапа работы GCC:
- препроцессирование;
- трансляция в ассемблерный код;
- преобразование ассемблерного кода в объектный;
- компоновка объектного кода.
Чтобы посмотреть на промежуточный результат, к примеру в виде ассемблерного кода, используй в GCC опцию -S :
gcc -S -masm = intel example. c
Обрати внимание на два момента. Первый — мы в данном случае не задаем имя выходного файла с помощью опции -o (GCC сам определит его из исходного, добавив расширение *. s , что и означает присутствие в файле ассемблерного кода). Второй момент — опция -masm=intel , которая говорит о том, что ассемблерный код в выходном файле необходимо генерировать с использованием синтаксиса Intel (по умолчанию будет синтаксис AThttps://xakep.ru/2022/05/11/elf-anatomy/» target=»_blank»]xakep.ru[/mask_link]