ARM Assembly для хакеров: изучение 32-битной архитектуры для разработки эксплойтов

  • Автор темы Автор темы LeSh1y777
  • Дата начала Дата начала

LeSh1y777

Пользователь
Регистрация
25/9/25
Сообщения
5,682
Репутация
49
Лайки
153
Депозит
-8.95$
Возможно, вы уже заметили, что процессоры ARM используются повсюду — в телефонах, маршрутизаторах, смарт-телевизорах и, конечно же, в устройствах Интернета вещей. Фактически, ARM стала одной из самых распространённых архитектур процессоров в мире. И, как и традиционные ПК, устройства Интернета вещей на базе ARM уязвимы к классическим методам эксплуатации уязвимостей, таким как переполнение буфера.

Если вас интересует разработка эксплойтов или обратная разработка вредоносных программ, изучение ассемблера — это базовый навык. Понимание того, как код взаимодействует с памятью на самом низком уровне, необходимо для выявления уязвимостей и создания эффективных эксплойтов.

Учитывая широкое распространение устройств ARM и их часто игнорируемые уязвимости безопасности, число атак на них, вероятно, увеличится. И как кибервоину, вам необходимо понимать, как эти системы работают на уровне сборки, чтобы эффективно анализировать, защищать их и эксплуатировать.

В предыдущих статьях мы изучили архитектуру процессора ARM и приступили к сборке 64-битного ARM с использованием набора инструкций AArch64 — современного стандарта 64-битной ОС Raspberry Pi.

Теперь, чтобы лучше понять основы ARM, мы переключим внимание на 32-битную сборку ARM (ARMv7-A).

Что такое язык ассемблера?​

Ассемблер (ASM или asm) — это любой низкоуровневый язык программирования с очень строгим соответствием между инструкциями языка и инструкциями машинного кода архитектуры. В ассемблере обычно на каждую машинную инструкцию приходится один оператор (1:1). Поскольку ASM зависит от инструкций машинного кода, каждый язык ассемблера специфичен для конкретной архитектуры компьютера.

В данном случае мы будем изучать 32-битную сборку ARM.

Зачем изучать 32-битный ассемблер ARM?​

От промышленных контроллеров и медицинского оборудования до потребительской электроники, большинство встраиваемых и IoT-устройств по-прежнему работают на 32-битных процессорах ARM. Эти системы не модернизируются, как настольные компьютеры, — у них длительный жизненный цикл, ограниченный объём памяти и они используют более компактные и простые наборы инструкций, такие как ARMv7. Например, маршрутизаторы, IP-камеры и концентраторы для умного дома обычно работают на однокристальных системах (SoC) на базе ARMv7, часто с ядрами Linux и средами BusyBox.

arm_asm_ip_camera-1024x512.webp
Умная IP-камера на процессорах ARM Cortex-A35 (Amlogic C305X и C308X)
В отличие от современных настольных компьютеров или облачных систем, многие 32-битные устройства ARM, представленные на рынке, не имеют защиты, по умолчанию работают с правами root и не имеют регулярных обновлений или циклов исправлений. Чтобы воспользоваться их уязвимостями, необходимо понимать их набор инструкций, соглашения о вызовах, структуру памяти и двоичный интерфейс — всё это требует 32-битной сборки ARM.

Многие образцы вредоносного ПО, находящиеся в открытом доступе (Mirai, Mozi), скомпилированы для 32-битной архитектуры ARM. Анализируя реальные угрозы, вы будете дизассемблировать 32-битные исполняемые файлы ARM, а не только 64-битные.

Кроме того, 32-битный ARM проще в освоении и отлично подходит для создания прочной основы. Людей, хорошо знающих ассемблер ARM, немного, поэтому его изучение может помочь улучшить карьерные возможности и оставаться в авангарде кибербезопасности.

Регистры

Регистры — это области памяти компьютера, где хранятся данные. При работе с ассемблером мы обычно используем эти регистры для перемещения и обработки информации, поэтому вам следует с ними познакомиться.

arm_asm_registers.webp

32-разрядные процессоры ARM имеют 16 регистров общего назначения. Вот эти регистры:

R0–R3: Регистры аргументов (используются для параметров функций и возвращаемых значений)
R4–R11: Регистры общего назначения для локальных переменных и временного хранения
R12: Регистр временных интервалов внутрипроцедурных вызовов (IP)
R13 : Указатель стека (SP) — указывает на вершину стека
R14: Регистр ссылок (LR) — хранит адреса возврата для вызовов функций
R15: Счетчик программ (PC) — указывает на текущую выполняемую инструкцию

Также имеется специальный регистр — xPSR: расширенный регистр состояния программы (объединяет флаги условий, текущий номер исключения и состояние выполнения).

Флаги

Флаги в 32-битном ассемблере ARM — это отдельные биты в специальном регистре, которые указывают состояние операций в процессоре. Регистр состояния программы имеет ширину 32 бита, но основные используемые флаги — это всего несколько ключевых битов. Наиболее интересными являются следующие флаги:

Флаг Z (ноль): указывает, равен ли результат операции нулю.
Флаг C (перенос): указывает на перенос или заём в арифметических операциях.
Флаг V (переполнение): указывает на переполнение в знаковой арифметике.

Эти флаги позволяют условно выполнять инструкции на основе результатов предыдущих операций и обновляются многими арифметическими и логическими инструкциями с суффиксом «S», например, ADDS.

Инструкции ARM​

Инструкции ARM следуют предсказуемому шаблону, что делает чтение дизассемблированного кода более интуитивным:

<операция>{<условие>}{S} <назначение>, <операнд1>, <операнд2>

Вот некоторые из самых популярных инструкций:

MOV – переместить копирует значение из исходного файла в целевой. Например:

MOV R0, R1 ; Copy R1 to R0

; означает комментарий в Ассамблее.

LDR – load копирует значение из памяти в регистр. Например:

LDR R0, [R1] ; Load the value from the address in R1 into R0

STR – store копирует значение из регистра в память. Например:

STR R0, [R1] ; Store the value in R0 to the address in R1

CMP – сравнивает и вычитает второй операнд из первого, а также устанавливает флаги условий. Например:

CMP R0, R1 ; Compare R0 with R1 (sets flags, but doesn't store result)

B – переход по метке осуществляется при выполнении условия. Например:

BEQ label ; Branch to 'label' if equal (Z flag is set)

И – побитовое И выполняет логическую операцию И над каждым битом операндов. Например:

AND R0, R1, R2 ; R0 = R1 AND R2

ORR – побитовое ИЛИ выполняет логическое ИЛИ над каждым битом операндов. Например:

ORR R0, R1, R2 ; R0 = R1 OR R2

EOR (исключающее ИЛИ) выполняет логическую операцию XOR над каждым битом операндов. Например:

EOR R0, R1, R2 ; R0 = R1 XOR R2

BIC – сброс бита выполняет операцию R1 И (НЕ R2). Например:

BIC R0, R1, R2 ; R0 = R1 AND NOT R2

PUSH – сохраняет регистры в стеке. Например:

PUSH {R0, R1} ; Push R0 and R1 onto the stack

POP – восстанавливает регистры из стека. Например:

POP {R0, R1} ; Pop values into R0 and R1 from the stack

BL – переход по ссылке переходит к подпрограмме и сохраняет адрес возврата в LR. Например:

BL myFunction ; Call subroutine 'myFunction'

BX – переход по адресу и переключение набора инструкций при необходимости. Например:

BX LR ; Return from subroutine (branch to address in LR)

SVC – вызов супервизора запускает программное прерывание для перехода в режим супервизора. Например:

SVC #0 ; Call operating system service

ADR – загрузка адреса метки в регистр. Например:

ADR R0, label ; Load the address of 'label' into R0

Краткое содержание​

32-битный ассемблер ARM поначалу может показаться сложным, но его логичная структура и единообразный формат инструкций делают его более доступным для многих аналитиков, чем x86. В этой статье мы рассмотрели причины изучения 32-битного ассемблера, изучили флаги и регистры, а затем рассмотрели некоторые наиболее часто используемые инструкции.
 
Назад
Сверху Снизу