Skip to content

Instantly share code, notes, and snippets.

@pwn0rz
Created May 30, 2021 09:12
Show Gist options
  • Save pwn0rz/a06611c865d304d514b14aa76f8ec9be to your computer and use it in GitHub Desktop.
Save pwn0rz/a06611c865d304d514b14aa76f8ec9be to your computer and use it in GitHub Desktop.
The MIG from FairplayIOKit to fairplayd
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <mach/mach.h>
#include <CommonCrypto/CommonCrypto.h>
#include <ctype.h>
void hexdump(void *ptr, int buflen) {
unsigned char *buf = (unsigned char*)ptr;
int i, j;
for (i=0; i<buflen; i+=16) {
printf("%06x: ", i);
for (j=0; j<16; j++)
if (i+j < buflen)
printf("%02x ", buf[i+j]);
else
printf(" ");
printf(" ");
for (j=0; j<16; j++)
if (i+j < buflen)
printf("%c", isprint(buf[i+j]) ? buf[i+j] : '.');
printf("\n");
}
}
#pragma pack(push, 4)
struct FPRequest{
mach_msg_header_t header;
mach_msg_body_t body;
mach_msg_ool_descriptor_t ool;
NDR_record_t ndr;
uint32_t size;
uint64_t cpu_type;
uint64_t cpu_subtype;
};
struct FPResponse{
mach_msg_header_t header;
mach_msg_body_t body;
mach_msg_ool_descriptor_t ool1;
mach_msg_ool_descriptor_t ool2;
uint64_t unk1;
uint8_t unk2[136];
uint8_t unk3[84];
uint32_t size1;
uint32_t size2;
uint64_t unk5;
};
#pragma pack(pop)
int fairplay_rpc(mach_port_t fp_port,const char *filepath,struct FPResponse *res){
union Message
{
struct FPRequest In;
struct FPResponse Out;
};
union Message msg;
bzero(&msg,sizeof(msg));
struct FPRequest *req = &msg.In;
//make the checker happy
req->header.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND);
req->header.msgh_size = 0x48;
req->header.msgh_id = 502;
req->header.msgh_remote_port = fp_port;
req->header.msgh_local_port = mig_get_reply_port();
req->header.msgh_voucher_port = MACH_PORT_NULL;
req->body.msgh_descriptor_count = 1;
req->size = strlen(filepath) + 1;
req->ool.size = req->size;
req->ool.address = strdup(filepath);
req->ool.type = MACH_MSG_OOL_DESCRIPTOR;
req->ool.copy = MACH_MSG_PHYSICAL_COPY;
req->ool.deallocate = FALSE;
req->ndr = NDR_record;
req->cpu_type = 0x0100000c;
req->cpu_subtype = 0x00000000;
mach_error_t err;
if( MACH_MSG_SUCCESS != (err = mach_msg(&req->header,MACH_SEND_MSG | MACH_RCV_MSG | MACH_MSG_OPTION_NONE,req->header.msgh_size,sizeof(struct FPResponse),mig_get_reply_port(),MACH_MSG_TIMEOUT_NONE,MACH_PORT_NULL))){
printf("[!] failed to send/recv unfreed mig requets : %s\n",mach_error_string(err));
return -1;
}
memcpy(res,&msg.Out,sizeof(struct FPResponse));
printf("[+] mig requests success\n");
return 0;
}
int main(int argc,char *argv[])
{
if(argc != 2){
printf("[!] usage : %s : /path/to/executable",argv[0]);
return 0;
}
printf("sizeof(struct FPRequest) = %#lx, sizeof(struct FPResponse) = %#lx\n",sizeof(struct FPRequest),sizeof(struct FPResponse));
//printf("sizeof(mach_msg_header_t) = %#lx\n",sizeof(mach_msg_header_t));
mach_port_t unfreed_port = 0xa03;
if(KERN_SUCCESS != host_get_unfreed_port(mach_host_self(),&unfreed_port)){
printf("[!]failed to get unfreed port\n");
return -1;
}
printf("[+] got unfreed port : %#x\n",unfreed_port);
struct FPResponse res;
fairplay_rpc(unfreed_port,argv[1],&res);
printf("size : %#x, id : %d, ool vm1 : %p, size = %#x, ool vm2 : %p, size = %#x\n",res.header.msgh_size,res.header.msgh_id,res.ool1.address,res.ool1.size,res.ool2.address,res.ool2.size);
if(res.header.msgh_size <= 0x24){
//invalid response
printf("[!] mig response invalid\n");
return -1;
}
CC_SHA1_CTX ctx;
uint8_t hash[20];
CC_SHA1_Init(&ctx);
CC_SHA1_Update(&ctx,res.ool1.address,res.ool1.size);
CC_SHA1_Final(hash,&ctx);
printf("ool1: \n");
hexdump(res.ool1.address,res.ool1.size);
CC_SHA1_Init(&ctx);
CC_SHA1_Update(&ctx,res.ool2.address,res.ool2.size);
CC_SHA1_Final(hash,&ctx);
printf("ool2: \n");
hexdump(res.ool2.address,res.ool2.size);
printf("unk1: %#llx\n",res.unk1);
printf("unk2: \n");
hexdump(res.unk2,136);
printf("unk3: \n");
hexdump(res.unk3,84);
printf("size1: %#x\n",res.size1);
printf("size1: %#x\n",res.size2);
printf("unk5: %#llx\n",res.unk5);
}
@pwn0rz
Copy link
Author

pwn0rz commented May 30, 2021

Root required, and may not work on macOS 11.3 and newer, maybe Apple add some checks on the MIG call. More details will be available soon

@pwn0rz
Copy link
Author

pwn0rz commented Jun 20, 2021

Lol, It works again, on macOS 12

@pwn0rz
Copy link
Author

pwn0rz commented Jun 25, 2021

It works on 11.4_20F7 too

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment