一、项目背景
在现代移动安全领域,攻击者常通过内核驱动 (Kernel Driver) 绕过用户空间的权限限制,直接读取或修改目标进程的内存。这类攻击具有极强的隐蔽性,传统用户态检测手段难以感知内核层的活动。
本文构建的 Demo 设定如下:
- 攻击端 (root):运行于已安装 KPM 内核模块的设备上,通过 hook
prctl 系统调用实现跨进程内存读写。目标:读取防御端进程的内存数据。
- 防御端 (用户层):仅使用普通用户权限,不依赖任何内核模块或 root 权限。目标:检测是否有外部进程通过内核驱动读取了自己的内存。
目标平台环境:
- SoC: Qualcomm Snapdragon (ARMv8-A)
- Kernel: Linux 5.4.210-qgki, 39-bit VA, 3 级页表 (PGD → PMD → PTE),4KB 页面
- 补丁框架:APatch Next 11021
- 编译器:
aarch64-linux-gnu-gcc/g++ (GNU 工具链) 及 aarch64-none-elf-gcc (KPM 交叉编译)
项目涉及的内核与用户空间文件结构如下:
kernel_read_detect/ # 用户态项目(防御端 + 攻击端)
├── defense.c # 防御端综合检测程序(C)
├── cache_test.c # CPU 缓存时序检测独立测试(C)
├── attack.cpp # 攻击端读取程序(C++)
├── kernel_driver.h # 内核驱动 C++ 封装(prctl 跨进程调用)
├── precise_test.sh # 四项测试脚本(baseline/WB/WC/DMA)
├── detailed_test.sh # 逐检测方法详细数据采集脚本
└── Makefile # ARM64 交叉编译
KernelPatch-0.11.1-dev/kpms/
├── prctlhookRWMemory/ # 原始 KPM 模块(access_process_vm,已弃用)
│ ├── Kernel_prctl.c
│ ├── Kernel_prctl.h
│ └── Makefile
└── prctlhookRWMemoryNew/ # 当前 KPM 模块(物理直读 + vmap Device)
├── Kernel_prctl.c # ~790 行,统一 WB/WC/DMA 三条读取路径
├── Kernel_prctl.h
└── Makefile
参考项目:
├── rwprocmem33_20250520/ # ARM64 物理内存读写驱动 (phy_mem.h)
└── vm_rw_detect/ # PMU 检测研究 & perf_event 交叉通道
二、技术架构
2.1 内核驱动接口 (KPM prctl Hook)
KPM (Kernel Patch Module) 是 KernelPatch/APatch 框架下的内核模块系统。本项目使用一个 hook prctl 系统调用的 KPM 模块,通过自定义命令码实现内存读写。这些命令码及其功能如下表所示:
| 命令码 |
值 |
功能 |
PRCTL_MEM_READ |
0x4D454D01 |
内存读取(物理直读 WB,性能优先) |
PRCTL_MEM_WRITE |
0x4D454D02 |
内存写入(物理直写 WB) |
PRCTL_GET_PID |
0x4D454D03 |
按进程名查找 PID |
PRCTL_MEM_READ_SAFE |
0x4D454D04 |
内存读取(WC,绕过 L1/L2) |
PRCTL_MEM_WRITE_SAFE |
0x4D454D05 |
内存写入(WC) |
PRCTL_MEM_READ_DMA |
0x4D454D06 |
内存读取(vmap Device-nGnRnE,绕过全部缓存) |
用户态调用方式如下:
struct mem_operation {
pid_t target_pid; // 目标进程 PID
uint64_t addr; // 目标虚拟地址
void *buffer; // 数据缓冲区(用户态指针)
uint64_t size; // 读写字节数
};
struct mem_operation op = { target_pid, addr, buf, size };
prctl(PRCTL_MEM_READ, (unsigned long)&op, 0, 0, 0);
KPM 在 syscall_hook_demo_init 中通过 fp_hook_syscalln(__NR_prctl, 5, before_prctl, 0, 0) 注册 hook。用户态调用 prctl 时,before_prctl 函数会拦截并处理自定义命令,其他命令则透传给原始 prctl。
2.2 原始实现:access_process_vm 路径
在原始的 prctlhookRWMemory 模块中,PRCTL_MEM_READ 对应的函数虽名为 “phys”,但实际上仍调用 access_process_vm_safe(),如以下代码所示:
// 原始 Kernel_prctl.c 第 160 行 — 名为 phys 实则 access_process_vm
long bytes_read = access_process_vm_safe(task, current_vaddr,
kernel_buffer, chunk_size, 0);
真正手动遍历物理地址的代码 (read_phys_addr_direct) 被整个注释掉了,从未编译进模块。
2.3 access_process_vm 的可检测副作用
access_process_vm 是内核中用于跨进程内存访问的标准函数,它在内部调用 get_user_pages_remote(),其调用逻辑如下:
access_process_vm()
→ get_user_pages_remote(target_mm, addr, ...)
→ 页面 non-present → handle_mm_fault()
→ 分配物理页(零页)
→ 设置 PTE present bit = 1
→ target->min_flt++ ← 目标进程缺页计数 +1
→ 页面已 present → 直接 pin
→ copy_to_user / copy_from_user ← 拷贝数据
核心发现: get_user_pages 在处理 non-present 页面时,会在目标进程的上下文中触发 minor page fault,分配物理页并设置 PTE 的 Present 位。即使后续拷贝失败,这些副作用已经产生。
三、防御端:用户层检测方法
防御端实现了 5 种完全基于用户态权限的检测方法,所有方法均在 defense.c 中实现。其中,Cache Timing 是唯一能检测物理内存直读的手段,另有独立测试程序 cache_test.c。
3.1 方法一:Pagemap Present 检测 (核心方法 ★)
原理: 利用 madvise(MADV_DONTNEED) 将监控页变为 non-present 状态,然后周期性检查 /proc/self/pagemap 的 bit 63。如果 access_process_vm 读取了这些页面,get_user_pages 会触发 handle_mm_fault,使 present bit 变为 1。
实现细节:
// 1. 分配检测页并使其 non-present
void *addr = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
memset(addr, 0xDD, 1); // 先 touch 确保 VMA 有效
madvise(addr, PAGE_SIZE, MADV_DONTNEED); // 回收物理页
// 2. 验证 non-present
int present = page_is_present(addr); // 读 /proc/self/pagemap
// 3. 检测循环(每 5 秒)
for (int i = 0; i < g_detect_page_count; i++) {
if (page_is_present(g_detect_pages[i]) == 1) {
// 检测到外部访问!页面被 access_process_vm 触碰了
detected++;
}
madvise(g_detect_pages[i], PAGE_SIZE, MADV_DONTNEED); // 重置
}
关键时序: 必须是先检查,后清除。早期实现错误地先 clear_refs 再检查,导致攻击留下的证据在检查前被清除。修正后的流程是:先检查 pagemap,发现 present 则告警,然后再 madvise(DONTNEED) 重置,等待数秒后进入下一轮检测。
验证实验: 通过直接测试确认了 access_process_vm 读取 DONTNEED 页面时,即使 prctl 返回失败 (-EINVAL),仍触发了一次 minor fault 并使页面变为 present:
Self page: 0x7e04c95000, present=0
After DONTNEED: present=0
prctl: ret=-1 errno=22 val=0x0000000000000000
min_flt after: delta=1 ← 虽然读失败了,缺页还是发生了
present after read: 1 ← 页面变为 present!
局限性: 需要内核开启 CONFIG_MEM_SOFT_DIRTY,但测试设备上未开启。不过,对 present bit (bit 63) 的检测不需要任何内核配置,通用性更好。
3.2 方法二:PerfEvent 交叉通道检测
原理: /proc/self/stat 中的 min_flt 字段计数了所有归属于该进程的 minor faults,包括外部进程通过 access_process_vm 触发的。而 perf_event(PERF_COUNT_SW_PAGE_FAULTS_MIN) 只在 current == self 时才计数。两者的差值即为外部触发的缺页数。
实现:
// 打开 perf_event 计数器
struct perf_event_attr a;
a.type = PERF_TYPE_SOFTWARE;
a.config = PERF_COUNT_SW_PAGE_FAULTS_MIN;
a.disabled = 0;
int fd = perf_event_open(&a, 0, -1, -1, 0);
// 每轮检测:
unsigned long stat_flt = read_stat_min_flt(); // /proc/self/stat
uint64_t perf_val;
read(fd, &perf_val, sizeof(perf_val)); // perf_event
long external = (stat_flt - last_stat) - (perf_val - last_perf);
if (external > 0) {
// 外部进程在我们的页面上触发了缺页!
}
实测效果: 攻击使用 access_process_vm 时,ext=+37 (37 次外部缺页),pagemap 同时命中 8/8。攻击使用物理直读时,ext=0,完全绕过。
3.3 方法三:金丝雀值完整性校验
定期检查堆和 mmap 区域中的魔数值是否被篡改,用于检测写入攻击。对纯读取攻击无效。
3.4 方法四:PMU 硬件计数器 (ARMv8)
通过 perf_event_open(type=PERF_TYPE_RAW, config=event_code<<8) 监控 ARMv8 PMU 事件。下表列出了部分可监控的事件:

发现:
- Type=7 (ARMv8 PMUv3) 在 task-context 和 system-wide 模式下均失败 (
EACCES),需通过 type=4 (PERF_TYPE_RAW) 访问。
- System-wide (pid=-1) 模式也失败 (
EACCES),只能使用 task-context (pid=0)。
- REMOTE_ACCESS / BUS_ACCESS 存在严重假阳性:即使没有攻击,也会出现 +90 以上的增量,可能来自系统调度或电源管理活动,需调高阈值。
3.5 方法五:CPU 缓存时序检测 (Flush+Reload ★ 物理直读检测)
这是本项目最重要的发现:CPU 缓存时序检测是唯一能检测物理内存直读的用户层方法。
关于此项技术的硬件基础及相关内存映射类型的缓存行为分析,均在安全/渗透/逆向领域有深入探讨。
原理一:ARM 缓存是物理标记的
无论 PIPT 还是 VIPT,标签比较用的都是物理地址。因此,不同虚拟地址 (VA_A 和 VA_B) 映射到同一物理地址 (PA) 时,缓存控制器都能通过物理标签匹配到同一缓存行,这是整个检测方法的硬件基础。
用户态 VA_A (defense) 内核态 VA_B (memremap)
0x738eb18000 0xffffff8000123000
│ │
│ 页表遍历 │ 页表遍历
▼ ▼
┌─────────────────────────────────────────┐
│ 物理地址: 0x1234567000 │
│ ┌─────────────────┐ │
│ │ 4KB 物理页 │ │
│ │ 64 个缓存行 │ │
│ └────────┬────────┘ │
└───────────────────┼─────────────────────┘
│
┌───────────▼───────────┐
│ ARM CPU Cache │
│ ┌─────────────────┐ │
│ │ TAG = PA[47:12] │ │ ← 物理地址匹配
│ │ DATA = 64 bytes │ │
│ │ STATE = Shared │ │
│ └─────────────────┘ │
│ │
│ 不同 VA,同一 PA │
│ → 命中! │
└───────────────────────┘
原理二:KPM 的可缓存内存映射
KPM 模块通过 memremap(phys, 4096, MEMREMAP_WB) 创建临时内核虚拟地址映射。MEMREMAP_WB 映射为 Normal Cacheable Write-Back 类型,CPU 对此类内存的读取会经过 L1/L2 缓存。
ARM64 将内存类型主要分为 Normal 与 Device 两大类,其缓存行为如下:

如果 KPM 使用 MEMREMAP_WC (Write-Combine,不可缓存),则数据不会进入缓存,本检测方法失效。 但 MEMREMAP_WC 在 ARM64 上实际映射为 Device GRE 类型,对普通 RAM 读写性能极差且可能导致对齐异常,实践中极少使用。
原理三:缓存一致性协议 (MESI/MOESI)
ARM 多核 SoC 通过 AMBA CHI 或 CCI 实现跨核缓存一致性。KPM 的 memcpy 读取整页 (64 个缓存行) 后,数据进入 KPM 所在 CPU 核的 L1/L2 缓存。当防御进程在不同核上访问同一物理页时,缓存一致性协议介入,延迟因层级而异:
- 同一 Cluster (共享 L2): ~15-20 cycles
- 不同 Cluster (通过 CCI/CCN): ~40-80 cycles
- 数据完全不在任何缓存 (DRAM): ~200+ cycles
三种命中延迟都远低于 DRAM 访问,这就是缓存时序检测的物理基础。
原理四:DC CIVAC 与 Point of Coherency
ARM 架构定义了多个 "点" 来描述缓存操作的范围。DC CIVAC (Clean + Invalidate to PoC) 指令保证:
- 若缓存行为 Dirty,则写回数据到 PoC。
- 该缓存行在所有核的 L1/L2 中全部失效。
- 操作完成后,该缓存的唯一有效副本在 PoC (L3/DRAM),任何核下次访问都必须从 PoC 获取。
配合 DSB ISH 指令,可确保后续的计时测量在缓存完全清空后进行。
原理五:信号放大——为什么遍历全部 64 个缓存行
cntvct_el0 的典型频率约 19.2 MHz,每个 tick 约 52 ns。若 CPU 主频为 2 GHz,每个 tick 覆盖约 104 个 CPU 周期。单次 L1 命中 (~4 cycles) 约 0.04 ticks,计数值不变,与 DRAM 访问 (~200 cycles,约 1.9 ticks) 难以可靠区分。通过遍历页面全部 64 个缓存行,可将信号放大 64 倍,使不同缓存层级之间的差异从无法区分变为显著可区分 (2-3 vs 31 vs 123 ticks)。
Flush+Reload 完整流程
- Flush (DC CIVAC): 防御进程执行 DC CIVAC 清空探测页的所有缓存行,然后执行 DSB ISH 等待操作完成。
- Wait (
usleep 5ms): 防御进程主动让出 CPU。攻击进程可在此期间运行,KPM 的 memcpy 将数据加载到缓存。
- Measure (
time_page_access): 防御进程遍历页面 64 个缓存行并测量总访问时间。若时间低于设定阈值 (e.g. 50 ticks),则判定为缓存命中,触发告警。
从测量值反推缓存层级
实测数据验证了各缓存层级的理论计算值,如下所示:

ARM64 汇编实现
/* 读取虚拟计数器 (cntvct_el0, ~19.2MHz) */
static inline u64 cntvct(void){
u64 v;
asm volatile("isb\n\tmrs %0, cntvct_el0" : "=r"(v));
return v;
}
/* DC CIVAC: Clean + Invalidate data Cache line to Point of Coherency */
static inline void dc_civac(void *addr){
asm volatile("dc civac, %0" :: "r"(addr) : "memory");
}
/* DSB ISH: 确保缓存操作对 Inner Shareable 域内所有核可见 */
static inline void dsb_ish(void){
asm volatile("dsb ish" ::: "memory");
}
/* 遍历页面全部 64 个缓存行,测量总访问时间 */
static u64 time_page(volatile char *addr){
u64 t0 = cntvct();
for (int off = 0; off < 4096; off += 64) { // 每个缓存行 64 字节
asm volatile("" ::: "memory");
volatile char v = addr[off]; // 访问该缓存行
(void)v;
}
asm volatile("" ::: "memory");
return cntvct() - t0;
}
关键参数:阈值的选择
各缓存层级的性能指标参考下表:

阈值设为 50 ticks:能捕获 L1/L2 命中和跨核缓存一致性传输,同时过滤 L3 和 DRAM 访问。
高频探测循环
为提高捕获概率,每个检测轮次内执行 60 次快速探测(每 5ms 一次),300ms 的总探测窗口保证了至少数次与攻击操作重叠。
攻击端配合:整页读取
关键发现:必须让 KPM 模块读取整页 (4096 字节),而非 8 字节。读取整页会使 memcpy 加载全部 64 个缓存行,极大地提高了防御端的命中率。
实测效果
攻击使用物理直读 (PRCTL_MEM_READ, 整页 4096 字节) 时,缓存时序检测的命中率可达 76% - 80%,效果显著。
四、攻击端:从 access_process_vm 到物理直读
4.1 用户态调用封装
攻击端使用 kernel_driver.h 中的 c_driver 类,通过解析 /proc/<pid>/maps 自动发现目标的匿名内存区域进行读取。相关代码框架可参考 C/C++ 中的相关实现模式。
4.2 原始模块的检测结果
当 KPM 使用 access_process_vm 路径时,99 次读取(792 字节)产生了 37–38 次外部可检测的 minor faults,8/8 的 pagemap 检测页全部命中,传统的用户态检测手段对其非常有效。
4.3 物理直读模块的设计与实现
目标:实现真正的物理内存直接读取,绕过 access_process_vm 及其所有副作用。
4.3.1 ARM64 页表遍历
核心函数 walk_page_table() 手动遍历 ARM64 多级页表。PGD 层级直接读内核 VA,PMD/PTE 层级使用 memremap 映射物理页后读取条目。该实现参考了 rwProcMem33 项目的 get_task_proc_phy_addr 函数,但根据 KPM 环境限制进行了适配,改用手动计算索引和直接提取物理地址。
4.3.2 绕过 __virt_to_phys 不可用的问题
ARM64 上 __virt_to_phys 是内联宏,不作为内核符号导出。解决方案: 完全不依赖 VA→PA 转换。PGD 直接读内核 VA,子级页表物理地址来自 PTE 条目本身(通过 memremap 访问)。
4.3.3 动态探测 mm_struct->pgd 偏移量
由于内核 __randomize_layout (randstruct) 的影响,pgd 指针偏移量可能变化。通过多进程扫描策略,成功找到 pid=1000, pgd_off=0x48, levels=3。
4.3.4 物理直读的完整流程
- 获取目标进程 PGD 内核虚拟地址。
- 调用
walk_page_table() 手动遍历 PGD→PMD→PTE,将 VA 转换为 PA。
- 使用
memremap(phys, 4096, MEMREMAP_WB) 将物理页映射到内核虚拟地址。
- 通过
memcpy 直接拷贝数据,然后 memunmap。
- 最后将数据通过
copy_to_user 传回用户态。
五、实验结果
5.1 四种读取模式与实验设计
KPM 模块演进至 v4.0,支持三种读取路径 (对应三个 prctl 命令码),加上纯防御端基线对照,共四种测试模式。下表总结了各模式与内存类型及缓存行为的关系:

5.2 统一对照测试结果
为确保目标地址一致,攻击端采用精确地址模式,循环反复读取防御端指定的 8 个缓存探测页。
- 基线(无任何读取): 300 次缓存探测全部零命中,无 PMU 假阳性。
- WB 模式(有缓存读取):
memcpy 数据留在 L1/L2,缓存时序检测率 96.7% (58/60 子探测命中),几乎被完全检出。
- WC 模式(无缓存读取,移除 WB 回退后): 数据不进入 L1/L2,仅在 SLC 残留。检测率骤降至 ~0%(仅剩冷启动噪声)。
- DMA 模式 (Device-nGnRnE): Device 事务完全旁路 L1/L2/SLC。全部 5 种用户层检测方法零告警,检测率 0%。
5.3 四种模式检测率总览
测试模式 Pagemap PerfEvent PMU REMOTE 缓存时序(子探测) 综合检测率
──────────────────────────────────────────────────────────────────────────────────
无任何读取 (基线) OK OK OK 0/60 (0%) 0% (基线)
有缓存读取 (WB) OK* OK* OK 58/60 (96.7%) ~97%
无缓存读取 (WC) OK* OK* OK 0/60 (0%) ¹ ~0%¹
DMA读取 (Device) 绕过 绕过 绕过 0/60 (0%) 0%
──────────────────────────────────────────────────────────────────────────────────
* Pagemap/PerfEvent 仅对 access_process_vm 触发的缺页有效; 物理直读不触发缺页故 ext:0
¹ 移除 WB 回退后重新测试结果。之前 61.7% 由回退路径导致, 仅第 0 轮有冷启动噪声
5.4 WC 模式残余命中的微架构分析
经移除 WB 回退代码的对照实验证实,此前 WC 模式 61.7% 的检测率完全由 WB 回退路径导致。当 memremap(MEMREMAP_WC) 失败时,KPM 静默降级为 WB,数据进入 L1/L2 被检出。去除回退后,WC 的 Normal NC 内存虽可能在 SLC 中被缓存,但用户态 Flush+Reload 无法可靠区分 SLC 命中的细微延迟差异,实际与 DMA 一样不可检测。完全消除残余命中的方法可参考下表:

5.5 各版本原理详解
-
v1.0 — access_process_vm:标准内核路径。 带来大量可检测副作用。access_process_vm 的检测面分析如下:

-
v2.0 — 手动页表遍历 + memremap WB:绕过 Pagemap/PerfEvent。 不影响进程缺页计数,但 memcpy 数据仍流经 CPU 缓存。
-
v2.1 — 整页读取 (8字节→4096字节):信号放大。
-
v3.0 — memremap WC:绕过 L1/L2。
-
v3.1 — 移除 WB 回退:消除隐蔽性隐患。
-
v4.0 — vmap Device-nGnRnE:终极规避。 该模式下 PTE 属性分析如下:

所有缓存层级均被绕过,是用户层检测的真空地带。
六、开发过程中的关键难点与解决方案
- 难点一:交叉编译环境配置。 通过
override 指令强制覆盖 make 内置 CC 变量解决。
- 难点二:C 与 C++ 的
prctl 结构体差异。 C 语言调用始终返回 -EINVAL,改用 C++ 封装类正确对齐结构体后解决。
- 难点三:Soft-Dirty 检测的时序 Bug。 修正为先检查后重置,避免在检查前清除攻击证据。
- 难点四:
CONFIG_MEM_SOFT_DIRTY 未开启。 改用 Present bit + MADV_DONTNEED 替代。
- 难点五:缓存时序检测的调试与突破。 历经五代迭代,依次解决了单次读取信号弱、CPU 占用冲突、攻击覆盖不全、跨核阈值误判、PID 传递错误等问题。最终参数如下:

- 难点六:KPM 模块无法访问框架内部变量。 改为手工计算或运行时探测替代。
- 难点七:
__virt_to_phys 不是内核导出符号。 利用内核线性映射特性,直接从 PGD 的内核 VA 读取。
- 难点八:
init 进程无用户空间页表。 扩展为多 PID 扫描验证。
七、技术总结
7.1 检测方法有效性矩阵
不同攻击方式下,各检测方法的表现总结如下:

7.2 核心发现
CPU 缓存时序检测 (Flush+Reload) 是目前最有效的物理内存直读用户层检测手段,其有效性完全取决于攻击端的内存映射类型:
MEMREMAP_WB (可缓存): 缓存时序以高命中率稳定检出。
MEMREMAP_WC (Normal Non-Cacheable): 检测率骤降,仅 PMU REMOTE_ACCESS 存在偶发假阳性。
vmap Device-nGnRnE (DMA 硬件读取): 全部 5 种用户层检测方法均无法检出,攻击侧在用户层检测面上取得完全优势。
- 对抗 DMA 模式,防御需向上迁移至系统级监控,如 IOMMU/SMMU 审计或总线级监控。
7.3 攻防演进路线
v1.0 KPM: access_process_vm (8字节读)
→ Pagemap + PerfEvent 完全检出(检测率 ~95%+)
v2.0 KPM: 物理直读 + 手动页表遍历 + MEMREMAP_WB (8字节读)
→ 绕过 Pagemap + PerfEvent,但缓存时序信号太弱
v2.1 KPM: 物理直读 + 整页读取 (4096字节, MEMREMAP_WB)
→ 绕过 Pagemap + PerfEvent
→ 缓存时序检测以 75-80% 命中率检出 → 攻防新平衡
v3.0 KPM: 物理直读 + MEMREMAP_WC (无缓存, Non-Cacheable)
→ 缓存时序降至 6%(92% 降幅),仅 PMU 可检出
→ 攻击侧首次取得显著优势
v4.0 KPM: 物理直读 + vmap Device-nGnRnE (DMA 硬件读取)
→ 全部 5 种用户层检测方法均无法检出(检测率 ~0%)
→ 攻击侧在用户层检测面上取得完全优势
→ 防御需向上迁移至系统级监控(SMMU/IOMMU 审计、总线监控)
7.4 未来方向
攻击端进一步规避:
- WC 模式页表遍历也用 WC,消除页表页缓存污染。
- 读取后
DC CIVAC 自清洗,主动逐出 SLC 数据。
- 跨 Cluster 攻击,利用独立 SLC 规避缓存一致性嗅探。
防御端检测增强:
- 缩短探测间隔至 1ms,提高命中率。
- 结合 PMU + 缓存时序 + PerfEvent 多模态交叉验证,降低假阳性。
- 在多 CPU 核心同时部署探测页。
系统级监控(对抗 DMA 模式的关键):
- IOMMU/SMMU 审计:捕获异常设备地址空间映射。
- 总线级监控:检测异常 Device 类型总线事务模式。
- 利用 ARMv8.5 MTE (Memory Tagging Extension):进行内存标签验证。
参考资料
- Linux Kernel 5.4 ARM64 页表实现:
arch/arm64/include/asm/pgtable.h
- KernelPatch KPM 框架:
https://github.com/bmax121/KernelPatch
- APatch Next:
https://github.com/bmax121/APatch
- rwProcMem33 物理内存读写驱动:
rwprocmem33_20250520/rwProcMem33-master/rwProcMem33Module/rwProcMem_module/phy_mem.h
- PMU 事件编码:ARM Architecture Reference Manual ARMv8, Chapter D7
access_process_vm 内核实现:mm/memory.c, mm/gup.c
本文档随项目代码一起维护,文件路径:/home/zzz/Desktop/kernel_read_detect/article.md