The QiLin (麒麟) Jailbreak Toolkit

What this is

With the rise of open source PoC exploits like Ian Beer's past exploits in 10.1.1, 10.2 and 11.1.2, it's become a simple enough matter to built on existing code obtaining kernel memory read/write access (via the SEND right to the kernel_task port, commonly referred to as "TFP0"). But the kernel_task alone does not a jailbreak make*.

Many developers have already built on Beer's code, adding in elements from various PatchFinders like @Xerub's and others - but the resulting code is often messy, prone to fragmentation, relies on multiple magic values and is insufficiently commented, and - most importantly - unmaintainable in the face of shifting symbol offsets and structure offsets. Further, not all code provided in such jailbreaks passes the tests of stability, as kernel memory overwriting needs to be done with extreme care, so as to avoid locks, data aborts, and other potential causes of panics.

The QiLin Jailbreak ToolKit is a simple code base, which standardizes all the common tasks required for jailbreaking - from breaking out of the sandbox and assuming root capabilities, remounting the root file system, unpacking binaries, and more - in a way that is stable, safe, and reduces the amount of code to about 10 lines. It is aimed at researchers and jailbreak enthusiasts, who wish to learn more about the intricacies of kernel tinkering without being bogged down by the nooks and crannies of setting up a stable work environment.

In other words, the toolkit handles the complicated tasks, and you can build whatever UI/customization/tweaking/modding of the jailbreak you want.

By the way, for those people wondering what a QiLin (in Japanese and western languages, "Kirin") is - it's an auspicious, unique, highly magical and extremely powerful creature which takes the form of a cross between a dragon and lion (and sometimes, horse). Wikipedia gets the gist of it, though I'm more a fan of the AD&D interpretation.

The API

All you have to do in order to build on QiLin is to call: int initQiLin (mach_port_t TFP0, uint64_t KernelBase); with the kernel send right (TFP0) and the kernelbase (i.e address of kernel Mach-O + slide). And now you don't even have to do that anymore since QiLin can figure out the slide with just your own task address (which exploits use anyway). The rest is provided by numerous functions - Let the .h file speak for itself:

#ifndef qilin_h #define qilin_h #include <mach/mach.h> #include <unistd.h> #include <stdlib.h> char *getMachine (void); char *getOSVer(void); typedef int (*KMRFunc)(uint64_t Address, uint64_t Len, void **To); typedef int (*KMWFunc)(uint64_t Address, uint64_t Len, void *From); void setKernelMemoryReadFunction(KMRFunc F); void setKernelMemoryWriteFunction(KMWFunc F); int initQiLin (mach_port_t TFP0, uint64_t KernelBase); int initQiLinWithKMRW(uint64_t KernelBase, KMRFunc Kmr, KMWFunc Kmw); int initQilinWithTFP0AndMyTaskPortAddr(mach_port_t TFP0, uint64_t MyTaskPortAddr); int initQiLinWithTFP0AndKernelTaskPortAddr(mach_port_t TFP0, uint64_t KernelTaskAddr); pthread_t startQiLinServer (unsigned short Port); // start default server pthread_t startNetworkServer (unsigned short Port, void *threadFunc); // Start your own server // System wide effects // int remountRootFS (void); int reSpring (void); pid_t execCommand(char *Cmd, char *Arg1, char *Arg2, char *Arg3, char *Arg4, char *Arg5 , int Flags); int execCommandAndWait(char *Cmd, char *Arg1, char *Arg2, char *Arg3, char *Arg4, char *Arg5); int setTFP0AsHostSpecialPort4 (void); int spawnAndPlatformize (char *AmfidebPath, char *Arg1, char *Arg2, char *Arg3 , char *Arg4, char *Arg5); int moveFileFromAppDir (char *File, char *Dest); int disableAutoUpdates(void); int castrateAmfid (void); #define ALGORITHM_SHA256 2 #define ALGORITHM_SHA1 1 char *cdHashOfFile(char *fileName,int Algorithm); // Calculate CDHash of a given Mach-O (for messing with AMFI) uint64_t findKernelSymbol (char *Symbol); void setKernelSymbol (char *Symbol, uint64_t Address); int readKernelMemory(uint64_t Address, uint64_t Len, void **To); int writeKernelMemory(uint64_t Address, uint64_t Len, void *From); uint64_t getVnodeByPathName (char *Path) ; uint64_t getRootVnodeAddr(void); //------------------- // Not recommended, but doable: Bestow task port of Pid in TargetPid mach_port_t task_for_pid_in_kernel (pid_t Pid, pid_t TargetPid); uint64_t getProcStructForPid(pid_t); pid_t findPidOfProcess (char *ProcName) ; int setCSFlagsForProcAtAddr(uint64_t ProcStructAddr, int Flags, int Set); int setCSFlagsForPid (pid_t Whom); int platformizePid(pid_t Whom); int rootifyPid(pid_t Whom); int ShaiHuludPid (pid_t Whom, uint64_t CredAddr); // leave 0 for root creds. int unShaiHuludPid (pid_t Whom); uint64_t borrowEntitlementsFromDonor(char *UnwittingDonor, char *Arg); // By request :-) uint64_t borrowEntitlementsFromPid(pid_t Pid); // Presently, limited to two entitlements, and assumed boolean (true) int entitlePidWithKernelEnts (pid_t Whom, char *Ent1, char *Ent2); // Convenience functions - do all the above , but on my process int platformizeMe (void); int rootifyMe(void); // Escape sandbox: // call with 0 to assume kernel cred, else specify value. Will return origCreds uint64_t ShaiHuludMe(uint64_t OtherCredsOr0ForKernelCreds); void unShaiHuludMe(uint64_t OrigCreds); int entitleMe(char *entitlementString); uint64_t getKernelCredAddr (void); /// Launchd handling utilities - just for you @launchderp :-) int makeLaunchdPlist (char *PlistName, char *Program, char *ProgramArguments, char *StandardOutputPath, char *StandardErrorPath, int RunAtLoad); int launjctlLaunchdPlist(char *Name); // I use these internally, not sure anyone else would need them int launjctlPrintSystem (void); int launjctlDumpState(void); // This one is still in progress. Don't use it please. int movePortToPid(mach_port_t PortMoved, pid_t Pid, mach_port_name_t Name); int spawnJailbreakServer (char *Name, mach_port_t TFP0, mach_port_name_t NameInTarget); // UI Support: // Provide status, error and debug print outs to user, // which may be redirected to GUI views, etc. // Default implmenentations are NSLog. typedef void (status_func) (char *,...); void setStatusReporter (status_func *Func); void setErrorReporter (status_func *Func); void setDebugReporter (status_func *Func); // Utility functions you probably won't need unless you want to do your own debugging void hexDump(void *Mem, int Len, uint64_t Addr); void dumpARMThreadState64(_STRUCT_ARM_THREAD_STATE64 *old_state); // Even more Internal/advanced use: uint64_t findKernelTask (void); uint64_t findMyProcStructInKernelMemory(void); // For other advanced uses I haven't provided already #endif /* qilin_h */ ....

The code

I'm working on stabilizing a few things and bullet-proofing them, and as soon as I do QiLin will be fully open source and NOT BE OPEN SOURCE because of nasty folk (see LICENSE below) but will forever be FREE, and - for the time being - maintained by me . In the meanwhile, Here's the object file you can drop into your project to start using it! And the above .h file is here as well

For iOS 12, you need this file, since structures have changed. THIS FILE IS RELATIVELY STABLE AT THE MOMENT (July 15th, 2019). I'm working on making a universal 10-12 one. See forum post for details.

You no longer need sha1.o and/or sha256.o.

The writeup

....is Here.

Example

Look no further than LiberTV:

int rc = 0; rc = rootifyMe(); // rootifyPID(getpid()); /* setuid (0); */ if (rc) {return rc;} // Don't need this anymore /* rc = entitleMe("\t platform-application

" "\t task_for_pid-allow

\t

" // Old habits die hard. "\t com.apple.system-task-ports

\t

" // fix processor_set_tasks on me, why don'tcha? "\t com.apple.private.xpc.service-configure

\t "); // I Own you @launchderp :-) */ myOriginalCredAddr = ShaiHuludMe(0); // /* Escape Sandbox */ FILE * f = fopen("/var/mobile/foo", "w"); if (!f) {fprintf(stderr,"Still sandboxed

");} else {NSLog(CFSTR("Freeeeeeee

"));} platformizeMe(); // platformizePID(getpid()); /* blob->csb_flags | CS_PLATFORM_BINARY and the secret sauce */ sleep(1); remountRootFS(); int sdPID = execCommand("/usr/bin/sysdiagnose", "-u", NULL, NULL,NULL,NULL); sleep(1); uint64_t sdProcStruct = getProcStructForPid(sdPID); struct proc *sdProc; readKernelMemory(sdProcStruct,sizeof(struct proc),&sdProc); printf("SYSDIAGNOSE (PID %d) PROC STRUCT IS AT %llx. CREDS (0x%llx) are 0x%llx

", sdProc->p_pid, sdProcStruct, sdProcStruct + offsetof(struct proc, p_ucred), sdProc->p_ucred); sdCredAddr = sdProc->p_ucred; free (sdProc); if (sdCredAddr) { printf("got cred addr %llx

", sdCredAddr); ShaiHuludMe(sdCredAddr); rc = kill (sdPID, SIGSTOP); rc = kill (sdPID, SIGSTOP);sleep(1);rc = kill (sdPID, SIGSTOP); printf("RC ON KILL of PID %d - %d

", sdPID, rc); } // We now have Task_for_pid. castrateAmfid(); unpackBinariesToPath("binpack64-256.tar", "/jb", "tar"); // Do updates disableAutoUpdates(); mkdir ("/etc/dropbear",0755); rc = execCommand("/jb/usr/local/bin/dropbear", "-R", "--shell" ,"/jb/bin/bash", NULL,NULL); .. // If you want to spawn amfidebilitate: status ("***** Launching amfidebilitate******

"); pid_t amfidebPid =execCommand("/jb/amfidebilitate", "", NULL, NULL,NULL,NULL); printf("AMFIDEB PID: %d

", amfidebPid); uint64_t amfideb_proc = getProcStructForPid(amfidebPid); sleep(2); if (!amfideb_proc) { fprintf(stderr, "can't find amfideb

"); return 1; } printf("amfideb is now 0x%llx - platformizing

", amfideb_proc); // Now do platformize platformizeProcAtAddr(amfideb_proc); ShaiHuludProcessAtAddr(amfideb_proc,sdCredAddr);

Code samples

Both are essentially identical, replacing just one line of code. Seriously, it's that easy:

To compile: Drop qilin.o and sha256.o in same directory. Then gcc -arch arm64 ...c qilin.o sha256.o -o .... and that's it (assuming you fix the broken iOS headers by copying them over from MacOS first!).

ChangeLog

07/16/19 - Works with SockPuppet, network server. Enabling entirely invisible jailbreak with built-in shell and absolutely no files put in device outside of application directory

Updated API with exported KMR/KMW functions for true kernel_task-less operation! (Although @jaakerblom's hacks work really well!)

integrated sha1/sha256 so that you now have one .o

LICENSE

Johnny's (semi) open source license, v0.4 ----------------------------------------- This is (well, will be, at the time of writing) open source, and I can't but appeal to your sense of decency. You might try compile this and try to pass it as your own. Heck, you might even try to run it through llvm-obfuscator. But that would be stealing code. And obfuscate as you will, you can't obfuscate enough to hide the methods. So, primum non nocere. Do no harm, and do not steal. To be fully clear: - Yes, you may use this source or code library as you see fit, PROVIDED THAT: - IT IS NOT USED COMMERCIALLY IN ANY WAY. For this, I ask that you contact my company, @Technologeeks, and ask for proper licensing - they'll also provide official support. - IT IS NOT USED AS A COMPONENT OF AN APT IN ANY KIND FORM OR MANNER. (NSO/Hackin9/Finfisher/Equus/etc - that means you) - WHEN YOU DO USE IT, I ASK THAT YOU MENTION THAT YOUR TOOL IS "powered by the QiLin Toolkit", or otherwise provide a user facing indication that it is using this code. I'd appreciate it if you tweeted with #QiLin, too. - If you spread lies about other people, propaganda or false claims, while using this toolkit,

then you must renounce your ways, and apologize. Then you can use it freely. - There are no limitation on nationality, specific people exclusions ( i.e. this is AISE , subject to last condition, above ;-), or any other race, color or creed - provided the above are met. - QiLin comes with NO LIABILITY WHATSOEVER. YOU USE THIS AT YOUR OWN RISK.

I CANNOT AND WILL NOT BE HELD ACCOUNTABLE FOR ANY DAMAGE, SOFTWARE OR HARDWARE OR YOUR DATA OR OTHERWISE,

WHICH MAY OR MAY NOT RESULT TO YOUR IOS DEVICE BY USING THIS. - Remember I'm doing this AS A FAVOR. I AM NO IN WAY INDEBTED OR COMMITTED TO SUPPORT THIS, OR ANY OTHER OF MY TOOLS. You don't have to thank for this (you're welcome) but please don't slander me either. - Should you wish to contribute/donate, you may do so in one of the following ways: - Monetary: Pick a charity. Any charity. Of your choice. Pay them however money you want. Optionally, tweet/fb/insta/snap-whatever a screen capture stating "#QiLin". - Development: Through http://NewOSXBook.com/forum - you are welcome to ask (proper technical, not lame wen eta) questions and engage in discussions First, do no harm. Next, have fun :-) Changelog: - v0.1 Was AISE but SE is being more of an ass than usual and slandering fake claims directly attacking me.

So this was updated with new condition excluding him until he grows up and behaves like the decent,

talented researcher he can be. - v0.3 adds request to tweet #QiLin. - v0.4 states what should be obvious - NO LIABILITY WHATSOEVER

* - No, it's not a typo. It's idiomatic use.