load the new ios kernelcache in ida, symbolize it, and debug it.


  • when you install iOS on your device, you sign a file who state that you won’t reverse
    engineer the software.
    IMO, this is a broken approach from apple, so lets have a publicly available source code,
    with a (sortof commit log via diffing).
  • i wanted to show that you can use publicly-community avialable tools & a bit of hacking, to achive a reasnoable
    research environment (ofc that getting a fully paid ida is a much better solution).
  • i try to share information that would have saved me a couple of hours / days, when possible.


for help and new information please see the ‘notes’ section at the end of this
page ;)

Whats not working | TODO:

  • handle PAC instructions better (while debugging..).
    for now i implemented a workaround:
    (follow the repo for progress, submit pull req!).
  • auto map memory cpu context, section permissions etc.

What is working?

  • ‘memory breakpoint’ aka access violation.
  • debugging with the diaseambly.
  • debugging c, e.g decompiler output.
  • Tracing, registers, steping, calling functions, etc..


  • download the and install plugins and scripts from:
  • symbolize the kernelcache with jtool2 and the ida scripts (/scripts/

get a symbolized ios kernelcache in ida:
    download ota | ipsw..
    then, for some reason the zip format is not the same as before,
    i had to do the following:
    root:ios13_iphone12 akayn$ sudo port install p7zip
    root:ios13_iphone12 akayn$ 7za x iPhone12,3,iPhone12,5_13.0_17A577_Restore.ipsw
    then locate the kernelcache.release.iphone12
    root:ios13_iphone12 akayn$ git clone
    root:ios13_iphone12 akayn$ python xnu-qemu-arm64-scripts/ kernelcache.release.iphone12 kernelcache.release.asn1decoded
    root:ios13_iphone12 akayn$ python2 xnu-qemu-arm64-scripts/ kernelcache.release.asn1decoded kernelcache.release.iphone12.out
    now download jtool2 from: and run:
    root:ios13_iphone12 akayn$ ./jtool2 -S kernelcache.release.iphone12
    root:ios13_iphone12 akayn$ ./jtool2 --analyze kernelcache.release.iphone12
    now load the kernelcache.release.iphone12.out in ida and wait for the autoanlysis to finish..
    (change line 70 in this file with the symbols file created by jtool2..)
    load script->this script..
    and you got a (sortof) symbolized kernel in ida..
    expected output:
        Symbolizing KernelCache...
        Matched: _memcpy_chk with sub_FFFFFFF007B79114 symbolizing..
        Matched: _ipc_kobject_alloc_port with sub_FFFFFFF007B7B95C symbolizing..
        Matched: _stackshot_init with sub_FFFFFFF007B7BFF4 symbolizing..
        Matched: _do_stackshot with sub_FFFFFFF007B7CF5C symbolizing..
        Matched: _ipc_entry_dealloc with sub_FFFFFFF007B82094 symbolizing..
        Matched: _ipc_importance_init with sub_FFFFFFF007B8695C symbolizing..
        Matched: _ipc_bootstrap with sub_FFFFFFF007B86E08 symbolizing..
        Matched: _ipc_init with sub_FFFFFFF007B870B4 symbolizing..
        Matched: _ipc_mqueue_send with sub_FFFFFFF007B8C500 symbolizing..
        Matched: _ipc_right_destroy with sub_FFFFFFF007B8E60C symbolizing..
        Matched: _hw_lock_lock_contended with sub_FFFFFFF007B8E720 symbolizing..
        Matched: _ipc_port_release_send with sub_FFFFFFF007B93148 symbolizing..
        Matched: _panic with sub_FFFFFFF007B93914 symbolizing..
        Matched and Symbolized 1545 functions.
    there might be some errors, dismiss them..        
    exampled output in ida, assuming you installed the plugins etc..
__TEXT_EXEC.__text:FFFFFFF007F75578 ; void __cdecl kernel_debug(uint32_t debugid, uintptr_t arg1, 
                                                                uintptr_t arg2, uintptr_t arg3, 
                                                                uintptr_t arg4, uintptr_t arg5)
__TEXT_EXEC.__text:FFFFFFF007F75578 _kernel_debug                           ; CODE XREF: sub_FFFFFFF007B844D4+E0p
__TEXT_EXEC.__text:FFFFFFF007F75578                                         ; sub_FFFFFFF007BA78B8+22Cp ...
__TEXT_EXEC.__text:FFFFFFF007F75578                 MRS             X8, TPIDR_EL1
__TEXT_EXEC.__text:FFFFFFF007F7557C                 CBZ             X8, loc_FFFFFFF007F7558C
__TEXT_EXEC.__text:FFFFFFF007F75580                 LDR             X5, [X8,#0x3F8]
__TEXT_EXEC.__text:FFFFFFF007F75584                 MOV             X6, #0
__TEXT_EXEC.__text:FFFFFFF007F75588                 B               sub_FFFFFFF007F75598
__TEXT_EXEC.__text:FFFFFFF007F7558C ; ---------------------------------------------------------------------------
__TEXT_EXEC.__text:FFFFFFF007F7558C loc_FFFFFFF007F7558C                    ; CODE XREF: _kernel_debug+4j
__TEXT_EXEC.__text:FFFFFFF007F7558C                 MOV             X5, #0
__TEXT_EXEC.__text:FFFFFFF007F75590                 MOV             X6, #0
__TEXT_EXEC.__text:FFFFFFF007F75594                 B               sub_FFFFFFF007F75598
__TEXT_EXEC.__text:FFFFFFF007F75594 ; End of function _kernel_debug             

void __cdecl kernel_debug(uint32_t debugid, uintptr_t arg1, 
                          uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5)
  unsigned __int64 v6; // x8

  v6 = _ReadStatusReg(TPIDR_EL1);
  if ( v6 )
    sub_FFFFFFF007F75598(*(_QWORD *)&debugid, arg1, arg2, arg3, arg4, *(_QWORD *)(v6 + 1016), 0LL);
    sub_FFFFFFF007F75598(*(_QWORD *)&debugid, arg1, arg2, arg3, arg4, 0LL, 0LL);
    TODO: support exported structures etc..
          handle duplicate names better..
  • install unicorn:
  • load (my fork to work around pac for now..), into ida.

debugging a function call

go to the diassembly (after loading the uEmu), right click the address of the function.
navigate to the eEmu plugin->edit->(start|reset). it would prompt you to load values to registers-> change the PC to point to the function. regarding arguments:

start of an instruction
function start
current byte have cross-references to it
has immediate value
type: void __cdecl _kernel_debug(uint32_t debugid, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5)
   0: 0004 W0         uint32_t debugid;
   1: 0008 X1         uintptr_t arg1;
   2: 0008 X2         uintptr_t arg2;
   3: 0008 X3         uintptr_t arg3;
   4: 0008 X4         uintptr_t arg4;
   5: 0008 X5         uintptr_t arg5;
  RET                 void;
has typeinfo
the type information is definitive
function stack modification is unknown

  CPU context at [ 0xFFFFFFF007F75578: MRS X8, TPIDR_EL1 ]

   X0: 0x0000000000001337    X17: 0x0000000000000000  
   X1: 0x0001111111111111    X18: 0x0000000000000000  
   X2: 0x0000002222222222    X19: 0x0000000000000000  
   X3: 0x0000000000000041    X20: 0x0000000000000000  
   X4: 0x0000000000000042    X21: 0x0000000000000000  
   X5: 0x00000000FFFFFFFF    X22: 0x0000000000000000  
   X6: 0x0000000000000000    X23: 0x0000000000000000  
   X7: 0x0000000000000000    X24: 0x0000000000000000  
   X8: 0x0000000000000000    X25: 0x0000000000000000  
   X9: 0x0000000000000000    X26: 0x0000000000000000  
  X10: 0x0000000000000000    X27: 0x0000000000000000  
  X11: 0x0000000000000000    X28: 0x0000000000000000  
  X12: 0x0000000000000000     PC: 0xFFFFFFF007F75578  
  X13: 0x0000000000000000     SP: 0xFFFFFFF007F75578  
  X14: 0x0000000000000000     FP: 0x0000000000000000  
  X15: 0x0000000000000000     LR: 0x0000000000000000  
  X16: 0x0000000000000000   NZCV: 0x0000000040000000

load the registers acordingly..
hit run | step..

hit run:
[uEmu]: * TRACE<I> 0xFFFFFFF007F7559C | FF C3 01 D1      | SUB             SP, SP, #0x70
[uEmu]: * TRACE<I> 0xFFFFFFF007F755A0 | FC 6F 01 A9      | STP             X28, X27, [SP,#0x60+var_50]
[uEmu]: * TRACE<I> 0xFFFFFFF007F755A4 | FA 67 02 A9      | STP             X26, X25, [SP,#0x60+var_40]
[uEmu]: * TRACE<I> 0xFFFFFFF007F755A8 | F8 5F 03 A9      | STP             X24, X23, [SP,#0x60+var_30]
[uEmu]: * TRACE<I> 0xFFFFFFF007F755AC | F6 57 04 A9      | STP             X22, X21, [SP,#0x60+var_20]
[uEmu]: * TRACE<I> 0xFFFFFFF007F755B0 | F4 4F 05 A9      | STP             X20, X19, [SP,#0x60+var_10]
[uEmu]: * TRACE<I> 0xFFFFFFF007F755B4 | FD 7B 06 A9      | STP             X29, X30, [SP,#0x60+var_s0]
[uEmu]: * TRACE<I> 0xFFFFFFF007F755B8 | FD 83 01 91      | ADD             X29, SP, #0x60
[uEmu]: * TRACE<I> 0xFFFFFFF007F755BC | F9 03 06 AA      | MOV             X25, X6
[uEmu]: * TRACE<I> 0xFFFFFFF007F755C0 | FB 03 05 AA      | MOV             X27, X5
[uEmu]: * TRACE<I> 0xFFFFFFF007F755C4 | F5 03 04 AA      | MOV             X21, X4
[uEmu]: * TRACE<I> 0xFFFFFFF007F755C8 | F6 03 03 AA      | MOV             X22, X3
[uEmu]: * TRACE<I> 0xFFFFFFF007F755CC | F7 03 02 AA      | MOV             X23, X2
[uEmu]: * TRACE<I> 0xFFFFFFF007F755D0 | F8 03 01 AA      | MOV             X24, X1
[uEmu]: * TRACE<I> 0xFFFFFFF007F755D4 | F3 03 00 AA      | MOV             X19, X0
[uEmu]: * TRACE<I> 0xFFFFFFF007F755D8 | 6A CC 04 94      | BL              sub_FFFFFFF0080A8780
[uEmu]: * TRACE<I> 0xFFFFFFF0080A8780 | 7F 23 03 D5      | PACIBSP
[uEmu]: * TRACE<I> 0xFFFFFFF0080A8784 | FD 7B BF A9      | STP             X29, X30, [SP,#-0x10+var_s0]!
[uEmu]: * TRACE<I> 0xFFFFFFF0080A8788 | FD 03 00 91      | MOV             X29, SP
[uEmu]: * TRACE<I> 0xFFFFFFF0080A878C | 88 D0 38 D5      | MRS             X8, TPIDR_EL1
[uEmu]: * TRACE<I> 0xFFFFFFF0080A8790 | 09 E1 41 F9      | LDR             X9, [X8,#0x3C0]
[uEmu]: ! <M> Missing memory at 0x3c0, data size = 8, data value = 0x0
[uEmu]:   map [3C0:3C7] -> [0:FFF]
[uEmu]: * TRACE<I> 0xFFFFFFF0080A8794 | A9 01 00 B4      | CBZ             X9, loc_FFFFFFF0080A87C8
[uEmu]: * TRACE<I> 0xFFFFFFF0080A87C8 | 88 D0 38 D5      | MRS             X8, TPIDR_EL1
[uEmu]: * TRACE<I> 0xFFFFFFF0080A87CC | 08 BD 41 F9      | LDR             X8, [X8,#0x378]
[uEmu]: * TRACE<I> 0xFFFFFFF0080A87D0 | 00 C5 41 F9      | LDR             X0, [X8,#0x388]
[uEmu]: * TRACE<I> 0xFFFFFFF0080A87D4 | 60 00 00 B4      | CBZ             X0, loc_FFFFFFF0080A87E0
[uEmu]: * TRACE<I> 0xFFFFFFF0080A87E0 | A8 9A 00 D0      | ADRP            X8, #qword_FFFFFFF0093FEC38@PAGE
[uEmu]: * TRACE<I> 0xFFFFFFF0080A87E4 | 00 1D 46 F9      | LDR             X0, [X8,#qword_FFFFFFF0093FEC38@PAGEOFF]
[uEmu]: * TRACE<I> 0xFFFFFFF0080A87E8 | FD 7B C1 A8      | LDP             X29, X30, [SP+var_s0],#0x10
[uEmu]: * TRACE<I> 0xFFFFFFF0080A87EC | FF 0F 5F D6      | RETAB

NOTE that the decompiler window would also step threw instructions..

Credits and links!

  • Alex Hude(!) for the original ida-unicorn bindings-> eEmu:
  • xerub and synactive: the pac plugin:,
  • alpha for the python wrapper scripts for decompression.
  • jtool2:
  • fix arm registers and adds information to every instruction:
  • unicorn engine:
  • ida:


iOS 13.0 (17A577) for iPhone 11 Pro,3/17A577
  • 12.1_13.0.i64:,
    $ openssl dgst -sha256 12.1_13.0.i64
    SHA256(12.1_13.0.i64)= 0c82a24aaaf1a44bb3222dc34cb2204edd1faea34625fad461f5c7ab0d47d5ea
iOS 13.1 (17A844) for iPhone 11 Pro,3/17A844
  • 12.3_13.1.i64:,
    $ openssl dgst -sha256 12.3_13.1.i64
    SHA256(12.3_13.1.i64)= a4f7f1d3203828951333e9cc8ef14bccef758627ecdc413be8225306d0cf261d
iOS 13.1.1 (17A854) for iPhone 11 Pro Max,5/17A854
  • 12.5_13.1.1.i64:,
    $ openssl dgst -sha256 12.5_13.1.1.i64
    SHA256(12.5_13.1.1.i64)= 20d61e59ae9b4fccd54d14476155822577500a59c9691badd91c11871c91e347
iOS 13.1.2 (17A860) for iPhone 11 Pro,3/17A860
  • 12.3_13.1.2.i64:,
    $ openssl dgst -sha256 12.3_13.1.2.i64
    SHA256(12.3_13.1.2.i64)= a4121822fd3e865d6ca0f39557e61e7baf8387edd9030a304da001cd5376d374
iOS (17B5059g) for iPhone 11,1/17B5059g
  • 12.1_13.2b.i64:,
    $ openssl dgst -sha256 12.1_13.2b.i64
    SHA256(12.1_13.2b.i64)= 7801741b4d67f1f45068eb2314293705f4037817c3d8b8f4931d25b3649ea103
iOS (17B5068e) for iPhone 11,1/17B5068e
  • 12.1_13.2b2.i64:,
    $ openssl dgst -sha256 12.1_13.2b2.i64
    SHA256(12.1_13.2b2.i64)= 2035abd2005b04528606e857ada04c2bbfd342c39737d1582b09cf2d654ce97a
iOS (17A878) for iPhone 11,1/17A878
  • 12.1_13.1.3.i64:,
    $ openssl dgst -sha256
    SHA256( 5b76f298e43a19412ef69e836f397aea5f07230dd6f5a6fa176b81be85eaff28


  • 13.0 -> 13.1 -> 13.1.1 changed the logic in ‘check_boolean_entitlement’ and several ‘mpo’ functions- #.
  • if you open 13.1.1, then look for sub_FFFFFFF00810D298.
  • as far as i can tell the 13.1.1 and 13.1.2 kernelcaches are mostly identical.
  • in order to decompress the ios 13.2 beta (1) you would need to (convert lzfse to lzss) run the following:
    $ ./img4 -J -i ../kernelcache.release.iphone12b -o ../kernelcache.release.iphone12b.lz
    afterwards everything is the same..
  • 13.2b2 - killed jtool2, so the idb here is symbolized with diaphora.
  • 13.1.3 - jtool2 is functional again, its not bvx2 decoded so the initial instructions should work the same.