macOS MIG - Mach Interface Generator

HackTricks'i Destekleyin

Temel Bilgiler

MIG, Mach IPC kod oluşturma sürecini basitleştirmek için oluşturulmuştur. Temelde, sunucu ve istemcinin iletişim kurması için gerekli kodu oluşturur. Oluşturulan kodun kötü görünmesine rağmen, bir geliştiricinin bunu içe aktarması yeterli olacak ve kodu öncekinden çok daha basit olacaktır.

Tanım, .defs uzantısını kullanarak Arayüz Tanım Dili (IDL) ile belirtilir.

Bu tanımlar 5 bölüme sahiptir:

  • Alt sistem bildirimi: Alt sistem anahtar kelimesi, adı ve kimliği belirtmek için kullanılır. Sunucunun çekirdekte çalışması gerekiyorsa KernelServer olarak işaretlenebilir.

  • Dahil ve içe aktarmalar: MIG, C ön işleyiciyi kullanır, bu nedenle içe aktarmaları kullanabilir. Ayrıca, kullanıcı veya sunucu oluşturulan kodlar için uimport ve simport kullanmak mümkündür.

  • Tür bildirimleri: Veri tiplerini tanımlamak mümkündür, ancak genellikle mach_types.defs ve std_types.defs içe aktarılır. Özel olanlar için bazı sözdizimi kullanılabilir:

  • [in/out]tran: Gelen veya giden bir iletiyi çevirmesi gereken işlev

  • c[user/server]type: Başka bir C türüne eşleme.

  • destructor: Tür serbest bırakıldığında bu işlevi çağırın.

  • İşlemler: Bunlar RPC yöntemlerinin tanımlarıdır. 5 farklı tür vardır:

  • routine: Yanıt bekler

  • simpleroutine: Yanıt beklemiyor

  • procedure: Yanıt bekler

  • simpleprocedure: Yanıt beklemiyor

  • function: Yanıt bekler

Örnek

Çok basit bir işlevle bir tanım dosyası oluşturun:

myipc.defs
subsystem myipc 500; // Arbitrary name and id

userprefix USERPREF;        // Prefix for created functions in the client
serverprefix SERVERPREF;    // Prefix for created functions in the server

#include <mach/mach_types.defs>
#include <mach/std_types.defs>

simpleroutine Subtract(
server_port :  mach_port_t;
n1          :  uint32_t;
n2          :  uint32_t);

İlk argümanın bağlanacak bağlantı noktası olduğunu ve MIG'in yanıt bağlantı noktasını otomatik olarak ele alacağını unutmayın (mig_get_reply_port() çağrılmadığı sürece istemci kodunda). Ayrıca, işlemlerin kimliğinin belirtilen alt sistem kimliği ile başlayarak ardışık olacağını unutmayın (bu nedenle bir işlem kullanımdan kaldırıldığında silinir ve hala kimliğini kullanmak için skip kullanılır).

Şimdi, birbirleriyle iletişim kurabilecek sunucu ve istemci kodunu oluşturmak için MIG'i kullanın ve Çıkarma işlevini çağırmak için:

mig -header myipcUser.h -sheader myipcServer.h myipc.defs

Çeşitli yeni dosyalar mevcut dizinde oluşturulacaktır.

Daha karmaşık bir örneği sisteminizde şu komutla bulabilirsiniz: mdfind mach_port.defs Ve aynı klasörden derleyebilirsiniz: mig -DLIBSYSCALL_INTERFACE mach_ports.defs

myipcServer.c ve myipcServer.h dosyalarında SERVERPREFmyipc_subsystem yapısının bildirimi ve tanımını bulabilirsiniz, bu yapı temelde alınan mesaj kimliğine göre çağrılacak işlevi tanımlar (başlangıç numarasını 500 olarak belirttik):

/* Description of this subsystem, for use in direct RPC */
const struct SERVERPREFmyipc_subsystem SERVERPREFmyipc_subsystem = {
myipc_server_routine,
500, // start ID
501, // 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)},
}
};

Önceki yapıya dayanarak myipc_server_routine işlevi mesaj kimliğini alacak ve çağrılacak uygun işlevi döndürecektir:

mig_external mig_routine_t myipc_server_routine
(mach_msg_header_t *InHeadP)
{
int msgh_id;

msgh_id = InHeadP->msgh_id - 500;

if ((msgh_id > 0) || (msgh_id < 0))
return 0;

return SERVERPREFmyipc_subsystem.routine[msgh_id].stub_routine;
}

Bu örnekte tanımladığımız sadece 1 fonksiyon var, ancak daha fazla fonksiyon tanımlasaydık, bunlar SERVERPREFmyipc_subsystem dizisinin içinde olacaktı ve ilk fonksiyon 500 ID'ye, ikinci fonksiyon ise 501 ID'ye atanacaktı...

Eğer fonksiyondan bir yanıt bekleniyorsa, mig_internal kern_return_t __MIG_check__Reply__<name> fonksiyonu da mevcut olacaktı.

Aslında bu ilişkiyi myipcServer.h dosyasındaki subsystem_to_name_map_myipc yapısında (**diğer dosyalardaki subsystem_to_name_map_*** yapısında) tanımlamak mümkündür:

#ifndef subsystem_to_name_map_myipc
#define subsystem_to_name_map_myipc \
{ "Subtract", 500 }
#endif

Son olarak, sunucunun çalışmasını sağlamak için önemli bir işlev olan myipc_server olacaktır, bu işlev aslında alınan kimliğe ilişkin işlevi çağıracaktır:

mig_external boolean_t myipc_server
(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
{
/*
* typedef struct {
* 	mach_msg_header_t Head;
* 	NDR_record_t NDR;
* 	kern_return_t RetCode;
* } mig_reply_error_t;
*/

mig_routine_t routine;

OutHeadP->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REPLY(InHeadP->msgh_bits), 0);
OutHeadP->msgh_remote_port = InHeadP->msgh_reply_port;
/* Minimal size: routine() will update it if different */
OutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t);
OutHeadP->msgh_local_port = MACH_PORT_NULL;
OutHeadP->msgh_id = InHeadP->msgh_id + 100;
OutHeadP->msgh_reserved = 0;

if ((InHeadP->msgh_id > 500) || (InHeadP->msgh_id < 500) ||
	    ((routine = SERVERPREFmyipc_subsystem.routine[InHeadP->msgh_id - 500].stub_routine) == 0)) {
		((mig_reply_error_t *)OutHeadP)->NDR = NDR_record;
((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID;
return FALSE;
}
	(*routine) (InHeadP, OutHeadP);
	return TRUE;
}

Önceki vurgulanan satırları kontrol ederek, kimliğe göre çağrılacak işlevlere erişimi kontrol edin.

Aşağıdaki kod, istemcinin sunucudan çıkarmak için işlevleri çağırabileceği basit bir sunucu ve istemci oluşturmak için kullanılan koddur:

// 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_t SERVERPREFSubtract(mach_port_t server_port, uint32_t n1, uint32_t n2)
{
printf("Received: %d - %d = %d\n", n1, n2, n1 - n2);
return KERN_SUCCESS;
}

int main() {

mach_port_t port;
kern_return_t kr;

// Register the mach service
kr = bootstrap_check_in(bootstrap_port, "xyz.hacktricks.mig", &port);
if (kr != KERN_SUCCESS) {
printf("bootstrap_check_in() failed with code 0x%x\n", kr);
return 1;
}

// 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);
}