#include <mach/mach.h> #include <mach/task.h> #include <sys/signal.h> #include <libproc.h> #include <dlfcn.h> #include <stdio.h> #include <pthread.h> #include <CoreFoundation/CoreFoundation.h> extern void NSLog(CFStringRef, ...); #include <unistd.h> #include <stdlib.h> // exit #include <mach-o/loader.h> // for Mach-O handling #include <mach-o/fat.h> uint64_t amfidTEXTaddress = 0; #ifdef _11 uint32_t MVSACI_offset = 0x100004150 - 0x100000000; #else uint32_t MVSACI_offset = 0x100004140 - 0x100000000; #endif // // Missing headers // 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 ); kern_return_t mach_vm_read_overwrite ( vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, vm_offset_t data, mach_msg_type_number_t *dataCnt ); FILE *OUT = NULL; void debug (char *Msg, ...) { static char buffer[2048]; va_list args; va_start (args, Msg); vsprintf (buffer, Msg, args); va_end (args); NSLog(CFSTR("DEBUG: %s\n"), buffer); fprintf(OUT, "DEBUG: %s\n", buffer); } void status (char *Msg, ...) { static char buffer[2048]; va_list args; va_start (args, Msg); vsprintf (buffer, Msg, args); va_end (args); NSLog(CFSTR("%s\n"), buffer); fprintf(OUT, "%s\n", buffer); } void error (char *Msg, ...) { static char buffer[2048]; va_list args; va_start (args, Msg); vsprintf (buffer, Msg, args); va_end (args); NSLog(CFSTR("ERROR: %s\n"), buffer); fprintf(OUT, "Error: %s\n", buffer); //exit(strlen(Msg)); // :-) } pid_t findPidOfProcess (char *ProcName) { char buffer[256]; int rc = 0 ; int pid = 0; // Brute force-ish. Better would be to get list of pids first.. for (pid = 1; pid < 65536; pid++) { // Interesting behavior: proc_name only works for processes with same uid. rc = proc_name(pid, // int pid, buffer, // void * buffer, 256); // uint32_t buffersize) //if (rc){ printf("PID %d: %s\n", pid, buffer);} if (rc && strcmp(buffer,ProcName) == 0) { return pid; } } return 0; } // Code signing support #define ALGORITHM_SHA256 256 #define ALGORITHM_SHA1 1 int algorithm = ALGORITHM_SHA256; const struct ccdigest_info *ccsha256_di(void); void cchmac(const struct ccdigest_info *di, unsigned long key_len, const void *key, unsigned long data_len, const void *data, unsigned char *mac); void ccdigest(const struct ccdigest_info *di, unsigned long len, const void *data, void *digest); static inline unsigned char *mysha1 (void *Data, int Len) { static unsigned char sha256[32] = {0}; ccdigest(ccsha256_di(), 0x1000, // data_len Data, // const void *data sha256); // unsigned char *mac); return (sha256); } int MISdoNotValidateSignatureButCopyInfo(char *Path, void *Options, char *outDict) { // Not yet return 0; } //doNotValidateCodeSignatureButCopyInfo const struct ccdigest_info *ccsha256_di(void); const struct ccdigest_info *ccsha1_di(void); void cchmac(const struct ccdigest_info *di, unsigned long key_len, const void *key, unsigned long data_len, const void *data, unsigned char *mac); void ccdigest(const struct ccdigest_info *di, unsigned long len, const void *data, void *digest); static inline unsigned char doSHA256 (void *Data, int Len, unsigned char *Buf) { static unsigned char sha256[32] = {0}; ccdigest(ccsha256_di(), Len, // data_len Data, // const void *data Buf); // unsigned char *mac); return (Buf); } static inline unsigned char doSHA1 (void *Data, int Len, unsigned char *Buf) { static unsigned char sha1[32] = {0}; ccdigest(ccsha1_di(), Len, // data_len Data, // const void *data Buf); // unsigned char *mac); return (Buf); } #define FAULTING_ADDRESS 0x454d41524542494c // De profondu lacu unsigned char *cdHashOfFile(char *Path, int Algorithm ) { struct stat stBuf ; if (access (Path, F_OK)) { fprintf(stderr,"File %s apparently not found!\n", Path); return NULL; } int fd = open (Path, O_RDONLY); if (fd == -1) { fprintf(stderr,"Unable to open File %s - %s\n", Path ,strerror(errno)); return NULL; } int rc = fstat (fd,&stBuf); // NSLog(CFSTR("Processing file %s\n"), Path); char *fileContents = malloc(stBuf.st_size); read (fd, fileContents, stBuf.st_size); close(fd); struct mach_header_64 *mh = (struct mach_header_64 *) fileContents; if (mh->magic != MH_MAGIC_64) { // Give FAT a change... if (mh->magic == FAT_CIGAM) { struct fat_header *fh = (struct fat_header *) mh; fprintf(OUT, "# fat archs: %d\n", ntohl(fh->nfat_arch)); struct fat_arch *fa = (struct fat_arch *) (fh +1); int arch = 0; for (arch = 0; arch < ntohl(fh->nfat_arch); arch++) { fprintf(OUT, "ARCH: 0x%x\n", fa->cputype); if (fa->cputype == 0xc000001) { // CPU_TYPE_ARM64) fprintf(OUT, "Adjusting header to 0x%x\n", ntohl(fa->offset)); mh = (struct mach_header_64 *) (fileContents + ntohl(fa->offset)); } fa++; // maybe next arch?: } // end for #if 0 struct fat_header { uint32_t magic; /* FAT_MAGIC or FAT_MAGIC_64 */ uint32_t nfat_arch; /* number of structs that follow */ }; struct fat_arch { cpu_type_t cputype; /* cpu specifier (int) */ cpu_subtype_t cpusubtype; /* machine specifier (int) */ uint32_t offset; /* file offset to this object file */ uint32_t size; /* size of this object file */ uint32_t align; /* alignment as a power of 2 */ }; #endif printf ("MH MAGIC IS NOW %x\n", mh->magic); } else { error ("Found magic 0x%x at off file - this is not an MH_MAGIC_64 nor a FAT_MAGIC..\n", mh->magic); return(NULL);} } fprintf (OUT,"Got Header with %d Load commands\n", mh->ncmds); int lcNum = 0; struct load_command *lc = (struct load_command *) ((char *)mh + sizeof(struct mach_header_64)); while (lcNum < mh->ncmds -1) { lc = (struct load_command *)((char *)lc + lc->cmdsize); lcNum++; } // printf("Load command %d - 0x%x (0x%x)\n", lcNum, lc->cmd, LC_CODE_SIGNATURE); if (lc->cmd != LC_CODE_SIGNATURE) { debug( "Last load command is not an LC_CODE_SIGNATURE...\n"); free(fileContents); return NULL;; } // Want to get the code signature blob: struct linkedit_data_command *ldc = (struct linkedit_data_command *) lc; int csBlobOffset = ldc->dataoff; int csBlobSize = ldc->datasize; struct blobDesc { uint32_t blobType; uint32_t blobOffset; }; struct superblob { uint32_t magic; uint32_t size; uint32_t numBlobs; struct blobDesc blobDesc[0]; } *b = (struct superblob *) ((char *)mh + ldc->dataoff); if (memmem(b, ntohl(b->size), "Apple Worldwide Developer Relations", strlen("Apple Worldwide Developer Relations"))) { debug("Request for a dev signed party - allowing this\n"); } else if (memmem(b,ntohl(b->size), "Apple Certi", 10)) { free(fileContents); debug("Request for an App store binary - not touching this\n"); return NULL; } struct __CodeDirectory { uint32_t magic; /* magic number (CSMAGIC_CODEDIRECTORY) */ uint32_t length; /* total length of CodeDirectory blob */ uint32_t version; /* compatibility version */ uint32_t flags; /* setup and mode flags */ uint32_t hashOffset; /* offset of hash slot element at index zero */ uint32_t identOffset; /* offset of identifier string */ uint32_t nSpecialSlots; /* number of special hash slots */ uint32_t nCodeSlots; /* number of ordinary (code) hash slots */ uint32_t codeLimit; /* limit to main image signature range */ uint8_t hashSize; /* size of each hash in bytes */ uint8_t hashType; /* type of hash (cdHashType* constants) */ uint8_t platform; /* unused (must be zero) */ uint8_t pageSize; /* log2(page size in bytes); 0 => infinite */ uint32_t spare2; /* unused (must be zero) */ } *cdb; int kSecCodeMagicCodeDirectory = 0xfade0c02; /* CodeDirectory */ cdb = (struct __CodeDirectory *) ((char *) b + ntohl(b->blobDesc[0].blobOffset)); int numBlob = 0; status("GOT BLOB, MAGIC: 0x%x, offset: %x, type: %x\n", ntohl(cdb->magic), ntohl(b->blobDesc[0].blobOffset), ntohl(b->blobDesc[0].blobType)); int matchingBlob = 0; int match = 0; while (numBlob < ntohl(b->numBlobs)) { if (cdb->magic != htonl (kSecCodeMagicCodeDirectory)) { fprintf(OUT, "Blob Magic: 0x%x - not a code directory (!= 0x%x)\n", ntohl(cdb->magic), htonl (kSecCodeMagicCodeDirectory)); } else // is a code directory. if (cdb->hashSize != (Algorithm == ALGORITHM_SHA256 ? 32 : 20)) { fprintf(OUT,"Blob %d hash size: %d (need %d)\n", cdb->hashSize, (Algorithm == ALGORITHM_SHA256 ? 32 : 20)); } else { // MATCH match++; break; } numBlob++; cdb = (struct __CodeDirectory *) ((char *) b + ntohl(b->blobDesc[numBlob].blobOffset)); /* status("GOT BLOB, MAGIC: 0x%x, offset: %x, type: %x\n", ntohl(cdb->magic), ntohl(b->blobDesc[numBlob].blobOffset), ntohl(b->blobDesc[numBlob].blobType)); */ } // while if (!match) { fprintf(stderr,"Can't find a CD Blob match\n"); return (NULL); } printf("CD Blob magic: 0x%x (CodeDir: 0x%lx)\n", ntohl(cdb->magic),kSecCodeMagicCodeDirectory); uint32_t cdSize = ntohl(cdb->length); static unsigned char cdHash[32]; switch (Algorithm) { case ALGORITHM_SHA256: doSHA256(cdb, cdSize, cdHash); break; case ALGORITHM_SHA1: status("Doing SHA1\n"); doSHA1(cdb, cdSize, cdHash); break; } free(fileContents); return (char *)cdHash; } // End code signing support uint64_t MVSACI_addr = 0; mach_port_t g_AmfidPort = MACH_PORT_NULL; int exceptionHandler (mach_port_t ExceptionPort) { #define BUFSIZE 0x1000 mach_msg_header_t* msg = (mach_msg_header_t *) alloca(BUFSIZE);; for(;;){ kern_return_t kr; kr = mach_msg(msg, MACH_RCV_MSG | MACH_MSG_TIMEOUT_NONE, // no timeout 0, BUFSIZE, ExceptionPort, 0, 0); // We get this from mach_exc.defs, with an application of mig // Note that packing the structure is essential since it is // not aligned on any boundaries.. #pragma pack(1) struct mach_exc_msg { mach_msg_header_t Head; /* start of the kernel processed data */ mach_msg_body_t msgh_body; mach_msg_port_descriptor_t thread; mach_msg_port_descriptor_t task; /* end of the kernel processed data */ NDR_record_t NDR; exception_type_t exception; mach_msg_type_number_t codeCnt; int64_t code[2]; int flavor; mach_msg_type_number_t old_stateCnt; natural_t old_state[614]; } ; #pragma pack() struct mach_exc_msg *excMsg = (struct mach_exc_msg *)msg; // Ian Beer uses thread_get_state() - which he would need, since he uses exception_raise, // but if you use raise_state_identity, you get everything. if ((excMsg->Head.msgh_id !=2405) && (excMsg->Head.msgh_id != 2407)) { fprintf(stderr, "Message isn't 2407.. this is weird\n"); } #if 0 // from osfmk/mach/arm/_structs.h: _STRUCT_ARM_THREAD_STATE64 { __uint64_t __x[29]; /* General purpose registers x0-x28 */ __uint64_t __fp; /* Frame pointer x29 */ __uint64_t __lr; /* Link register x30 */ __uint64_t __sp; /* Stack pointer x31 */ __uint64_t __pc; /* Program counter */ __uint32_t __cpsr; /* Current program status register */ __uint32_t __pad; /* Same size for 32-bit or 64-bit clients */ }; #endif // hexDump(excMsg, 0x300, 0); printf("TASK: 0x%x, Thread: 0x%x - CODE: 0x%llx/0x%llx, flavor: %x\n", excMsg->task, excMsg->thread, excMsg->code[0], excMsg->code[1], excMsg->flavor); mach_port_t thread_port = excMsg->thread.name; mach_port_t task_port = excMsg->task.name; #ifndef TEST _STRUCT_ARM_THREAD_STATE64 * old_state = (_STRUCT_ARM_THREAD_STATE64 *) malloc (614*4); // = (_STRUCT_ARM_THREAD_STATE64 *)excMsg->old_state; mach_msg_type_number_t cnt = 68; //sizeof(ARM_THREAD_STATE64)/4;; kr = thread_get_state(thread_port, // ARM_THREAD_STATE64, // thread_state_flavor_t flavor (thread_state_t)old_state, &cnt); // dumpARMThreadState64(old_state); uint64_t fileNameAddr = old_state->__x[25]; uint64_t optionsAddr = old_state->__x[1]; char *fileName = malloc(0x200); uint64_t fileNameSize = 0x200 ; // kr = task_get_special_port (mach_task_self(), TASK_DEBUG_CONTROL_PORT, &g_AmfidPort); kr = mach_vm_read_overwrite(task_port, // target_task fileNameAddr, // address fileNameSize, // mach_vm_size_t size (mach_vm_address_t )fileName, &fileNameSize); debug("Got request - kr: %d - FileName (@0x%llx): %s (fileNameSize : %d)\n", kr, fileNameAddr, fileName, fileNameSize); unsigned char *cdh; cdh = cdHashOfFile(fileName, algorithm); if (!cdh) { mach_vm_write (task_port, old_state->__pc, MVSACI_addr,sizeof(uint64_t)); old_state->__pc =MVSACI_addr; debug("File error or not self signed... redirected to original MVSACI @0x%llx\n", MVSACI_addr); } else { kr = mach_vm_write(task_port, old_state->__x[24], (mach_vm_address_t) cdh, 20); // yep, 20, not 32.. if (kr ==0 ) { debug("written cdhash for algorithm %d (0x%x 0x%x 0x%x...0x%x) to 0x%llx - kr %d\n", algorithm, cdh[0], cdh[1], cdh[2], cdh[19], old_state->__x[24] , kr); } else { error ("Error %d writing CDHash back into AMFI at 0x%llx\n", kr, old_state->__x[24]); } uint32_t one = 1; kr = mach_vm_write(task_port, old_state->__x[20], (mach_vm_address_t) &one,sizeof(one)); // Legacy VPN plugins : // uint32_t five = 5; // kr = mach_vm_write (AmfidPort, old_state->__x[28], &five, sizeof(five)); // recover #ifdef _11 old_state->__pc = (old_state->__lr & 0xfffffffffffff000) + 0x1000; // resume #else old_state->__pc = (old_state->__lr & 0xfffffffffffff000) + 0x0ef4; // resume #endif } printf("will resume at 0x%llx\n",old_state->__pc); // ------------------------------- #pragma pack(1) typedef struct { mach_msg_header_t Head; NDR_record_t NDR; kern_return_t RetCode; /* int flavor; mach_msg_type_number_t new_stateCnt; natural_t new_state[614];*/ } excReplyMsg; #pragma pack(0) //#if 0 kr = thread_set_state(thread_port, // ARM_THREAD_STATE64, // thread_state_flavor_t flavor (thread_state_t)old_state, cnt); printf("set state %d - Cnt: %d\n",kr, cnt); //#endif excReplyMsg excReply = {0}; // memcpy(excReply.new_state, old_state, sizeof (*old_state)); // excReply.new_stateCnt= excMsg->old_stateCnt ;; excReply.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(excMsg->Head.msgh_bits), 0); excReply.Head.msgh_size = sizeof(excReply); excReply.Head.msgh_remote_port = excMsg->Head.msgh_remote_port; excReply.Head.msgh_local_port = MACH_PORT_NULL; excReply.Head.msgh_id = excMsg->Head.msgh_id + 100; // excReply.flavor= excMsg->flavor; excReply.NDR = excMsg->NDR; excReply.RetCode = KERN_SUCCESS; kr = mach_msg(&excReply.Head, MACH_SEND_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(excReply), 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); // mach_port_deallocate(mach_task_self(), thread_port); // mach_port_deallocate(mach_task_self(), task_port); // printf("sent reply - %d - Flavor %d, %d bytes, %x\n", excReply.Head.msgh_id , excReply.flavor, // excReply.new_stateCnt ,kr); // printf("REPLY KR: %d\n", kr); //dumpARMThreadState64(excReply.new_state); fflush(NULL); #endif // TEST } return 0; } void setExceptionHandlerForTask(mach_port_t Victim, void *Handler) { mach_port_t exc_port; // Chapter 11 of the old MOXiI book, if anyone's interested.. mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &exc_port); mach_port_insert_right(mach_task_self(), exc_port, exc_port, MACH_MSG_TYPE_MAKE_SEND); #ifndef TEST kern_return_t kr = task_set_exception_ports(Victim, EXC_MASK_ALL, exc_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, ARM_THREAD_STATE64); #endif pthread_t exception_handling_thread; pthread_create(&exception_handling_thread, NULL, Handler, (void *) (mach_port_t) exc_port); printf("SET EXCEPTION HANDLER\n"); } // setExceptionHandlerForTask #define FAULTING_ADDRESS 0x454d41524542494c // De profondu lacu int castrateAmfid (mach_port_t AmfidPort) { status("Got AMFId's port (0x%x) - Let's castrate this bastard\n", AmfidPort); // The quick and dirty way is to do it with Ian's method. This also has the upside of enabling // an effective hook on all third party application startup (or library validations) // A better way is to patch up AMFId's code because there's plenty of space to fit in // a SHA-256 CDHash calculator and just jump to it instead of MISValidateSignatureAndCopyInfo // Anyway: // (TvOS 11.1, BEE6...CC3 , 270.20.2.0.0) // // __DATA __la_symbol_ptr 0x100004150 0x02D1 libmis.dylib _MISValidateSignatureAndCopyInfo pid_t amfidPid = 0; kern_return_t kr = pid_for_task (AmfidPort, &amfidPid); while (amfidPid <1 ) { if (amfidPid = -1) { debug("Error getting PID from task port. Was I handed an invalid task port?\n"); } status("HERE - 0x%x, %d\n", AmfidPort, amfidPid); printf("Sleeping\n"); fflush(NULL); sleep(1); pid_t amfidPid = findPidOfProcess("amfid"); mach_port_deallocate (mach_task_self(), AmfidPort); kern_return_t kr = task_for_pid(mach_task_self(), amfidPid, &AmfidPort); printf("TFP ON %d - KR %d port %x\n", amfidPid, kr, AmfidPort); printf("KR %d on port %x\n", kr, AmfidPort); amfidPid = 0 ; kr = pid_for_task (AmfidPort, &amfidPid); } struct proc_regionwithpathinfo regionsWithPaths; int reg = 0 ; uint64_t addr = 0; int size = 0 ; status("Getting region info:\n"); fflush(NULL); int rc = proc_pidinfo( amfidPid, PROC_PIDREGIONPATHINFO, addr, // uint64_t arg, ®ionsWithPaths, sizeof (struct proc_regionwithpathinfo));; status("Set exception handler:\n"); setExceptionHandlerForTask(AmfidPort, exceptionHandler); amfidTEXTaddress = regionsWithPaths.prp_prinfo.pri_address; uint64_t len = sizeof(void *); uint64_t faultingAddr ; retry: kr = mach_vm_read_overwrite (AmfidPort, amfidTEXTaddress + MVSACI_offset, sizeof(void *) , &MVSACI_addr, &len); if (kr == KERN_SUCCESS) { void *h = dlopen("libmis.dylib", 0); void *MISValidateSignatureAndCopyInfo = (void *) dlsym(h, "MISValidateSignatureAndCopyInfo"); debug("Original address of MVSACI: 0x%llx\n", MVSACI_addr); debug("NOW SET TO %llx\n", MISValidateSignatureAndCopyInfo); MVSACI_addr = (uint64_t) MISValidateSignatureAndCopyInfo; } else { error("Unable to read amfid's memory\n"); return -1; sleep(2); } faultingAddr = FAULTING_ADDRESS; status("HERE STILL\n"); fflush(NULL); kr = mach_vm_write(AmfidPort, amfidTEXTaddress + MVSACI_offset, &faultingAddr, sizeof(void *)); if (kr ==0 ) { status("patched AMFI through port 0x%x @0x%llx to Faulting addr: 0x%llx\n",AmfidPort,amfidTEXTaddress + MVSACI_offset, faultingAddr );} else { printf("KR: %d\n", kr); error("Failed to patch AMFI @0x%llx\n",amfidTEXTaddress + MVSACI_offset ); } uint64_t tryAgain; kr = mach_vm_read_overwrite (AmfidPort, amfidTEXTaddress + MVSACI_offset, sizeof(void *) , &tryAgain, &len); status("TRY AGAIN : 0x%llx\n", tryAgain); return 0; } struct kevent ke; int getKqueueForPid (pid_t pid) { // This is a direct rip from Listing 3-1 in the first edition of MOXiI: int kq = kqueue(); if (kq == -1) { perror("kqueue"); printf("UNABLE TO CREATE KQUEUE\n"); return -1;} // Set process fork/exec notifications else { EV_SET(&ke, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT_DETAIL , 0, NULL); // Register event int rc = kevent(kq, &ke, 1, NULL, 0, NULL); if (rc < 0) { perror ("kevent"); printf("UNABLE TO GET KEVENT\n"); return -2;} } return kq; } #ifndef TEST int main (int argc, char **argv) { // Ain't no terminating us // First find amfid OUT = fopen ("/tmp/amfidebilitate.out", "w"); if (!OUT) { OUT = stdout;} if (argc > 1) { if (strcmp(argv[1], "sha1") == 0) { printf("WILL USE SHA-1\n"); algorithm = ALGORITHM_SHA1; } else { printf("WILL USE SHA-256\n"); algorithm = ALGORITHM_SHA256; } } status ("THIS IS AMFIDEBILITATE - Compiled on " __DATE__ "/" __TIME__); sleep(3); mach_port_t tsp = MACH_PORT_NULL; kern_return_t kr = task_get_special_port (mach_task_self(), TASK_DEBUG_CONTROL_PORT, &tsp); kr = KERN_SUCCESS; tsp = 0xbb07; tsp= MACH_PORT_NULL; #define CS_OPS_ENTITLEMENTS_BLOB 7 struct blob { uint32_t type; uint32_t len; char data[0]; }; struct blob *entBlob = alloca(1024); int entBlobLen = 1024; bzero (entBlob, entBlobLen); extern int csops (pid_t, int, char * ,int *); int rc = csops (getpid(), CS_OPS_ENTITLEMENTS_BLOB, entBlob, &entBlobLen); extern int errno; if (rc) printf("CSOPS RC: %d, %s\n", rc,strerror(errno)); else { printf("RETRIEVED BLOB: %s\n", entBlob->data); } #if 0 if (kr == KERN_SUCCESS) { pid_t amfidPid = 0 ; kern_return_t kr = pid_for_task(tsp, &amfidPid); while (kr == 5) { status("retrying -- amfid - Pid: %d (KR %d)\n", amfidPid, kr); // kr = task_get_special_port (mach_task_self(), TASK_DEBUG_CONTROL_PORT, &tsp); kr = pid_for_task(tsp, &amfidPid); sleep(1); } g_AmfidPort = tsp; } #endif // Got it. Don't want no signals signal(1, SIG_IGN); signal(2, SIG_IGN); signal(15, SIG_IGN); pid_t amfidPid; if (tsp == MACH_PORT_NULL) { debug("Using task_for_pid. Please make sure you've platformized me..\n"); if (getuid()) { error ("I have to run as root\n"); } amfidPid = findPidOfProcess("amfid"); if (!amfidPid) { error ("I can't find amfid!\n"); } g_AmfidPort = MACH_PORT_NULL; kern_return_t kr = task_for_pid (mach_task_self(), amfidPid, &g_AmfidPort); if (kr != KERN_SUCCESS) { error("Can't get amfid's task port\n"); exit(12); } else { status("GOT AMFID (PID %d)'s PORT %d\n", amfidPid, g_AmfidPort); } } castrateAmfid(g_AmfidPort); // Main thread continues to listen for the off chance that amfid will be killed - // yes, people - it can happen - either due to a bug of mine, but more likely // because launchd will be fed up with it being idle. // Anyway, in either case we need to redo this. pid_t pid = amfidPid; // PID to monitor int kq; // The kqueue file descriptor int rc; // collecting return values int done; getKqueueForPid (amfidPid); for (;;) { kq = getKqueueForPid(amfidPid); struct kevent ke; memset(&ke, '\0', sizeof(struct kevent)); // This blocks until an event matching the filter occurs rc = kevent(kq, NULL, 0, &ke, 1, NULL); if (rc >= 0) { // Don't really care about the kevent - we know it's only because AMFI's dead close (kq); status ("AMFI has died!\n"); // TODO: Hook launchd, because it will respawn amfid. Though that's a pain pid_t new_amfidPid = findPidOfProcess("amfid"); while (! new_amfidPid) { sleep(1); new_amfidPid = findPidOfProcess("amfid"); } amfidPid = new_amfidPid; kern_return_t kr = task_for_pid (mach_task_self(), amfidPid, &g_AmfidPort); castrateAmfid (g_AmfidPort); status("*Sigh* Long live amfi - %d... ZZzzz\n", amfidPid); } } // end for } #else int main (int argc, char **argv) { OUT =stderr; unsigned char *h = cdHashOfFile(argv[1], ALGORITHM_SHA256); printf("HERE\n"); if (h) { printf("Hash : 0x%x 0x%x...0x%x\n", h[0], h[1], h[31]); } return 0; } #endif