Создание заплаток на ассемблере FASM — Архив WASM.RU

Все статьи

Создание заплаток на ассемблере FASM — Архив WASM.RU

Содержание

  • Введение
  • Бинарные файлы
  • Файлы формата PE
  • Заключение

Введение

Аналогичным англоязычным названием является - "patch", но использовать я буду отечественный вариант "заплатка".

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

Основной инструмент - FlatAssembler. Компилятор генерирует очень компактный код и предоставляет абсолютный контроль над размещением данных.

Дополнительная особенность - это ужаснейщий препроцессор.

Также потребуется программа, которая запищет изменения.

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

Исходный файл с описанием изменений ничем не отличается от обыкновенной программы на ассемблере, единственное, блок кода/данных нужно заключать в макрокоманды __setorg/__mkdiff. Первая определяет положение в файле, по которому будет записан блок, а вторая определяет конец блока.

Бинарные файлы

При изменении бинарного файла, положение установленное макрокомандой __setorg в точности совпадает с позицией в реальном файле.

	; Файл 1.asm
	; Определить строку "Hello" начиная с 8-го байта

	include 'patchit.inc'	; Определение макрокоманд

	__setorg 8              ; Устанавливаем позицию в файле
	db 'Hello'		; Определяем данные
	__mkdiff                ; Принять изменения
Также можно использовать ассемблер и изменять значения счетчика команд.

Например, нам требуется изменить *.com программу так, чтобы при запуске управление передовалось нашей подпрограмме.

	; Файл 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 если требуется изменить всего одну строку.

	; Файл 3.asm
	; Пример использования __mkchng

	include 'patchit.inc'

	__mkchng 10, <db 'Hello'>
	; Заменяется на
	; __setorg 10
	; db 'Hello'
	; __mkdiff

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

	; Файл 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).

        ; Файл 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.

2002-2013 (c) wasm.ru