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 built whatever UI/customization/tweaking/modding of the jailbreak you want.

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). The rest is provided by numerous functions - Let the .h file speak for itself:


//
//  jjt.h
//  QiLin
//
//  Created by JL on 12/7/17.
//  Copyright © 2017 NewOSXBook. All rights reserved.

// Revision 3: Added spawnAndPlatformize(),
//             moved to posix_spawn() implementation for exec() family
//             actually exported the set*Reporter functions (formerly ErrorHandler.. etc -
//             "Reporter" is more accurate, because they allow you to propagate messages to
//             a GUI.
//

#ifndef qilin_h
#define qilin_h
#include 
#include 
#include 

char *getMachine (void);
char *getOSVer(void);

// MUST call this first

int initQiLin (mach_port_t TFP0, uint64_t KernelBase);

// System wide effects
//
int remountRootFS (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);

// 1/17/18 - This is super useful
int spawnAndPlatformize (char *AmfidebPath, char *Arg1, char *Arg2, char *Arg3 , char *Arg4, char *Arg5);


int moveFileFromAppDir (char *File, char *Dest);
int disableAutoUpdates(void);

// Code signing

// Will set AMFId's exception ports and thereby disable code signing
//
int castrateAmfid (void);

// Utility function - you probably won't need this directly.
#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)


// Kernel Memory access (wrappers over kernel_task send right)
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);

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

// Process manipulation functions

// Finds the address of struct proc for this pid_t in kernel memory.
uint64_t getProcStructForPid(pid_t);


// Finds the pid of a process given its (base) name. Note this will only
// work on processes you are the owner of (or all, if root) - this is intentional
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);
int unShaiHuludPid (pid_t Whom);

// 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 maintained by me for the time being. 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 the moment, you also need sha1.o and/or sha256.o. This is temporary.
  • 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("\tplatform-application\n"
                           "\ttask_for_pid-allow\n\t\n"                        // Old habits die hard.
                           "\tcom.apple.system-task-ports\n\t\n"               // fix processor_set_tasks on me, why don'tcha?
                           "\tcom.apple.private.xpc.service-configure\n\t"); // I Own you @launchderp :-)
            
    */
            
       myOriginalCredAddr =     ShaiHuludMe(0);     //   /* Escape Sandbox */
        
       FILE * f = fopen("/var/mobile/foo", "w");
        if (!f) {fprintf(stderr,"Still sandboxed\n");}
        else {NSLog(CFSTR("Freeeeeeee\n"));}
        
        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\n", 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\n", 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\n", 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******\n");
             pid_t amfidebPid =execCommand("/jb/amfidebilitate", "", NULL, NULL,NULL,NULL);
            printf("AMFIDEB PID: %d\n", amfidebPid);
            uint64_t amfideb_proc =  getProcStructForPid(amfidebPid);
    
            sleep(2);
    
            if (!amfideb_proc) {
                fprintf(stderr, "can't find amfideb\n");
                return 1;
            }
            printf("amfideb is now 0x%llx - platformizing\n", amfideb_proc);
            // Now do platformize
    
            platformizeProcAtAddr(amfideb_proc);        ShaiHuludProcessAtAddr(amfideb_proc,sdCredAddr);
            
    

    LICENSE

    Johnny's open source license, v0.1
    ----------------------------------
    
    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.
    
      - There are no limitation on nationality, specific people exclusions (i.e. this is AISE ;-), or any other race, 
         color or creed - provided the above are met.
    
    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 :-)