找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

5409

积分

0

好友

760

主题
发表于 2026-6-30 23:08:20 | 查看: 164| 回复: 0

一、项目背景

在现代移动安全领域,攻击者常通过内核驱动 (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 事件。下表列出了部分可监控的事件:

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 两大类,其缓存行为如下:

Normal WB, Normal WT与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 完整流程

  1. Flush (DC CIVAC): 防御进程执行 DC CIVAC 清空探测页的所有缓存行,然后执行 DSB ISH 等待操作完成。
  2. Wait (usleep 5ms): 防御进程主动让出 CPU。攻击进程可在此期间运行,KPM 的 memcpy 将数据加载到缓存。
  3. 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 物理直读的完整流程

  1. 获取目标进程 PGD 内核虚拟地址。
  2. 调用 walk_page_table() 手动遍历 PGD→PMD→PTE,将 VA 转换为 PA。
  3. 使用 memremap(phys, 4096, MEMREMAP_WB) 将物理页映射到内核虚拟地址。
  4. 通过 memcpy 直接拷贝数据,然后 memunmap
  5. 最后将数据通过 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 的检测面分析如下:
    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 属性分析如下:
    Device nGnRnE属性对检测的影响分析表

    所有缓存层级均被绕过,是用户层检测的真空地带。

六、开发过程中的关键难点与解决方案

  • 难点一:交叉编译环境配置。 通过 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




上一篇:AI短剧流水线拆解:四道技术关卡与反直觉的赚钱真相
下一篇:Android 向后兼容机制揭秘:从 Desugaring 到 Project Mainline 的技术演进
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-8-17 00:57 , Processed in 1.282727 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表