Содержание статьи
Символический эмулятор позволяет развернуть поиск дыр на 180 градусов. Фаззинг, скажем, через AFL пробует все возможные входные данные. Angr же, напротив, перебирает все возможные пути исполнения, воссоздавая входные данные, при которых мы достигли интересующего нас участка кода.
Например, возьмем код из моей статьи про Intel Pin:
#include <stdio.h>#include <string.h>int main(int argc, char* argv[]){ if (argc == 2) { if (strcmp(argv[1], "secret") == 0) { printf("You did it!\n"); } else { printf("Better luck next time\n"); } }}
Полный перебор шести символов потребует 256 в 6-й степени попыток. Для Angr есть всего одна развилка: пойти налево или направо. И он пойдет и туда, и туда! Нам остается лишь сказать ему, в какой момент остановиться и подсчитать входные данные.
import sysimport angrimport claripyproject = angr.Project('get_pass.bin')arg = claripy.BVS('arg', 8*10)initial_state = project.factory.entry_state(args=['./a.out', arg])initial_state.options.add('SYMBOL_FILL_UNCONSTRAINED_MEMORY')def is_successful(state): stdout_output = state.posix.dumps(sys.stdout.fileno()) return b'You did it' in stdout_outputsimulation = project.factory.simgr(initial_state)simulation.explore(find=is_successful)if simulation.found: solution_state = simulation.found[0] solution = solution_state.solver.eval(arg, cast_to=bytes).decode() print('Password:', solution)
Запустив скрипт, за секунду получаем искомый пароль.
$
Password:
Не пересказывая всю документацию, объясню, что необходимо для старта.
Первым делом ставим Angr (потребуется Python 3.8 или новее):
pip install angr
Angr спроектирован для работы из консоли. Документация зачастую не раскрывает всех возможностей, так что советую изучать инструмент «живьем». По каждому объекту в интерактивном режиме можно получить справку из docstring
командой help(
(или project?
, если у тебя iPython).
Пользоваться справкой можно так же, как и man
: управление — на стрелках, выход через q
.
Ну а смотреть поля и методы классов удобно через автодополнение: допиши к названию класса точку и пару раз нажми Tab.
Основные концепции
Все начинается с класса Project
, его создание — это начало взаимодействия с Angr. Проект отвечает за загрузку и первичный анализ.
Передаем путь до исследуемого файла и, чтобы начать симуляцию со старта программы, создаем новое состояние через factory.
. Фабрика создает экземпляры основных классов. Состояние — это объект SimState
, фактически — снимок виртуальной машины. Он содержит блок кода, память, регистры, стек вызовов и другие вещи, реализуемые как плагины к SimState
.
initial_state.regs.rip
<BV64 0x401080>
Используемые в симуляции данные хранятся в битовом массиве bitvector
. Он строго ограничен по длине и может быть переполнен, то есть ведет себя как процессорный регистр. Его размер всегда указывается в битах.
Существует два основных типа: BVV
(bit-vector value) и BVS
(bit-vector symbol). Первый представляет конкретные значения чисел. Второй содержит только имя и размер. Это основа символического исполнения, конкретного значения здесь нет.
Базовые блоки
Каждое состояние связано с конкретным блоком кода. Местный базовый блок — это набор инструкций, который заканчивается командой передачи управления. Каждый шаг эмуляции перемещает нас к следующему блоку, создавая новое состояние.
Продолжение доступно только участникам
Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».
Присоединяйся к сообществу «Xakep.ru»!
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее