Создание заплаток на ассемблере FASM — Архив WASM.RU Содержание Введение Бинарные файлы Файлы формата PE Заключение Введение Аналогичным англоязычным названием является - "patch", но использовать я буду отечественный вариант "заплатка". Рассматривать мы будем создание заплаток для бинарных файлов и исполняемых файлов формата PE. Способ подходит как для изменения нескольких байт, так и для создания подпрограмм реализующих дополнительную функциональность. Основной инструмент - FlatAssembler. Компилятор генерирует очень компактный код и предоставляет абсолютный контроль над размещением данных. Дополнительная особенность - это ужаснейщий препроцессор. Также потребуется программа, которая запищет изменения. Принцип работы достаточно прост, все изменения описываются в исходном файле, после компиляции выходной файл и вывод препроцессора используются программой правки для внесения изменений. Исходный файл с описанием изменений ничем не отличается от обыкновенной программы на ассемблере, единственное, блок кода/данных нужно заключать в макрокоманды __setorg/__mkdiff. Первая определяет положение в файле, по которому будет записан блок, а вторая определяет конец блока. Бинарные файлы При изменении бинарного файла, положение установленное макрокомандой __setorg в точности совпадает с позицией в реальном файле. Код (ASM): ; Файл 1.asm ; Определить строку "Hello" начиная с 8-го байта include 'patchit.inc' ; Определение макрокоманд __setorg 8 ; Устанавливаем позицию в файле db 'Hello' ; Определяем данные __mkdiff ; Принять изменения Также можно использовать ассемблер и изменять значения счетчика команд. Например, нам требуется изменить *.com программу так, чтобы при запуске управление передовалось нашей подпрограмме. Код (ASM): ; Файл 2.asm ; Изменение инструкций *.com программы include 'patchit.inc' ; Изменить первую инструкцию __setorg 0 org $100 ; адрес по которому загружается программа jmp $120 ; передать управление по адресу $120 __mkdiff ; Подпрограмма выводит на консоль cтроку текста __setorg $20 ; переместить положение в файле org $120 ; установить адрес mov ah,13h mov al,1 xor bh,bh mov bl,07h xor dx,dx mov bp,msg_text mov cx,msg_size int $10 ret msg_text: dw 'Hello sailor!' msg_size = $ - msg_text __mkdiff В дополнение можно рассказать о нескольких особенностях использования. Изменять небольшие участки удобно макрокомандой __mkchng, она заменят набор команд __setorg/__mkdiff если требуется изменить всего одну строку. Код (ASM): ; Файл 3.asm ; Пример использования __mkchng include 'patchit.inc' __mkchng 10, <db 'Hello'> ; Заменяется на ; __setorg 10 ; db 'Hello' ; __mkdiff Для контроля выхода за пределы файла можно использовать макродирективу __maxorg, при этом необходимо указать размер файла непосредственно в байтах, либо полный или относительный путь к файлу, тогда макрос сам вычислит размер. Превышение этого значения приведет к ощибке компиляции. Код (ASM): ; Файл 4.asm ; Пресечение выхода за границу файла include 'patchit.inc' __maxorg 2 ; максимальный размер 2 байта __mkchng 0, <db 1,2,3> ; error 'выход за границу файла' ; Аналогичный способ если доступен файл __maxorg '1.asm' __mkchng 10000,<db 'ups!'> ; error 'выход за границу файла' Файлы формата PE Правка исполняемых файлов особенно утомительный процесс, так как значение адресов и смещений запущенной программы не соответствует их положению в файле. И для того чтобы узнать позицию инструкции в файле(RVA) по адресу памяти(VA), нужно произвести вычисление вида: RVA_секции + VA_базы - VA_инструкцииИспользуя макроопределения можно достаточно реально воспроизвести ситуацию, когда при написании кода вам необходимо знать только адрес в памяти(VA), тогда как программа, используя информацию о файле, сама вычислит действительный адрес инструкции(RVA). Используя макроопределения ситуация упрощается, устанавливать положение маркера можно по виртуальному адресу.Все, что потребуется - это используя макродирективу __format_pe указать основные характеристики - базовый адрес загрузки и секции. Описание секции состоит из трех параметров "VA RA N". Где, VA - относительный адрес секции в памяти, RA - позиция секции в файле, N - реальный размер секции в байтах. Узнать значения можно постмотрев заголовок файла в отладчике или специальной программомой для работы c файлами формата PE(я использовал PeID). Код (ASM): ; Файл 5.asm ; Пример изменения PE файла include 'patchit.inc' __format_pe $400000,\ ; Базовый адрес загрузки (ImageBase) $1000, $400, $200,\ ; Секция кода '.code' $2000, $600, $200 ; Секция данных '.data' ; Адреса импортируемых функци _MessageBoxA = $403044 _ExitProcess = $40303C __setorg $401000 push 0 push dword caption push dword message push 0 call dword [_MessageBoxA] push 0 call dword [_ExitProcess] __mkdiff __setorg $402000 message db 'The file was patched by unknown hacker',0 caption db 'Attention!' __mkdiff Теперь положение в файле вычисляется по виртуальному адресу. Выход за пределы секции контролируется и вызывает ошибку компиляции. Заключение Программа правки и примеры находятся в приложении к статье. В качестве дополнительного описания могу посоветовать только исходный код, он достаточно небольшой. Хочется поблагодарить товарища Tomasz Grysztar за отличний ассемблер, кодеров с wasm.ru и flatassembler.net/board Исходники к статье. Сайт автора - www.assert.i8.com. © Smile