Благодаря одному товарищу из комментариев в предыдущих постах касательно упаковщика выявился один занятный баг в коде, который я поспешил исправить. Комментатор, не разобравшись в деталях работы пакера, утверждал, что код, запакованный им, окажется неспособным работать с SEH при условии, что DEP включен. При таких условиях код работал хорошо (так как весь распакованный код в памяти находится в пределах одной-единственной секции PE-файла, помеченной как исполняемая. UPX имеет такую же логику работы.). Но случайно была обнаружена следующая ошибка: если программа собрана в MSVC++, использует SEH и имеет релокации, при первом же возникшем исключении она упадет с некоторой долей вероятности (точнее, если файл загрузился не по своему базовому адресу). DEP тут, конечно же, не при чем. Все дело оказалось в злополучной директории IMAGE_LOAD_CONFIG_DIRECTORY. Она создается линкером Visual Studio. Из полезной информации она содержит таблицу адресов (RVA) SE-обработчиков и указатель на внутреннюю переменную crt __security_cookie. Как выяснилось, эта директория нужна не только для внутренностей CRT (хотя она, кажется, как раз хотела плевать на эту структуру), но и системному загрузчику (по крайней мере, в Win7. WinXP, похоже, тоже плевал на эту директорию). Упаковщик, который я описываю, перемещает эту директорию в другую секцию (см. здесь). Поэтому исправить ошибку можно, добавив в таблицу релокаций, создаваемую упаковщиком, несколько записей, которые будут править адреса, указывающие на security cookie и таблицу обработчиков SEH, чтобы он мог считать интересующую его информацию из этой директории на этапе загрузки.
Помимо правки этой ошибки я обновил код упаковщика, чтобы он собирался с использованием последней на данный момент версией библиотеки для работы с PE-файлами (PE Bliss). Ее всегда можно скачать отсюда.
Кстати, насчет библиотеки PE Bliss. Сейчас в свободное время я допиливаю новую версию, в которой появятся следующие дополнительные возможности (список примерный и может измениться):
- высокоуровневая работа с дополнительными типами ресурсов PE-файлов;
- детальный разбор .NET-бинарников (метаданные, сигнатуры, ресурсы);
- обертка над библиотекой на C++/CLI, которая позволит .NET-разработчикам удобно использовать функционал библиотеки в софте на C# или Visual Basic .NET.
Скачать исходники упаковщика: packer source
Скачать собранный вариант: packer binary
UPDATE 24.05.2016: доработки генерации таблиц релокации. В некоторых случаях (например, когда TLS-данных слишком много и присутствует директория load config, адреса в таблице релокации могли переполняться, и файл после упаковки не работал).
Доброго времени суток.
Подскажи пожалуйста при компиляции этого проэкта с новой библиотекой "PE Bliss" проблемы с бустом не может найти вод такую либу "libboost_program_options-vc100-mt-s-1_53.lib"
Написано чтоб она подлинковалось нужно в проперти проэкта Configuration Properties/"C/C++"/Code Generation/Runtime Library/ стояло /MD
Но эт вроде не есть хорошо
Нужно, чтобы стояло /MT. Буст должен быть собран тоже статически. Ну или /MD и буст динамически, но тогда у exe-файла будут зависимости от DLL-файлов Visual Studio Runtime, поэтому я не использую такой вариант.
Dx, доброго времени суток. Пишу диплом связанный с .net pe и хотел бы с вами проконсультироваться по этому поводу. Мне нужно разобраться во всех аспектах .net pe и я особо не понимаю многих вещей , которые мне говорит мой дипломный руководитель. Можно ли как то с вами связаться вне этого блога? Заранее спасибо
Я не смогу оказать консультации по .NET-формату PE-файлов, потому что уже сам его забыл (да и не особо разбирался). Могу порекомендовать хорошую статью, которую сам когда-то читал: https://www.codeproject.com/Articles/12585/The-NET-File-Format
Еще можно читануть исходники .NET, они же теперь в открытом доступе: https://github.com/dotnet
Возможно, появились с того времени, как я смотрел этот формат, какие-то еще хорошие статьи по этому поводу, стоит поискать.
Наконец то у меня нашлось время поиграться с этой тулзой ;)
Скомпилил, значит, я динамическую библиотеку с "хитрыми секциями". Запустил. И...
1. Как я и ожидал, результирующая библиотека работает как задумывалось. А вот "хитрые секции" не работают. :(
"Хитрой секцией" в моем случае была только одна:
".sdata"
VirtSize: 00008000h VirtAddr: 00009000h
raw data offs: 00000000h raw data size: 00000000h
relocation offs: 00000000h relocations: 00000000h
line # offs: 00000000h line #'s: 00000000h
characteristics: D0000080h
UNINITIALIZED_DATA SHARED READ WRITE ALIGN_DEFAULT(16)
2. Заглянул в процесс (с помощью процесс эксплорера) и посмотрел на мою либу - результат не важнецкий. Впрочем я и этого ожидал.
Вместо ожидаемых 6 секций с "правильными" флагами протекции памяти:
MyLib.dll: Image (Commit), 0x6b5b0000, 4 kB, R
MyLib.dll: Image (Commit), 0x6b5b1000, 32 kB, RX
MyLib.dll: Image (Commit), 0x6b5b9000, 32 kB, RW
MyLib.dll: Image (Commit), 0x6b5c1000, 8 kB, R
MyLib.dll: Image (Commit), 0x6b5c3000, 8 kB, RW
MyLib.dll: Image (Commit), 0x6b5c5000, 8 kB, R
получил небезопасного вида картину:
MyLib.dll: Image (Commit), 0x6b5b0000, 4 kB, R
MyLib.dll: Image (Commit), 0x6b5b1000, 92 kB, RWX
Итого:
1. Не "работают" расшаренные секции файла
2. Исполняемый модуль стал небезопасным - т.е. подверженным удачным атакам эксплоитами
Не думаю, что Вы сможете починить пункт 1 и не станете чинить пункт 2.
И еще один момент - модуль в памяти "пожирнел" на 1 страницу.
Это конечно не страшно, мне попадались "экземпляры", утяжеляющие на 0,5МБ ;)
Да, починить первое вряд ли будет возможно. Интересно, кстати, как с shared-секциями работает UPX, портит ли он их. Второй пункт связан с первым, потому что упаковщик весь код собирает в одну секцию с атрибутами RWX, а потом просто восстанавливает таблицу секций. Как вариант, можно было паковать секции по отдельности, и тут на блоге где-то даже лежит старый вариант пакера, который так делает, но тогда результат по эффективности сжатия будет хуже, хотя атрибуты секций при этом сохранятся.
Насчет 2 - Вам просто следовало бы сохранить еще и флаги защиты в блоках информации о секциях. А потом в лоадере их выставить с помощью VirtualProtect, разумеется после распаковки :)
Давече глянул и "старый вариант пакера" - результат монопенисуальный: во все секции, которые он упаковал добавил флаг "W" (типа чтоб можно было распаковать). Хоть он и восстановил флаги в РЕ-заголовке, но с флагами протекции памяти ничего не сделал.
Доброго времени суток!
Подскажите, какие особенности формата PE64 необходимо учитывать при создании упаковщика?
В целом отличий от PE32 нет, за исключением того, что виртуальные адреса (VA) занимают не 4 байта, а 8.
Ну и еще PE64 по-другому работает SEH, там используются Exception tables, и это отдельная директория в PE-файле. С этим стоит разбираться отдельно, но не думаю, что это слишком сложно, потому что в MSDN есть полная документация на этот счет.
@dx, Здраствуйте! Есть ли рабочая версия пакера PE64? Какие оссобенности в написании распаковщика для 64битных файлов?
http://forum.kaimi.io/viewtopic.php?id=573
Когда будут новые посты в блоге??((
Без постов веселее, самобытнее.
Будут, мы работаем над этим)
Друзья а можете переделать ваш ssh-брут, на брут кошельков btc и его форков?
И какая связь вообще? Просьба из разряда переделать Блокнот в Калькулятор.
Когда ждать новую версию PE Bliss?
В процессе. Сейчас свободного времени немного, поэтому разрабатываю медленно. Срок не могу назвать точно.
dx, подскажи плиз.
Если я коментирую вот эту часть:
//Пересоберем ресурсы, если есть, что пересобирать
if(!new_root_dir.get_entry_list().empty())
rebuild_resources(image, new_root_dir, added_section, added_section.get_raw_data().size());
анпакер падает. апи в анпакере сам ищу, хендл kernel32 получаю из PEB.
что не так делаю?
ой, вернее импорты комментирую
//Пересоберем импорты
rebuild_imports(image, imports, added_section, settings);
Ну, если комментируешь, то нужно тогда выпилить таблицу импортов у упакованного файла, раз сам их ищешь.
Добавь что-то вроде
image.remove_directory(IMAGE_DIRECTORY_ENTRY_IMPORT);
ближе к концу.
Спасибо, помогло!
Отличный PE-packer!
Спасибо за интересные статьи, очень много нового узнал. Библиотека PE-Bliss тоже порадовала. Где кошельки для перечисления благодарности? =)
Добавили кошельки на главную страницу справа. Авось пригодятся)
packer source невозможно скачать через хром, блокирует.
dx, перезалей с паролем =)
В статьях написано , что либа допилена до стадии 1.9 . Но скачать можно только 1.0.0 от ноября 12 . Почему так ?
Где написано про 1.9? Может, 0.9? 1.0.0 была последней.
Воистину 0.1.9 . Нолик я в начале как-то проигнорировал . Извиняйте за глупый конфуз . Вопрос можно удалить .
Упаковщик overlay не умеет сохранять?
Нет, потому что в этом нет смысла в целом, не удастся сохранить оверлей по тому же смещению, по которому он располагался до упаковки.
Немного поковыряв код распаковщика столкнулся с тем, что при загрузке упакованного exe возникает ошибка доступа по адрессу TlsIndex (поле tls_index в packed_file_info) еще до запуска кода. В упаковщике код не трогал (атрибуты .rsrc RWE ).
Есть мысли?
Были такие проблемы на Win10 кажется. Когда упаковщик делал, не было еще возможности проверить на десятке. А сейчас уже лень разбираться, где баг.
Проблема возникает на Win7. Стоит размеру кода стаба стать больше 4Кб. Пробовал вырубать tls - но что-то портит память секции распаковщика.
Я пробовал в свое время разные бинари с tls, всё было нормально. Сложно сказать, в чем проблема. У меня такой баг не проявлялся, возможно, это зависит еще и от компилятора (каким компилятором, кстати, исходный файл собран?). Нужно убедиться, что tls index корректен, и адрес, по которому он указывает, существует в бинарнике после его загрузки.
Упаковываемый файл собран компилятором среды Borland Delphi 7. Проект упаковщика собирался компилятором Visual Studio 2008.
Ошибка возникает на этапе загрузки exe в память...
http://rghost.ru/6WKfQd5sk
В чем проблема найти ошибку, если это так принципиально? Ну либо воспользоваться каким-нибудь UPX'ом, если упаковщик неважен.
Хочется найти программу с открытым кодом либо написать самому средство защиты программы с привязкой к железу и паролю пользователя. Первое не попадалось (может Вы встречали?), а защите с закрытыми исходниками я не доверяю. Второе интереснее, но опыта ноль.
Это упаковщик, а не протектор. Снять его не составляет никакой проблемы. А для тех, для кого это может представлять проблему, они и, не знаю, добавленный в код защищаемого софта пароль на открытие не снимут.
Вижу в архиве анпакер, отличающийся от оригинального. В упаковщик вносились изменения?
В упаковщик практически нет, только в части точки входа
image.set_ep(image.rva_from_section_offset(unpacker_added_section, entry_point_offset));
и выкинут boost.
А распаковщик сильные изменения претерпел? Может быть, указаны/вычислены некорректные адреса для tls? Может быть, 2008-я студия генерирует код по-другому (я компилировал, вроде бы, всё это в 2010-й), поэтому какие-то оффсеты поменялись. Оригинальный упаковщик нормально пакует файл?
В студии 2010 экспресс те же проблемы. Оригинальный упаковщик все сжимает нормально. Тут похоже беда не в коде как таковом. Достаточно в распаковщике закоментировать функцию извлечения серийника материнки и все начинает работать. Ошибки Все каким-то образом завязано на размер распаковщика.
О полноценном протекторе речи нет - планируется только зашифровать код после сжатия.
Я и говорил о том, что при изменении размера упаковщика меняются адреса всяких ресурсов и индексов. Там же они часточно были просчитаны вручную, надо их правильно пересчитывать. Они точно правильно вычислены?
В бинарнике с rghost вижу как минимум то, что TLS Data некорректная, отличается от оригинального бинарника. Почему-то записались неправильные данные.
Данные TLS пишутся вот здесь:
//Дополняем секцию данными для инициализации
//локальной памяти потока
unpacker_added_section.get_raw_data() += tls->get_raw_data();
Да, неплохо было бы получить модифицированный код упаковщика и распаковщика, так сложно сказать, в чем проблема.
Без проблем:
http://rghost.ru/private/7MGN6WqC4/dafc66c48261c1ddbfdca13f54f619f5
Посмотрел. Проблема в том, что таблица релокаций, которая строится упаковщиком, некорректная. Последние три элемента должны корректировать VA-адреса из структуры TLS (а именно, StartAddressOfRawData, EndAddressOfRawData и AddressOfIndex). Так как бинарник имеет релокации, загрузчик его самовольно перемещает, как захочет, а эти три поля остаются необработанными (релокации применяются черт знает к каким адресам). В итоге загрузчик пытается осуществить запись по VA-адресу AddressOfIndex, а он не пересчитан, отсюда и ошибка access violation - такого адреса не существует. Если убрать релокации, то всё начинает работать, что ожидаемо.
Код не смотрел, предлагаю для начала самостоятельно изучить, почему таблица релокации для TLS строится кривой.
Ну и да, напомню еще, что данные TLS (RawData) после упаковки борландовского бинарника оказываются кривыми, но такой косяк происходит и в оригинальном упаковщике. Посмотрю попозже, возможно, я просто не помню, как это должно работать.
Посмотрел, с raw data всё нормально, борланд в приложенном бинарнике проставил сырым данным TLS длину 10, а размер секции .tls равен нулю. Получается, все 10 байтов - это нули. В упакованном бинарнике так и оказывается. Итого, нужно только понять, почему твой код некорректно рассчитывает адреса релокаций для TLS.
Интересно стало, в чем проблема с релокациями, нашлась ошибка. Упаковщик создавал таблицу релокаций для адреса, куда загрузчик должен был прописать адрес точки входа, и для всех полей таблицы TLS. Если упаковщик оказывается слишком большого размера, то значения полей в таблице релокаций переполняются (т.к. от RVA каждой таблицы есть возможность отступить всего на 2047 байтов вперед - размер поля смещения в таблице всего 11 байтов). Решение: создать несколько таблиц релокаций для потенциально сильно удаленных друг от друга областей.
Я это проделал, вот твой файл с изменениями: http://rghost.net/private/69FjLyGFp/be9750e494f044be2f0b30daf886d794
Скоро обновлю оригинальный упаковщик в статье (так как в нем такая проблема тоже теоретически может возникнуть с директорией load config).
Ну и еще: в твоем распаковщике empty_tls_callback_offset, похоже, некорректный. В оригинале он указывает на инструкцию ret 0xc, а в твоем на набор каких-то левых инструкций. Это уже исправляй сам.
Кстати, хотел спросить, как ты отлаживаешь упаковщик, если он в конфигурации Debug у тебя даже не собирается? +)
Спасибо! Я признаться увидел что смещение ограничено, и уже задумался как сдвинуть tls в начало секции распаковщика, что оказалось геморно в плане учета в коде распаковщика...
Отлаживать в visual studio 2008 не приходилось, т.к. проблема возникла еще в visual studio 2010 express, но подумал что накосячил в настройках и решил пересобрать проект в более привычной visual studio 2008 и вычистить настройки проекта. Когда и здесь не заработало - понял что проблема глубже..
за empty_tls_callback_offset спасибо, вчера только сдвинул инструкцию и просчитался...
Рекомендую пользоваться CFF Explorer'ом, очень удобный софт для того, чтобы посмотреть, что получилось после упаковки. Достаточно приятные фичи - конвертация адресов с просмотром в hex-редакторе, что по ним лежит, ну и quick disassembler для дизассемблирования по конкретным адресам.
Спасибо, обязательно посмотрю.
Я пользовался IDA и OllyDbg
Народ, как можно связаться с автором сайта по почте?