
BARF : кросс-платформенный фреймворк с открытым исходным кодом для анализа и реверс-инжиниринга бинарного кода
Анализ бинарного кода является ключевой деятельностью во многих областях компьютерных наук и дисциплин программной инженерии, начиная от безопасности программного обеспечения и анализа программ и заканчивая обратной разработкой. Ручной бинарный анализ — сложная и трудоёмкая задача, и существуют программные инструменты, которые стремятся автоматизировать или помочь аналитикам-людям. Однако большинство таких инструментов имеют ряд технических и коммерческих ограничений, которые ограничивают доступ и использование значительной частью академического и практикующего сообществ. BARF — это фреймворк с открытым исходным кодом для бинарного анализа, который стремится поддерживать широкий спектр задач анализа бинарного кода, распространённых в дисциплине информационной безопасности. Это платформа с возможностью написания скриптов, поддерживающая подъём инструкций из нескольких архитектур, трансляцию бинарного кода в промежуточное представление, расширяемый фреймворк для плагинов анализа кода и взаимодействие с внешними инструментами, такими как отладчики, SMT-решатели и инструменты инструментирования. Фреймворк в первую очередь предназначен для анализа с участием человека, но может быть полностью автоматизирован.
Проект BARF включает BARF и связанные инструменты и пакеты. На данный момент проект состоит из следующих компонентов:
Для получения дополнительной информации см.:
Текущее состояние:
| Последний релиз | v0.6.0 |
|---|---|
| URL | https://github.com/programa-stic/barf-project/releases/tag/v0.6.0 |
| Журнал изменений | https://github.com/programa-stic/barf-project/blob/v0.6.0/CHANGELOG.md |
Все пакеты протестированы на Ubuntu 16.04 (x86_64).
BARF — это пакет Python для бинарного анализа и обратной разработки. Он может:
ELF, PE и т.д.),В настоящее время находится в разработке.
BARF зависит от следующих SMT-решателей:
Следующая команда устанавливает BARF в вашу систему:
$ sudo python setup.py install
Вы также можете установить его локально:
$ sudo python setup.py install --user
sudo pip install pyasmjitsudo apt-get install graphvizЭто очень простой пример, показывающий, как открыть бинарный файл и вывести каждую инструкцию с её переводом на промежуточный язык (REIL).
from barf import BARF
# Открываем бинарный файл.
barf = BARF("examples/misc/samples/bin/branch4.x86")
# Выводим ассемблерные инструкции.
for addr, asm_instr, reil_instrs in barf.translate():
print("{:#x} {}".format(addr, asm_instr))
# Выводим перевод в REIL.
for reil_instr in reil_instrs:
print("\t{}".format(reil_instr))
Мы также можем восстановить CFG и сохранить его в файл .dot.
# Восстанавливаем CFG.
cfg = barf.recover_cfg()
# Сохраняем CFG в файл .dot.
cfg.save("branch4.x86_cfg")
Мы можем проверять ограничения на код с помощью SMT-решателя. Например, предположим, у вас есть следующий код:
80483ed: 55 push ebp
80483ee: 89 e5 mov ebp,esp
80483f0: 83 ec 10 sub esp,0x10
80483f3: 8b 45 f8 mov eax,DWORD PTR [ebp-0x8]
80483f6: 8b 55 f4 mov edx,DWORD PTR [ebp-0xc]
80483f9: 01 d0 add eax,edx
80483fb: 83 c0 05 add eax,0x5
80483fe: 89 45 fc mov DWORD PTR [ebp-0x4],eax
8048401: 8b 45 fc mov eax,DWORD PTR [ebp-0x4]
8048404: c9 leave
8048405: c3 ret
И вы хотите узнать, какие значения нужно присвоить ячейкам памяти ebp-0x4, ebp-0x8 и ebp-0xc, чтобы получить определённое значение в регистре eax после выполнения кода.
Сначала добавляем инструкции в компонент анализатора.
from barf import BARF
# Открываем ELF-файл
barf = BARF("examples/misc/samples/bin/constraint1.x86")
# Добавляем инструкции для анализа.
for addr, asm_instr, reil_instrs in barf.translate(0x80483ed, 0x8048401):
for reil_instr in reil_instrs:
barf.code_analyzer.add_instruction(reil_instr)
Затем генерируем выражения для каждой интересующей переменной и добавляем нужные ограничения на них.
ebp = barf.code_analyzer.get_register_expr("ebp", mode="post")
# Предусловия: задаём диапазон для переменных a и b
a = barf.code_analyzer.get_memory_expr(ebp-0x8, 4, mode="pre")
b = barf.code_analyzer.get_memory_expr(ebp-0xc, 4, mode="pre")
for constr in [a >= 2, a <= 100, b >= 2, b <= 100]:
barf.code_analyzer.add_constraint(constr)
# Постусловия: задаём желаемое значение для результата
c = barf.code_analyzer.get_memory_expr(ebp-0x4, 4, mode="post")
for constr in [c >= 26, c <= 28]:
barf.code_analyzer.add_constraint(constr)
Наконец, проверяем, могут ли установленные ограничения быть выполнены.
if barf.code_analyzer.check() == 'sat':
print("[+] Выполнимо! Возможные присваивания:")
# Получаем конкретные значения для выражений
a_val = barf.code_analyzer.get_expr_value(a)
b_val = barf.code_analyzer.get_expr_value(b)
c_val = barf.code_analyzer.get_expr_value(c)
# Выводим значения
print("- a: {0:#010x} ({0})".format(a_val))
print("- b: {0:#010x} ({0})".format(b_val))
print("- c: {0:#010x} ({0})".format(c_val))
assert a_val + b_val + 5 == c_val
else:
print("[-] Невыполнимо!")
Эти и другие примеры можно посмотреть в каталоге examples.
Фреймворк разделён на три основных компонента: core, arch и analysis.
Этот компонент содержит основные модули:
REIL: Предоставляет определения для языка REIL. Также реализует эмулятор и парсер.SMT: Предоставляет средства для взаимодействия с SMT-решателями Z3 и CVC4. Кроме того, предоставляет функциональность для перевода инструкций REIL в выражения SMT.BI: Модуль Binary Interface отвечает за загрузку бинарных файлов для обработки (использует PEFile и PyELFTools).Каждая поддерживаемая архитектура представлена как подкомпонент, содержащий следующие модули.
Architecture: Описывает архитектуру, т.е. регистры, размер адреса памяти.Translator: Предоставляет переводчики в REIL для каждой поддерживаемой инструкции.Disassembler: Предоставляет функции дизассемблирования (использует Capstone).Parser: Преобразует инструкции из строковой формы в объектную.На данный момент этот компонент состоит из модулей: Control-Flow Graph, Call Graph и Code Analyzer. Первые два предоставляют функциональность для восстановления CFG и CG соответственно. Последний является высокоуровневым интерфейсом к функциональности, связанной с SMT-решателем.
BARFgadgets — это скрипт Python, построенный на BARF, который позволяет искать, классифицировать и проверять ROP-гаджеты внутри бинарной программы. Этап поиска находит все гаджеты, оканчивающиеся на ret, jmp и call внутри бинарного файла. Этап классификации классифицирует ранее найденные гаджеты согласно следующим типам:
Это делается с помощью эмуляции инструкций. Наконец, этап проверки состоит в использовании SMT-решателя для проверки семантики, присвоенной каждому гаджету на втором этапе.
usage: BARFgadgets [-h] [--version] [--bdepth BDEPTH] [--idepth IDEPTH] [-u]
[-c] [-v] [-o OUTPUT] [-t] [--sort {addr,depth}] [--color]
[--show-binary] [--show-classification] [--show-invalid]
[--summary SUMMARY] [-r {8,16,32,64}]
filename
Tool for finding, classifying and verifying ROP gadgets.
positional arguments:
filename Binary file name.
optional arguments:
-h, --help show this help message and exit
--version Display version.
--bdepth BDEPTH Gadget depth in number of bytes.
--idepth IDEPTH Gadget depth in number of instructions.
-u, --unique Remove duplicate gadgets (in all steps).
-c, --classify Run gadgets classification.
-v, --verify Run gadgets verification (includes classification).
-o OUTPUT, --output OUTPUT
Save output to file.
-t, --time Print time of each processing step.
--sort {addr,depth} Sort gadgets by address or depth (number of
instructions) in ascending order.
--color Format gadgets with ANSI color sequences, for output
in a 256-color terminal or console.
--show-binary Show binary code for each gadget.
--show-classification
Show classification for each gadget.
--show-invalid Show invalid gadget, i.e., gadgets that were
classified but did not pass the verification process.
--summary SUMMARY Save summary to file.
-r {8,16,32,64} Filter verified gadgets by operands register size.
Для получения дополнительной информации см. README.
BARFcfg — это скрипт Python, построенный на BARF, который позволяет восстанавливать
граф потока управления бинарной программы.
usage: BARFcfg [-h] [-s SYMBOL_FILE] [-f {txt,pdf,png,dot}] [-t]
[-d OUTPUT_DIR] [-b] [--show-reil]
[--immediate-format {hex,dec}] [-a | -r RECOVER]
filename
Tool for recovering CFG of a binary.
positional arguments:
filename Binary file name.
optional arguments:
-h, --help show this help message and exit
-s SYMBOL_FILE, --symbol-file SYMBOL_FILE
Load symbols from file.
-f {txt,pdf,png,dot}, --format {txt,pdf,png,dot}
Output format.
-t, --time Print process time.
-d OUTPUT_DIR, --output-dir OUTPUT_DIR
Output directory.
-b, --brief Brief output.
--show-reil Show REIL translation.
--immediate-format {hex,dec}
Output format.
-a, --recover-all Recover all functions.
-r RECOVER, --recover RECOVER
Recover specified functions by address (comma
separated).
BARFcg — это скрипт Python, построенный на BARF, который позволяет восстанавливать
граф вызовов бинарной программы.
usage: BARFcg [-h] [-s SYMBOL_FILE] [-f {pdf,png,dot}] [-t] [-a | -r RECOVER]
filename
Tool for recovering CG of a binary.
positional arguments:
filename Binary file name.
optional arguments:
-h, --help show this help message and exit
-s SYMBOL_FILE, --symbol-file SYMBOL_FILE
Load symbols from file.
-f {pdf,png,dot}, --format {pdf,png,dot}
Output format.
-t, --time Print process time.
-a, --recover-all Recover all functions.
-r RECOVER, --recover RECOVER
Recover specified functions by address (comma
separated).
PyAsmJIT — это пакет Python для генерации и выполнения ассемблерного кода x86_64/ARM.
Этот пакет был разработан для тестирования перевода инструкций BARF из x86_64/ARM в REIL. Основная идея — иметь возможность запускать фрагменты кода нативно. Затем тот же фрагмент переводится в REIL и выполняется в REIL VM. Наконец, оба итоговых контекста (полученный через нативное выполнение и через эмуляцию) сравниваются на предмет различий.
Для получения дополнительной информации см. PyAsmJIT.
Лицензия BSD 2-Clause. Для получения дополнительной информации см. LICENSE.