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:
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_kernel_map symbol, however, in the disassembly this is just 0.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
Screenshots
See above
Environment (please complete the following information):
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.
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)
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
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.__constsection 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 intoOptions->Decompiler->Analysisand untick theRespect readonly flagsoption.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.