Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Angr — эмулятор на стероидах. Он кросс‑платформенный и поддерживает большинство популярных архитектур: с ним на Linux можно искать уязвимости в PE32, а на Windows — ковырять прошивки роутеров. В этой статье я на примере работы в Linux покажу, как его использовать.
Символический эмулятор позволяет развернуть поиск дыр на 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 timen"); } }}
Полный перебор шести символов потребует 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)
Запустив скрипт, за секунду получаем искомый пароль.
$ python angr_get_pass.py
Password: secret
Не пересказывая всю документацию, объясню, что необходимо для старта.
Первым делом ставим Angr (потребуется Python 3.8 или новее):
pip install angr
Angr спроектирован для работы из консоли. Документация зачастую не раскрывает всех возможностей, так что советую изучать инструмент «живьем». По каждому объекту в интерактивном режиме можно получить справку из docstring
командой help(project)
(или project?
, если у тебя iPython).
Пользоваться справкой можно так же, как и man
: управление — на стрелках, выход через q
.
Ну а смотреть поля и методы классов удобно через автодополнение: допиши к названию класса точку и пару раз нажми Tab.
Все начинается с класса Project
, его создание — это начало взаимодействия с Angr. Проект отвечает за загрузку и первичный анализ.
Передаем путь до исследуемого файла и, чтобы начать симуляцию со старта программы, создаем новое состояние через factory.entry_state
. Фабрика создает экземпляры основных классов. Состояние — это объект SimState
, фактически — снимок виртуальной машины. Он содержит блок кода, память, регистры, стек вызовов и другие вещи, реализуемые как плагины к SimState
.
initial_state.regs.rip <BV64 0x401080>
Используемые в симуляции данные хранятся в битовом массиве bitvector
. Он строго ограничен по длине и может быть переполнен, то есть ведет себя как процессорный регистр. Его размер всегда указывается в битах.
Существует два основных типа: BVV
(bit-vector value) и BVS
(bit-vector symbol). Первый представляет конкретные значения чисел. Второй содержит только имя и размер. Это основа символического исполнения, конкретного значения здесь нет.
Каждое состояние связано с конкретным блоком кода. Местный базовый блок — это набор инструкций, который заканчивается командой передачи управления. Каждый шаг эмуляции перемещает нас к следующему блоку, создавая новое состояние.
Источник: xakep.ru