Новости
13.02.2025
Книга: «Blue Fox: взлом и реверс-инжиниринг ARM»
Что такое реверс-инжиниринг?
Процессоры Arm используются в миллиардах устройств по всему миру — от смартфонов и планшетов до автомобильных систем и умных гаджетов. Реверс-инжиниринг — это процесс анализа чужого программного обеспечения или аппаратного устройства, позволяющий быстро разобраться в принципах работы. Без него сейчас не обойтись, именно этот навык позволяет разработчикам, инженерам и специалистам по инфобезу изучать новые технологии, выявлять уязвимости и создавать более безопасные и эффективные системы.
Конечно же, сегодня мы расскажем о новой книге «Blue Fox: взлом и реверс-инжиниринг ARM», которая поможет разобраться во внутреннем устройстве архитектуры ARM и реверс-инжениринге.
Что внутри книги?
Изначально планировалось, что книга под авторством Марии Маркстедтер будет содержать обзор инструкций Arm, главы по реверс-инжинирингу (обратной разработке), а также главы о внутренних механизмах смягчения последствий использования эксплойтов и методах их обхода. Однако объем книги оказался настолько большим, что пришлось разделить его на две части: Blue Fox и Red Fox.
- Blue Fox — охватывает аналитику — вы узнаете все необходимое для того, чтобы начать заниматься реверс-инжинирингом. Без глубокого понимания основ вы не сможете перейти к более сложным темам, таким как анализ уязвимостей и разработка эксплойтов.
- Red Fox — речь пойдет о наступательном подходе к безопасности — понимании внутренних механизмов защиты от эксплойтов, методов их обхода и распространенных уязвимостях.
Почему начать изучение реверс-инжиниринга нужно с «Blue Fox»?
На самом деле не нужно знать все инструкции Arm, чтобы заниматься реверс-инжинирингом. Многие из них используются в специфических сценариях, с которыми вы можете никогда не столкнуться. Цель «Blue Fox» — дать вам достаточно знаний, чтобы уверенно применять их в своей работе.
Эта книга содержит уникальные пояснения, которые вы не найдете даже в официальном руководстве Arm. Например, такие инструкции, как MOV или ADD, описаны кратко и понятно, но многие другие выполняют сложные операции, которые трудно понять без детального объяснения. В «Blue Fox» большинство инструкций сопровождаются иллюстрациями, которые показывают, что происходит внутри системы.
Для кого книга «Blue Fox»?
Если вы только начинаете свой путь в реверс-инжиниринге, важно понимать, как устроены бинарные файлы, как они компилируются и от каких окружений зависят. Книга фокусируется на средах Linux и формате файлов ELF, но это не ограничивает ее применимость. Инструкции Arm остаются инструкциями Arm, независимо от платформы. Даже если вы проведете реверс-инжиниринг двоичных файлов Arm, скомпилированных для macOS или Windows, смысл самих инструкций останется неизменным.
И почему книга «Blue Fox» стоит того, чтобы её прочитали?
- Книга создана экспертом: глубокое понимание реверс-инжиниринга от опытного автора, который потратил множество часов на изучение архитектуры и упрощение сложных концепций.
- Обучение на практике: пошаговые примеры статического и динамического анализа помогают закрепить теоретические знания и сразу применить их на практике.
- Доступность информации: тысячи страниц технической документации сокращены до необходимого минимума и снабжены комментариями и практическими советами.
- Полное покрытие темы: книга охватывает все основные аспекты реверс-инжиниринга Arm, предоставляя ценные ресурсы для профессионалов всех уровней.
Вы уже изучали реверс-инжиниринг или пока посматриваете со стороны, прежде чем погрузиться в пучину неизведанного? Если вам интересно изучить новое, то дополнительно мы нашли и перевели для вас гайд:
Как заняться реверс-инжинирингом — руководство для начинающих
Как понятно из названия, реверс-инжиниринг — это выяснение, как что функционирует, в направлении снизу вверх. Реверс-инжиниринг – это область информатики, изучающая, как именно работает программа. В реальной практике реверс-инжиниринг может пригодиться в различных ситуациях. Например, мы хотим воссоздать какую-то программу с внесёнными в неё улучшениями. Возможно, мы просто пробуем понять, как что-то работает для дальнейшего более профессионального изучения, например, для анализа вредоносного ПО. Реверс-инжиниринг нужен везде.
Основы
Теперь, уяснив, что такое реверс-инжиниринг, давайте вкратце обсудим некоторые его концепции.
Первым делом нужно понять, что для реверс-инжиниринга необходимо знать, как работает программа. Большинство программ, с которыми нам сегодня приходится работать, написаны на компилируемых языках. Кроме компилируемых языков (C, C++), также существуют интерпретируемые языки (Python, Javascript), либо такие, которые используют слегка иные механизмы (например, Java).
В этой статье мы сосредоточимся только на реверс-инжиниринге компилируемых программ.
Компиляторы

Компилятор — это программа, которая берет код, написанный на каком-либо высокоуровневом языке, и преобразует его в низкоуровневые машинные команды (инструкции). Такой пакет инструкций называется «исполняемый двоичный файл», «исполняемый файл» или просто «бинарник», его можно выполнить на компьютере.
Source program // Исходный код программы
Compiler // Компилятор
Parser // Парсер
AST // Абстрактное синтаксическое дерево
Code generator // Генератор кода
Assembler and Linker // Сборщик и линковщик
Machine language // Машинный язык
Operating System // Операционная система
CPU // Процессор
Raw Hardware I/O Devices // Аппаратные устройства ввода/вывода
Когда мы выполняем проект по реверс-инжинирингу, наша цель — попытаться понять, как работает двоичный файл.
Например
Простейший фрагмент кода на С может иметь вид
int a = 12, b = 5;
int c = a + b;
Его можно преобразовать в ассемблер x86–64 следующим образом
push 12
push 5
mov rax, [rsp + 0x8]
mov rbx, [rsp]
add rax, rbx
push rax
Когда этот код далее собирается в машинные инструкции (архитектура AMD64 Linux), можно получить следующий результат (шестнадцатеричное представление последовательности байт)
0x6A 0xC 0x6A 0x5 0x48 0x8B 0x44 0x24 0x8 0x48 0x8B 0x1C 0x24 0x48 0x1 0xD8 0x50
Если открыть в редакторе шестнадцатеричного кода любой двоичный файл, то последовательности байт в шестнадцатеричном представлении будут выглядеть очень схоже.
Некоторые полезные инструменты
Теперь представьте, что у вас есть исполняемый файл. Если просто просмотреть шестнадцатеричный дамп, нам это особенно ничего не даст.

Образец программы Hello World на C

Выдержка из шестнадцатеричного дампа вышеприведённого кода.
Как понятно из этих иллюстраций, простая программа Hello World может превратиться в сотни байт инструкций. Например, в программе, исходный код которой состоит из 7 строк, насчитывается 997 строк шестнадцатеричного дампа!
Инструменты дизассемблирования
Чтобы код было удобнее читать, используются дизассемблеры. Тогда как сборщик преобразует ассемблерный код в машинные инструкции, дизассемблер действует прямо наоборот.
GDB — один из самых старых и мощных инструментов, которым можно пользоваться для дизассемблирования. Однако это может быть сложно, поскольку эта программа ориентирована, прежде всего, на работу с командной строкой. Поэтому, если подробно не знать всех ее команд, вы почти ничего не сможете с её помощью сделать. Есть и другие инструменты, в частности, of Ghidra, Ida или Binary Ninja. С ними обработка двоичных файлов получается интерактивнее и проще.

Дизассемблирование функции main() в GDB
Согласитесь, так гораздо лучше, чем пытаться читать двоичный файл с листа. Но читать ассемблерный код вообще непросто, и в нём можно запутаться, особенно в более сложных программах.
Декомпиляторы
Познакомимся с декомпиляторами. Опять же, по названию можно догадаться, что они делают. Они берут ассемблер, сгенерированный инструментами дизассемблирования, и дают на выход (обычно) удобочитаемый код на желаемом языке.
В таких программах как Ghidra, Ida и т.д. предусмотрены плагины-декомпиляторы, которые очень хорошо справляются с подобной работой. Но в данном случае нужно отметить важную разницу: сборщики переводят ассемблер в машинный код с точностью «один к одному», а декомпилированный код может быть неполным переводом с ассемблера.
Декомпиляция — это в основном очень сложный процесс, особенно по мере усложнения самих запрограммированных концепций (например, классов и объектов). Полученный в результате код следует считать только псевдокодом.

Интерфейс Ghidra (в качестве образца загружена программа Hello World)
Обзор конкурса CTF в области реверс-инжиниринга
Конкурсы в жанре CTF (Capture The Flag, «Захватить флаги») — отличный способ напрактиковаться в области кибербезопасности. В рамках конкурса проводятся соревнования в различных категориях кибербезопасности. На каждом этапе требуется заполучить «флаг», обычно представляющий собой строку в конкретном формате, например, flag{...}
. Разумеется, та информация, которая содержится в фигурных скобках, уникальна для каждого конкурса.
Реверс-инжиниринг — очень популярная категория, входящая в большинство CTF.
Csaw CTF 2023 / Rebug 2
На конкурсе Csaw CTF, который проводится примерно в середине сентября, есть и задания, рассчитанные на новичков. Rebug 2 — именно такой конкурс в области реверс-инжиниринга.
Вот его описание^

Перевод скриншота: На этот раз ввод не предоставляется ;). Попытайтесь добыть флаг из бинарника. Когда найдёте ответ на эту программу, пожалуйста, сообщите флаг в следующем формате:
csawctf{вывод}
Автор: Махмуд Шабана
Скачав файл, я первым делом (как обычно) выполнил команду file
.
В результате получаем элементарную, но полезную информацию о файле. Из неё можно сделать вывод, что перед нами 64-разрядный исполняемый файл в формате ELF, а также выяснить ещё некоторые детали.
Далее нужно выполнить команду strings
.
В случае именно с этим двоичным файлом ничего полезного мы не получим. Но иногда при помощи команды strings можно ухватить ценные ниточки.
Также можно попробовать и некоторые другие базовые команды Linux, например, strace
и ltrace
.
Декомпиляция
Я открыл мой двоичный файл при помощи Ghidra. Выполнив первичный анализ, который обычно делает Ghidra, я начал рассматривать декомпиляцию главной функции.

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

Опять же, здесь много такого кода, который выглядит почти как полная чепуха. Но в этой функции есть интересующий нас вызов xoring()
. Перейдя к xoring()
, получим следующее.

Здесь мне в глаза сразу же бросился массив под названием flag
. Напомню: в условиях конкурса было сказано, что мы должны найти флаг в двоичном файле.
Из кода, окружающего переменную, ясно следует, что эта функция «создаёт» флаг.
В данный момент мы стремимся получить содержимое flag
. Следует отметить, что внутри главной функции есть цикл for, в рамках которого и вызывается printbinchar()
. Следовательно, чтобы узнать полное значение флага, мы должны получить содержимое массива уже после того, как поток управления выйдет из цикла.
Динамический анализ
До сих пор мы занимались исключительно статическим анализом. При помощи статического анализа в основном выясняют логику потока выполнения программы.
Теперь мы знаем, как работает код, и нам требуется выяснить, что содержится в памяти во время выполнения. Для этого переключимся на динамический анализ.
Существуют различные инструменты для динамического анализа, но, опять же, самый мощный из них — GDB. Хотя, выше я уже рассказывал, почему работа с GDB может оказаться сложной.
В GDB добавляются определенные улучшения, в частности, pwndbg, peda или GEF, благодаря которым инструмент становится удобнее. Также есть альтернативное решение Radare.
Запускаем Radare2 следующей командой:

Здесь используются два аргумента. -d
предназначен для отладочного режима, а -AA
— для полного анализа двоичного файла.
Последний штрих
Чтобы узнать, что содержится в переменной flag, необходимо выполнить три простых шага:
- Найти адрес
flag
в памяти - Остановить программу сразу после того, как она выйдет из цикла в
main()
. - Просмотреть содержимое
flag
в памяти, воспользовавшись тем адресом, что мы нашли выше.
1. Адрес в памяти
К счастью, именно в случае с данным бинарником нам не требуется адрес, по которому flag
расположена в памяти. Дело в том, что, если рассмотреть соответствующие инструкции ассемблера в массиве операций


то видно, что адрес, по которому flag
находится в памяти, загружен в регистр RDX
. Если также просмотреть код, который идёт далее, то можно убедиться, что этот RDX
больше нигде не используется. Таким образом, можно не отслеживать адрес flag
, а в любой момент узнать этот адрес, проверив регистр RDX
.
2. Остановить выполнение
Одна из наилучших черт динамического анализа — возможность расставлять точки останова. Пользуясь такими точками, можно приостановить выполнение кода почти в любой точке, после чего начать выполнять инструкции вручную.
Чтобы поставить точку останова, нужно обратиться в Radare к функции main()
. Для этого можно ввести s main
, а затем написать pdf
, чтобы приступить к её дизассемблированию. В Radare главная функция обычно называется просто ‘main’.


Посмотрим, как идёт дизассемблирование функции main


Я поставил точку останова прямо перед завершением программы, так как цикл for — это последний участок кода в функции main.
Точка останова ставится при помощи db
. В данном случае требуется адрес той инструкции, в которой будет ставиться точка останова.
Получаем флаг
Далее требуется выполнить двоичный файл. Для этого можно воспользоваться dc
.

Программа выполняется, а потом, как только она достигнет точки останова, выполнение прекращается. Теперь нам нужно заглянуть в ту точку памяти, где находится flag
. Это можно сделать при помощи команды pxw
. Здесь p
означает «print» (печать), x
означает hex (шестнадцатеричный), w
означает «word» (слово). Таким образом, эта команда будет выводить содержимое памяти 16-разрядными фрагментами в шестнадцатеричном формате. Интересующая нас память хранится в RDX
, поэтому, чтобы получить содержимое RDX
, можно воспользоваться командой dr
.
В конечном итоге команда принимает вид:-

Здесь dr rdx
заключается в обратные штрихи для того, чтобы сначала была выполнена эта команда, а затем её вывод применялся при выполнении команды pxw
.
Получаем следующий вывод:

Желтый текст — это представление содержимого памяти в кодировке ASCII, искомая информация.
Вот и всё, мы успешно захватили флаг!
Преобразовав его в формат, указанный в описании задания, получим csawctf{01011100010001110000}
.
Самое сложное — сделать первый шаг. Мы познакомились с реверс-инжинирингом, а теперь ещё пара слов о книге «Blue Fox».
Об авторе:
Мария Маркстедтер — генеральный директор и основатель компании Azeria Labs, выпускающей курсы по реверс-инжинирингу и эксплуатации уязвимостей ARM. Мария занималась тестированием на проникновение и анализом угроз, а также была директором по продуктам в стартапе Corellium, Inc, специализирующемся на виртуализации.
Она получила степень бакалавра и магистра в области корпоративной безопасности и работала над исследованиями по смягчению последствий эксплойтов вместе с компанией Arm в Кембридже.
В 2018 году Мария была включена в список Forbes “30 до 30 лет”, а в 2020-м получила звание “Человек года в области кибербезопасности” по версии Forbes. С 2017 года она является членом Наблюдательного совета по тренингам и брифингам Black Hat® в ЕС и США.
Если интересно продолжить освоение темы, переходите на сайт издательского дома «Питер» и приобретайте «Blue Fox: взлом и реверс-инжиниринг ARM».
Комментарии: 0
Пока нет комментариев