Introduction to ARM64v8
Last updated
Last updated
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Στην αρχιτεκτονική ARMv8, τα επίπεδα εκτέλεσης, γνωστά ως Επίπεδα Εξαίρεσης (ELs), καθορίζουν το επίπεδο προνομίων και τις δυνατότητες του περιβάλλοντος εκτέλεσης. Υπάρχουν τέσσερα επίπεδα εξαίρεσης, που κυμαίνονται από EL0 έως EL3, το καθένα εξυπηρετεί διαφορετικό σκοπό:
EL0 - Λειτουργία Χρήστη:
Αυτό είναι το λιγότερο προνομιακό επίπεδο και χρησιμοποιείται για την εκτέλεση κανονικού κώδικα εφαρμογής.
Οι εφαρμογές που εκτελούνται στο EL0 είναι απομονωμένες η μία από την άλλη και από το λογισμικό του συστήματος, ενισχύοντας την ασφάλεια και τη σταθερότητα.
EL1 - Λειτουργία Πυρήνα Λειτουργικού Συστήματος:
Οι περισσότεροι πυρήνες λειτουργικών συστημάτων εκτελούνται σε αυτό το επίπεδο.
Το EL1 έχει περισσότερα προνόμια από το EL0 και μπορεί να έχει πρόσβαση σε πόρους του συστήματος, αλλά με ορισμένους περιορισμούς για να διασφαλιστεί η ακεραιότητα του συστήματος.
EL2 - Λειτουργία Υπερχειριστή:
Αυτό το επίπεδο χρησιμοποιείται για εικονικοποίηση. Ένας υπερχειριστής που εκτελείται στο EL2 μπορεί να διαχειρίζεται πολλαπλά λειτουργικά συστήματα (κάθε ένα στο δικό του EL1) που εκτελούνται στο ίδιο φυσικό υλικό.
Το EL2 παρέχει δυνατότητες για απομόνωση και έλεγχο των εικονικών περιβαλλόντων.
EL3 - Λειτουργία Ασφαλούς Παρακολούθησης:
Αυτό είναι το πιο προνομιακό επίπεδο και χρησιμοποιείται συχνά για ασφαλή εκκίνηση και αξιόπιστα περιβάλλοντα εκτέλεσης.
Το EL3 μπορεί να διαχειρίζεται και να ελέγχει τις προσβάσεις μεταξύ ασφαλών και μη ασφαλών καταστάσεων (όπως ασφαλής εκκίνηση, αξιόπιστο OS, κ.λπ.).
Η χρήση αυτών των επιπέδων επιτρέπει έναν δομημένο και ασφαλή τρόπο διαχείρισης διαφορετικών πτυχών του συστήματος, από τις εφαρμογές χρήστη έως το πιο προνομιακό λογισμικό του συστήματος. Η προσέγγιση του ARMv8 στα επίπεδα προνομίων βοηθά στην αποτελεσματική απομόνωση διαφορετικών στοιχείων του συστήματος, ενισχύοντας έτσι την ασφάλεια και την ανθεκτικότητα του συστήματος.
ARM64 έχει 31 γενικούς καταχωρητές, που φέρουν ετικέτες x0
έως x30
. Κάθε ένας μπορεί να αποθηκεύσει μια 64-bit (8-byte) τιμή. Για λειτουργίες που απαιτούν μόνο 32-bit τιμές, οι ίδιοι καταχωρητές μπορούν να προσπελαστούν σε 32-bit λειτουργία χρησιμοποιώντας τα ονόματα w0 έως w30.
x0
έως x7
- Αυτοί χρησιμοποιούνται συνήθως ως καταχωρητές scratch και για τη μεταφορά παραμέτρων σε υπορουτίνες.
x0
μεταφέρει επίσης τα δεδομένα επιστροφής μιας συνάρτησης
x8
- Στον πυρήνα Linux, το x8
χρησιμοποιείται ως αριθμός κλήσης συστήματος για την εντολή svc
. Στο macOS, το x16 είναι αυτό που χρησιμοποιείται!
x9
έως x15
- Περισσότεροι προσωρινοί καταχωρητές, συχνά χρησιμοποιούμενοι για τοπικές μεταβλητές.
x16
και x17
- Καταχωρητές Ενδο-διαδικαστικής Κλήσης. Προσωρινοί καταχωρητές για άμεσες τιμές. Χρησιμοποιούνται επίσης για έμμεσες κλήσεις συναρτήσεων και PLT (Procedure Linkage Table) stubs.
x16
χρησιμοποιείται ως αριθμός κλήσης συστήματος για την svc
εντολή στο macOS.
x18
- Καταχωρητής πλατφόρμας. Μπορεί να χρησιμοποιηθεί ως γενικός καταχωρητής, αλλά σε ορισμένες πλατφόρμες, αυτός ο καταχωρητής είναι δεσμευμένος για συγκεκριμένες χρήσεις πλατφόρμας: Δείκτης στο τρέχον περιβάλλον νήματος στο Windows, ή για να δείξει τη δομή τρέχουσας εκτελούμενης εργασίας στον πυρήνα linux.
x19
έως x28
- Αυτοί είναι οι καταχωρητές που διατηρούνται από τον καλούμενο. Μια συνάρτηση πρέπει να διατηρεί τις τιμές αυτών των καταχωρητών για τον καλούντα, οπότε αποθηκεύονται στο στοίβα και ανακτώνται πριν επιστρέψουν στον καλούντα.
x29
- Δείκτης πλαισίου για την παρακολούθηση του πλαισίου στοίβας. Όταν δημιουργείται ένα νέο πλαίσιο στοίβας επειδή καλείται μια συνάρτηση, ο x29
καταχωρητής αποθηκεύεται στο στοίβα και η νέα διεύθυνση δείκτη πλαισίου είναι (sp
διεύθυνση) αποθηκεύεται σε αυτόν τον καταχωρητή.
Αυτός ο καταχωρητής μπορεί επίσης να χρησιμοποιηθεί ως γενικός καταχωρητής αν και συνήθως χρησιμοποιείται ως αναφορά σε τοπικές μεταβλητές.
x30
ή lr
- Καταχωρητής σύνδεσης. Διατηρεί τη διεύθυνση επιστροφής όταν εκτελείται μια εντολή BL
(Branch with Link) ή BLR
(Branch with Link to Register) αποθηκεύοντας την τιμή pc
σε αυτόν τον καταχωρητή.
Μπορεί επίσης να χρησιμοποιηθεί όπως οποιοσδήποτε άλλος καταχωρητής.
Εάν η τρέχουσα συνάρτηση πρόκειται να καλέσει μια νέα συνάρτηση και επομένως να επαναγράψει το lr
, θα το αποθηκεύσει στο στοίβα στην αρχή, αυτό είναι το επιλόγιο (stp x29, x30 , [sp, #-48]; mov x29, sp
-> Αποθήκευση fp
και lr
, δημιουργία χώρου και λήψη νέου fp
) και θα το ανακτήσει στο τέλος, αυτό είναι το πρόλογο (ldp x29, x30, [sp], #48; ret
-> Ανάκτηση fp
και lr
και επιστροφή).
sp
- Δείκτης στοίβας, χρησιμοποιείται για την παρακολούθηση της κορυφής της στοίβας.
Η τιμή sp
θα πρέπει πάντα να διατηρείται τουλάχιστον σε ευθυγράμμιση quadword ή μπορεί να προκύψει εξαίρεση ευθυγράμμισης.
pc
- Μετρητής προγράμματος, που δείχνει στην επόμενη εντολή. Αυτός ο καταχωρητής μπορεί να ενημερωθεί μόνο μέσω γενεών εξαιρέσεων, επιστροφών εξαιρέσεων και κλάδων. Οι μόνοι κανονικοί εντολές που μπορούν να διαβάσουν αυτόν τον καταχωρητή είναι οι εντολές branch with link (BL, BLR) για να αποθηκεύσουν τη διεύθυνση pc
στο lr
(Καταχωρητής Σύνδεσης).
xzr
- Καταχωρητής μηδέν. Ονομάζεται επίσης wzr
στην 32-bit μορφή του. Μπορεί να χρησιμοποιηθεί για να αποκτήσει εύκολα την τιμή μηδέν (συνηθισμένη λειτουργία) ή για να εκτελέσει συγκρίσεις χρησιμοποιώντας subs
όπως subs XZR, Xn, #10
αποθηκεύοντας τα αποτελέσματα που προκύπτουν πουθενά (στο xzr
).
Οι καταχωρητές Wn
είναι η 32bit έκδοση του καταχωρητή Xn
.
Επιπλέον, υπάρχουν άλλοι 32 καταχωρητές μήκους 128bit που μπορούν να χρησιμοποιηθούν σε βελτιστοποιημένες λειτουργίες πολλαπλών δεδομένων με μία εντολή (SIMD) και για την εκτέλεση αριθμητικών υπολογισμών κινητής υποδιαστολής. Αυτοί ονομάζονται καταχωρητές Vn αν και μπορούν επίσης να λειτουργούν σε 64-bit, 32-bit, 16-bit και 8-bit και τότε ονομάζονται Qn
, Dn
, Sn
, Hn
και Bn
.
Υπάρχουν εκατοντάδες καταχωρητές συστήματος, που ονομάζονται επίσης ειδικοί καταχωρητές (SPRs), που χρησιμοποιούνται για παρακολούθηση και έλεγχο της συμπεριφοράς των επεξεργαστών.
Μπορούν να διαβαστούν ή να ρυθμιστούν μόνο χρησιμοποιώντας τις ειδικές εντολές mrs
και msr
.
Οι ειδικοί καταχωρητές TPIDR_EL0
και TPIDDR_EL0
βρίσκονται συχνά κατά την αντίστροφη μηχανική. Το επίθημα EL0
υποδηλώνει την ελάχιστη εξαίρεση από την οποία μπορεί να προσπελαστεί ο καταχωρητής (σε αυτή την περίπτωση το EL0 είναι το κανονικό επίπεδο εξαίρεσης (προνομίων) με το οποίο εκτελούνται τα κανονικά προγράμματα).
Συνήθως χρησιμοποιούνται για την αποθήκευση της βάσης διεύθυνσης της περιοχής αποθήκευσης τοπικών νημάτων μνήμης. Συνήθως ο πρώτος είναι αναγνώσιμος και εγγράψιμος για προγράμματα που εκτελούνται στο EL0, αλλά ο δεύτερος μπορεί να διαβαστεί από το EL0 και να γραφεί από το EL1 (όπως ο πυρήνας).
mrs x0, TPIDR_EL0 ; Διαβάστε το TPIDR_EL0 στο x0
msr TPIDR_EL0, X0 ; Γράψτε το x0 στο TPIDR_EL0
PSTATE περιέχει αρκετά στοιχεία διαδικασίας σειριακά στο ορατό από το λειτουργικό σύστημα SPSR_ELx
ειδικό καταχωρητή, όπου το X είναι το επίπεδο άδειας της ενεργοποιημένης εξαίρεσης (αυτό επιτρέπει την ανάκτηση της κατάστασης της διαδικασίας όταν τελειώνει η εξαίρεση).
Αυτά είναι τα προσβάσιμα πεδία:
Οι σημαίες συνθηκών N
, Z
, C
και V
:
N
σημαίνει ότι η λειτουργία απέδωσε αρνητικό αποτέλεσμα
Z
σημαίνει ότι η λειτουργία απέδωσε μηδέν
C
σημαίνει ότι η λειτουργία είχε μεταφορά
V
σημαίνει ότι η λειτουργία απέδωσε υπερχείλιση υπογραφής:
Το άθροισμα δύο θετικών αριθμών αποδίδει αρνητικό αποτέλεσμα.
Το άθροισμα δύο αρνητικών αριθμών αποδίδει θετικό αποτέλεσμα.
Στην αφαίρεση, όταν αφαιρείται ένας μεγάλος αρνητικός αριθμός από έναν μικρό θετικό αριθμό (ή το αντίστροφο), και το αποτέλεσμα δεν μπορεί να αναπαρασταθεί εντός του εύρους του δεδομένου μεγέθους bit.
Προφανώς, ο επεξεργαστής δεν γνωρίζει αν η λειτουργία είναι υπογεγραμμένη ή όχι, οπότε θα ελέγξει το C και το V στις λειτουργίες και θα υποδείξει αν συνέβη μεταφορά σε περίπτωση που ήταν υπογεγραμμένη ή μη υπογεγραμμένη.
Όχι όλες οι εντολές ενημερώνουν αυτές τις σημαίες. Ορισμένες όπως CMP
ή TST
το κάνουν, και άλλες που έχουν ένα s επίθημα όπως ADDS
το κάνουν επίσης.
Η τρέχουσα σημαία πλάτους καταχωρητή (nRW
): Εάν η σημαία έχει την τιμή 0, το πρόγραμμα θα εκτελείται στην κατάσταση εκτέλεσης AArch64 μόλις επανεκκινηθεί.
Το τρέχον Επίπεδο Εξαίρεσης (EL
): Ένα κανονικό πρόγραμμα που εκτελείται στο EL0 θα έχει την τιμή 0
Η σημαία μοναδικού βήματος (SS
): Χρησιμοποιείται από αποσφαλματωτές για να εκτελούν μοναδικά βήματα ρυθμίζοντας τη σημαία SS σε 1 μέσα στο SPSR_ELx
μέσω μιας εξαίρεσης. Το πρόγραμμα θα εκτελέσει ένα βήμα και θα εκδώσει μια εξαίρεση μοναδικού βήματος.
Η σημαία κατάστασης παράνομης εξαίρεσης (IL
): Χρησιμοποιείται για να σημάνει πότε ένα προνομιακό λογισμικό εκτελεί μια μη έγκυρη μεταφορά επιπέδου εξαίρεσης, αυτή η σημαία ρυθμίζεται σε 1 και ο επεξεργαστής ενεργοποιεί μια εξαίρεση παράνομης κατάστασης.
Οι σημαίες DAIF
: Αυτές οι σημαίες επιτρέπουν σε ένα προνομιακό πρόγραμμα να επιλέξει να αποκλείσει ορισμένες εξωτερικές εξαιρέσεις.
Εάν A
είναι 1 σημαίνει ότι θα ενεργοποιηθούν ασύγχρονοι τερματισμοί. Η I
ρυθμίζει την αντίδραση σε εξωτερικά αιτήματα διακοπής (IRQs). και το F σχετίζεται με Γρήγορα Αιτήματα Διακοπής (FIRs).
Οι σημαίες επιλογής δείκτη στοίβας (SPS
): Προνομιακά προγράμματα που εκτελούνται στο EL1 και άνω μπορούν να εναλλάσσουν τη χρήση του δικού τους καταχωρητή δείκτη στοίβας και του καταχωρητή μοντέλου χρήστη (π.χ. μεταξύ SP_EL1
και EL0
). Αυτή η εναλλαγή πραγματοποιείται γράφοντας στον ειδικό καταχωρητή SPSel
. Αυτό δεν μπορεί να γίνει από το EL0.
Η σύμβαση κλήσης ARM64 καθορίζει ότι οι πρώτες οκτώ παράμετροι σε μια συνάρτηση μεταφέρονται στους καταχωρητές x0
έως x7
. Επιπλέον παράμετροι μεταφέρονται στο στοίβα. Η τιμή επιστροφής μεταφέρεται πίσω στον καταχωρητή x0
, ή στο x1
επίσης αν είναι 128 bits. Οι καταχωρητές x19
έως x30
και sp
πρέπει να διατηρούνται κατά τις κλήσεις συναρτήσεων.
Όταν διαβάζετε μια συνάρτηση σε assembly, αναζητήστε τον πρόλογο και το επιλόγιο της συνάρτησης. Ο πρόλογος συνήθως περιλαμβάνει αποθήκευση του δείκτη πλαισίου (x29
), ρύθμιση ενός νέου δείκτη πλαισίου, και κατανομή χώρου στοίβας. Το επιλόγιο συνήθως περιλαμβάνει αποκατάσταση του αποθηκευμένου δείκτη πλαισίου και επιστροφή από τη συνάρτηση.
Η Swift έχει τη δική της σύμβαση κλήσης που μπορεί να βρεθεί στο https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64
Οι εντολές ARM64 γενικά έχουν τη μορφή opcode dst, src1, src2
, όπου opcode
είναι η λειτουργία που θα εκτελεστεί (όπως add
, sub
, mov
, κ.λπ.), dst
είναι ο καταχωρητής προορισμού όπου θα αποθηκευτεί το αποτέλεσμα, και src1
και src2
είναι οι καταχωρητές πηγής. Οι άμεσες τιμές μπορούν επίσης να χρησιμοποιηθούν αντί για καταχωρητές πηγής.
mov
: Μεταφορά μιας τιμής από έναν καταχωρητή σε έναν άλλο.
Παράδειγμα: mov x0, x1
— Αυτό μεταφέρει την τιμή από x1
στο x0
.
ldr
: Φόρτωση μιας τιμής από μνήμη σε έναν καταχωρητή.
Παράδειγμα: ldr x0, [x1]
— Αυτό φορτώνει μια τιμή από τη διεύθυνση μνήμης που υποδεικνύεται από το x1
στο x0
.
Λειτουργία Offset: Ένα offset που επηρεάζει τον αρχικό δείκτη υποδεικνύεται, για παράδειγμα:
ldr x2, [x1, #8]
, αυτό θα φορτώσει στο x2 την τιμή από x1 + 8
ldr x2, [x0, x1, lsl #2]
, αυτό θα φορτώσει στο x2 ένα αντικείμενο από τον πίνακα x0, από τη θέση x1 (δείκτης) * 4
Προκαθορισμένη Λειτουργία: Αυτό θα εφαρμόσει υπολογισμούς στον αρχικό δείκτη, θα πάρει το αποτέλεσμα και θα αποθηκεύσει επίσης τον νέο αρχικό δείκτη στον αρχικό δείκτη.
ldr x2, [x1, #8]!
, αυτό θα φορτώσει το x1 + 8
στο x2
και θα αποθηκεύσει στο x1 το αποτέλεσμα του x1 + 8
str lr, [sp, #-4]!
, Αποθήκευση του καταχωρητή σύνδεσης στο sp και ενημέρωση του καταχωρητή sp
Μετά την Ενημέρωση Λειτουργία: Αυτό είναι όπως η προηγούμενη αλλά η διεύθυνση μνήμης προσπελάζεται και στη συνέχεια υπολογίζεται και αποθηκεύεται το offset.
ldr x0, [x1], #8
, φορτώνει το x1
στο x0
και ενημερώνει το x1 με x1 + 8
Διεύθυνση Σχετική με το PC: Σε αυτή την περίπτωση, η διεύθυνση που θα φορτωθεί υπολογίζεται σχετική με τον καταχωρητή PC
ldr x1, =_start
, Αυτό θα φορτώσει τη διεύθυνση όπου ξεκινά το σύμβολο _start
στο x1 σχετική με το τρέχον PC.
str
: Αποθήκευση μιας τιμής από έναν καταχωρητή σε μνήμη.
Παράδειγμα: str x0, [x1]
— Αυτό αποθηκεύει την τιμή στο x0
στη διεύθυνση μνήμης που υποδεικνύεται από το x1
.
ldp
: Φόρτωση Ζεύγους Καταχωρητών. Αυτή η εντολή φορτώνει δύο καταχωρητές από διαδοχικές μνήμες. Η διεύθυνση μνήμης σχηματίζεται συνήθως προσθέτοντας ένα offset στην τιμή ενός άλλου καταχωρητή.
Παράδειγμα: ldp x0, x1, [x2]
— Αυτό φορτώνει το x0
και το x1
από τις διευθύνσεις μνήμης στο x2
και x2 + 8
, αντίστοιχα.
stp
: Αποθήκευση Ζεύγους Καταχωρητών. Αυτή η εντολή αποθηκεύει δύο καταχωρητές σε διαδοχικές μνήμες. Η διεύθυνση μνήμης σχηματίζεται συνήθως προσθέτοντας ένα offset στην τιμή ενός άλλου καταχωρητή.
Παράδειγμα: stp x0, x1, [sp]
— Αυτό αποθηκεύει το x0
και το x1
στις διευθύνσεις μνήμης στο sp
και sp + 8
, αντίστοιχα.
stp x0, x1, [sp, #16]!
— Αυτό αποθηκεύει το x0
και το x1
στις διευθύνσεις μνήμης στο sp+16
και sp + 24
, αντίστοιχα, και ενημερώνει το sp
με sp+16
.
add
: Προσθέτει τις τιμές δύο καταχωρητών και αποθηκεύει το αποτέλεσμα σε έναν καταχωρητή.
Σύνταξη: add(s) Xn1, Xn2, Xn3 | #imm, [shift #N | RRX]
Xn1 -> Προορισμός
Xn2 -> Λειτουργία 1
Xn3 | #imm -> Λειτουργία 2 (καταχωρητής ή άμεσο)
[shift #N | RRX] -> Εκτέλεση μιας μετατόπισης ή κλήση RRX
Παράδειγμα: add x0, x1, x2
— Αυτό προσθέτει τις τιμές στο x1
και x2
και αποθηκεύει το αποτέλεσμα στο x0
.
add x5, x5, #1, lsl #12
— Αυτό ισούται με 4096 (ένα 1 μετατοπισμένο 12 φορές) -> 1 0000 0000 0000 0000
adds
Αυτή εκτελεί μια add
και ενημερώνει τις σημαίες
sub
: Αφαιρεί τις τιμές δύο καταχωρητών και αποθηκεύει το αποτέλεσμα σε έναν καταχωρητή.
Ελέγξτε τη σύνταξη add
.
Παράδειγμα: sub x0, x1, x2
— Αυτό αφαιρεί την τιμή στο x2
από το x1
και αποθηκεύει το αποτέλεσμα στο x0
.
subs
Αυτό είναι όπως το sub αλλά ενημερώνει τη σημαία
mul
: Πολλαπλασιάζει τις τιμές δύο καταχωρητών και αποθηκεύει το αποτέλεσμα σε έναν καταχωρητή.
Παράδειγμα: mul x0, x1, x2
— Αυτό πολλαπλασιάζει τις τιμές στο x1
και x2
και αποθηκεύει το αποτέλεσμα στο x0
.
div
: Διαιρεί την τιμή ενός καταχωρητή με έναν άλλο και αποθηκεύει το αποτέλεσμα σε έναν καταχωρητή.
Παράδειγμα: div x0, x1, x2
— Αυτό διαιρεί την τιμή στο x1
με το x2
και αποθηκεύει το αποτέλεσμα στο x0
.
lsl
, lsr
, asr
, ror
, rrx
:
Λογική μετατόπιση αριστερά: Προσθέτει 0s από το τέλος μετακινώντας τα άλλα bits προς τα εμπρός (πολλαπλασιάζει με n-φορές 2)
Λογική μετατόπιση δεξιά: Προσθέτει 1s στην αρχή μετακινώντας τα άλλα bits προς τα πίσω (διαιρεί με n-φορές 2 σε μη υπογεγραμμένα)
Αριθμητική μετατόπιση δεξιά: Όπως lsr
, αλλά αντί να προσθέτει 0s αν το πιο σημαντικό bit είναι 1, προστίθενται 1s (διαιρεί με n-φορές 2 σε υπογεγραμμένα)
Μετατόπιση δεξιά: Όπως lsr
αλλά ό,τι αφαιρείται από τα δεξιά προστίθεται στα αριστερά
Μετατόπιση Δεξιά με Επέκταση: Όπως ror
, αλλά με τη σημαία μεταφοράς ως το "πιο σημαντικό bit". Έτσι η σημαία μεταφοράς μετακινείται στο bit 31 και το αφαιρεθέν bit στη σημαία μεταφοράς.
bfm
: Μεταφορά Bit Field, αυτές οι λειτουργίες αντιγράφουν bits 0...n
από μια τιμή και τα τοποθετούν σε θέσεις m..m+n
. Το #s
καθορίζει τη θέση του αριστερού bit και το #r
την ποσότητα μετατόπισης δεξιά.
Μεταφορά bitfield: BFM Xd, Xn, #r
Υπογεγραμμένη μεταφορά bitfield: SBFM Xd, Xn, #r, #s
Μη υπογεγραμμένη μεταφορά bitfield: UBFM Xd, Xn, #r, #s
Εξαγωγή και Εισαγωγή Bitfield: Αντιγράφει ένα bitfield από έναν καταχωρητή και το αντιγράφει σε έναν άλλο καταχωρητή.
BFI X1, X2, #3, #4
Εισάγει 4 bits από το X2 από το 3ο bit του X1
BFXIL X1, X2, #3, #4
Εξάγει από το 3ο bit του X2 τέσσερα bits και τα αντιγράφει στο X1
SBFIZ X1, X2, #3, #4
Επεκτείνει το σήμα 4 bits από το X2 και τα εισάγει στο X1 ξεκινώντας από τη θέση bit 3 μηδενίζοντας τα δεξιά bits
SBFX X1, X2, #3, #4
Εξάγει 4 bits ξεκινώντας από το bit 3 του X2, επεκτείνει το σήμα τους και τοποθετεί το αποτέλεσμα στο X1
UBFIZ X1, X2, #3, #4
Μηδενίζει 4 bits από το X2 και τα εισάγει στο X1 ξεκινώντας από τη θέση bit 3 μηδενίζοντας τα δεξιά bits
UBFX X1, X2, #3, #4
Εξάγει 4 bits ξεκινώντας από το bit 3 του X2 και τοποθετεί το μηδενισμένο αποτέλεσμα στο X1.
Επέκταση Σημασίας σε X: Επεκτείνει το σήμα (ή προσθέτει απλώς 0s στην μη υπογεγραμμένη έκδοση) μιας τιμής για να μπορέσει να εκτελέσει λειτουργίες με αυτήν:
SXTB X1, W2
Επεκτείνει το σήμα ενός byte από το W2 στο X1 (W2
είναι το μισό του X2
) για να γεμίσει τα 64bits
SXTH X1, W2
Επεκτείνει το σήμα ενός 16bit αριθμού από το W2 στο X1 για να γεμίσει τα 64bits
SXTW X1, W2
Επεκτείνει το σήμα ενός byte από το W2 στο X1 για να γεμίσει τα 64bits
UXTB X1, W2
Προσθέτει 0s (μη υπογεγραμμένα) σε ένα byte από το W2 στο X1 για να γεμίσει τα 64bits
extr
: Εξάγει bits από ένα καθορισμένο ζεύγος καταχωρητών που συνδυάζονται.
Παράδειγμα: EXTR W3, W2, W1, #3
Αυτό θα συνδυάσει W1+W2 και θα πάρει από το bit 3 του W2 έως το bit 3 του W1 και θα το αποθηκεύσει στο W3.
cmp
: Συγκρίνει δύο καταχωρητές και ρυθμίζει τις σημαίες συνθηκών. Είναι ένα ψευδώνυμο του subs
ρυθμίζοντας τον καταχωρητή προορισμού στο μηδενικό καταχωρητή. Χρήσιμο για να γνωρίζετε αν m == n
.
Υποστηρίζει την ίδια σύνταξη με subs
Παράδειγμα: cmp x0, x1
— Αυτό συγκρίνει τις τιμές στο x0
και x1
και ρυθμίζει τις σημαίες συνθηκών αναλόγως.
cmn
: Συγκρίνει αρνητικό τελεστή. Σε αυτή την περίπτωση είναι ένα ψευδώνυμο του adds
και υποστηρίζει την ίδια σύνταξη. Χρήσιμο για να γνωρίζετε αν m == -n
.
ccmp
: Συνθήκη σύγκρισης, είναι μια σύγκριση που θα εκτελείται μόνο αν μια προηγούμενη σύγκριση ήταν αληθής και θα ρυθμίσει συγκεκριμένα τα bits nzcv.
cmp x1, x2; ccmp x3, x4, 0, NE; blt _func
-> αν x1 != x2 και x3 < x4, πηγαίνετε στη func
Αυτό συμβαίνει επειδή ccmp
θα εκτελείται μόνο αν η προηγούμενη cmp
ήταν NE
, αν δεν ήταν τα bits nzcv
θα ρυθμιστούν σε 0 (που δεν θα ικανοποιήσει τη σύγκριση blt
).
Αυτό μπορεί επίσης να χρησιμοποιηθεί ως ccmn
(το ίδιο αλλά αρνητικό, όπως cmp
έναντι cmn
).
tst
: Ελέγχει αν οποιαδήποτε από τις τιμές της σύγκρισης είναι και οι δύο 1 (λειτουργεί όπως μια ANDS χωρίς να αποθηκεύει το αποτέλεσμα οπουδήποτε). Είναι χρήσιμο για να ελέγξετε έναν καταχωρητή με μια τιμή και να δείτε αν οποιοδήποτε από τα bits του καταχωρητή που υποδεικνύεται στην τιμή είναι 1.
Παράδειγμα: tst X1, #7
Ελέγξτε αν οποιοδήποτε από τα τελευταία 3 bits του X1 είναι 1
teq
: Λειτουργία XOR απορρίπτοντας το αποτέλεσμα
b
: Ανεξάρτητη Κλάση
Παράδειγμα: b myFunction
Σημειώστε ότι αυτό δεν θα γεμίσει τον καταχωρητή σύνδεσης με τη διεύθυνση επιστροφής (δεν είναι κατάλληλο για κλήσεις υπορουτίνων που χρειάζονται επιστροφή)
bl
: Κλάδος με σύνδεση, χρησιμοποιείται για να καλέσει μια υπορουτίνα. Αποθηκεύει τη διεύθυνση επιστροφής στο x30
.
Παράδειγμα: bl myFunction
— Αυτό καλεί τη συνάρτηση myFunction
και αποθηκεύει τη διεύθυνση επιστροφής στο x30
.
Σημειώστε ότι αυτό δεν θα γεμίσει τον καταχωρητή σύνδεσης με τη διεύθυνση επιστροφής (δεν είναι κατάλληλο για κλήσεις υπορουτίνων που χρειάζονται επιστροφή)
blr
: Κλάδος με Σύνδεση σε Καταχωρητή, χρησιμοποιείται για να καλέσει μια υπορουτίνα όπου ο στόχος είναι καθορισμένος σε έναν καταχωρητή. Αποθηκεύει τη διεύθυνση επιστροφής στο x30
. (Αυτό είναι
Παράδειγμα: blr x1
— Αυτό καλεί τη συνάρτηση της οποίας η διεύθυνση περιέχεται στο x1
και αποθηκεύει τη διεύθυνση επιστροφής στο x30
.
ret
: Επιστροφή από υπορουτίνα, συνήθως χρησιμοποιώντας τη διεύθυνση στο x30
.
Παράδειγμα: ret
— Αυτό επιστρέφει από την τρέχουσα υπορουτίνα χρησιμοποιώντας τη διεύθυνση επιστροφής στο x30
.
b.<cond>
: Συνθήκες κλάσης
b.eq
: Κλάδος αν ίσος, με βάση την προηγούμενη εντολή cmp
.
Παράδειγμα: b.eq label
— Εάν η προηγούμενη εντολή cmp
βρήκε δύο ίσες τιμές, αυτό πηγαίνει στην label
.
b.ne
: Κλάδος αν Όχι Ίσος. Αυτή η εντολή ελέγχει τις σημαίες συνθηκών (οι οποίες ρυθμίστηκαν από μια προηγούμενη εντολή σύγκρισης), και αν οι συγκρινόμενες τιμές δεν ήταν ίσες, κλάδος σε μια ετικέτα ή διεύθυνση.
Παράδειγμα: Μετά από μια εντολή cmp x0, x1
, b.ne label
— Εάν οι τιμές στο x0
και x1
δεν ήταν ίσες, αυτό πηγαίνει στην label
.
cbz
: Σύγκριση και Κλάδος σε Μηδέν. Αυτή η εντολή συγκρίνει έναν καταχωρητή με το μηδέν, και αν είναι ίσοι, κλάδος σε μια ετικέτα ή διεύθυνση.
Παράδειγμα: cbz x0, label
— Εάν η τιμή στο x0
είναι μηδέν, αυτό πηγαίνει στην label
.
cbnz
: Σύγκριση και Κλάδος σε Μη Μηδέν. Αυτή η εντολή συγκρίνει έναν καταχωρητή με το μηδέν, και αν δεν είναι ίσοι, κλάδος σε μια ετικέτα ή διεύθυνση.
Παράδειγμα: cbnz x0, label
— Εάν η τιμή στο x0
είναι μη μηδέν, αυτό πηγαίνει στην label
.
tbnz
: Δοκιμή bit και κλάδος σε μη μηδέν
Παράδειγμα: tbnz x0, #8, label
tbz
: Δοκιμή bit και κλάδος σε μηδέν
Παράδειγμα: tbz x0, #8, label
Συνθήκες επιλεγμένων λειτουργιών: Αυτές είναι λειτουργίες των οποίων η συμπεριφορά ποικίλλει ανάλογα με τα bits συνθηκών.
csel Xd, Xn, Xm, cond
-> csel X0, X1, X2, EQ
-> Εάν είναι αληθές, X0 = X1, εάν είναι ψευδές, X0 = X2
csinc Xd, Xn, Xm, cond
-> Εάν είναι αληθές, Xd = Xn, εάν είναι ψευδές, Xd = Xm + 1
cinc Xd, Xn, cond
-> Εάν είναι αληθές, Xd = Xn + 1, εάν είναι ψευδές, Xd = Xn
csinv Xd, Xn, Xm, cond
-> Εάν είναι αληθές, Xd = Xn, εάν είναι ψευδές, Xd = NOT(Xm)
cinv Xd, Xn, cond
-> Εάν είναι αληθές, Xd = NOT(Xn), εάν είναι ψευδές, Xd = Xn
csneg Xd, Xn, Xm, cond
-> Εάν είναι αληθές, Xd = Xn, εάν είναι ψευδές, Xd = - Xm
cneg Xd, Xn, cond
-> Εάν είναι αληθές, Xd = - Xn, εάν είναι ψευδές, Xd = Xn
cset Xd, Xn, Xm, cond
-> Εάν είναι αληθές, Xd = 1, εάν είναι ψευδές, Xd = 0
csetm Xd, Xn, Xm, cond
-> Εάν είναι αληθές, Xd = <όλα 1>, εάν είναι ψευδές, Xd = 0
adrp
: Υπολογίστε τη διεύθυνση σελίδας ενός συμβόλου και αποθηκεύστε την σε έναν καταχωρητή.
Παράδειγμα: adrp x0, symbol
— Αυτό υπολογίζει τη διεύθυνση σελίδας του symbol
και την αποθηκεύει στο x0
.
ldrsw
: Φόρτωση μιας υπογεγραμμένης 32-bit τιμής από τη μνήμη και επέκταση της υπογραφής σε 64 bits.
Παράδειγμα: ldrsw x0, [x1]
— Αυτό φορτώνει μια υπογεγραμμένη 32-bit τιμή από τη διεύθυνση μνήμης που υποδεικνύεται από το x1
, την επεκτείνει σε 64 bits και την αποθηκεύει στο x0
.
stur
: Αποθήκευση μιας τιμής καταχωρητή σε μια διεύθυνση μνήμης, χρησιμοποιώντας ένα offset από έναν άλλο καταχωρητή.
Παράδειγμα: stur x0, [x1, #4]
— Αυτό αποθηκεύει την τιμή στο x0
στη διεύθυνση μνήμης που είναι 4 bytes μεγαλύτερη από τη διεύθυνση που είναι ήδη στο x1
.
svc
: Κάντε μια κλήση συστήματος. Σημαίνει "Supervisor Call". Όταν ο επεξεργαστής εκτελεί αυτή την εντολή, μεταβαίνει από τη λειτουργία χρήστη σε λειτουργία πυρήνα και πηγαίνει σε μια συγκεκριμένη τοποθεσία στη μνήμη όπου βρίσκεται ο κωδικός χειρισμού κλήσεων συστήματος του πυρήνα.
Παράδειγμα:
Αποθήκευση του καταχωρητή σύνδεσης και του δείκτη πλαισίου στο στοίβα:
Ρύθμιση του νέου δείκτη πλαισίου: mov x29, sp
(ρυθμίζει τον νέο δείκτη πλαισίου για την τρέχουσα συνάρτηση)
Δημιουργία χώρου στη στοίβα για τοπικές μεταβλητές (αν χρειάζεται): sub sp, sp, <size>
(όπου <size>
είναι ο αριθμός των byte που χρειάζονται)
Αποδέσμευση τοπικών μεταβλητών (αν έχουν αποδεσμευτεί): add sp, sp, <size>
Αποκατάσταση του καταχωρητή σύνδεσης και του δείκτη πλαισίου:
Επιστροφή: ret
(επιστρέφει τον έλεγχο στον καλούντα χρησιμοποιώντας τη διεύθυνση στο μητρώο σύνδεσης)
Το Armv8-A υποστηρίζει την εκτέλεση 32-bit προγραμμάτων. AArch32 μπορεί να εκτελείται σε ένα από δύο σύνολα εντολών: A32
και T32
και μπορεί να αλλάξει μεταξύ τους μέσω interworking
.
Προνομιακά 64-bit προγράμματα μπορούν να προγραμματίσουν την εκτέλεση 32-bit προγραμμάτων εκτελώντας μια μεταφορά επιπέδου εξαίρεσης σε χαμηλότερο προνομιακό 32-bit.
Σημειώστε ότι η μετάβαση από 64-bit σε 32-bit συμβαίνει με χαμηλότερο επίπεδο εξαίρεσης (για παράδειγμα, ένα 64-bit πρόγραμμα σε EL1 που ενεργοποιεί ένα πρόγραμμα σε EL0). Αυτό γίνεται ρυθμίζοντας το bit 4 του SPSR_ELx
ειδικού μητρώου σε 1 όταν το νήμα διαδικασίας AArch32
είναι έτοιμο να εκτελεστεί και το υπόλοιπο του SPSR_ELx
αποθηκεύει το AArch32
CPSR. Στη συνέχεια, η προνομιακή διαδικασία καλεί την εντολή ERET
ώστε ο επεξεργαστής να μεταβεί σε AArch32
εισερχόμενος σε A32 ή T32 ανάλογα με το CPSR**.**
Η interworking
συμβαίνει χρησιμοποιώντας τα J και T bits του CPSR. J=0
και T=0
σημαίνει A32
και J=0
και T=1
σημαίνει T32. Αυτό μεταφράζεται βασικά σε ρύθμιση του χαμηλότερου bit σε 1 για να υποδείξει ότι το σύνολο εντολών είναι T32.
Αυτό ρυθμίζεται κατά τη διάρκεια των εντολών κλάδου interworking, αλλά μπορεί επίσης να ρυθμιστεί άμεσα με άλλες εντολές όταν το PC ρυθμίζεται ως το μητρώο προορισμού. Παράδειγμα:
Ένα άλλο παράδειγμα:
Υπάρχουν 16 32-bit καταχωρητές (r0-r15). Από r0 έως r14 μπορούν να χρησιμοποιηθούν για οποιαδήποτε λειτουργία, ωστόσο μερικοί από αυτούς είναι συνήθως δεσμευμένοι:
r15
: Μετρητής προγράμματος (πάντα). Περιέχει τη διεύθυνση της επόμενης εντολής. Στην A32 τρέχουσα + 8, στην T32, τρέχουσα + 4.
r11
: Δείκτης πλαισίου
r12
: Καταχωρητής κλήσης εντός διαδικασίας
r13
: Δείκτης στοίβας
r14
: Καταχωρητής σύνδεσης
Επιπλέον, οι καταχωρητές υποστηρίζονται σε banked registries
. Αυτά είναι μέρη που αποθηκεύουν τις τιμές των καταχωρητών επιτρέποντας την εκτέλεση γρήγορων εναλλαγών πλαισίου στη διαχείριση εξαιρέσεων και σε προνομιακές λειτουργίες για να αποφευχθεί η ανάγκη να αποθηκεύονται και να επαναφέρονται οι καταχωρητές κάθε φορά.
Αυτό γίνεται με την αποθήκευση της κατάστασης του επεξεργαστή από το CPSR
στο SPSR
της λειτουργίας του επεξεργαστή στην οποία λαμβάνεται η εξαίρεση. Κατά την επιστροφή από την εξαίρεση, το CPSR
επαναφέρεται από το SPSR
.
Στην AArch32 το CPSR λειτουργεί παρόμοια με το PSTATE
στην AArch64 και αποθηκεύεται επίσης στο SPSR_ELx
όταν λαμβάνεται μια εξαίρεση για να αποκατασταθεί αργότερα η εκτέλεση:
Τα πεδία είναι χωρισμένα σε ορισμένες ομάδες:
Καταχωρητής Κατάστασης Εφαρμογής (APSR): Αριθμητικές σημαίες και προσβάσιμες από EL0
Καταχωρητές Κατάστασης Εκτέλεσης: Συμπεριφορά διαδικασίας (διαχειρίζεται από το OS).
Οι σημαίες N
, Z
, C
, V
(όπως στην AArch64)
Η σημαία Q
: Ρυθμίζεται σε 1 όποτε συμβαίνει κορεσμός ακέραιων αριθμών κατά την εκτέλεση μιας εξειδικευμένης εντολής αριθμητικής κορεσμού. Μόλις ρυθμιστεί σε 1
, θα διατηρήσει την τιμή μέχρι να ρυθμιστεί χειροκίνητα σε 0. Επιπλέον, δεν υπάρχει καμία εντολή που να ελέγχει την τιμή της έμμεσα, πρέπει να γίνει διαβάζοντάς την χειροκίνητα.
GE
(Μεγαλύτερο ή ίσο) Σημαίες: Χρησιμοποιείται σε SIMD (Μοναδική Εντολή, Πολλαπλά Δεδομένα) λειτουργίες, όπως "παράλληλη πρόσθεση" και "παράλληλη αφαίρεση". Αυτές οι λειτουργίες επιτρέπουν την επεξεργασία πολλών σημείων δεδομένων σε μια μόνο εντολή.
Για παράδειγμα, η εντολή UADD8
προσθέτει τέσσερις ζεύξεις byte (από δύο 32-bit τελεστές) παράλληλα και αποθηκεύει τα αποτελέσματα σε έναν 32-bit καταχωρητή. Στη συνέχεια ρυθμίζει τις σημαίες GE
στο APSR
με βάση αυτά τα αποτελέσματα. Κάθε σημαία GE αντιστοιχεί σε μία από τις προσθέσεις byte, υποδεικνύοντας αν η πρόσθεση για εκείνο το ζεύγος byte υπερχειλίζει.
Η εντολή SEL
χρησιμοποιεί αυτές τις σημαίες GE για να εκτελέσει συνθήκες.
Τα bits J
και T
: J
πρέπει να είναι 0 και αν T
είναι 0 χρησιμοποιείται το σύνολο εντολών A32, και αν είναι 1, χρησιμοποιείται το T32.
Καταχωρητής Κατάστασης IT Block (ITSTATE
): Αυτά είναι τα bits από 10-15 και 25-26. Αποθηκεύουν συνθήκες για εντολές μέσα σε μια ομάδα με πρόθεμα IT
.
E
bit: Υποδεικνύει την endianness.
Bits Μάσκας Λειτουργίας και Εξαίρεσης (0-4): Καθορίζουν την τρέχουσα κατάσταση εκτέλεσης. Το 5ο υποδεικνύει αν το πρόγραμμα εκτελείται ως 32bit (ένα 1) ή 64bit (ένα 0). Τα άλλα 4 αντιπροσωπεύουν τη λειτουργία εξαίρεσης που χρησιμοποιείται αυτή τη στιγμή (όταν συμβαίνει μια εξαίρεση και διαχειρίζεται). Ο αριθμός που έχει ρυθμιστεί υποδεικνύει την τρέχουσα προτεραιότητα σε περίπτωση που προκληθεί άλλη εξαίρεση ενώ αυτή διαχειρίζεται.
AIF
: Ορισμένες εξαιρέσεις μπορούν να απενεργοποιηθούν χρησιμοποιώντας τα bits A
, I
, F
. Αν A
είναι 1 σημαίνει ότι θα προκληθούν ασύγχρονοι τερματισμοί. Το I
ρυθμίζει την αντίδραση σε εξωτερικά αιτήματα διακοπής υλικού (IRQs). και το F σχετίζεται με Γρήγορα Αιτήματα Διακοπής (FIRs).
Δείτε το syscalls.master. Οι κλήσεις συστήματος BSD θα έχουν x16 > 0.
Δείτε στο syscall_sw.c τον πίνακα mach_trap_table
και στο mach_traps.h τα πρωτότυπα. Ο μέγιστος αριθμός Mach traps είναι MACH_TRAP_TABLE_COUNT
= 128. Οι Mach traps θα έχουν x16 < 0, οπότε πρέπει να καλέσετε τους αριθμούς από την προηγούμενη λίστα με ένα μείον: _kernelrpc_mach_vm_allocate_trap
είναι -10
.
Μπορείτε επίσης να ελέγξετε libsystem_kernel.dylib
σε έναν αποσυμπιεστή για να βρείτε πώς να καλέσετε αυτές τις (και BSD) κλήσεις συστήματος:
Σημειώστε ότι Ida και Ghidra μπορούν επίσης να αποσυμπιέσουν συγκεκριμένα dylibs από την κρυφή μνήμη απλά περνώντας την κρυφή μνήμη.
Μερικές φορές είναι πιο εύκολο να ελέγξετε τον αποσυμπιεσμένο κώδικα από το libsystem_kernel.dylib
παρά να ελέγξετε τον πηγαίο κώδικα επειδή ο κώδικας αρκετών syscalls (BSD και Mach) παράγεται μέσω scripts (ελέγξτε τα σχόλια στον πηγαίο κώδικα) ενώ στο dylib μπορείτε να βρείτε τι καλείται.
Το XNU υποστηρίζει έναν άλλο τύπο κλήσεων που ονομάζεται εξαρτώμενες από τη μηχανή. Οι αριθμοί αυτών των κλήσεων εξαρτώνται από την αρχιτεκτονική και ούτε οι κλήσεις ούτε οι αριθμοί είναι εγγυημένο ότι θα παραμείνουν σταθεροί.
Αυτή είναι μια σελίδα μνήμης που ανήκει στον πυρήνα και είναι χαρτογραφημένη στο χώρο διευθύνσεων κάθε διεργασίας χρήστη. Σκοπός της είναι να διευκολύνει τη μετάβαση από τη λειτουργία χρήστη στον χώρο του πυρήνα πιο γρήγορα από τη χρήση syscalls για υπηρεσίες πυρήνα που χρησιμοποιούνται τόσο πολύ ώστε αυτή η μετάβαση να είναι πολύ αναποτελεσματική.
Για παράδειγμα, η κλήση gettimeofdate
διαβάζει την τιμή του timeval
απευθείας από τη σελίδα comm.
Είναι πολύ συνηθισμένο να βρείτε αυτή τη λειτουργία να χρησιμοποιείται σε προγράμματα Objective-C ή Swift. Αυτή η λειτουργία επιτρέπει την κλήση μιας μεθόδου ενός αντικειμένου Objective-C.
Παράμετροι (περισσότερες πληροφορίες στα docs):
x0: self -> Δείκτης στην περίπτωση
x1: op -> Επιλογέας της μεθόδου
x2... -> Υπόλοιπες παράμετροι της καλούμενης μεθόδου
Έτσι, αν βάλετε σημείο διακοπής πριν από τον κλάδο σε αυτή τη λειτουργία, μπορείτε εύκολα να βρείτε τι καλείται στο lldb με (σε αυτό το παράδειγμα το αντικείμενο καλεί ένα αντικείμενο από το NSConcreteTask
που θα εκτελέσει μια εντολή):
Ρυθμίζοντας τη μεταβλητή περιβάλλοντος NSObjCMessageLoggingEnabled=1
είναι δυνατή η καταγραφή όταν καλείται αυτή η συνάρτηση σε ένα αρχείο όπως το /tmp/msgSends-pid
.
Επιπλέον, ρυθμίζοντας OBJC_HELP=1
και καλώντας οποιοδήποτε δυαδικό, μπορείτε να δείτε άλλες μεταβλητές περιβάλλοντος που θα μπορούσατε να χρησιμοποιήσετε για να log όταν συμβαίνουν ορισμένες ενέργειες Objc-C.
Όταν καλείται αυτή η συνάρτηση, είναι απαραίτητο να βρείτε τη μέθοδο που καλείται από την υποδεικνυόμενη παρουσία, για αυτό γίνονται διαφορετικές αναζητήσεις:
Εκτέλεση αισιόδοξης αναζήτησης cache:
Αν είναι επιτυχής, ολοκληρώθηκε
Απόκτηση runtimeLock (ανάγνωση)
Αν (realize && !cls->realized) πραγματοποιήστε την πραγματοποίηση της κλάσης
Αν (initialize && !cls->initialized) πραγματοποιήστε την αρχικοποίηση της κλάσης
Δοκιμάστε την cache της κλάσης:
Αν είναι επιτυχής, ολοκληρώθηκε
Δοκιμάστε τη λίστα μεθόδων της κλάσης:
Αν βρεθεί, γεμίστε την cache και ολοκληρώθηκε
Δοκιμάστε την cache της υπερκλάσης:
Αν είναι επιτυχής, ολοκληρώθηκε
Δοκιμάστε τη λίστα μεθόδων της υπερκλάσης:
Αν βρεθεί, γεμίστε την cache και ολοκληρώθηκε
Αν (resolver) δοκιμάστε τον επιλυτή μεθόδων και επαναλάβετε από την αναζήτηση κλάσης
Αν είστε ακόμα εδώ (= όλα τα άλλα έχουν αποτύχει) δοκιμάστε τον προωθητή
Για να μεταγλωττίσετε:
Για να εξαγάγετε τα bytes:
Για νεότερες εκδόσεις macOS:
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)