Linux arm64 Static Linear Map KASLR Bypass
Tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
概述
针对 arm64 构建的 Android 内核几乎普遍启用了 CONFIG_ARM64_VA_BITS=39(3 级分页)和 CONFIG_MEMORY_HOTPLUG=y。由于内核虚拟空间仅有 512 GiB 可用,Linux 开发者选择将 linear map 锚定在尽可能低的内核虚拟地址(VA),以便将来热插拔的 RAM 可以向上扩展映射。自从提交 1db780bafa4c 之后,arm64 甚至不再尝试随机化该位置,这意味着:
PAGE_OFFSET = 0xffffff8000000000被编译进内核。PHYS_OFFSET来源于导出的memstart_addr,在出厂 Android 设备上实际上是恒定的(今天为 0x80000000)。
因此,每个物理页都有一个确定性的 linear-map 虚拟地址,该地址与 KASLR slide 无关:
#define phys_to_virt(p) (((unsigned long)(p) - 0x80000000UL) | 0xffffff8000000000UL)
如果攻击者能够得知或影响某个物理地址(kernel object、PFN 来自 /proc/pagemap,或甚至是 user-controlled page),他们就能立即知道对应的内核虚拟地址,而不会 leaking 随机化的主内核映射。
读取 memstart_addr 并确认变换
memstart_addr 在 /proc/kallsyms 中导出,可在已 root 的设备上读取,或通过任意 kernel-read primitive 读取。Project Zero 使用 Jann Horn 的 tracing-BPF helper (bpf_arb_read) 将其直接转储:
grep memstart /proc/kallsyms
# ... obtains memstart_addr virtual address
./bpf_arb_read <addr_of_memstart_addr> 8
00 00 00 80 00 00 00 00 这些字节确认了 memstart_addr = 0x80000000。一旦 PAGE_OFFSET 和 PHYS_OFFSET 被固定,arm64 linear map 对任意物理地址就是一个静态仿射变换。
Deriving stable .data addresses on devices with a fixed kernel physbase
许多 Pixel 机型仍然在每次启动时将内核解压到 phys_kernel_base = 0x80010000(可在 /proc/iomem 中看到)。将其与静态变换结合,可为任意数据符号得到跨重启稳定的地址:
- 从
/proc/kallsyms(或精确的vmlinux)记录_stext和目标符号的随机化内核虚拟地址。 - 计算偏移:
offset = sym_virt - _stext_virt。 - 加上静态启动时的 physbase:
phys_sym = 0x80010000 + offset。 - 转换为 linear-map VA:
virt_sym = phys_to_virt(phys_sym)。
示例(在 Pixel 9 上的 modprobe_path):offset = 0x1fe2398,phys = 0x81ff2398,virt = 0xffffff8001ff2398。多次重启后,bpf_arb_read 0xffffff8001ff2398 返回相同字节,因此利用载荷可以将 0xffffff8000010000 视为所有 .data 偏移的合成、非随机基址。
该映射为 RW,因此任何能将攻击者数据放入内核虚拟地址空间的原语(double free、UAF、non-paged heap write 等)都可以在不泄露真实 KASLR slide 的情况下修补 credentials、LSM hooks 或 dispatch tables。唯一的限制是 .text 在 linear map 中被映射为 non-executable,因此 gadget hunting 仍然需要传统的 leak。
PFN spraying when the kernel physbase is randomized
例如 Samsung 等厂商会随机化内核加载 PFN,但静态 linear map 仍可被滥用,因为 PFN 分配并非完全随机:
- Spray user pages:
mmap()大约 5 GiB,触碰每页以触发页面错误将其换入。 - Harvest PFNs:读取每页的
/proc/pagemap(或使用其他 PFN leak)以收集 backing PFN 列表。 - Repeat and profile:重启,重复运行 100×,构建直方图显示每个 PFN 被攻击者控制的频率。有些 PFN 非常热点(在启动后短时间内 100/100 次都被分配)。
- Convert PFN → kernel VA:
phys = (pfn << PAGE_SHIFT) + offset_in_pagevirt = phys_to_virt(phys)
- Forge kernel objects in those pages 并将受害者指针(UAF、overflow 等)引导到已知的 linear-map 地址。
因为 linear map 是 identity-mapped 的 RW 内存,这项技术允许你在真实内核基址移动时,仍能在确定性的 kernel VAs 上放置完全由攻击者控制的数据。利用可以在喷射的页面内预构造伪造的 file_operations、cred 或 refcount 结构,然后将现有的内核指针 pivot 到这些结构上。
Practical workflow for arm64 Android exploits
- Info gathering
- 使用 root 或内核读原语从
/proc/kallsyms导出memstart_addr、_stext和目标符号。 - 在 Pixel 设备上,从
/proc/iomem信任静态 physbase;在其他设备上,准备 PFN profiler。
- Address calculation
- 应用上面的偏移计算,并将得到的 linear-map VAs 缓存到利用中。
- 对于 PFN spraying,保留一个反复落入攻击者内存的“可靠” PFN 列表。
- Exploit integration
- 当可用 arbitrary write 时,直接在预计算地址处修补目标(如
modprobe_path、init_cred或 security ops 数组)。 - 当只有堆损坏时,在已知受控的页面中制作伪造对象,并将受害者指针重定向到那些 linear-map VA。
- Verification
- 在进行破坏性写入之前,使用
bpf_arb_read或任何安全的读原语对计算出的地址进行合理性检查,确认其包含预期字节。
该工作流程消除了 Android 上面向数据的内核利用中的 KASLR-leak 阶段,从而显著降低了利用复杂度并提高了可靠性。
参考资料
Tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
HackTricks

