Ghidra: Decompiler not picking up x0 on arm64/iOS

Created on 30 Dec 2019  路  6Comments  路  Source: NationalSecurityAgency/ghidra

Describe the bug
I am reversing an iOS 13.3 kernelcache with Ghidra 9.1.1. I have noticed that sometimes when a pointer is moved into x0 with an ldr or ldr/adrp, the decompilation doesn't seem to pick up that the value was there. So, say for example we have:

ldr x0, _some_symbol
mov w1, 0x1
... several other registers
bl _some_function

The decompiler should output something like

_some_function(_some_symbol, 1, ...other args);

Instead, we get this

_some_function(0, 1, ...other args);

I'm not sure when this began happening. I'm comparing against an iOS 12 kernelcache and everything seems to be okay there. I feel like I started seeing it somewhere around late iOS 12 or early iOS 13.

To Reproduce
Steps to reproduce the behavior:

  1. Open an iOS 13.3 kernelcache. I'm currently reversing the iPod Touch 7G, which can be extracted from this IPSW.
  2. Perform the normal analysis and let it finish.
  3. If using the same kernelcache, go to address 0xfffffff00717a124. If using another kernelcache, you can look for the string "wqt_min_free," which corresponds to the function waitq_bootstrap, which can be seen here
  4. In the assembly listing you can see that x0 is loaded with the address of the _kernel_map symbol, however, in the disassembly this is just 0.
    13_3

Expected behavior
The function call to _kernel_memory_allocate should have _kernel_map as its first argument instead of 0. The image below, from iOS 12.0 beta 1 on iPhone 6, shows the expected behavior
12beta1

Screenshots
See above

Environment (please complete the following information):

  • OS: Happens on both Windows 10 and macOS 10.15.2
  • Java Version: 11
  • Ghidra Version: 9.1.1

Additional context
I've seen this pop up in several other places, but it's mostly been an annoyance that I haven't had a chance to report. Right now I can't think of any offhand, but if I can find another example I will update this.

I initially thought it might be because the 13.3 iPodTouch kernelcache is just doing an ldr instead of ldr/adrp, but the same thing happens on an iPhone XS 13.3 which does have the ldr/adrp pair.

Most helpful comment

Ah! I think I got it figured out. So it seems like some symbols that used to be in RW- memory (including _kernel_map) were moved to a __DATA_CONST.__const section that is marked read-only at some point between iOS 12 and 13. If I manually go into the Memory Map and mark the section as RW- it picks up the symbol. So what I did was just go into Options->Decompiler->Analysis and untick the Respect readonly flags option.

So not a bug, just Apple being Apple and doing things to annoy me. :) Going to close this since it's not actually a bug. Thanks for looking into this even if it turned out to be nothing.

All 6 comments

could u paste in the pcode for the 2 ldr from those screenshots and also the instruction info's left panel (Instruction Summary) on the bad one

Here's the instruction info for the ldr:

Instruction Summary
-------------------
Mnemonic          : ldr
Number of Operands: 2
Address           : ram:fffffff00717a124
Flow Type         : FALL_THROUGH
Fallthrough       : fffffff00717a128
Delay slot depth  : 0
Hash              : c276ebb8

Input Objects:
   ram:fffffff0070d0aa8
Result Objects:
   x0
Constructor Line #'s:
   instruction(3810), ldr(2970), AddrLoc19(2064), 
   Rt_GPR64(1906)

Byte Length : 4
Instr Bytes : 00100000 01001100 10101011 01011000
Mask        : 00000000 00000000 00000000 11111111
Masked Bytes: 00000000 00000000 00000000 01011000

Instr Context:
   [Instruction context has not been set]

Here's the pcode for the bad version, starting at the ldr and ending at the bl:

    f00717a124 20 4c ab      ldr       x0,_kernel_map
                                                (register, 0x4000, 8) = LOAD (const, 0x1b1, 8), 
    f00717a128 b4 2b 00      adrp      x20,-0xff890f000
                                                (register, 0x40a0, 8) = COPY (const, 0xfffffff00
    f00717a12c 94 82 31      add       x20,x20,#0xc60
                                                (unique, 0x1be0, 8) = COPY (const, 0xc60, 8)
                                                (register, 0x105, 1) = INT_CARRY (register, 0x40
                                                (register, 0x106, 1) = INT_SCARRY (register, 0x4
                                                (unique, 0x1c00, 8) = INT_ADD (register, 0x40a0,
                                                (register, 0x107, 1) = INT_SLESS (unique, 0x1c00
                                                (register, 0x108, 1) = INT_EQUAL (unique, 0x1c00
                                                (register, 0x40a0, 8) = COPY (unique, 0x1c00, 8)
    f00717a130 e4 07 1f      orr       w4,wzr,#0x6
                                                (unique, 0x30, 4) = COPY (const, 0x0, 4)
                                                (unique, 0x5930, 4) = INT_OR (unique, 0x30, 4), 
                                                (register, 0x4020, 8) = INT_ZEXT (unique, 0x5930
    f00717a134 25 02 80      mov       w5,#0x11
                                                (register, 0x4028, 8) = COPY (const, 0x11, 8)
    f00717a138 e1 03 14      mov       x1=>PTR_DAT_fffffff0076f1c60,x20           = fffffff007789738
                                                (register, 0x4008, 8) = COPY (register, 0x40a0, 8)
    f00717a13c e2 03 13      mov       x2,x19
                                                (register, 0x4010, 8) = COPY (register, 0x4098, 8)
    f00717a140 03 00 80      mov       x3,#0x0
                                                (register, 0x4018, 8) = COPY (const, 0x0, 8)
    f00717a144 d8 ff 00      bl        FUN_fffffff0071ba0a4                       undefined FUN_fffffff0071ba0
                                                (register, 0x40f0, 8) = INT_ADD (const, 0xffffff
                                                CALL (ram, 0xfffffff0071ba0a4, 8)

And finally here's the pcode for the good version:

    f0076f1e8c c8 95 00      adrp      x8,-0xff7655000
                                                (register, 0x4040, 8) = COPY (const, 0xfffffff00
    f0076f1e90 00 31 41      ldr       x0,[x8, #0x260]=>_kernel_map               = ??
                                                (unique, 0xc90, 8) = INT_ADD (register, 0x4040, 
                                                (register, 0x4000, 8) = LOAD (const, 0x1b1, 8), 
    f0076f1e94 b4 8d 00      adrp      x20,-0xff775b000
                                                (register, 0x40a0, 8) = COPY (const, 0xfffffff00
    f0076f1e98 94 42 31      add       x20,x20,#0xc50
                                                (unique, 0x1be0, 8) = COPY (const, 0xc50, 8)
                                                (register, 0x105, 1) = INT_CARRY (register, 0x40
                                                (register, 0x106, 1) = INT_SCARRY (register, 0x4
                                                (unique, 0x1c00, 8) = INT_ADD (register, 0x40a0,
                                                (register, 0x107, 1) = INT_SLESS (unique, 0x1c00
                                                (register, 0x108, 1) = INT_EQUAL (unique, 0x1c00
                                                (register, 0x40a0, 8) = COPY (unique, 0x1c00, 8)
    f0076f1e9c e4 07 1f      orr       w4,wzr,#0x6
                                                (unique, 0x30, 4) = COPY (const, 0x0, 4)
                                                (unique, 0x5930, 4) = INT_OR (unique, 0x30, 4), 
                                                (register, 0x4020, 8) = INT_ZEXT (unique, 0x5930
    f0076f1ea0 25 02 80      mov       w5,#0x11
                                                (register, 0x4028, 8) = COPY (const, 0x11, 8)
    f0076f1ea4 e1 03 14      mov       x1=>_global_waitqs,x20                     = fffffff008a0cd98
                                                (register, 0x4008, 8) = COPY (register, 0x40a0, 8)
    f0076f1ea8 e2 03 13      mov       x2,x19
                                                (register, 0x4010, 8) = COPY (register, 0x4098, 8)
    f0076f1eac 03 00 80      mov       x3,#0x0
                                                (register, 0x4018, 8) = COPY (const, 0x0, 8)
    f0076f1eb0 f7 7c 01      bl        _kernel_memory_allocate                    undefined _kernel_memory_all
                                                (register, 0x40f0, 8) = INT_ADD (const, 0xffffff
                                                CALL (ram, 0xfffffff00775128c, 8)

The only thing that looks weird in that instruction from a quick look is the size.ldstr=1 (from the manual means size=8), but is only reading 4... you might try changing that to 8 and restart ghidra, (though I don't think that will change the generated pcode, so may not have any effect)

https://github.com/NationalSecurityAgency/ghidra/blob/cbe5b9e9cae03ce4dea117799afc03e4ad32a488/Ghidra/Processors/AARCH64/data/languages/AARCH64base.sinc#L2973

Nope, that did not seem to change anything.

Ah! I think I got it figured out. So it seems like some symbols that used to be in RW- memory (including _kernel_map) were moved to a __DATA_CONST.__const section that is marked read-only at some point between iOS 12 and 13. If I manually go into the Memory Map and mark the section as RW- it picks up the symbol. So what I did was just go into Options->Decompiler->Analysis and untick the Respect readonly flags option.

So not a bug, just Apple being Apple and doing things to annoy me. :) Going to close this since it's not actually a bug. Thanks for looking into this even if it turned out to be nothing.

Sweet. That same issue bit me last week too, but in my case Ghidra just removed it all as dead code, didn't think about that affecting global reads for arguments

Was this page helpful?
0 / 5 - 0 ratings

Related issues

CalcProgrammer1 picture CalcProgrammer1  路  3Comments

marcushall42 picture marcushall42  路  3Comments

huettenhain picture huettenhain  路  3Comments

chibicitiberiu picture chibicitiberiu  路  3Comments

0x6d696368 picture 0x6d696368  路  3Comments