MIG iliumbwa ili kurahisisha mchakato wa uundaji wa Mach IPC. Kimsingi inazalisha msimbo unaohitajika kwa server na mteja kuwasiliana na ufafanuzi fulani. Hata kama msimbo uliozalishwa ni mbaya, mendelezi atahitaji tu kuingiza na msimbo wake utakuwa rahisi zaidi kuliko hapo awali.
Ufafanuzi umeainishwa katika Lugha ya Ufafanuzi wa Interface (IDL) kwa kutumia kiambishi cha .defs.
Mifano hii ina sehemu 5:
Tangazo la subsistimu: Neno muhimu subsistimu linatumika kuashiria jina na id. Pia inawezekana kuashiria kama KernelServer ikiwa server inapaswa kukimbia kwenye kernel.
Injizeni na uagizaji: MIG inatumia C-preprocessor, hivyo ina uwezo wa kutumia uagizaji. Zaidi ya hayo, inawezekana kutumia uimport na simport kwa msimbo ulioandikwa na mtumiaji au server.
Matangazo ya aina: Inawezekana kufafanua aina za data ingawa kawaida itauagiza mach_types.defs na std_types.defs. Kwa aina za kawaida baadhi ya sintaks inaweza kutumika:
[in/out]tran: Kazi inayohitaji kutafsiriwa kutoka ujumbe unaoingia au kwenda ujumbe unaotoka
c[user/server]type: Ramani kwa aina nyingine ya C.
destructor: Itumie kazi hii wakati aina inachiliwa.
Operesheni: Hizi ni ufafanuzi wa mbinu za RPC. Kuna aina 5 tofauti:
routine: Inatarajia jibu
simpleroutine: Haitarajii jibu
procedure: Inatarajia jibu
simpleprocedure: Haitarajii jibu
function: Inatarajia jibu
Example
Create a definition file, in this case with a very simple function:
myipc.defs
subsystem myipc 500; // Arbitrary name and iduserprefix USERPREF; // Prefix for created functions in the clientserverprefix SERVERPREF; // Prefix for created functions in the server#include<mach/mach_types.defs>#include<mach/std_types.defs>simpleroutineSubtract(server_port : mach_port_t;n1 : uint32_t;n2 : uint32_t);
Kumbuka kwamba hoja ya kwanza ni bandari ya kuunganisha na MIG itashughulikia bandari ya majibu kiotomatiki (isipokuwa unaita mig_get_reply_port() katika msimbo wa mteja). Zaidi ya hayo, ID ya operesheni itakuwa mfuatano ikianza na ID ya mfumo ulioonyeshwa (hivyo ikiwa operesheni imeondolewa inafutwa na skip inatumika ili bado kutumia ID yake).
Sasa tumia MIG kuunda msimbo wa seva na mteja ambao utaweza kuwasiliana kati yao ili kuita kazi ya Subtract:
Kadhaa ya faili mpya zitaundwa katika saraka ya sasa.
Unaweza kupata mfano mgumu zaidi katika mfumo wako kwa: mdfind mach_port.defs
Na unaweza kuikamilisha kutoka kwenye folda ile ile kama faili kwa: mig -DLIBSYSCALL_INTERFACE mach_ports.defs
Katika faili myipcServer.c na myipcServer.h unaweza kupata tangazo na ufafanuzi wa struct SERVERPREFmyipc_subsystem, ambayo kimsingi inafafanua kazi ya kuita kulingana na kitambulisho cha ujumbe kilichopokelewa (tulionyesha nambari ya kuanzia ya 500):
/* Description of this subsystem, for use in direct RPC */conststruct SERVERPREFmyipc_subsystem SERVERPREFmyipc_subsystem = {myipc_server_routine,500, // start ID501, // end ID(mach_msg_size_t)sizeof(union __ReplyUnion__SERVERPREFmyipc_subsystem),(vm_address_t)0,{{ (mig_impl_routine_t) 0,// Function to call(mig_stub_routine_t) _XSubtract,3,0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__Subtract_t)},}};
/* Description of this subsystem, for use in direct RPC */externconststruct SERVERPREFmyipc_subsystem {mig_server_routine_t server; /* Server routine */mach_msg_id_t start; /* Min routine number */mach_msg_id_t end; /* Max routine number + 1 */unsignedint maxsize; /* Max msg size */vm_address_t reserved; /* Reserved */struct routine_descriptor /* Array of routine descriptors */routine[1];} SERVERPREFmyipc_subsystem;
Kulingana na muundo wa awali, kazi myipc_server_routine itapata kitambulisho cha ujumbe na kurudisha kazi sahihi ya kuita:
Katika mfano huu tumefafanua tu kazi 1 katika maelezo, lakini kama tungeweza kufafanua kazi zaidi, zingekuwa ndani ya array ya SERVERPREFmyipc_subsystem na ya kwanza ingekuwa imepewa ID 500, ya pili ingekuwa imepewa ID 501...
Ikiwa kazi ilitarajiwa kutuma reply kazi mig_internal kern_return_t __MIG_check__Reply__<name> pia ingekuwepo.
Kwa kweli inawezekana kubaini uhusiano huu katika struct subsystem_to_name_map_myipc kutoka myipcServer.h (subsystem_to_name_map_*** katika faili zingine):
Hatimaye, kazi nyingine muhimu ili kufanya seva ifanye kazi itakuwa myipc_server, ambayo ndiyo itakayofanya kuita kazi inayohusiana na kitambulisho kilichopokelewa:
Angalia mistari iliyosisitizwa hapo awali inayoingia kwenye kazi ya kuita kwa ID.
Ifuatayo ni msimbo wa kuunda seva na mteja ambapo mteja anaweza kuita kazi ya Kupunguza kutoka kwa seva:
// gcc myipc_server.c myipcServer.c -o myipc_server#include<stdio.h>#include<mach/mach.h>#include<servers/bootstrap.h>#include"myipcServer.h"kern_return_tSERVERPREFSubtract(mach_port_t server_port,uint32_t n1,uint32_t n2){printf("Received: %d - %d = %d\n", n1, n2, n1 - n2);return KERN_SUCCESS;}intmain() {mach_port_t port;kern_return_t kr;// Register the mach servicekr =bootstrap_check_in(bootstrap_port,"xyz.hacktricks.mig",&port);if (kr != KERN_SUCCESS) {printf("bootstrap_check_in() failed with code 0x%x\n", kr);return1;}// myipc_server is the function that handles incoming messages (check previous exlpanation)mach_msg_server(myipc_server,sizeof(union __RequestUnion__SERVERPREFmyipc_subsystem), port, MACH_MSG_TIMEOUT_NONE);}
// gcc myipc_client.c myipcUser.c -o myipc_client#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<mach/mach.h>#include<servers/bootstrap.h>#include"myipcUser.h"intmain() {// Lookup the receiver port using the bootstrap server.mach_port_t port;kern_return_t kr =bootstrap_look_up(bootstrap_port,"xyz.hacktricks.mig",&port);if (kr != KERN_SUCCESS) {printf("bootstrap_look_up() failed with code 0x%x\n", kr);return1;}printf("Port right name %d\n", port);USERPREFSubtract(port,40,2);}
The NDR_record
The NDR_record inasafirishwa na libsystem_kernel.dylib, na ni struct inayoruhusu MIG kubadilisha data ili iweze kutumika bila kujali mfumo inatumika kama MIG ilipangwa kutumika kati ya mifumo tofauti (na sio tu kwenye mashine moja).
Hii ni ya kuvutia kwa sababu ikiwa _NDR_record inapatikana katika binary kama utegemezi (jtool2 -S <binary> | grep NDR au nm), inamaanisha kwamba binary ni mteja au Server wa MIG.
Zaidi ya hayo MIG servers zina meza ya dispatch katika __DATA.__const (au katika __CONST.__constdata katika macOS kernel na __DATA_CONST.__const katika kernel nyingine za *OS). Hii inaweza kutolewa kwa jtool2.
Na MIG clients zitatumia __NDR_record kutuma na __mach_msg kwa servers.
Binary Analysis
jtool
Kama binaries nyingi sasa zinatumia MIG kufichua mach ports, ni ya kuvutia kujua jinsi ya kutambua kwamba MIG ilitumika na kazi ambazo MIG inatekeleza na kila kitambulisho cha ujumbe.
jtool2 inaweza kuchambua habari za MIG kutoka kwa binary ya Mach-O ikionyesha kitambulisho cha ujumbe na kutambua kazi ya kutekeleza:
jtool2-d__DATA.__constmyipc_server|grepMIG
Zaidi ya hayo, kazi za MIG ni vifungashio vya kazi halisi inayoitwa, ambayo inamaanisha kwamba kupata usambazaji wake na kutafuta BL unaweza kukusaidia kupata kazi halisi inayoitwa:
jtool2-d__DATA.__constmyipc_server|grepBL
Assembly
Ilielezwa awali kwamba kazi ambayo itashughulikia kuita kazi sahihi kulingana na kitambulisho cha ujumbe kilichopokelewa ilikuwa myipc_server. Hata hivyo, kwa kawaida hutakuwa na alama za binary (hakuna majina ya kazi), hivyo ni ya kuvutia kuangalia inavyoonekana baada ya kutafsiriwa kwani itakuwa karibu sana (kanuni ya kazi hii ni huru kutoka kwa kazi zilizowekwa):
int_myipc_server(int arg0,int arg1) {var_10 = arg0;var_18 = arg1;// Maagizo ya awali ya kutafuta viashiria sahihi vya kazi*(int32_t*)var_18 =*(int32_t*)var_10 &0x1f;*(int32_t*)(var_18 +0x8) =*(int32_t*)(var_10 +0x8);*(int32_t*)(var_18 +0x4) =0x24;*(int32_t*)(var_18 +0xc) =0x0;*(int32_t*)(var_18 +0x14) =*(int32_t*)(var_10 +0x14) +0x64;*(int32_t*)(var_18 +0x10) =0x0;if (*(int32_t*)(var_10 +0x14) <=0x1f4&&*(int32_t*)(var_10 +0x14) >=0x1f4) {rax =*(int32_t*)(var_10 +0x14);// Kuitisha sign_extend_64 ambayo inaweza kusaidia kutambua kazi hii// Hii inahifadhi katika rax kiashiria cha simu ambacho kinahitaji kuitwa// Angalia matumizi ya anwani 0x100004040 (array ya anwani za kazi)// 0x1f4 = 500 (kitambulisho cha kuanzia) rax =*(sign_extend_64(rax -0x1f4)*0x28+0x100004040); var_20 = rax;// Ikiwa - vinginevyo, ikiwa inarudi uongo, wakati vinginevyo inaita kazi sahihi na inarudi kweliif (rax ==0x0) {*(var_18 +0x18) =**_NDR_record;*(int32_t*)(var_18 +0x20) =0xfffffffffffffed1;var_4 =0x0;}else {// Anwani iliyohesabiwa inayoiita kazi sahihi na hoja 2 (var_20)(var_10, var_18); var_4 =0x1;}}else {*(var_18 +0x18) =**_NDR_record;*(int32_t*)(var_18 +0x20) =0xfffffffffffffed1;var_4 =0x0;}rax = var_4;return rax;}
Hii ni kazi ile ile iliyotafsiriwa katika toleo tofauti la Hopper bure:
int_myipc_server(int arg0,int arg1) {r31 = r31 -0x40;saved_fp = r29;stack[-8] = r30;var_10 = arg0;var_18 = arg1;// Maagizo ya awali ya kutafuta viashiria sahihi vya kazi*(int32_t*)var_18 =*(int32_t*)var_10 &0x1f|0x0;*(int32_t*)(var_18 +0x8) =*(int32_t*)(var_10 +0x8);*(int32_t*)(var_18 +0x4) =0x24;*(int32_t*)(var_18 +0xc) =0x0;*(int32_t*)(var_18 +0x14) =*(int32_t*)(var_10 +0x14) +0x64;*(int32_t*)(var_18 +0x10) =0x0;r8 =*(int32_t*)(var_10 +0x14);r8 = r8 -0x1f4;if (r8 >0x0) {if (CPU_FLAGS & G) {r8 =0x1;}}if ((r8 &0x1) ==0x0) {r8 =*(int32_t*)(var_10 +0x14);r8 = r8 -0x1f4;if (r8 <0x0) {if (CPU_FLAGS & L) {r8 =0x1;}}if ((r8 &0x1) ==0x0) {r8 =*(int32_t*)(var_10 +0x14);// 0x1f4 = 500 (kitambulisho cha kuanzia) r8 = r8 -0x1f4;asm { smaddl x8, w8, w9, x10 };r8 =*(r8 +0x8);var_20 = r8;r8 = r8 -0x0;if (r8 !=0x0) {if (CPU_FLAGS & NE) {r8 =0x1;}}// Vile vile ikiwa - vinginevyo kama katika toleo la awali// Angalia matumizi ya anwani 0x100004040 (array ya anwani za kazi)if ((r8 &0x1) ==0x0) {*(var_18 +0x18) =**0x100004000;*(int32_t*)(var_18 +0x20) =0xfffffed1;var_4 =0x0;}else {// Kuitisha anwani iliyohesabiwa ambapo kazi inapaswa kuwa (var_20)(var_10, var_18); var_4 =0x1;}}else {*(var_18 +0x18) =**0x100004000;*(int32_t*)(var_18 +0x20) =0xfffffed1;var_4 =0x0;}}else {*(var_18 +0x18) =**0x100004000;*(int32_t*)(var_18 +0x20) =0xfffffed1;var_4 =0x0;}r0 = var_4;return r0;}
Kwa kweli ikiwa utaenda kwenye kazi 0x100004000 utapata array ya routine_descriptor structs. Kigezo cha kwanza cha struct ni anwani ambapo kazi imeanzishwa, na struct inachukua 0x28 bytes, hivyo kila byte 0x28 (kuanzia byte 0) unaweza kupata byte 8 na hiyo itakuwa anwani ya kazi ambayo itaitwa:
Kanuni iliyozalishwa na MIG pia inaita kernel_debug ili kuzalisha kumbukumbu kuhusu operesheni za kuingia na kutoka. Inawezekana kuangalia hizo kwa kutumia trace au kdv: kdv all | grep MIG