提问人:Jorayen 提问时间:10/21/2023 更新时间:10/21/2023 访问量:53
反编译 ARM64 并了解分支目标边界
Decompiling ARM64 and understanding branch targets bounderies
问:
从 arm64 反编译代码时,如何知道无条件分支指令是否是同一函数中标签的分支,而不是其他函数的分支?b
最先进的反编译器如何识别分支目标是仍在函数中还是新函数?他们是否依赖于分支目标的值,并查看它是否落在细分市场中的不同部分?
如果分支目标位于同一部分中,但仍被视为新功能,该怎么办?ARM64 是否有经验法则说,如果分支目标离当前地址太远,则将其视为新边界,从而被视为新函数?就像在 x86 中一样,远跳和短跳有不同的编码,其中短跳可能被视为函数中的标签,而远跳可能不是。TEXT
我可能会补充一点,我现在正在检查的目标二进制文件是用 Objective-C 编写的 Machos,并且我尝试使用 Ghidra 验证我的发现,因此它可能会使用一些更启发式的方法,例如查看跳转目标是否在该部分或该部分中,甚至分析块结构以识别更多过程(尽管从 Ghidra 反编译来看,最后一点似乎没有识别这些结构)?__stubs
__objc_stubs
答:
从 arm64 反编译代码时,如何知道无条件分支指令 b 是否是同一函数中标签的分支,而不是其他函数的分支?
你真的不知道。你充其量只能做出一个有根据的猜测。根据我的经验,即使是最先进的反编译器也非常不擅长这一点。好的允许用户手动覆盖此类检测。
核心问题是在程序集级别没有“功能”的概念。导出到更高级别的语言(如 C)的标签应该符合一定的 ABI,但对于其他任何事情,所有的赌注都是失败的。即使使用导出的内容,如果您遇到恶意作者(考虑:恶意软件),那么他们也可能会选择破坏此合同,以掩盖二进制文件的工作原理。但即使使用非恶意二进制文件,如果有人将 Apple 支持的 arm64 目标用于 arm64 目标,你也会受到伤害。-O3 -flto -moutline
不过,您可以使用一些启发式方法:
x30 是否保存在某个地方?
通常,这将通过指令发生,并随着减少而发生。如果是这种情况,那么您可能会查看同一函数中的分支。如果不是这种情况,那么您不知道这是尾部调用还是同一函数中的跳转。stp x29, x30, [sp, ...]
sp
b
假设:x30 用作链路寄存器。混淆器可以使用其他东西,例如通过函数调用,然后是链接寄存器。这也可以按功能随机分配。
adr x17, ...; b _func
x17
当前地址和跳转目标之间是否有任何函数?
也许你的二进制文件有符号,也许是LC_FUNCTION_STARTS,也许你的反编译已经识别了函数单元,等等。假设:函数的所有基本块彼此相邻,并且不是碎片化和分散的。通常情况就是这样,但同样,作为混淆技术的一部分,这个假设可能会被打破。
跳跃目标是否从任何其他函数跳转到?
如果代码中的其他调用站点已确定属于其他函数,则跳转目标不能属于其中任何一个函数。注意:功能概述,见下一点。
调用的代码是否保持您期望从函数中获得的 ABI 输入和输出?
ABI 违规应该很容易确定。ABI 一致性需要显式寄存器溢出之类的东西来给你信心。但是,如果它符合预期的ABI,那么它很可能是它自己的功能。如果不是,那么可能是跳转到它的函数的一部分,或者是概述的代码。
但这些都不能保证会成功,而且总会有这两种选择都可能的情况。
评论
bl
A
B
B
A
B
B
B
__TEXT.__text
评论