Introduction to x64
Introduction to x64
x64, також відомий як x86-64, є 64-бітною архітектурою процесора, яка переважно використовується в настільних і серверних обчисленнях. Виникнувши з архітектури x86, виробленої Intel, і пізніше прийнятої AMD під назвою AMD64, це поширена архітектура в персональних комп'ютерах і серверах сьогодні.
Registers
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.
Calling Convention
Конвенція виклику x64 варіюється між операційними системами. Наприклад:
Windows: Перші чотири параметри передаються в регістри
rcx
,rdx
,r8
таr9
. Подальші параметри поміщаються в стек. Значення повернення знаходиться вrax
.System V (зазвичай використовується в UNIX-подібних системах): Перші шість цілочисельних або вказівникових параметрів передаються в регістри
rdi
,rsi
,rdx
,rcx
,r8
таr9
. Значення повернення також знаходиться вrax
.
Якщо функція має більше ніж шість вхідних параметрів, інші передаються через стек. RSP, вказівник стека, повинен бути вирівняний на 16 байт, що означає, що адреса, на яку він вказує, повинна ділитися на 16 перед будь-яким викликом. Це означає, що зазвичай нам потрібно забезпечити правильне вирівнювання RSP у нашому shellcode перед викликом функції. Однак на практиці системні виклики працюють багато разів, навіть якщо ця вимога не виконується.
Calling Convention in Swift
Swift має свою власну конвенцію виклику, яку можна знайти в https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#x86-64
Common Instructions
Інструкції 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
: Оптимізована інструкція системного виклику на деяких платформах.
Function Prologue
Помістіть старий базовий вказівник:
push rbp
(зберігає базовий вказівник виклику)Перемістіть поточний вказівник стека в базовий вказівник:
mov rbp, rsp
(налаштовує новий базовий вказівник для поточної функції)Виділіть місце в стеці для локальних змінних:
sub rsp, <size>
(де<size>
— це кількість байтів, що потрібні)
Function Epilogue
Перемістіть поточний базовий вказівник у вказівник стека:
mov rsp, rbp
(звільняє локальні змінні)Витягніть старий базовий вказівник зі стека:
pop rbp
(відновлює базовий вказівник виклику)Повернення:
ret
(повертає управління виклику)
macOS
syscalls
Існують різні класи системних викликів, ви можете знайти їх тут:
Тоді ви можете знайти кожен номер системного виклику за цим посиланням:
Отже, щоб викликати системний виклик open
(5) з Unix/BSD класу, вам потрібно додати: 0x2000000
Отже, номер системного виклику для виклику open буде 0x2000005
Shellcodes
Щоб скомпілювати:
Щоб витягти байти:
Last updated