Как сшить exe с exe

Обновлено: 26.04.2024

Однако существуют программы, использующие сторонние библиотеки, но при этом состоящие из одного единственного файла. Все утилиты от SysInternals, а также любимый мной LINQPad представляют из себя один файл в котором содержится все, что требуется для работы. Пользоваться такими утилитами одно удовольствие — они сразу готовы к использованию, их удобно передавать и хранить.

В статье рассказывается, как создавать такие автономные программы из одного файла. Разобран пример как со сжатием зашить библиотеку AutoMapper в программу и как ее потом достать и использовать.

Исходный код к статье — скачать

Код программы использует стороннюю библиотеку AutoMapper. Чтобы убедиться в работоспособности библиотеки после ее зашития в ресурсы, в программе вызывается код из семплов к библиотеке. Этот код здесь не приведен, ибо это статья не об AutoMapper. Но сама библиотека интересная и полезная — рекомендую посмотреть, что же она делает в коде.

Если CLR не удалось найти сборку, вызывается событие AppDomain.AssemblyResolve. Событие дает возможность загрузить требуемую сборку вручную. Поэтому для реализации автономной программы, состоящей из одного exe файла, достаточно зашить все зависимые сборки в ресурсы и в обработчике AssemblyResolve подгружать их.

Удобно класть в ресурсы сборки в архивированном виде. Архивация уменьшает размер итоговой программы приблизительно в 2 раза. Скорость запуска увеличивается, но эти доли секунды мало кто заметит. А вот уменьшение размера файла позволит его быстрее качать по сети.

Итак, у нас есть работающий проект, использующий сторонние библиотеки. Хочется, чтобы exe файл проекта был автономен и не требовал наличия зависимых dll в своем каталоге.

Полученную ранее архивированную сборку добавляем в ресурсы проекта через Project Properties-Resources-Files. Студия при добавлении ресурса генерирует код, который позволяет использовать добавленный ресурс через Resources класс.

Регистрируем обработчик AssemblyResolve (до использования классов зависимой библиотеки):

AppDomain .CurrentDomain.AssemblyResolve += AppDomain_AssemblyResolve;
Код обработчика:
private static Assembly AppDomain_AssemblyResolve( object sender, ResolveEventArgs args )
if ( args.Name.Contains( "AutoMapper" ) )
Console .WriteLine( "Resolving assembly: " , args.Name );

// Загрузка запакованной сборки из ресурсов, ее распаковка и подстановка
using ( var resource = new MemoryStream ( Resources .AutoMapper_dll ) )
using ( var deflated = new DeflateStream ( resource, CompressionMode .Decompress ) )
using ( var reader = new BinaryReader ( deflated ) )
var one_megabyte = 1024 * 1024;
var buffer = reader.ReadBytes( one_megabyte );
return Assembly .Load( buffer );
>
>

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

По умолчанию зависимые библиотеки, добавляемые через References, копируются в выходную директорию проекта. Чтобы AssemblyResolve сработал, нужно либо скопировать выходной exe файл в другую директорию, либо запретить копировать зависимые библиотеки в конечную директорию через References-AutoMapper-Properties-Copy Local=false.

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

Фактически такие автономные программы не требуют установки и их удобно передавать по сети или хранить на флешке. Архивирование сборок позволяет уменьшить размер программы и больше таких программ разместить на флешке / быстрее выкачивать из сети.


Когда наш журнал был бумажным, мы считали не очень хорошей идеей делать серии зависимых друг от друга статей, ведь, чтобы освежить воспоминания месячной и двухмесячной давности, читателю пришлось бы поднимать подшивку. А теперь все просто :). Мы делаем цикл по реверсу малвари, две статьи уже вышло — вот нулевая (если кто не заметил, там офигенные ссылки, почитай, не пожалеешь. — Прим. ред.), вот первая. Если ты что-то забыл — вспоминай, а если нет — готовься узнать о том, как работают упаковщики и протекторы, для чего их используют и как с ними можно бороться.

WARNING

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

Сага о протекторах и упаковщиках

Один из излюбленных приемов зловредописателей — использование упаковщиков (packers) и протекторов (protectors) исполняемых файлов (хотя это также относится и к DLL). Изначально эти инструменты считались весьма банальными и были призваны, по сути, уменьшать размер скомпилированного файла, а в случае протекторов — позволять модифицировать авторам свои программы, превращая их, к примеру, в demo- или trial-версию, и не заморачиваться с защитой в основном коде. Но позднее вирусописатели приспособили эти инструменты в корыстных целях.

Создатели вредоносов успешно стали применять их, чтобы усложнить антивирусный и эвристический анализ, защитить свои детища от запуска в виртуальной среде, отладки, дизассемблирования и последующего анализа. Поэтому с тех пор навыки и умения распаковывать исполняемые файлы вошли в обязательные требования как для начинающего, так и для опытного реверс-инженера. Наиболее популярные сегодня упаковщики — UPX, ASPack, FSG, PeShield, VMProtect. Это, так сказать, джентльменский набор, с которым аналитику приходится сталкиваться каждый день.

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

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

Ликбез по теории

Итак, как мы понимаем, использование упаковщиков/протекторов/крипторов значительно усложняет реверсинг. Помимо этого, писатели зловредов могут использовать многократную упаковку (так называемый послойный пак), применять малоизвестные или вовсе самописные тулзы (для тех, кто хочет накодить что-то свое, небольшой ликбез), сигнатуры которых будут отсутствовать, к примеру, в том же PEiD. Интересно, что любой пакер, не созданный специально для шифрования малвари, оставляет свою уникальную сигнатуру в бинарнике, а соответственно, умея пользоваться Hex-редакторами, можно определить его сигнатуру и без PE-анализатора.

Общий принцип рассматриваемых инструментов упаковки/защиты таков: после клика на EXE-файле и его запуска выполнение основного кода программы начинается с так называемой точки входа (Entry Point) — адреса, по которому передается управление после загрузки программы в оперативную память. Когда программа запакована, алгоритм работы несколько изменится. Упаковщик запоминает точку входа EP, потом, используя алгоритмы архивирования, сжимает содержимое файла (как правило, это секция кода и данных), после чего дописывает свою сигнатуру после либо до сжатого кода программы и перенаправляет ее не в основной код программы, а в код упаковщика (точнее сказать — распаковщика). Сам же код распаковщика, находящийся теперь внутри файла, получает управление первым и распаковывает упакованные секции кода/данных в памяти! На диске исходный файл остается нетронутым, то есть упакованным, неизменным. После того как код и данные программы распакованы, код распаковщика восстанавливает таблицу импорта и передает управление основному коду программы, на бывшую точку входа, которая в упакованных программах называется оригинальной точкой входа (Original Entry Point). Если кратко, то это все основные моменты.

Схема упаковки исполняемого файла

Схема упаковки исполняемого файла


Другие статьи в выпуске:

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

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

Ручная и автоматическая распаковка

С большой долей вероятности все рабочие экземпляры малвари будут запакованы тем или иным упаковщиком/протектором. Но чтобы все-таки убедиться, что файл запакован, запускаем PEiD или любой другой PE-анализатор. В 90% случаев этого будет достаточно, PEiD имеет большую базу данных сигнатур и плагинов, что позволяет обойтись без лишних хлопот.

Дальнейшим шагом станет распаковка файла (восстановление) в его исходный (wild source) вид. И тут есть несколько сценариев действий. Первый — это использовать автораспаковщики, тулзы, специально заточенные под автоматическую распаковку файла, основываясь на уже известном алгоритме упаковщика/протектора. Например, UN-PACK — это анпакер для UPX, ACKiller — для программ, защищенных протектором ACProtect, Stripper — для файлов, запакованных ASProtect, ASPack unp — для накрытых упаковщиком ASPack.

Второй вариант — использовать универсальные распаковщики, например QuickUnpack, RL!dePacker или Dr.Web FLY-CODE Unpacker, основанный на движке FLY-CODE антивируса Dr.Web. Фича программ в том, что они сами автоматически анализируют файл и ищут в нем ОЕР, а после дампят программу (в том числе и импорт восстанавливают). Однако часты случаи, когда сдампленный файл оказывается неработоспособным из-за некорректности его обработки универсальным распаковщиком или из-за изменения алгоритма пакера, который несовместим с тем, что использует универсальный распаковщик. Но есть и плюс: иногда, если файл не удается распаковать до рабочего состояния, секция кода в любом случае получается распакованной, а этого вполне достаточно для анализа.

И третий сценарий, более длительный, но в перспективе более успешный, — ручная пошаговая распаковка с помощью OllyDbg. Если файл запакован чем-то неизвестным, это легко определить по наличию в таблице импорта защищаемого приложения WinAPI-функций из библиотеки kernel, таких как GetProcAddressA, LoadLibraryA или GetModuleHandle.

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

А вот аналогичная страница, но только на этот раз про распаковщики (на всякий случай зеркало тут).

Авторы вредоносного ПО широко используют упаковщики и протекторы для усложнения его детектирования и для противодействия анализу. Большинство из них анализируются стандартным арсеналом инструментов реверс-аналитика, но некоторые требуют нестандартного подхода и глубокого знания PE-архитектуры.

Учимся скрывать присутствие отладчика и обходить методы противодействия

В одной из статей нашего журнала были описаны наиболее интересные плагины для OllyDbg. Нам обязательно понадобятся:

  • OllyExt — содержит опции Anti-AntiDebug;
  • OllyDumpEx — отличный дампер процессов;
  • swordfish — быстрая установка точек останова;
  • uberstealth — фича Anti-AntiDebug, основанная на коде IDA Stealth.

Все самые нужные плагины OllyDbg 2.xx Plugins можно забрать с файлового архива Tuts4you тут и тут. Набор плагинов для IDA Pro с подробным описанием доступен на GitHub или на Tuts4you. Тем же, кто готов написать свой плагин, могу рекомендовать интересную статью.

Шифрование кода

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

Наиболее популярен плагин Krypto ANALyzer для PEiD. Найденные значения можно просто посмотреть или экспортировать в скрипт для дизассемблера IDA Pro.

Краткое руководство по анализу

Типовой набор действий банален: определение сигнатуры упаковщика, поиск OEP, дамп программы на диск, восстановление таблицы импорта, восстановление релоков, пересборка. А если же файл не просто был запакован, а еще и обработан протектором, то могут потребоваться дополнительные действия, такие, например, как удаление мусорных инструкций, обход антиотладочных приемов, изоляции функций проверки целостности кода CRC.

Несколько слов о динамических библиотеках. Распаковка DLL практически не отличается от распаковки EXE-файла. У DLL, как и у EXE, есть точка входа в код программы — Entry Point, созданная пакером, и оригинальная OEP. Таким образом, нужно остановиться на DLL в Entry Point, распарсить и оттуда идти к единственно верной OEP нашей DLL. Дальше можно стандартно дампить. И еще пара коротких абзацев из матчасти, которая сегодня нам пригодится.

Несколько слов о breakpoints (точках останова)

Точки останова — часто используемый и незаменимый прием любого реверс-аналитика. Основные режимы — это:

  • останов при чтении;
  • останов при записи;
  • выполнение памяти по заданному адресу.

Команда CALL $+5 POP REG характерна для защитных механизмов, к примеру копирующих себя на стек. А часто возникающая инструкция PUSHFD присутствует в самотрассирующихся программах и антиотладочных защитных механизмах.


Пред­ста­вим, что нам нуж­но запус­тить некий злов­редный код на машине жер­твы. Дос­тупа к это­му ком­пу у нас нет, и кажет­ся, что самым прос­тым вари­антом будет вынудить жер­тву сде­лать все за нас. Конеч­но, ник­то в здра­вом уме не запус­тит сом­нитель­ное ПО на сво­ем девай­се, поэто­му жер­тву нуж­но заин­тересо­вать — пред­ложить что‑то полез­ное. Тут в дело всту­пает джо­инер — тул­за, которая встро­ит в полез­ную наг­рузку наш код и скрыт­но его запус­тит.

warning

Статья пред­назна­чена для «белых хакеров», про­фес­сиональ­ных пен­тесте­ров и руково­дите­лей служ­бы информа­цион­ной безопас­ности (CISO). Ни автор, ни редак­ция не несут ответс­твен­ности за любой воз­можный вред, при­чинен­ный при­мене­нием информа­ции дан­ной статьи.

Су­щес­тву­ют ли готовые решения, пред­назна­чен­ные для склей­ки прог­рамм и вре­донос­ной наг­рузки? Безус­ловно, но здесь есть ряд проб­лем. Такие инс­тру­мен­ты детек­тятся анти­виру­сами, сто­ят денег и час­то про­дают­ся как сер­вис, то есть тре­буют опла­ты за разовую склей­ку. Бес­плат­ные и прос­тые спо­собы встро­ить полез­ную наг­рузку вида «помес­тим фай­лы в саморас­паковы­вающий­ся архив» и вов­се баналь­ный фуф­ломицин. Решение же, сде­лан­ное сво­ими руками, может быть улуч­шено, исправ­лено в слу­чае детек­та и, конеч­но, оста­нет­ся бес­плат­ным.

Немного теории

Джо­инер может и дол­жен скле­ивать два исполня­емых фай­ла. Пер­вый — визу­аль­ная обо­лоч­ка, кра­сивая кар­тинка и отвле­кающий маневр. Это то, что уви­дит юзер на экра­не сво­его компь­юте­ра, ког­да запус­тит исполня­емый файл. Вто­рой — полез­ная наг­рузка, которая запус­кает­ся без явно­го желания поль­зовате­ля. По умол­чанию вто­рой файл не будет как‑то скрыт: если в нем при­сутс­тву­ют окна или, нап­ример, гром­кое музыкаль­ное соп­ровож­дение, то это все юзер заметит. Поэто­му нуж­но обес­печить скрыт­ную работу полез­ной наг­рузки. Джо­инер лишь скле­ивает, но не мас­киру­ет вре­донос­ное при­ложе­ние.

А может ли джо­инер скле­ить исполня­емый файл с кар­тинкой? Может, но это не име­ет смыс­ла. Чис­то теоре­тичес­ки, если бы он скле­ивал исполня­емый файл и кар­тинку, на выходе все рав­но получал­ся бы исполня­емый файл, который не имел бы рас­ширения . jpg , . png или дру­гого подоб­ного. Редак­торы и прос­мот­рщи­ки кар­тинок такой файл открыть не смо­гут. Либо мы получим кар­тинку, но в таком слу­чае не смо­жем запус­тить исполня­емый файл. Есть еще вари­ант, ког­да при­ложе­ние стар­тует и откры­вает кар­тинку через API ShellExecute. Дей­ствие занят­ное, но толь­ко в качес­тве фокуса — поль­зы от него никакой.

Как устроен наш вариант

На­шей целью будет Windows 10 x64, но, поняв прин­цип, лег­ко мож­но перера­ботать инс­тру­мен­тарий под дру­гие вер­сии семей­ства Windows. Код дол­жен работать и на Windows 7/8, но не тес­тировал­ся там. Мы будем исполь­зовать смесь С++ и ассем­бле­ра.

Алгоритм работы

Обо­лоч­ка — наш пер­вый ехе , который будет виден кли­енту. Это, так ска­зать, при­ман­ка. Наг­рузка — вто­рой ехе , в котором содер­жится злов­редный кон­тент. В обо­лоч­ку добав­ляет­ся допол­нитель­ная сек­ция, куда записы­вает­ся шелл‑код и наг­рузка. Управле­ние сра­зу переда­ется на шелл‑код, задача которо­го — извлечь наг­рузку, сох­ранить ее на диск и запус­тить. На вер­хнем уров­не все сво­дит­ся к тому, что мы получа­ем некий бай­товый мас­сив, который дол­жны положить в допол­нитель­ную сек­цию. Потом оста­нет­ся лишь испра­вить точ­ку вхо­да у обо­лоч­ки, и все — склей­ка завер­шена.

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

Нам понадобится:

Запускаем Visual Studio 2019 и создаем консольный проект:


Теперь установим нужные NuGet пакеты, жмем в верхнем меню кнопку «Проект» и далее «Управление NuGet пакетами»

1. Жмем вкладку «Обзор» и вводим в строку поиска: SharpZipLib > «Установить»

2. Там же в строке поиска вводим «Costura.Fody» > «Установить»

3. Справа жмем по Program.cs


Начнем писать код.

Удаляем все в редакторе и вставляем мой код, в коде смотрите комментарии что можно изменить, название файлов, архивов, все что я комментил все можно изменить на ваши имена, поехали:

Учтите если вы назвали проект не как уменя: ViJoy

То после вставки кода переименуйте: namespace «ViJoy» < на свой


Для примера я буду использовать 2 программы:

  • putty.exe — в коде она как — exe1.exe
  • puttygen.exe — в коде она как — exe2.exe

Их мы и будем склеивать, вы можете представить это так:

  • exe1.exe — Это нормальная прога с которой надо клеить вашу малварь
  • exe2.exe — Это уже сама ваша малварь, стиллер, рат, криптолокер и т.д

Теперь надо 2 эти программы добавить в наш exe билд который мы написали.

Для начала будем использовать 7zip и запакуем их в 1 архив под паролем.

Выделяем эти 2 файла, жмем правой кнопкой мыши и жмем: 7-zip > добавить к архиву

  • Уровень сжатия — ультра
  • Формат архива — zip

Пароль любой, ваш, только в коде выше его не забудьте поменять в строке примерно 21й.

В моем случаи пароль будет 123

ahiv.zip, его давайте переименуем в другой формат и название:


Теперь этот архив надо добавить в наш exe который мы кодили в Visual Studio 2019 (Далее буду назвать это VS).

Открываем снова VS:

1. Жмем по проекту правой кнопкой мыши:


  • Справа будет меню, ищем кнопку «Ресурсы» и жмем.
  • Вверху будет кнопка: добавить ресурс, и выбираем наш архив: joy.cfg
  • Жмем стрелку рядом с названием: «Добавит ресурс», а не слово добавить ресурс, т.к тогда окно выбора файла не откроется.

Уже готово! Но. Теперь давайте скроем окно консоли. Опять правой кнопкой про проекту, скрин выше > свойства > слева в меню: Приложение > Тип выходных данных выбираем: приложение Windows

Теперь нам надо все собрать/скомпилить, ура!

Выбираем в окне VS вместо Debug > Release

Теперь соберем наши exe и весь проект в 1 exe!

Жмем в верхнем меню «СБОРКА» > «Собрать решение»

Что бы найти наш exe файл снова жмем по проекту правой кнопкой мыши > «открыть папку в проводнике»

Идем в папку bin > Release и видим наш exe файл. Запускаем. и Оп:


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

Исходники проекта который мы с вами разобрали в статье можете скачать тут

Поделись статьей с друзьями

Отказ от ответственности: Автор или издатель не публиковали эту статью для вредоносных целей. Вся размещенная информация была взята из открытых источников и представлена исключительно в ознакомительных целях а также не несет призыва к действию. Создано лишь в образовательных и развлекательных целях. Вся информация направлена на то, чтобы уберечь читателей от противозаконных действий. Все причиненные возможные убытки посетитель берет на себя. Автор проделывает все действия лишь на собственном оборудовании и в собственной сети. Не повторяйте ничего из прочитанного в реальной жизни. | Так же, если вы являетесь правообладателем размещенного на страницах портала материала, просьба написать нам через контактную форму жалобу на удаление определенной страницы, а также ознакомиться с инструкцией для правообладателей материалов. Спасибо за понимание.

app.exe, d1.dll d2.dll = app.exe

Обычно результатом компиляции проекта является сборка (assembly) проекта, а также его зависимости (Referenced Assemblies). Однако иногда нужно чтобы результатом был один файл единственный файл, независимый от других сборок. Например простая утилита, которую можно будет куда угодно скопировать и она будет работать.

Пример

Условно говоря после: Получаются:
Нам же нужно лишь один самодостаточный
То есть содержащий в себе dep1.dll и dep2.dll

На Хабре уже присутствует решение со встраиванием зависимостей в ресурсы, здесь я покажу как это сделать с помощью ILMerge и Post Build Event в Visual Studio.

Исходники
Инструменты

ILMerge — Программа от Microsoft Research, которая собственно и обладает требуемой функциональностью.
merge_all.bat — им мы воспользуемся в Post-build event.

Подготовка
Содержание merge_all.bat
Лицензия

С сайта ILMerge:
Commercial use permitted:
The language of ILMerge's license has raised many questions. In a nutshell: commercial use is permitted, redistribution is not. Read the license carefully for full details since I am not (nor do I wish to be!) a lawyer.

То есть встраивать в процесс сборки можно, а распространять со своим продуктом — нельзя.

Читайте также: