Reputation: 731
loc_10007390C
SUB X8, X29, #-stuff
LDUR X10, [X8,#-0x100] ;
LDR X0, [X10,#0x10] ;
SUB X8, X29, #-var_1E8
LDUR X2, [X8,#-0x100]
STP X0, XZR, [X2]
SUB X8, X29, #-var_1F0
LDUR X3, [X8,#-0x100]
NOP
LDR X8, =__NSConcreteStackBlock
STR X8, [X3]
STR D8, [X3,#8]
ADD X8, X3, #0x10
ADR X9, sub_100092800
NOP
PACIA X9, X8
ADR X8, unk_1001A2658
NOP
STP X9, X8, [X3,#0x10]
LDUR X8, [X29,#var_B8]
STR X8, [X3,#0x20]
LDUR X8, [X29,#var_C0]
STP X8, X10, [X3,#0x28]
LDUR W8, [X29,#anotherStuff]
STR W8, [X3,#0x38]
SUB X8, X29, #-var_290
LDUR W8, [X8,#-0x100]
STR W8, [X3,#0x3C]
MOV W1, #0
MOV W4, #1
BL do_the_dance
TST W0, #0xFF00
B.EQ loc_1000E8730
I'm a little perplexed about what ADR X9, sub_100092800 is doing. It looks like it's loading the address into X9, but does it call call the subroutine as well once it's loaded?
Upvotes: 1
Views: 204
Reputation: 39621
The instruction ADR X9, sub_100092800
loads the address of the symbol sub_100092800
into the X9 register. It does not itself call or otherwise branch to the code located there.
The address loaded into the X9 register is then modified by PACIA instruction as a security measure and then stored in memory by the following STP instruction. There's no indication in your code what then happens with modified value stored in memory, but it's likely at some point it gets loaded from memory, restored to the value it had before the PACIA instruction was used, and then called.
The NOP instruction is a red herring. It's the result of the fact that certain pseudo-instructions like ADRL always generate two real instructions even if it's possible use just one instruction to calculate the same result. The ADR instruction only works with addresses that are within one megabyte of the instruction. For symbols that are farther away two instructions are necessary to calculate the address, ADRP and ADD. At some point the assembler or linker determined that address of sub_100092800
was within 1M and replaced the ADRP and ADD instructions with an ADR and a NOP instruction.
Upvotes: 2
Reputation: 61388
From the listing, there's no call. It loads the PC-relative offset into the register, then does nothing with it. But look at the ADR
/NOP
sequences in a couple of places. It looks as if the NOP's are meant to be patched with a call command (BL
).
Several possibilities here. It could be that the disassembler is misreading the command. Unlikely, but check the machine code encoding, just in case. There could be a relocation directive that would patch those spots during module loading. Finally, there could be a piece of explicit self patching logic in the program itself, introduced specifically to thwart reverse engineers like yourself. The self patching will definitely be elsewhere in the module, to throw you off the scent.
EDIT: the code has a couple of funny tells. I don't know what is __NSConcreteStackBlock
, but it strongly suggests Apple/Cocoa. At the same time, the PACIA
command is specific to the ARM8.3 instruction set, and has to do with the pointer authentication logic for jump integrity protection. To the best of my knowledge, this is the stuff of the upcoming ptrauth/ARM64E initiative by Apple, which is supported by the latest Xcode and the latest iDevices, but not accepted by the App Store yet (as of the time of this writing, 5/18/2020). Pointer authentication is potentially fragile, Apple's official line is "try it in dev for now". My point is, it could be that some kind of function call point postprocessing that's a part of the ptrauth-aware code generation pipeline. I don't know enough about ptrauth to tell. :(
EDIT: yet another possibility. Did the assembly come, by any chance, from disassembling an object file, as opposed to a linked executable? Then the NOPs could be placeholders for cross module calls. That would also explain inconsistent label naming.
Upvotes: 1