ADR x9, sub_xxxxxx 是否调用子程序?为什么代码使用ADR/NOP

Does ADR x9, sub_xxxxxx call a subroutine? Why does code use ADR / NOP

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

我对 ADR X9,sub_100092800 在做什么感到有点困惑。看起来它正在将地址加载到X9中,但是加载后它是否也调用了子程序?

从列表中看,没有来电。它将 PC 相对偏移量加载到寄存器中,然后不对其执行任何操作。但是请看几个地方的 ADR/NOP 序列。看起来好像 NOP 是要用调用命令修补的​​ (BL)。

这里有几种可能性。可能是反汇编程序误读了命令。不太可能,但检查机器代码编码,以防万一。可能有一个重定位指令会在模块加载期间修补这些位置。最后,程序本身可能有一段明确的自我修补逻辑,专门用于阻止像你这样的逆向工程师。自我修补肯定会在模块的其他地方,让你闻风丧胆。


编辑:代码中有一些有趣的地方。我不知道什么是__NSConcreteStackBlock,但它强烈建议Apple/Cocoa。同时,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,最新的 Xcode 和最新的 iDevices 支持,但尚未被 App Store 接受(截至撰写本文时,2020 年 5 月 18 日) .指针身份验证可能很脆弱,Apple 的官方线路是 "try it in dev for now"。我的观点是,它可能是某种函数调用点后处理,它是 ptrauth 感知代码生成管道的一部分。我对 ptrauth 的了解还不够多。 :(


编辑:还有另一种可能性。程序集是否偶然来自反汇编目标文件,而不是链接的可执行文件?然后 NOP 可以作为跨模块调用的占位符。这也可以解释不一致的标签命名。

指令ADR X9, sub_100092800加载符号sub_100092800的地址到X9寄存器。它本身不会调用或以其他方式分支到位于那里的代码。

作为安全措施,加载到X9寄存器的地址随后被PACIA指令修改,然后通过以下STP指令存储在内存中。您的代码中没有指示存储在内存中的修改后的值会发生什么,但它很可能在某个时候从内存中加载,恢复到使用 PACIA 指令之前的值,然后被调用。

NOP 指令是一个转移注意力的问题。这是某些伪指令(如 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 和 ADD)的结果。在某些时候,汇编器或链接器确定 sub_100092800 的地址在 1M 以内,并将 ADRP 和 ADD 指令替换为 ADR 和 NOP 指令。