Исполнение файла как программы

Несколько недель назад я читал о PICO-8, выдуманной игровой консоли, обладающей большими ограничениями. Особо мой интерес привлёк новаторский способ распространения её игр — кодирование их изображение PNG. В него включается всё — код игры, ресурсы, вообще всё. Изображение может быть любым: скриншоты из игры, крутой арт или просто текст. Чтобы загрузить игру, нужно передать изображение на вход программы PICO-8, и можно начинать играть.

Это заставило меня задуматься: наверно, будет круто, если получится сделать то же самое с программами в Linux? Нет! Я понимаю, вы скажете, что это тупая идея, но я всё равно ею занялся, и ниже представлено описание одного из тупейших проектов, над которыми я работал в этом году.

Кодирование

Я не вполне понимаю, что именно делает PICO-8, но предположу, что она, вероятно, применяет техники стеганографии, скрывающие данные в «сырых» байтах изображения. В Интернете есть много ресурсов с объяснением принципов работы стеганографии, но самая её суть довольно проста: изображение, в котором вы хотите скрыть данные, состоит из байтов и из пикселей. Пиксели состоят из трёх значений красного, зелёного и синего (RGB), представленных в виде трёх байтов. Чтобы скрыть данные («полезную нагрузку»), мы, по сути, «смешиваем» байты полезной нагрузки с байтами изображения.

Как изменить программу открытия файла по умолчанию

Если просто заменить байты изображения байтами полезной нагрузки, то в картинке появятся области с искажёнными цветами, потому что они не будут совпадать с цветами исходного изображения. Хитрость заключается в том, чтобы быть как можно незаметнее, скрыть информацию на ровном месте. Это можно сделать, распределив байты полезной нагрузки по байтам изображения-прикрытия, пряча их в младших битах. Другими словами, вносить небольшие изменения в значения байтов, чтобы изменения цветов были недостаточно сильными для восприятия человеческим глазом.

Допустим, наша полезная нагрузка — это буква H , представляемая в двоичном коде как 01001000 (72), а изображение содержит набор чёрных пикселей.

Биты вводимых байтов распределены по 8 выходным байтам благодаря сокрытию их в младшем бите

На выходе мы получим несколько пикселей, которые будут чуть менее чёрными, чем ранее, но можно ли заметить разницу?

Цвета пикселей немного подкорректированы.

Возможно, чрезвычайно опытный знаток цветов сможет увидеть разницу, но в реальной жизни такие крошечные сдвиги заметны только машине. Чтобы получить нашу сверхсекретную букву H , достаточно просто считать 8 байт получившегося изображения и собрать их снова в 1 байт. Очевидно, что сокрытие единственной буквы — дурацкая затея, но масштаб передачи можно свободно увеличивать. Допустим передать сверхсектерное предложение, копию «Войны и мира», ссылку на Soundcloud, компилятор Go — единственным ограничением будет количество доступных в изображении байтов, потому что их должно быть как минимум в 8 раз больше, чем во вводимой информации.

Работа с файлами с++. Запись в файл. c++ ofstream. Изучение С++ для начинающих. Урок #115

Сокрытие программ

Итак, вернёмся к нашей идее исполняемых файлов Linux в изображении. Если рассматривать исполняемые файлы просто как байты, то понятно, что их можно скрыть в изображениях, прямо как это делает PICO-8.

Прежде чем реализовывать это, я решил написать собственную библиотеку стеганографии и инструмент, поддерживающий кодирование и декодирование данных в PNG. Разумеется, существует множество уже готовых стеганографических библиотек и инструментов, но я лучше всего учусь, когда делаю что-то своё.

$ stegtool encode
—cover-image htop-logo.png
—input-data /usr/bin/htop
—output-image htop.png
$
$ echo «Super secret hidden message» | stegtool encode
—cover-image image.png
—output-image image-with-hidden-message.png
$ stegtool decode —image image-with-hidden-message.png
Super secret hidden message

Поскольку всё написано на Rust, было совсем не сложно скомпилировать это на WASM, поэтому можете поэкспериментировать самостоятельно.

Итак, теперь мы можем встраивать данные, добавляя исполняемые файлы в изображения. Но как нам их запускать?

Запускаем изображение

Проще всего было бы всего лишь запустить указанный выше инструмент, выполнить decode данных в новый файл, изменить права с помощью chmod +x , а затем запустить его. Это сработает, но будет слишком скучно. Я хотел сделать нечто в стиле PICO-8 — мы передаём некой сущности изображение PNG, и она делает всё остальное.

Читайте также:
Программа занятий для мужчин в домашних условиях

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

memfd_create

После прочтения этого поста стало очевидно, что можно создать файл в памяти и пометить его как исполняемый.

Разве не здорово было бы просто взять блок памяти, записать туда двоичные данные и запустить их без патчинга ядра, перезаписи execve(2) в userland или загрузки библиотеки в другой процесс?

В этом способе используется системный вызов memfd_create(2) для создания файла в пространстве имён /proc/self/fd вашего процесса и загрузки нужных вам данных в него при помощи write . Я потратил довольно много времени, разбираясь в привязках libc с Rust, чтобы всё это заработало, и мне сложно было понять передаваемые типы данных, документация по этим привязкам Rust не особо помогла.

Однако мне удалось получить нечто работающее.

unsafe < let write_mode = 119; // w // create executable in-memory file let fd = syscall(libc::SYS_memfd_create, if fd == -1 < return Err(String::from(«memfd_create failed»)); >let file = libc::fdopen(fd, // write contents of our binary libc::fwrite( data.as_ptr() as *mut libc::c_void, 8 as usize, data.len() as usize, file, ); >

Вызова /proc/self/fd/ как дочернего процесса от создавшего его родителя достаточно для запуска вашего двоичного файла.

let output = Command::new(format!(«/proc/self/fd/<>», fd)) .args(args) .stdin(std::process::Stdio::inherit()) .stdout(std::process::Stdio::inherit()) .stderr(std::process::Stdio::inherit()) .spawn();

Имея на руках эти строительные блоки, я написал программу pngrun для запуска изображений. По сути, она делает следующее:

  1. Принимает от стеганографического инструмента изображение, в которое встроен наш двоичный файл, и аргументы
  2. Декодирует его (т.е. извлекает и собирает заново байты)
  3. Создаёт файл в памяти при помощи memfd_create
  4. Помещает байты двоичного файла в файл в памяти
  5. Вызывает файл /proc/self/fd/ как дочерний процесс, передавая все аргументы из родительского.

$ pngrun htop.png

$ pngrun go.png run main.go
Hello world!

После завершения pngrun файл в памяти уничтожается.

binfmt_misc

Однако каждый раз вводить pngrun надоедает, поэтому последним простым трюком в этом бессмысленном проекте стало использование binfmt_misc — системы, позволяющей «исполнять» файлы на основании их типа файла. Думаю, в первую очередь эта функция разрабатывалась для интерпретаторов/виртуальных машин наподобие Java. Вместо ввода java -jar my-jar.jar достаточно ввести ./my-jar.jar и при этом будет вызван процесс java для запуска JAR. Однако при этом файл my-jar.jar сначала должен быть помечен как исполняемый.

То есть добавить в binfmt_misc запись для pngrun , чтобы получить возможность запускать любые png с установленным флагом x , можно так:

$ cat /etc/binfmt.d/pngrun.conf
:ExecutablePNG:E::png::/home/me/bin/pngrun:
$ sudo systemctl restart binfmt.d
$ chmod +x htop.png
$ ./htop.png

В чём смысл проекта

Ну, на самом деле особого смысла нет. Меня соблазнила идея о создании изображений PNG, которые могли бы запускать программы, и я её немного развил, однако проект всё равно был интересным. Есть что-то восхитительное в возможности распространения программ в виде изображений — вспомните забавные картонные коробки с программным обеспечением для PC с графическим оформлением на передней части. Почему бы не вернуть их обратно? (Хотя на самом деле не стоит.)

Проект очень туп и имеет множество изъянов, из-за которых становится совершенно бессмысленным и непрактичным. Самый главный изъян — для его работы на машине должна быть дурацкая программа pngrun . Однако я заметил некоторые странности в программах наподобие clang . Я закодировал её в этот забавный логотип LLVM, и хотя она работает нормально, при попытке компилирования происходит сбой.

$ ./clang.png —version
clang version 11.0.0 (Fedora 11.0.0-2.fc33)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /proc/self/fd
$ ./clang.png main.c
error: unable to execute command: Executable «» doesn’t exist!

Вероятно, это результат того, что файл анонимен, и проблему можно решить, если бы у меня был интерес к её изучению.

Почему ещё этот проект туп

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

Читайте также:
Программа с помощью которой осуществляется просмотр веб страниц называется

Кроме того, большинство ПО состоит не только из одного исполняемого файла, поэтому мечта о распространении PNG провалится в случае более сложных программ наподобие игр.

Вывод

Вероятно, это самый тупой проект среди тех, над которыми я работал этот год, но он определённо был забавным, я узнал о стеганографии, memfd_create , binfmt_misc и ещё немного поигрался с Rust.

  • Ненормальное программирование
  • Обработка изображений
  • Реверс-инжиниринг
  • Разработка под Linux

Источник: habr.com

Статья [0x02] Исследуем Portable Executable [Загрузка PE-файла]

Доброго времени суток, читатели. В прошлой статье, мы поверхностно изучили строение и формат PE-файла. В этой статье, мы изучим виртуальную память , познакомимся с процессом загрузки PE-файла в память , изучим его структуру в памяти , а также изучим процесс импорта . Если вы не прочитали предыдующую статью, то обязательно прочитайте.

loading.png


В иртуальная память

Процесс загрузки — это тот процесс, который происходит когда вы запускаете исполняемый файл. Для чего он нужен? Ну, перед тем как начать выполнение, программа должна быть загружена в адресное пространство (в виртуальную память).

У каждого исполняемого файла, загруженного в память есть своё адресное пространство. Такая память называется виртуальной. Виртуальная память — это максимально доступное адресное пространство для процесса. Размер виртуальной памяти зависит от ОС и от архитектуры. Для 32-битной программы Windows — это 4 GB.

Эта память делится на 2 части. Первая используется программой, а вторая системой.

virtual_memory.png

Виртуальная память управляются устройством управления памяти (Memory Managment Unit) (MMU). MMU делит физическую память на «куски» памяти одинакового размера. Эти «куски» называются страницами . MMU является компонентном аппаратного обеспечения. Со стороны ОС виртуальная память управляется Virtual Memory Manager ‘ом (VMM).

А после этого происходит преобразование (транслирование) адресов физической памяти (ОЗУ), к адресам в виртуальной памяти. Этот процесс изображён ниже.

ozu_virutal_memory.png

Каждая ячейка на изображении, эта страница памяти. Каждая страничка — кусок памяти фиксированного размера. Набор страничек физической памяти, выделенной процессу, называется рабочим множеством. Рабочее множество может увеличиваться и уменьшаться, в зависимости от нужд.

Выше, я умолчал об одной важной детали. О том, что виртуальная память может состоять не только из страниц ОЗУ, а может состоять (и состоит) из страниц более медленного хранилища, например жёсткого диска. В этом и кроется смысл виртуальной памяти — в объединении ОЗУ с жёстким диском, чтобы увеличить размер рабочего множества.

virtual_memory_2.png

Другими словами, диск является дополнением для ОЗУ. Задачей виртуальной памяти является борьба с нехваткой памяти . Как я говорил выше, у каждого загруженного исполняемого файла, есть своя выделенная ОС, виртуальная память.

Структура процесса в виртуальной памяти ​

  • ImageBase — адрес базовой загрузки
  • ImageSize — размер образа.

Так зачем же ImageBase процессу? Почему он не может быть, скажем, равен 0? Почему по умолчанию он равен 0x400000? Так же было бы гораздо проще!

На самом деле, ответ на этот вопрос очень прост. В промежутке адрессов от 0x00000000 до ImageBase находятся 2 области памяти, называемые кучей и стэком . Они используются программой в своих целях. Структура процесса в виртуальной памяти выглядит примерно так:

memory_map.png

Также в виртуальной памяти хранятся загруженные Dynamic Linked Libraries (DLLs) и различные структуры, а именно, PEBs (Process Environment Blocks) и TEBs (Thread Environment Blocks). Эти структуры хранят различную информацию о процессе и потоках.

  • VA (Virtual Address) — адрес ячейки в виртуальной памяти
  • RVA (Relative Virtual Address) — относительный виртуальный адрес

Загрузка исполняемого файла ​

  1. Разбор заголовков
  2. Разбор таблицы секций
  3. Проецирование файла в память
  4. Разбор таблицы импорта
  5. Запуск и исполнение

Разбор заголовков

    Разбор DOS заголовка
    1.1. Сначала, происходит проверка сигнатуры e_magic. Она должна быть равна «MZ».

1.2. После этого, происходит считывание поля e_lfanew и переход к разбору PE-заголовка

  • Magic (битность)
  • AddressOfEntryPoint (Relative Virtual Address (RVA) точки входа в программу)
  • ImageBase (предпочтительный адрес в виртуальной памяти, куда следует загружать виртуальный образ)
  • SectionAlignment (RVA начала секций в памяти будет дополнено до этого этого значения)
  • FileAlignment (смещение начала cекций в файле)
  • MajorSubsystemVersion (2 старших байта необходимой версии Windows)
  • MinorSubsystemVersion (2 младщих байта необходимой версии Windows)
  • SizeOfImage (размер виртуального образа в памяти)
  • SizeOfHeaders (размер заголовков образа в памяти)
  • Subsystem (тип подсистемы)
  • NumberOfRvaAndSizes (количество таблицы директорий)
  • DataDirectory (таблица директорий)
Читайте также:
Лучшие программы для создания графиков

Разбор таблицы секций ​

Для каждой секции из PE-файла считывается блок размером SizeOfRawData (секция) по смещению PointerToRawData, после этого этот блок будет загружен в виртуальную память по адресу ImageBase + VirtualAddress с различными характеристиками.

Проецирование ​

После разбора всех заголовков, происходит непосредственно загрузка заголовков и секций.

mapping.png

Сначала, по адресу базовой загрузки (ImageBase) происходит проецирование всех заголовков PE-файла.

После заголовков, начинается проецирование секций. Каждая секция будет загружена по адресу ImageBase + VirtualAddress, дополнена нулями до значения VirtualSize, кстати, это называется выравниванием , и для неё будут установлены определённые характеристики. Выравнивавание нужно, в первую очередь, чтобы поддержать структуру организации секции.

Разбор таблицы импорта

Вот мы и подошли вплотную к изучению импорта. Импорт — важнейший элемент любого исполняемого файла. Импорт позволяет использовать функции из других модулей нашей программой. Таблица импорта является каталогом и секцией по совместительству (обычно носит имя .idata). Эта таблица соотносит вызовы функций из DLL с их адресами.

Формат таблицы импорта зависит от режима импорта функций.

    Standard import
    Этот режим самый медленный, но и самый распространённый. В данном случае, информация о таблице секций заносится в элемент с индексом 1 (IMAGE_DIRECTORY_ENTRY_IMPORT) массива DataDirectory. Таблица импорта в этом случае является массивом элементов типа IMAGE_IMPORT_DESCRIPTOR, причём последний элемент должен быть нулевой. Структура IMAGE_IMPORT_DESCRIPTOR на языке C/C++ показана ниже:

typedef struct _IMAGE_IMPORT_DESCRIPTOR < DWORD OriginalFirstThunk; DWORD TimeDateStamp; DWORD ForwarderChain; DWORD Name; DWORD FirstThunk; >IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR;

  • OriginalFirstThunk
    Это четырёхбайтовое поле содержит RVA до INT (Import Name Table) или ILT (Import Lookup Table). Этот массив содержит RVA на структуры Hint (2 байта, специальный индекс функции в DLL), Name(имя импортируемой функии). Заканчивается нулевым элементом.
  • TimeDateStamp
    Данное поле, размером в 4 байта, содержит дату и время.
  • Name
    Четырёхбайтовое поле содержащее RVA до строки с именем библиотеки.
  • FirstThunk
    Это четырёхбайтовое поле содержит RVA до IAT (Import Address Table). При загрузке исполняемого файла, загрузчик загружает необходимые DLL и записывает в IAT адрес импортируемой функции.

Запуск программы

После разбора всех заголовков, разбора таблицы секций, проецирования файла в память и импорта функций начинается исполнение программы по адресу ImageBase + AddressOfEntryPoint. Обычно, AddressOfEntryPoint указывает на секцию кода (.text), которая содержит машинные инструкции, но это всего лишь соглашение и оно может быть несоблюдено.

Ну, на этом всё. Если есть какие-либо вопросы или поправки, буду рад если вы напишите комментарий. В следующей статье мы «вручную» создадим свой EXE-файл с использованием лишь одного Hex-редактора. После окончательного изучения PE мы начнём изучать его с точки зрения информационной безопасности.

Источник: codeby.net

Что такое файлы Исполняемое приложение?

Исполняемые файлы — это файлы, которые запускаются как программы в операционной системе при их открытии (запуске). В более общих чертах, исполняемый файл состоит из определенного количества инструкций, выполняемых компьютером при открытии файла.

Компьютерная программа — это не что иное, как последовательность инструкций (строк кода). При установке в компьютерной системе они существуют в виде исполняемых файлов.

Популярные расширения файлов исполняемых приложений

Executable App Types

Структура базы данных файлов — Расширения файлов Исполняемое приложение

Топ расширений файлов Исполняемое приложение

Расширение файла Общее количество файлов Первоначальный файл (дата) Последний файл (дата)
MST 728 luna.mst
(04/14/2008)
ShellUI.MST
(03/04/2020)
PNF 4489 machine.PNF
(11/02/2006)
volsnap.PNF
(03/23/2020)
XAP 134 CommunicatorContentBinApp.xap
(05/10/2017)
NativeHostPollApp.xap
(02/12/2020)
SCR 205 scrnsave.scr
(11/02/2006)
vaesaver.scr
(02/24/2020)
XBAP 6 XamlViewer_v0300.xbap
(04/11/2009)
XamlViewer_v0300.xbap
(10/05/2019)
VDM 848 mpasdlta.vdm
(11/02/2006)
MpAvBase.vdm
(02/25/2020)
EXE 32144 EXCH_regtrace.exe
(08/18/2001)
MpSigStub.exe
(03/30/2020)
PRX 2923 winsat.prx
(11/02/2006)
PcleLowQualityPAL.prx
(01/20/2020)
BAG 44 deCV5A-PropertyBag.bag
(06/18/2013)
saMV2A-PropertyBag.bag
(03/18/2017)
OUT 52 LXCACLN1.OUT
(09/18/2006)
test.xml.out
(02/17/2020)
BIN 13749 c2.bin
(09/18/2006)
ShutdownPerformanceDiagnostics_SystemData.bin
(03/30/2020)
DS 11 wiatwain.ds
(11/02/2006)
WR2.ds
(02/01/2020)
EFI 115 bootmgfw.efi
(04/11/2009)
SecConfig.efi
(03/04/2020)
MSC 153 comexp.msc
(09/18/2006)
WF.msc
(03/04/2020)
COM 138 chcp.com
(11/02/2006)
pxeboot.com
(03/04/2020)

Просмотреть все файлы расширений: # A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

Источник: www.exefiles.com

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru