BREAD (BIOS Reverse Engineering & Advanced Debugger) — это «инжектируемый» отладчик x86 в реальном режиме, который может отлаживать произвольный код реального режима (на реальном аппаратном обеспечении) с другого ПК через последовательный кабель.
BREAD возник в результате многих неудачных попыток реконструировать устаревший BIOS. Учитывая, что подавляющее большинство (если не весь) анализ BIOS выполняется статически с помощью дизассемблеров, понимание BIOS становится чрезвычайно трудным, поскольку невозможно узнать значения регистров или памяти в данном фрагменте кода.
Несмотря на это, BREAD также может отлаживать произвольный код в реальном режиме, например загрузочный код или программы DOS.
Быстрая демонстрация:
Изменение имени строки ЦП через BREAD
Этот отладчик разделен на две части: отладчик (полностью написанный на ассемблере и работающий на отлаживаемом оборудовании) и мост, написанный на C и работающий в Linux.
Отладчик представляет собой внедряемый код, написанный в 16-битном реальном режиме и может быть размещен в ПЗУ BIOS или в любом другом коде реального режима. При выполнении он устанавливает соответствующие обработчики прерываний, переводит процессор в одношаговый режим и ожидает команд на последовательном порту.
С другой стороны, мост является связующим звеном между отладчиком и GDB. Мост связывается с GDB через TCP и пересылает запросы/ответы отладчику через последовательный порт. Идея моста состоит в том, чтобы устранить сложность пакетов GDB и установить более простой протокол для связи с машиной. Кроме того, более простой протокол позволяет уменьшить окончательный размер кода, что упрощает внедрение отладчика в различные среды.
Как показано на следующей схеме:
+---------+ simple packets +----------+ GDB packets +---------+
| | --------------- > | | --------------- > | |
| dbg | | bridge | | gdb |
| ( real HW ) | <- -------------- | ( Linux ) | <- -------------- | ( Linux ) |
+---------+ serial +----------+ TCP +---------+
Благодаря реализации заглушки GDB BREAD имеет множество готовых функций. Поддерживаются следующие команды:
Реверс-инжиниринг необработанного двоичного файла, такого как BIOS, в GDB автоматически подразумевает отсутствие исходных символов. Однако по мере продвижения процесса RE пользователь/программист/хакер лучше понимает определенные части кода, а инструменты статического анализа, такие как IDA, Cutter, Ghidra и другие, позволяют добавлять аннотации, комментарии, определения функций, и многое другое. Эти улучшения значительно повышают производительность пользователя.
Имея это в виду, в проекте есть сопутствующий скрипт Python под symbolify.py
. Учитывая список символов (метку адреса), он генерирует минимальный файл ELF с добавлением этих символов. Этот ELF можно позже загрузить в GDB и использовать для значительного упрощения процесса отладки.
Файл символов может содержать пробелы, пустые строки, комментарии (#) и комментарии в адресной строке. Адреса могут быть в десятичном или шестнадцатеричном формате, а метки/символы (разделенные одним или несколькими пробелами) могут иметь форму [a-z0-9_]+, как в (реальный пример можно найти в файле символов/ami_ipm41d3. текст):
#
# This is a comment
#
0xdeadbeef my_symbol1
0x123 othersymbol # This function does xyz
# Example with decimal address
456 anotherone
Например, учитывая файл символов, доступный по адресу символы/ami_ipm41d3.txt, пользователь может сделать что-то вроде:
$ ./simbolify.py symbols/ami_ipm41d3.txt ip41symbols.elf
Затем загрузите его в GDB, как показано ниже:
(gdb) add-symbol-file ip41symbols.elf 0
add symbol table from file "ip41symbols.elf" at
.text_addr = 0x0
(y or n) y
Reading symbols from ip41symbols.elf...
(No debugging symbols found in ip41symbols.elf)
(gdb) p cseg_
cseg_change_video_mode_logo cseg_get_cpuname
(gdb) p cseg_
Обратите внимание, что даже автозаполнение GDB работает так, как ожидалось, удивительно?
Сколько? Да. Поскольку отлаживаемый код не знает, что он отлаживается, он может мешать работе отладчика несколькими способами, вот некоторые из них:
Переход в защищенный режим: если отлаживаемый код переключается в защищенный режим, структуры обработчиков прерываний и т. д. изменяются, и отладчик больше не будет вызываться в этом месте кода. Однако возможно, что возврат в реальный режим (полное восстановление предыдущего состояния) позволит отладчику снова работать.
Изменения IDT: если по какой-либо причине отлаживаемый код меняет IDT или его базовый адрес, обработчики отладчика не будут вызваны должным образом.
Стек: BREAD использует стек и предполагает, что он существует! Его не следует вставлять в места, где стек еще не настроен.
Для отладки BIOS существуют и другие ограничения, такие как: невозможно отладить код BIOS с самого начала (загрузочный блок), поскольку для правильной работы BREAD требуется минимальная настройка (например, ОЗУ). Однако можно выполнить «теплую перезагрузку», установив для CS:EIP значение F000:FFF0
. В этом случае инициализацию BIOS можно повторить еще раз, поскольку BREAD уже правильно загружен. Обратите внимание, что «путь кода» инициализации BIOS во время «теплой» перезагрузки может отличаться от «холодной» перезагрузки, и поток выполнения может быть не совсем таким же.
Для сборки требуется только GNU Make, компилятор C (например, GCC, Clang или TCC), NASM и компьютер с Linux.
Отладчик имеет два режима работы: опрос (по умолчанию) и на основе прерываний:
Режим опроса — это самый простой подход, который должен хорошо работать в различных средах. Однако из-за характера опроса наблюдается высокая загрузка ЦП:
$ git clone https://github.com/Theldus/BREAD.git
$ cd BREAD/
$ make
Режим на основе прерываний оптимизирует загрузку ЦП за счет использования прерываний UART для получения новых данных вместо постоянного их запроса. Это приводит к тому, что ЦП остается в состоянии «остановки» до получения команд от отладчика и, таким образом, не позволяет ему потреблять 100% ресурсов ЦП. Однако, поскольку прерывания не всегда разрешены, этот режим не установлен в качестве опции по умолчанию:
$ git clone https://github.com/Theldus/BREAD.git
$ cd BREAD/
$ make UART_POLLING=no
Для использования BREAD требуется только последовательный кабель (и да, на вашей материнской плате есть разъем COM, проверьте руководство) и вставка кода в соответствующее место.
Для внедрения необходимо внести минимальные изменения в dbg.asm (источник отладчика). Необходимо изменить «ORG» кода, а также способ возврата кода (найдите в коде « >> CHANGE_HERE <<
» для мест, которые необходимо изменить).
На примере устаревшего AMI, где модуль отладчика будет размещен на месте логотипа BIOS ( 0x108200
или FFFF:8210
), а следующие инструкции в ПЗУ заменены дальним вызовом модуля:
...
00017EF2 06 push es
00017EF3 1E push ds
00017EF4 07 pop es
00017EF5 8BD8 mov bx , ax - ┐ replaced by: call 0xFFFF : 0x8210 (dbg.bin)
00017EF7 B8024F mov ax , 0x4f02 - ┘
00017EFA CD10 int 0x10
00017EFC 07 pop es
00017EFD C3 ret
...
достаточно следующего патча:
diff --git a/dbg.asm b/dbg.asm
index caedb70..88024d3 100644
--- a/dbg.asm
+++ b/dbg.asm
@@ -21,7 +21,7 @@
; SOFTWARE.
[BITS 16]
- [ORG 0x0000] ; >> CHANGE_HERE <<
+ [ORG 0x8210] ; >> CHANGE_HERE <<
%include "constants.inc"
@@ -140,8 +140,8 @@ _start:
; >> CHANGE_HERE <<
; Overwritten BIOS instructions below (if any)
- nop
- nop
+ mov ax, 0x4F02
+ int 0x10
nop
nop
Важно отметить, что если вы изменили несколько инструкций в своем ПЗУ для вызова кода отладчика, их необходимо восстановить перед выходом из отладчика.
Причина замены этих двух инструкций заключается в том, что они выполняются непосредственно перед тем, как BIOS отображает логотип на экране, который теперь является отладчиком, обеспечивая выполнение нескольких ключевых моментов:
Найти подходящее место для вызова отладчика (где BIOS уже инициализировался достаточно, но не слишком поздно) может быть непросто, но возможно.
После этого dbg.bin
готов к вставке в правильное место в ПЗУ.
Отладка программ DOS с помощью BREAD немного сложна, но возможна:
dbg.asm
, чтобы DOS воспринимал его как действительную программу DOS:times
)int 0x20
)Следующий патч решает эту проблему:
diff --git a/dbg.asm b/dbg.asm
index caedb70..b042d35 100644
--- a/dbg.asm
+++ b/dbg.asm
@@ -21,7 +21,10 @@
; SOFTWARE.
[BITS 16]
- [ORG 0x0000] ; >> CHANGE_HERE <<
+ [ORG 0x100]
+
+ times 40*1024 db 0x90 ; keep some distance,
+ ; 40kB should be enough
%include "constants.inc"
@@ -140,7 +143,7 @@ _start:
; >> CHANGE_HERE <<
; Overwritten BIOS instructions below (if any)
- nop
+ int 0x20 ; DOS interrupt to exit process
nop
Создайте загрузочный образ дискеты FreeDOS (или DOS), содержащий только ядро и терминал: KERNEL.SYS
и COMMAND.COM
. Также добавьте к этому образу дискеты программу, которую необходимо отладить, и DBG.COM
( dbg.bin
).
После создания образа необходимо выполнить следующие действия:
bridge
(инструкции см. в следующем разделе).DBG.COM
.DBG.COM
продолжаться до его завершения.Важно отметить, что DOS не стирает образ процесса после выхода. В результате отладчик можно настроить как любую другую программу DOS и установить соответствующие точки останова. Начало отладчика заполнено NOP, поэтому ожидается, что новый процесс не будет перезаписывать память отладчика, что позволит ему продолжать работу даже после того, как он окажется «завершенным». Это позволяет BREAD отлаживать другие программы, включая саму DOS.
Bridge — это связующее звено между отладчиком и GDB, и его можно использовать по-разному, как на реальном оборудовании, так и на виртуальной машине.
Его параметры:
Usage: ./bridge [options]
Options:
-s Enable serial through socket, instead of device
-d <path> Replaces the default device path (/dev/ttyUSB0)
(does not work if -s is enabled)
-p <port> Serial port (as socket), default: 2345
-g <port> GDB port, default: 1234
-h This help
If no options are passed the default behavior is:
./bridge -d /dev/ttyUSB0 -g 1234
Minimal recommended usages:
./bridge -s (socket mode, serial on 2345 and GDB on 1234)
./bridge (device mode, serial on /dev/ttyUSB0 and GDB on 1234)
Чтобы использовать его на реальном оборудовании, просто вызовите его без параметров. При желании вы можете изменить путь к устройству с помощью параметра -d
:
./bridge
или ./bridge -d /path/to/device
)Single-stepped, you can now connect GDB!
а затем запустите GDB: gdb
. Для использования в виртуальной машине порядок выполнения немного меняется:
./bridge
или ./bridge -d /path/to/device
)make bochs
или make qemu
).Single-stepped, you can now connect GDB!
а затем запустите GDB: gdb
.В обоих случаях обязательно запускайте GDB внутри корневой папки BRIDGE, так как в этой папке есть вспомогательные файлы для правильной работы GDB в 16-битной версии.
BREAD всегда открыт для сообщества и готов принять вклад, будь то проблемы, документация, тестирование, новые функции, исправления ошибок, опечатки и т. д. Добро пожаловать на борт.
BREAD лицензируется по лицензии MIT. Написано Дэвидсоном Фрэнсисом и (надеюсь) другими участниками.
Точки останова реализованы как аппаратные точки останова и поэтому имеют ограниченное количество доступных точек останова. В текущей реализации одновременно активна только одна точка останова! ↩
Аппаратные точки наблюдения (например, точки останова) также поддерживаются только по одной. ↩
Обратите внимание, что регистры отладки по умолчанию не работают на виртуальных машинах. Для bochs его необходимо скомпилировать с флагом --enable-x86-debugger=yes
. Для Qemu его необходимо запустить с включенным KVM: --enable-kvm
( make qemu
уже делает это). ↩