Joker is a quick and dirty iOS kernelcache handling utility I've written to assist in my reverse engineering. Apple tries their damn hardest to make reversing the kernel as hard as possible: With every release, more symbols are stripped. The kernelcache, being prelinked, requires less symbols to begin with (and tables in memory, as all LINKEDIT segments, are jettisoned). And - let's not forget - the kernelcache is encrypted. 32-bit kernelcaches can be decrypted thanks to the holy work by @xerub and others, but no 64-bit kernelcache keys exist (publicly), and the only way to "see" the kernel is by dumping it.

This hasn't stopped jailbreakers in the past, and will hopefully not stop us in the future. joker is another humble contribution I can provide to the community, and to all reversers out there. It uses the same machlib as its sibling jtool, and the two in fact can finally play well together (see below)

The tool is primarily designed for iOS (naturally), but since the XNU data structures are pretty much identical, it works pretty well with some switches (-m, -s) on the OS X kernel, as well.

Usage Examples


With no arguments, joker will strive to explain itself:

Zephyr:JTool morpheus$ joker
Usage: joker [-j] [-MmaSsKk] _filename_
 _filename_ should be a decrypted iOS kernelcache, or kernel dump. 

 -m: dump Mach Traps and MIG tables (NEW)
 -a: dump everything
 -k: dump kexts
 -K: kextract [kext_bundle_id_or_name_shown_in_-k|all]
 -S: dump sysctls
 -s: dump UNIX syscalls
 -j: Jtool compatible output (to companion file)

2.2.1 (w/64 kextraction, MIG) Stable version (and kextraction on 64-bit!)
 Tested on ARMv7/s 3.x-9.21b1, and ARM64 8.x/9.21b1

With just a filename, it will provide you with a brief identification of the file in question, by looking at the LC_SOURCE_VERSION. It will also print the sysent table address.

Zephyr:JTool morpheus$ joker ~/Documents/iOS/9b/kernel.9b.4S.decrypted
Source Version:          3216.
This is iOS 9.x, or later
Found iOS 8+ sysent table @3eb684 (Addr: 0x803ec684)


Since 32-bit kernelcaches can be obtained in entirety, before LINKEDIT and PRELINK_INFO are removed, joker can both list as well as extract kexts (what I call 'kextract'):

Zephyr:JTool morpheus$ joker -k ~/Documents/iOS/9b/kernel.9b.4S.decrypted | more
Source Version:          3216.
This is iOS 9.x, or later
Found iOS 8+ sysent table @3eb684 (Addr: 0x803ec684)
Processing kexts
OFFSET: 1095000
0x804ba000: Mach Kernel Pseudoextension (
0x804bc000: Unsupported Pseudoextension (
0x804bf000: Private Pseudoextension (
0x804c5000: I/O Kit Pseudoextension (
0x804df000: Libkern Pseudoextension (
0x810d2000: tlsnke (
0x810da000: AppleDiagnosticDataAccessReadOnly (
0x810dd000: AppleA5IOP (
Got 171 kexts

To extract, simply specify the name of the kext , not the bundle ID (annoying because of spaces, I know - but I'll add that in later)

# First locate kext
Zephyr:JTool morpheus$ joker -k ~/Documents/iOS/9b/kernel.9b.4S.decrypted | grep sandbox
0x80e50000: Seatbelt sandbox policy (
# Now extract
Zephyr:JTool morpheus$ joker -e "Seatbelt sandbox policy" ~/Documents/iOS/9b/kernel.9b.4S.decrypted 
Source Version:          3216.
This is iOS 9.x, or later
Found iOS 8+ sysent table @3eb684 (Addr: 0x803ec684)
Processing kexts
Attempting to kextract Seatbelt sandbox policy
Found Seatbelt sandbox policy at load address: 80e50000, offset: e05000
Extracted Seatbelt sandbox policy
# extracted kext will be dropped to same directory
Zephyr:JTool morpheus$ ls -l Seatbelt\ sandbox\ policy 
-rw-rw-rw-  1 morpheus  staff  499712 Aug  7 16:56 Seatbelt sandbox policy
Zephyr:JTool morpheus$ file !$ 
file Seatbelt\ sandbox\ policy 
Seatbelt sandbox policy: Mach-O kext bundle arm

# BackEndBilly from the forum noted that extraction by name fails on "/" in name,
# (and messy with lots of spaces) so this is now easier, by bundle ID, as of v2.1.1:
bash-3.2# ./joker -k ~/Documents/iOS/9b/kernel.9b.4S.decrypted | grep MobileFil
0x80728000: AppleMobileFileIntegrity (
bash-3.2# ./joker -K  ~/Documents/iOS/9b/kernel.9b.4S.decrypted 
This is a 32-bit kernel from iOS 9.x, or later (3216.
Found iOS 8+ sysent table @3eb684 (Addr: 0x803ec684)
Processing kexts
Attempting to kextract
Found at load address: 80728000, offset: 6dd000
bash-3.2# file Mach-O kext bundle arm

Note that the kernelcache you see in OS X (shoved deep in /System/Library/Caches/ is lzss or lzvn (10.10+) compressed, so this won't work there - it doesn't make sense to implement decompression when you have the free floating kexts in /System/Library/Extensions.

32 and 64-bit (OS X too!)

Using -s will get you a full dump of the __sysctl_set section. This is useful because the sysctl descriptors have plenty of useful kernel addresses - both of the variables behind the sysctl as well as any handlers:

# especially designed to be grep(1) friendly - you can get your sysctl + 6 lines
Zephyr:JTool morpheus$ joker -s ~/Documents/iOS/9b/kernel.9b.4S.decrypted | 
			 	grep -A 6 vnode_enfor
0x80411fc0: security.mac.vnode_enforce	Description: Enforce MAC policy on vnode operations
		Handler: 0x802b5171
		Format: IU
		Parent: 0x80414b90
		Arg1: 80406028
		Arg2: 0x0

Oh, and - this works on OS X kernels too.

Hands down the most useful symbolication is via "-m", which symbolicates Mach traps and UN*X syscalls. joker will automatically suppress enosys and "old" syscalls which don't really do anything, but will nonetheless provide you with the addresses:

Zephyr:JTool morpheus$ joker -a ~/Documents/iOS/9b/kernel.9b.4S.decrypted  | more
Source Version:          3216.
This is iOS 9.x, or later
ARM Exception Vector is at file offset @0xc6000 (Addr: 0x800c7000)
Found iOS 8+ sysent table @3eb684 (Addr: 0x803ec684)
Syscalls at address 0x803ec684
Suppressing enosys (0xffffffff802c14bd) and old (0xffffffff802c14cd)
1. exit                 802a0f48 T
2. fork                 802a5734 T
3. read                 802c14e8 T
4. write                802c1924 T
5. open                 800f5344 T
6. close                80290e68 T
7. wait4                802a288c T
9. link                 800f5c70 T
10. unlink               800f5d24 T
490. netagent_trigger     80152f38 T
491. stack_snapshot_with_config 80287fc4 T
493. grab_pgo_data        80303030 T
Zephyr:JTool morpheus$$ joker -m -m -d  ~/Documents/iOS/9b/13A4254v.bin | more
This is a 64-bit Kernel
Source Version:          3216.
This is iOS 9.x, or later
Syscalls at address 0xffffff8005ef60c0
Sysent offset in file (for patching purposes):  4f20c0
Suppressing enosys (0xffffff8005d73640) and old (0xffffff8005d73620)
1.. exit                 0xffffff8005d49f5c
2.. fork                 0xffffff8005d4f338
3.. read                 0xffffff8005d73668
489.. mremap_encrypted     0xffffff8005d5111c
490.. netagent_trigger     0xffffff8005bac3f4
491.. stack_snapshot_with_config 0xffffff8005d29a98
493.. grab_pgo_data        0xffffff8005dc91b0
# Unexpected bonus - also works on OS X kernels :-)
Zephyr:JTool morpheus$ joker -m /System/Library/Kernels/kernel  | grep mmap
This is a 64-bit Kernel
# Albeit not as useful since most symbols are still exported (and there's the KDK)
197.. mmap                 0xffffff80007c8990
Zephyr:JTool morpheus$ jtool -S /System/Library/Kernels/kernel | grep mmap | grep 8990
ffffff80007c8990 T _mmap

jtool interoperability:

The latest and greatest feature (besides 64-bit) is JTool support - the latter can now work with "companion files", which are simply text files which follow a simple convention (0xaddress:symbol:comment). You can use the new -j to auto-create that file

Zephyr:JTool morpheus$ joker  -j -m ~/Documents/iOS/9b/13A4254v.bin  
This is a 64-bit Kernel
Source Version:          3216.
This is iOS 9.x, or later
Opened companion File: /Users/morpheus/Documents/iOS/9b/13A4254v.bin.ARM64.397D09B8-4B9B-3771-ACEE-7143647BD873
Opening companion file
Syscalls at address 0xffffff8005ef60c0
Sysent offset in file (for patching purposes):  4f20c0
Suppressing enosys (0xffffff8005d73640) and old (0xffffff8005d73620)
Output written to /Users/morpheus/Documents/iOS/9b/13A4254v.bin.ARM64.397D09B8-4B9B-3771-ACEE-7143647BD873 in Jtool-compatible format. Run jtool with --jtooldir . or set JTOOLDIR=
# File format is crude, I'll admit, but it makes it all the more easier for manual editing
Zephyr:JTool morpheus$ head -5 /Users/morpheus/Documents/iOS/9b/13A4254v.bin.ARM64.397D09B8-4B9B-3771-ACEE-7143647BD873 
# We can now use jtool, since the companion file was created for us - and use symbols from it as we disassemble!
Zephyr:JTool morpheus$ jtool -d stack_snapshot_with_config ~/Documents/iOS/9b/13A4254v.bin
Opened companion File: 13A4254v.bin.ARM64.397D09B8-4B9B-3771-ACEE-7143647BD873
Disassembling from file offset 0x325a98, Address 0xffffff8005d29a98  to next symbol
ffffff8005d29a98        STP    X22, X21, [SP,#-48]!
ffffff8005d29a9c        STP    X20, X19, [SP,#16]
ffffff8005d29aa0        STP    X29, X30, [SP,#32]
ffffff8005d29aa4        ADD    X29, SP, #32; R29 = SP + 0x20
ffffff8005d29aa8        SUB    X31, X31, #64
ffffff8005d29aac        MOV    X19, X1
ffffff8005d29ab0        MOV    X20, X0
ffffff8005d29ab4        BL     _kauth_cred_get  ; 0xffffff8005d2f300
ffffff8005d29ab8        MOV    X21, X0
ffffff8005d29abc        ADD    X8, X21, #1; ..R8 = R21 (0x0) + 0x1 = 0x1 
ffffff8005d29ac0        CMP    X8, #1
ffffff8005d29ac4        B.HI   0xffffff8005d29ae0       ; 0xffffff8005d29ae0
ffffff8005d29ac8        ADRP   X8, 390; ->R8 = 0xffffff8005eaf000 
ffffff8005d29acc        ADD    X8, X8, #1478; ..R8 = R8 (0xffffff8005eaf000) + 0x5c6 = 0xffffff8005eaf5c6 "kauth_cred_getuid"
ffffff8005d29ad0        STP    X8, X21, [SP,#0]
ffffff8005d29ad4        ADRP   x0, 390; ->R0 = 0xffffff8005eaf000 
ffffff8005d29ad8        ADD    X0, X0, #1454; ..R0 = R0 (0xffffff8005eaf000) + 0x5ae = 0xffffff8005eaf5ae ""%s: bad credential %p""
ffffff8005d29adc        BL     _panic   ; 0xffffff8005a2b960
; _panic("%s: bad credential %p", arg2, arg3);

This is especially useful since IDA pro 6.5, for all its amazing features (and hefty price tag) provides this helpful notification when loading a kernel dump :

Mach Traps

lso, Mach traps are back - task_for_pid is especially useful (to apply the tfp0 patch, which brings back the kernel_task to userland.

$ ./joker -m  /System/Library/Kernels/kernel.3247
This is a 64-bit kernel from OS X 10.11, or later (3247.
mach_trap_table offset in file/memory (for patching purposes): 0x801900/ffffff8000a01900
Kern invalid should be ffffff8000309000. Ignoring those
 10 _kernelrpc_mach_vm_allocate_trap         ffffff80002dde60 -
 12 _kernelrpc_mach_vm_deallocate_trap       ffffff80002ddf10 -
 14 _kernelrpc_mach_vm_protect_trap          ffffff80002ddfb0 -
 93 mk_timer_arm_trap                        ffffff80002f5410 -
 94 mk_timer_cancel_trap                     ffffff80002f54f0 -
100 iokit_user_client_trap                   ffffff80008e52d0 -
# On OS X, the above are actually exported, so you can
# verify joker's got it right
$ jtool -S !$ | grep ffffff80008e52d0
jtool -S /System/Library/Kernels/kernel.3247 | grep ffffff80008e52d0
ffffff80008e52d0 T _iokit_user_client_trap

MIG Tables

Mach uses messages, and message serialization uses MIG. The Mach Interface Generator generates the boilerplate code required for parsing messages, and - as can be expected - leave easily recognizable patterns all over the place. joker now recognizes the dispatch tables left behind (mig_e), and proceeds to symbolicate the functions as well.

Note that the functions symbolicated are the proxies - the actual functions that do the work are called from these. But it's fairly simple to figure out, because the proxies basically call the message check functions, then the ...internal ones.

This is primarily useful for iOS, of course, but all the symbols are stripped there. So the ..internal pattern can be more readily seen with the OS X xnu, wherein the internal functions are exported (but the mig ones from the tables aren't:

host_priv_subsystem is  @0xffffff8000a02a90!
	0: host_get_boot_info_mig_wrapper: ffffff800032ea60 (400)
_host_subsystem is  @0xffffff8000a030d8!
	0: host_info_mig_wrapper: ffffff8000332300 (200)
	19: mach_vm_page_info_mig_wrapper: ffffff8000338cd0 (4819)
..# Note joker can detected if Apple updates their defs
	Warning: This kernel is newer than joker is (224 < 227)!
mach_port_subsystem is  @0xffffff8000a03558!
	0: mach_port_names_mig_wrapper: ffffff80003346b0 (3200)
task_subsystem is  @0xffffff8000a04728!
	0: task_create_mig_wrapper: ffffff800033fec0 (3400)
	41: task_swap_mach_voucher_mig_wrapper: ffffff8000342c50 (3441)
thread_act_subsystem is  @0xffffff8000a04dd8!
	0: thread_terminate_mig_wrapper: ffffff8000342f30 (3600)
	26: thread_set_mach_voucher_mig_wrapper: ffffff8000344d40 (3626)
	27: thread_swap_mach_voucher_mig_wrapper: ffffff8000344ee0 (3627)

# Unfortunately, jtool doesn't do x86, so use otool:
$ otool -tV /System//Library/Kernels/kernel.3247 |grep -A 100 ffffff8000344ee0  
ffffff8000344ee0        pushq   %rbp
ffffff8000344ee1        movq    %rsp, %rbp
ffffff8000344ee4        pushq   %r15
ffffff8000344ee6        pushq   %r14
ffffff8000344ee8        pushq   %r13
ffffff8000344eea        pushq   %r12
ffffff8000344ee0        pushq   %rbp
ffffff8000344ee1        movq    %rsp, %rbp
ffffff8000344ee4        pushq   %r15
ffffff8000344fe3        movq    %r12, %rsi
ffffff8000344fe6        callq   _thread_swap_mach_voucher

Again, note I use x86_64 here just to illustrate the idea because you can see the internal function is _thread_swap_mach_voucher, which means joker got the MIG dispatch correctly. To get this on iOS, by cross-correlating ARM64 and x86_64 assembly it's trivial to symbolicate the rest..

Version 3.0β1!

With iOS 10 and OS X 12 out, and the kernel segment layout modified, it's time for an improved joker! v3.0 is worthy of a major number increment, because it features integration with my machlib (the engine of disarm and jtool), which allows joker to disassemble in order to find functions! Presently I've implemented matching for the "low hanging fruit" (functions taking in strings), but this can be expanded for complex cases and smart pattern matching.

You might be wondering if joker hasn't lost its raison d'être, with Apple (intentionally/accidentally) providing a decrypted kernelcache. I believe it hasn't - namely:

Decompilation is not the usual functionality you'd want, and is also a bit slow. So try -j and let it take its time. You'll see:

morpheus@Zephyr (~/Documents/iOS/10) % joker -j xnu.3757.j99a                                                 13:00
This is a 64-bit kernel from iOS 10.x, or later (3757.
Opened companion File: xnu.3757.j99a.ARM64.9612A9D5-FA9B-3663-ADD0-C1852BE6674B
Opening companion file
Got 4498 syms
Looking for _secure_monitor ...  Found _secure_monitor at offset 0x7aec
Looking for _start_cpu ...  Found _start_cpu at offset 0x7018
Auto-Disassembling __TEXT_EXEC.__text from 0xfffffff00747c000 to find rest
This may take a little while, but you only need to do this once
Disassembling from file offset 0x78000, Address 0xfffffff00747c000 
GOT PE_Parse_boot_argn: 0xfffffff0078db018
GOT lck_grp_alloc_init: 0xfffffff0074ac1b4
GOT OSKextLog: 0xfffffff00783bf48
GOT lck_grp_init: 0xfffffff0074ac1b4
GOT PE_get_default: 0xfffffff0078db608
GOT __ZN9IOService15publishResourceEPKcP8OSObject: 0xfffffff007874e88
GOT __ZN8OSSymbol17withCStringNoCopyEPKc: 0xfffffff007849c28
GOT __ZN9IOService15publishResourceEPKcP8OSObject: 0xfffffff007849c28
GOT __ZN9IOService15publishResourceEPKcP8OSObject: 0xfffffff007874e88
GOT IOLog! 0xfffffff00785b5ec
ARM Exception Vector is at file offset @0x7b000 (Addr: 0xfffffff00747f000)
Output written to xnu.3757.j99a.ARM64.9612A9D5-FA9B-3663-ADD0-C1852BE6674B in Jtool-compatible format. 
Run jtool with --jtooldir . or set JTOOLDIR=
# Note that now function starts are also auto imported into companion file..
morpheus@Zephyr (~/Documents/iOS/10) % wc -l xnu.3757.j99a.ARM64.9612A9D5-FA9B-3663-ADD0-C1852BE6674B         13:03
   10791 xnu.3757.j99a.ARM64.9612A9D5-FA9B-3663-ADD0-C1852BE6674B
# All these go into companion file, of course, and you can verify those which ARE exported, like IOLog:
morpheus@Zephyr (~/Documents/iOS/10) % jtool -S xnu.3757.j99a| grep IOLog                                     13:04
Opened companion File: ./xnu.3757.j99a.ARM64.9612A9D5-FA9B-3663-ADD0-C1852BE6674B
Loading symbols...
fffffff00785b5ec T _IOLog # Matches!
fffffff00785b680 T _IOLogv

In some cases (notable, PE_parse_boot_argn), joker is more accurate than the actual symbol table, since the exported symbol is a wrapper over the real implementation, which is the one used frequently. If you want more symbols supported, let me know via the website forum, please.

Joker 3.0 also does MACF policies - presently only for Sandbox.kext , as AMFI's is now loaded in code (but *does* do AMFI as well in dumps). This gets the new hooks in Sandbox 570 (which I've highlighted below) and looks like this:

Zephyr:Sierra morpheus$ joker /tmp/ 
Found policy at 0xfffffff0055a05d0
	Policy name: Sandbox
	Full name of policy: Seatbelt sandbox policy
	Flags: 0
	Ops: fffffff0055a0620
		mpo_cred_check_label_update_execve: 0xfffffff00552a34c
                mpo_mount_check_snapshot_create: 0xfffffff005520970
		mpo_check_snapshot_delete: 0xfffffff005520a08
		mpo_vnode_check_clone: 0xfffffff005520aa0
		mpo_proc_check_get_cs_info: 0xfffffff005520c68 # The Hedgehog hook :-)
		mpo_proc_check_set_cs_info: 0xfffffff005520d1c
		mpo_iokit_check_hid_control: 0xfffffff005520d98

Other enhancements in 3.0 are JTOOLDIR=... so you can extract to elsehwere than /tmp, and a couple of really exciting features (like the auto-detection of IOUserClients), but that won't be out until the final version. The 2nd Beta adds detection of secure monitor (SMC) and the ARM exception vector, long missing in 64-bit

I use joker extensively (and exclusively, for lack of IDA) when writing my notes from iOS/OSX, now in its third year, and I hope you find it useful.

Again, if you encounter a bug/need a feature, don't just dismiss this and fire up IDA - tell me, and I'll gladly fix/add. I build my tools around my use cases, which is why I can't get everything

Version 3.0β2!

  • Now gets names of all kexts right, by either method #1 or method #2
  • Fixed that Annoying ID=... bug I had
  • joker now auto-symbolicates stubs in kexts!!! (most) stubs point to exported symbols in the kernel proper, and thanks to AAPL we now have those exports! joker auto follows the disassembly of stubs, e.g.
    fffffff00552fa64        ADRP   X16, 113                 ; ->R16 = 0xfffffff0055a0000 
    fffffff00552fa68        LDR    X16, [X16, #0]   ; -R16 = *(R16 + 0) =  *(0xfffffff0055a0000) = 0xfffffff007843ae4 ... ?..
    fffffff00552fa6c        BR     X16                              ;  0xfffffff007843ae4

    As you can see, machlib can follow the registers, and figure out the addresses. So, if the symbol for what's in X16 is exported, you can find it easily:

    morpheus@Zephyr (~)$ jtool -S ~/Documents/iOS/10/xnu.3705.j99a | grep fffffff007843ae4
    fffffff007843ae4 T _IOFree

    But.. why should you need to do this yourself? joker now does this automatically!

    morpheus@Zephyr (~)$ joker -K ~/Documents/iOS/10/xnu.3705.j99a
    This is a 64-bit kernel from iOS 10.x, or later (3705.
    ARM Exception Vector is at file offset @0x7b000 (Addr: 0xfffffff00747f000)
    Found at load address: 551c000, offset: 1a8c000
    Writing kext out to /tmp/
    Symbolicating stubs for  from off 0x13a64
    # Note that there are still symbols that are not exported by XNU, but ARE linked from stubs
    Unable to resolve kernel symbol at fffffff0040e4e84
    Symbolicated stubs to /tmp/
    morpheus@Zephyr (~)$ cat  /tmp/ 
    morpheus@Zephyr (~)$ jtool -d /tmp/ | grep "^; _panic"
    Opened companion File: /tmp/
    Loading symbols...
    Disassembling from file offset 0x770, Address 0xfffffff00551c770 
    ; _panic.stub("released collection's reference to profile");
    ; _panic.stub("cannot register builtin profile with no name");
    ; _panic.stub("failed to initialize platform sandbox");
    ; _panic.stub("unexpected filter type");
    ; _panic.stub("sfree on invalid allocation at %p"0xfe);
    ; _panic.stub("no profile to evaluate");
    ; _panic.stub("%s: matchlen (%zu) > pathlen (%zu)\n""(null)");
    ; _panic.stub("%s: failed to allocating matching dict""(null)");
    ; _panic.stub("%s: failed to lookup AMFI service\n""(null)");
    ; _panic.stub("failed to allocate OSSymbol for string \"%s\"""(null)");
    Zeng BanXian - this one's for you :-)
  • Version 3.0β3!

    Minor but useful change: If you feed joker an uncompressed (decrypted) kernelcache it will still complain, but will extract the KPP Mach-O at its end for you to /tmp. Still no reliable split-kexts, but I'm almost there (got other KPP-ressing matters to deal with..). Get beta here.

    Version 3.0β3!

    Version 3.1

  • Operates directly on a compressed kernelcache. I used the LZSS.c code from Apple's old iBoot. Also, ARM64 version is back, so you can run it on an iOS10 64-bit device directly!
  • Version 3.2

  • Joker gets in the zone - Mach zones, that is:
    morpheus@Zephyr (~/Documents/Work/JTool) % ./joker -j ~/Downloads/kernelcache.release.n66
    Feeding me a compressed kernelcache, eh? That's fine, now. I can decompress! (Type -dec _file_ if you want to save to file)!
    Compressed Size: 12537772, Uncompressed: 24854528. Unknown (CRC?): 0x95944450, Unknown 1: 0x1
    btw, KPP is at 12538208 (0xbf5160)..And I saved it for you in /tmp/kpp
    Got kernel at 437
    This is a 64-bit kernel from iOS 10.x (b7+), or later (3789.
    Opened companion File: /Users/morpheus/Downloads/kernelcache.release.n66.ARM64.977182E2-2525-386E-8808-457275346A3E
    Opening companion file
    Found _secure_monitor at offset 0x7b0c, Addr: 0xfffffff007087b0c
    Found _start_cpu at offset 0x7018, Addr: 0xfffffff007087018
    Auto-Disassembling __TEXT_EXEC.__text from 0xfffffff007080000 to find rest..
    This may take a little while, but you only need to do this once
    Disassembling from file offset 0x7c000, Address 0xfffffff007080000 
    GOT zinit: 0xfffffff0070e5700
    GOT PE_Parse_boot_argn: 0xfffffff0074e5a40
    GOT zp_factor: 0xfffffff007556340
    GOT PE_Parse_boot_argn: 0xfffffff0074e5a40
    GOT zp_scale: 0xfffffff007556344
    fffffff007585568:vm objects zone
    fffffff0075711f0:vm object hash entries zone
    fffffff007570cd0:maps zone
    fffffff007570b10:Reserved VM map entries zone
    fffffff007570cc0:VM map copies zone
    fffffff007570b18:VM map holes zone
    fffffff00758ad60:pmap zone
    fffffff007588bb0:vm pages array zone
    fffffff007588bb8:vm pages zone
    GOT lck_grp_alloc_init: 0xfffffff0070b23a8
    fffffff007570a90:mem_obj_control zone
    fffffff007570a70:device node pager structures zone
    fffffff007556338:waitq sets zone
    fffffff007537300:ipc spaces zone
    fffffff0075372d0:ipc ports zone
    fffffff0075372d8:ipc port sets zone
    fffffff0075372c0:ipc kmsgs zone
    fffffff007538428:ipc vouchers zone
    fffffff007538420:ipc voucher attr controls zone
    fffffff007537150:ipc task importance zone
    ... you get the idea

    Version 3.99

    - Not 4.0 because I still don't have USerClients working - Updated for iOS 11 β (Still not tested on MacOS 13, but should work) - Sandbox decomp likely broken (haven't tested, but there are more operation names , like dynamic-code-generation...I know, I'll fix it)
    morpheus@Chimera (~/Documents/Work/JTool) %./joker.universal -s ~/Downloads/kernelcache.release.ipad4 
    Feeding me a compressed kernelcache, eh? That's fine, now. I can decompress! (Type -dec _file_ if you want to save to file)!
    Compressed Size: 12693336, Uncompressed: 24969216. Unknown (CRC?): 0xc809f8d1, Unknown 1: 0x1
    btw, KPP is at 12693775 (0xc1b10f)..And I saved it for you in /tmp/kpp
    Got kernel at 440
    This is a 64-bit kernel from iOS 11.x (b1+), or later (4397.
    # Note also - as apparently two new Mach traps
    # KPP updated (haven't checked yet, so not sure it will defeat Luca's bypass, but nice AAPL are trying)
    186.. thread_selfcounts    0xfffffff0071a6c7c
    375.. kevent_id            0xfffffff0073cb0d0
    520.. terminate_with_payload 0xfffffff0073efdac
    521.. abort_with_payload   0xfffffff0073d9410
    522.. necp_session_open    0xfffffff0072465e8
    523.. necp_session_actrion 0xfffffff00724c538
    524.. setattrlistat        0xfffffff0071ae720
    525.. net_qos_guideline    0xfffffff0072d85c4
    526.. fmount               0xfffffff0071cf0a0
    527.. ntp_adjtime          0xfffffff007466ba4
    528.. ntp_gettime          0xfffffff007466a30
    529.. os_fault_with_payload 0xfffffff0073d9468

    Version 4.0

    Ok. So user clients are working :-) Specifically, here's how to use this:

    When kextract™ing an extension, joker will produce a companion file. The major change is that it now also scans __DATA_CONST.__const (where IO objects are) to find plenty of references back into the main kernel. It symbolicates all of those, and this gets you the IO* and OS* methods when you follow up with a jtool --jtooldir ... -d .. on the kext (remember to get the right dir for the companion file). It also detects the common structure with the layout of function pointers , which can then be identified as the IOExternalMethodDispatch struct.

    I DO NOT provide you user client names (yet). But I do provide a simple user_client_x_method_y format, like so:

    grep user_client /tmp/ | head -5

    so you get the idea.

    IF YOU WOULD LIKE TO HELP submit the names of UserClient methods you find through The forum , and future versions of Joker will provide those hard coded. But with 150+ drivers, I can't do this unless people help.


    Right here (Universal: OSX 64, iOS 32/64, and Linux 64)
    Source Caveat: Won't compile without machlib.


    v3.99 - update and minor fix for iOS 11β1
    v3.2 - decompilation now successfully gets all zones by decompiling zinit and tracking the return value to globals
    v3.1 - works on compressed kernelcaches (not iPhone 7 bvx2 (LZFSE), but classic complzss)
    v3.0 - kext support, split kext, MACF Policies, and preliminary sandbox decomp
    -- Minor fix to specify output dir for kextraction, as JOKER_DIR=
    -- validation on memem in case signature can't be found..
    v2.3 - Almost fully integrated with MachLib - Correctly identifies all kexts, even in a dump
    v2.2.1 - kextraction on 64 bit works! Can also ID the kexts, despite absence of __PRELINK_INFO. Use "all" for all kexts.
    v2.1.1 - preliminary kextraction from a 64 bit dump (sans __PRELINK_INFO), and fix for Billy's Bug
    v2.1 - (re)Added Mach trap table, MIG subsystems (+150 symbols!)
    v2.0 - jtool integration (write to companion file)


  • BackEndBilly (for telling me about the kext extraction bug)
  • Xerub
  • John Doe
  • Finger

  • i0n1c
  • License, etc

    Use it at will. You have my blessing, and I won't complain. A nice thank you would be appreciate if you find it useful, as well as feature requests, if you have any.

    joker is open source, so you can see the patterns in the kernelcache it locks on in order to its work. Machlib (its dependency) isn't, but I can license the latter if you're interested.