macOS MIG - Mach Interface Generator
Informazioni di Base
MIG è stato creato per semplificare il processo di creazione del codice Mach IPC. Fondamentalmente genera il codice necessario per far comunicare server e client con una definizione data. Anche se il codice generato è brutto, uno sviluppatore dovrà solo importarlo e il suo codice sarà molto più semplice rispetto a prima.
La definizione è specificata nel Linguaggio di Definizione dell'Interfaccia (IDL) utilizzando l'estensione .defs
.
Queste definizioni hanno 5 sezioni:
Dichiarazione del sottosistema: La parola chiave sottosistema viene utilizzata per indicare il nome e l'ID. È anche possibile contrassegnarlo come
KernelServer
se il server deve essere eseguito nel kernel.Inclusioni e importazioni: MIG utilizza il C-preprocessore, quindi è in grado di utilizzare le importazioni. Inoltre, è possibile utilizzare
uimport
esimport
per il codice generato dall'utente o dal server.Dichiarazioni di tipo: È possibile definire tipi di dati anche se di solito importerà
mach_types.defs
estd_types.defs
. Per quelli personalizzati si può utilizzare una certa sintassi:[i
n/out]tran
: Funzione che deve essere tradotta da un messaggio in ingresso o verso un messaggio in uscitac[user/server]type
: Mappatura verso un altro tipo C.destructor
: Chiama questa funzione quando il tipo viene rilasciato.Operazioni: Queste sono le definizioni dei metodi RPC. Ci sono 5 tipi diversi:
routine
: Si aspetta una rispostasimpleroutine
: Non si aspetta una rispostaprocedure
: Si aspetta una rispostasimpleprocedure
: Non si aspetta una rispostafunction
: Si aspetta una risposta
Esempio
Creare un file di definizione, in questo caso con una funzione molto semplice:
Si noti che il primo argomento è la porta da associare e MIG gestirà automaticamente la porta di risposta (a meno che non venga chiamato mig_get_reply_port()
nel codice client). Inoltre, l'ID delle operazioni sarà sequenziale a partire dall'ID del sottosistema indicato (quindi se un'operazione è deprecata, viene eliminata e viene utilizzato skip
per continuare a utilizzare il suo ID).
Ora utilizzare MIG per generare il codice server e client che saranno in grado di comunicare tra loro per chiamare la funzione Sottrai:
Saranno creati diversi nuovi file nella directory corrente.
Puoi trovare un esempio più complesso nel tuo sistema con: mdfind mach_port.defs
E puoi compilarlo dalla stessa cartella del file con: mig -DLIBSYSCALL_INTERFACE mach_ports.defs
Nei file myipcServer.c
e myipcServer.h
puoi trovare la dichiarazione e la definizione della struttura SERVERPREFmyipc_subsystem
, che definisce essenzialmente la funzione da chiamare in base all'ID del messaggio ricevuto (abbiamo indicato un numero iniziale di 500):
macOS IPC: Generatore di Interfacce MIG (Mach Interface Generator)
Il Generatore di Interfacce MIG (Mach Interface Generator) è uno strumento utilizzato per semplificare lo sviluppo di applicazioni che utilizzano la comunicazione tramite IPC (Inter-Process Communication) su macOS. Con MIG, è possibile definire interfacce di messaggi in un file di specifica e generare automaticamente il codice sorgente necessario per la comunicazione tra processi.
Vantaggi di MIG:
Riduzione degli errori: MIG gestisce la serializzazione e la deserializzazione dei messaggi, riducendo il rischio di errori di programmazione.
Efficienza: MIG genera codice ottimizzato per la comunicazione tra processi, garantendo prestazioni elevate.
Facilità di sviluppo: Definire interfacce di messaggi tramite MIG semplifica lo sviluppo di applicazioni complesse che richiedono IPC.
Utilizzando il Generatore di Interfacce MIG, è possibile migliorare la sicurezza e l'affidabilità delle applicazioni che dipendono dalla comunicazione tra processi su macOS.
Basandosi sulla struttura precedente, la funzione myipc_server_routine
otterrà l'ID del messaggio e restituirà la funzione corretta da chiamare:
In questo esempio abbiamo definito solo 1 funzione nelle definizioni, ma se avessimo definito più funzioni, sarebbero state all'interno dell'array di SERVERPREFmyipc_subsystem
e la prima sarebbe stata assegnata all'ID 500, la seconda all'ID 501...
Se ci si aspettasse che la funzione inviasse una risposta, esisterebbe anche la funzione mig_internal kern_return_t __MIG_check__Reply__<name>
.
Attualmente è possibile identificare questa relazione nella struttura subsystem_to_name_map_myipc
da myipcServer.h
(subsystem_to_name_map_***
in altri file):
Infine, un'altra funzione importante per far funzionare il server sarà myipc_server
, che è quella che effettivamente chiama la funzione relativa all'id ricevuto:
Controlla le linee precedentemente evidenziate accedendo alla funzione da chiamare tramite ID.
Il seguente è il codice per creare un semplice server e client in cui il client può chiamare le funzioni Sottrai dal server:
macOS IPC: Inter-Process Communication
macOS MIG (Mach Interface Generator)
Il Generatore di Interfacce Mach (MIG) è uno strumento utilizzato per semplificare lo sviluppo di IPC su macOS. Con MIG, è possibile definire interfacce di messaggistica tra processi e generare automaticamente il codice necessario per la comunicazione tra di essi. Questo semplifica notevolmente lo sviluppo di applicazioni che richiedono la comunicazione tra processi su macOS.
MIG traduce le dichiarazioni di funzioni in file di intestazione in codice sorgente C che gestisce la comunicazione IPC tra i processi. Questo processo di generazione di codice consente agli sviluppatori di concentrarsi sulla logica dell'applicazione senza doversi preoccupare dei dettagli di basso livello dell'IPC su macOS.
Utilizzando MIG, è possibile definire le interfacce IPC in un file di specifica e generare automaticamente il coddi sorgente C necessario per implementare tali interfacce. Questo rende più efficiente lo sviluppo di applicazioni che sfruttano l'IPC su macOS, consentendo agli sviluppatori di concentrarsi sulla funzionalità dell'applicazione piuttosto che sulla gestione della comunicazione tra processi.
In sintesi, macOS MIG è uno strumento potente per semplificare lo sviluppo di IPC su macOS, consentendo agli sviluppatori di creare applicazioni più complesse e funzionali che richiedono la comunicazione tra processi.
Il record NDR
Il record NDR è esportato da libsystem_kernel.dylib
ed è una struttura che consente a MIG di trasformare i dati in modo che siano agnostici del sistema in cui vengono utilizzati poiché MIG è stato pensato per essere utilizzato tra sistemi diversi (e non solo sulla stessa macchina).
Questo è interessante perché se _NDR_record
viene trovato in un binario come dipendenza (jtool2 -S <binary> | grep NDR
o nm
), significa che il binario è un cliente o un server MIG.
Inoltre, i server MIG hanno la tabella di dispatch in __DATA.__const
(o in __CONST.__constdata
nel kernel macOS e __DATA_CONST.__const
in altri kernel *OS). Questo può essere dumpato con jtool2
.
E i client MIG utilizzeranno il __NDR_record
per inviare con __mach_msg
ai server.
Analisi del Binario
jtool
Poiché molti binari ora utilizzano MIG per esporre le porte mach, è interessante sapere come identificare l'uso di MIG e le funzioni che MIG esegue con ciascun ID del messaggio.
jtool2 può analizzare le informazioni MIG da un binario Mach-O indicando l'ID del messaggio e identificando la funzione da eseguire:
Inoltre, le funzioni MIG sono solo wrapper della funzione effettiva che viene chiamata, il che significa che ottenendo il suo disassemblaggio e cercando BL potresti essere in grado di trovare la funzione effettivamente chiamata:
Assembly
È stato precedentemente menzionato che la funzione che si occuperà di chiamare la funzione corretta a seconda dell'ID del messaggio ricevuto era myipc_server
. Tuttavia, di solito non si avranno i simboli del binario (nessun nome di funzione), quindi è interessante controllare come appare decompilato poiché sarà sempre molto simile (il codice di questa funzione è indipendente dalle funzioni esposte):
Attualmente, se si accede alla funzione 0x100004000
, si troverà l'array di strutture routine_descriptor
. Il primo elemento della struttura è l'indirizzo in cui la funzione è implementata, e la struttura occupa 0x28 byte, quindi ogni 0x28 byte (a partire dal byte 0) è possibile ottenere 8 byte e quello sarà l'indirizzo della funzione che verrà chiamata:
Questi dati possono essere estratti utilizzando questo script di Hopper.
Debug
Il codice generato da MIG chiama anche kernel_debug
per generare log sulle operazioni in ingresso e in uscita. È possibile controllarli usando trace
o kdv
: kdv all | grep MIG
References
Last updated