Introduction to x64
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
x64, також відомий як x86-64, є 64-бітною архітектурою процесора, яка переважно використовується в настільних і серверних обчисленнях. Виникнувши з архітектури x86, виробленої Intel, і пізніше прийнятої AMD під назвою AMD64, це поширена архітектура в персональних комп'ютерах і серверах сьогодні.
x64 розширює архітектуру x86, маючи 16 загальних регістрів, позначених rax
, rbx
, rcx
, rdx
, rbp
, rsp
, rsi
, rdi
, і r8
до r15
. Кожен з цих регістрів може зберігати 64-бітне (8-байтове) значення. Ці регістри також мають 32-бітні, 16-бітні та 8-бітні підрегістри для сумісності та специфічних завдань.
rax
- Традиційно використовується для значень повернення з функцій.
rbx
- Часто використовується як базовий регістр для операцій з пам'яттю.
rcx
- Зазвичай використовується для лічильників циклів.
rdx
- Використовується в різних ролях, включаючи розширені арифметичні операції.
rbp
- Базовий вказівник для стекового фрейму.
rsp
- Вказівник стеку, що відстежує верхню частину стеку.
rsi
та rdi
- Використовуються для індексів джерела та призначення в операціях зі строками/пам'яттю.
r8
до r15
- Додаткові загальні регістри, введені в x64.
Конвенція виклику x64 варіюється між операційними системами. Наприклад:
Windows: Перші чотири параметри передаються в регістри rcx
, rdx
, r8
та r9
. Подальші параметри поміщаються в стек. Значення повернення знаходиться в rax
.
System V (зазвичай використовується в UNIX-подібних системах): Перші шість цілочисельних або вказівникових параметрів передаються в регістри rdi
, rsi
, rdx
, rcx
, r8
, і r9
. Значення повернення також знаходиться в rax
.
Якщо функція має більше ніж шість вхідних параметрів, інші передаються через стек. RSP, вказівник стеку, повинен бути вирівняний на 16 байт, що означає, що адреса, на яку він вказує, повинна ділитися на 16 перед будь-яким викликом. Це означає, що зазвичай нам потрібно забезпечити правильне вирівнювання RSP у нашому shellcode перед викликом функції. Однак на практиці системні виклики працюють багато разів, навіть якщо ця вимога не виконується.
Swift має свою власну конвенцію виклику, яку можна знайти в https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#x86-64
x64 інструкції мають багатий набір, зберігаючи сумісність з попередніми x86 інструкціями та вводячи нові.
mov
: Перемістити значення з одного регістру або місця в пам'яті в інше.
Приклад: mov rax, rbx
— Переміщує значення з rbx
в rax
.
push
і pop
: Помістити або витягти значення з стеку.
Приклад: push rax
— Поміщає значення в rax
на стек.
Приклад: pop rax
— Витягує верхнє значення зі стеку в rax
.
add
і sub
: Операції додавання та віднімання.
Приклад: add rax, rcx
— Додає значення в rax
і rcx
, зберігаючи результат в rax
.
mul
і div
: Операції множення та ділення. Примітка: ці інструкції мають специфічну поведінку щодо використання операндів.
call
і ret
: Використовуються для виклику та повернення з функцій.
int
: Використовується для виклику програмного переривання. Наприклад, int 0x80
використовувався для системних викликів у 32-бітному x86 Linux.
cmp
: Порівняти два значення та встановити прапори ЦП на основі результату.
Приклад: cmp rax, rdx
— Порівнює rax
з rdx
.
je
, jne
, jl
, jge
, ...: Умовні стрибки інструкції, які змінюють потік управління на основі результатів попереднього cmp
або тесту.
Приклад: Після інструкції cmp rax, rdx
, je label
— Стрибає до label
, якщо rax
дорівнює rdx
.
syscall
: Використовується для системних викликів в деяких x64 системах (як сучасний Unix).
sysenter
: Оптимізована інструкція системного виклику на деяких платформах.
Помістіть старий базовий вказівник: push rbp
(зберігає базовий вказівник виклику)
Перемістіть поточний вказівник стеку в базовий вказівник: mov rbp, rsp
(налаштовує новий базовий вказівник для поточної функції)
Виділіть місце в стеку для локальних змінних: sub rsp, <size>
(де <size>
— це кількість байтів, що потрібні)
Перемістіть поточний базовий вказівник до вказівника стеку: mov rsp, rbp
(звільняє локальні змінні)
Витягніть старий базовий вказівник зі стеку: pop rbp
(відновлює базовий вказівник виклику)
Повернення: ret
(повертає управління виклику)
Існують різні класи системних викликів, ви можете знайти їх тут:
Тоді ви можете знайти кожен номер системного виклику за цим посиланням:
Отже, щоб викликати системний виклик open
(5) з Unix/BSD класу, вам потрібно додати: 0x2000000
Отже, номер системного виклику для виклику open буде 0x2000005
Щоб скомпілювати:
Щоб витягти байти:
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)