背景
当前 HVM 已经具备 resident VMM、EPT 4KB split、EPT Rule、EPT Event Ring、CLOAK / HOOK split view,以及多核下的 EPTP-switching 后端。
从底层能力看,现有 EPT Rule 已经可以通过移除页的 R/W/X 权限制造 EPT violation,事件结构里也已经能够记录:
guestPhysicalAddress
guestLinearAddress
guestRip
qualification
CPU group / number
access type
ruleId
timestamp / sequence
但这些能力目前仍然偏向 HVM 自身的验证、tripwire 和底层诊断,还没有形成一个真正面向 ARK 使用场景的功能。
目前最典型的问题是:
Ksword 能告诉用户“SSDT / DriverObject / Callback / 内核代码已经发生异常”,但很多情况下无法继续回答:是谁改的、从哪里改的、第一次修改发生在什么时候。
传统快照式检测通常只能得到:
Before: nt!Foo
After : suspicious.sys+0x1234
却无法证明中间的修改动作到底来自哪里。
HVM/EPT 的价值不应该只是“再实现一种 Hook”,而应该提供传统 R0 驱动很难稳定提供的低层访问归因能力。
因此建议新增 HVM Memory Watch / First-touch Attribution。
第一阶段目标不是实现无限持续、逐条无损的硬件内存追踪器,而是先可靠解决一个非常明确的问题:
监视一个目标页的下一次 R/W/X 访问,在首次命中时记录访问者证据,自动解除该监视,让原指令正常继续,并保持 HVM resident 不退出。
也就是首先把“下一次是谁动了它”做可靠。
一、核心目标
实现一个用户可直接使用的 HVM Watch 功能。
用户可以对指定内核虚拟地址、物理地址或 Ksword 已知内核对象建立:
HVM Watch Read
HVM Watch Write
HVM Watch Execute
第一版统一采用:
Mode = ONESHOT / FIRST_TOUCH
语义必须明确:
安装 Watch;
对目标物理页设置对应 EPT tripwire;
第一次目标访问产生 EPT violation;
HVM 捕获访问现场;
Watch 原子地从 ARMED 进入 TRIGGERED;
自动恢复该页正常 EPT 权限;
完成必要的 EPT invalidation;
原 RIP 不推进;
VMRESUME;
原访问重新执行并正常完成;
resident HVM 继续运行;
Watch 进入 DISARMED,不会继续产生事件,除非用户主动重新 Arm。
最重要的验收语义是:
命中 Watch ≠ HVM 退场。
当前 strict EPT tripwire 命中后通过 devirtualize 来保证 guest 最终能够重新完成访问,这对于底层安全兜底是合理的,但不能作为用户层 Memory Watch 的正常行为。
Memory Watch 命中以后应该只解除这一条 Watch,不应该因为成功抓到一次访问就结束整个 resident monitor。
二、第一版明确要回答的问题
用户建立一次 Watch 后,最终至少应该能够回答:
监视的是什么?
发生了什么访问?
什么时候发生?
在哪一个 CPU 上?
访问的实际 GPA / GLA 是什么?
当时执行到哪个 RIP?
RIP 属于哪个模块?
能否解析到符号?
当时处于哪个地址空间?
HVM 在命中后是否仍然 resident?
一个理想的事件展示例如:
HVM WATCH HIT
Watch:
ID 17
Target \Driver\Foo
Field MajorFunction[IRP_MJ_DEVICE_CONTROL]
Requested VA FFFFF80112345678 Backing GPA 0000000183A45000
Access WRITE
Mode FIRST_TOUCH
Hit:
Time 10:35:21.334
CPU 6
GLA FFFFF80112345678 GPA 0000000183A45678
RIP FFFFF80652C01834 CR3 00000001xxxxxxxx
RSP FFFFxxxx`xxxxxxxx
Attribution:
Module suspicious.sys
Symbol suspicious!ModifyDispatch+0x34
HVM:
Watch State TRIGGERED -> DISARMED
Resident Before 8/8
Resident After 8/8
这里最重要的是:
它才真正回答“是谁动的”。
三、第一阶段不是 Continuous Watch
需要明确控制范围。
P0 不要求:
第一版只保证:
即:
FIRST_TOUCH
FIRST_WRITE
FIRST_READ
FIRST_EXECUTE
原因是当前 HVM 在 nested Hyper-V 环境已经实测没有 Monitor Trap Flag。
传统 persistent EPT watch 的典型实现是:
EPT violation
↓
临时恢复权限
↓
单步一条指令
↓
再次撤销权限
如果依赖 MTF,这条路径在当前 nested Hyper-V 环境不能作为通用方案。
因此本 ISSUE 不应该为了“Continuous”三个字,强行把:
一起塞进第一阶段。
第一版的完成条件就是:
可靠、非破坏性的 One-shot Watch。
Continuous Watch 后续单独评估。
四、监视粒度必须如实展示
EPT 权限是页粒度。
因此第一版 Watch 的真实硬件监视单位必须明确写成:
即使用户从:
DriverObject->MajorFunction[14]
这样的 8-byte 字段创建 Watch,真正安装到 EPT 上的仍然是该字段所在的整个 4KB 页。
UI 必须同时保留两套信息:
Requested Target:
VA FFFFFxxx`xxxx5678
Length 8
Effective Watch:
GPA 00000001`83A45000
Length 4096
不能在 UI 上把 EPT page watch 描述成“8 字节硬件断点”。
命中后如果 CPU 提供有效 GLA,则可以进一步判断:
并显示:
Exact target range: MATCH
或:
Same watched page, outside requested range
但这个判断属于事件归因,不改变第一阶段 EPT 本身仍是 page-granularity 的事实。
五、READ Watch 的架构语义要单独说明
EPT 权限组合存在架构限制。
不能简单假设:
可以作为普通叶项使用。
因此用户请求:
以后,实际生效权限可能同时影响 Write。
协议和 UI 都应该区分:
Requested Access
Effective Access
例如:
Requested: READ
Effective: READ | WRITE
如果硬件不支持需要的 execute-only 组合,也应该显示实际归一化后的结果,而不是假装只监视了用户点选的一项。
六、地址模型
P0 支持
优先支持:
Kernel VA
Physical Address
Kernel VA 创建 Watch 时:
VA
↓
当前页表解析
↓
GPA
↓
EPT 4K Page
Watch 内同时保存:
requestedVirtualAddress
requestedLength
physicalPage
pageOffset
addressResolutionTime
HVM generation
第一版不承诺自动跟踪 VA remap
如果 Watch 建立后:
随后 guest 页表被修改成:
第一版 Watch 仍然监视原来的:
不会声称自己自动跟踪了新的映射。
UI 应该允许重新解析并提示:
Current VA mapping no longer matches armed physical page
这种情况不能静默继续显示成“正在监视该 VA”。
七、建议复用现有 EPT Rule,而不是重新建立一套平行机制
当前已经有:
IOCTL_KSWORD_ARK_HVM_EPT_RULE
IOCTL_KSWORD_ARK_HVM_EVENTS
以及:
EPT_RULE_FLAG_LOG
EPT_RULE_FLAG_ALLOW_ONCE
EPT Rule table
EPT event ring
ruleId
R/W/X mask
因此实现上优先考虑:
给现有 EPT Rule 增加明确的 WATCH_ONCE / FIRST_TOUCH 处置语义。
而不是再新增一个几乎重复的 EPT page-rule subsystem。
例如逻辑上可以增加:
EPT_RULE_ACTION_TRIPWIRE
EPT_RULE_ACTION_WATCH_ONCE
或等价 flag。
但必须保证:
不能把现有 strict tripwire 的行为悄悄改掉。
Watch 应该是一种新的、显式请求的 action。
八、Watch 状态机
建议不要仅依赖 ruleId exists / not exists 表达生命周期。
至少具有:
CREATED
↓
ARMED
↓
TRIGGERED
↓
DISARMED
错误时:
删除后:
多核第一次命中必须通过原子状态转换保证:
只有一个 CPU 成为逻辑上的 first hit owner。
其它 CPU 如果在解除权限传播完成前也进入同一页的 EPT violation:
不应该产生第二个独立的 First-touch 事件;
不应该再次修改 Watch 生命周期;
不应该触发全局 devirtualization;
应按照已经处于 TRIGGERED 状态的规则安全等待/完成恢复路径。
最终用户看到的是:
一个 Watch
一个 first-hit
一个逻辑事件
而不是因为 SMP race 出现若干个看似不同的“第一次”。
九、Watch 命中事件需要补充的现场信息
现有 HVM event 已经有:
sequence
timestamp
GPA
GLA
RIP
qualification
CPU
access
ruleId
建议 Watch Hit 至少再保存:
watchId / ruleId
watchGeneration
guestRSP
guestCR3
requestedAddress
requestedLength
requestedAccess
effectiveAccess
GLA valid
rangeMatch
watchStateAfterHit
其中真正必须在 VM-exit 现场保存的是:
RIP
RSP
CR3
GPA
GLA
qualification
CPU
access
timestamp
不要在 VMX root 里做复杂 Windows 对象解析
VM-exit 热路径里不建议直接解析:
PEPROCESS
ETHREAD
模块路径
PDB symbol
调用栈
这些应该尽量留给 R0 普通上下文或 R3 做 enrichment。
流程建议:
VMX root
↓
记录最小可信现场
↓
event ring
↓
ArkDriverClient
↓
KSword Attribution
↓
Module / Symbol / Process / UI
这样 HVM 负责提供“事实”,Windows-aware 层负责解释事实。
十、RIP 归属必须作为 P0 功能
如果最终只能显示:
那么对普通用户价值仍然有限。
第一版必须至少做到:
RIP
↓
Loaded kernel module range
↓
module.sys + RVA
有符号时进一步显示:
无符号时:
如果 RIP 不属于任何已知 loaded module,则明确显示:
Unknown executable region
并提供:
而不能简单显示 Unknown 后结束。
十一、PID / TID 归因采用 Best-effort,不允许伪造确定性
建议事件记录 guestCR3。
用户态或正常 R0 上下文可以尝试:
得到:
但必须考虑:
KVA Shadow;
System address space;
kernel worker thread;
CR3 reuse;
进程退出;
事件和解析之间存在时间差。
因此显示结果需要区分:
Observed
Resolved
Inferred
Unavailable
例如:
CR3 0x12345000 Observed
PID 4120 Resolved from current process snapshot
TID Unknown
不能因为无法可靠获取 TID 就猜一个出来。
TID / ETHREAD 精确归因可以放到后续阶段。
十二、写入值的语义不要写错
第一版不要承诺:
都是精确的。
EPT violation 发生在导致访问的指令真正完成之前。
因此命中 WRITE 时:
此时可以得到“写之前”的现场,但在没有可靠 post-instruction trap / instruction emulation 的情况下,无法在同一个 VM-exit 中知道该指令最终写进去的完整结果。
所以第一阶段:
可以做
Arm 时保存一个:
命中后允许用户重新读取:
并在 UI 中明确标成:
不应该声称
除非以后有可靠的单指令完成观测机制。
同样,Baseline Snapshot 也需要注明:
它是 Arm 时的内容,不是对 DMA 或其它非 CPU/EPT 可见修改的绝对保证。
十三、UI
HVM 页面新增:
建议表格:
| ID |
Target |
Requested Range |
GPA Page |
Access |
Effective |
Mode |
State |
Hits |
Last RIP |
Module |
操作:
Add Watch
Remove
Re-arm
Clear
Show Event
Open Target Memory
Open Writer Disassembly
Copy Evidence
创建窗口:
Address type:
Kernel VA
Physical
Address:
Length:
Access:
[ ] Read
[ ] Write
[ ] Execute
Mode:
First touch (当前唯一支持)
[Arm]
下方必须显示:
EPT monitoring is page-granular.
Requested range: 8 bytes
Effective monitored page: 4096 bytes
十四、接入现有页面
功能不能永远只停留在 HVM 实验页。
完成底层和统一 UI API 后,建议增加:
之类的统一入口,使已有页面不需要理解 EPT 细节。
首批建议接入:
Memory
右键地址
→ HVM Watch
→ Read
→ Write
→ Execute
Kernel Disassembly
SSDT / SSSDT
选中 entry
→ HVM Watch Write
DriverObject / MajorFunction / FastIo
选中 dispatch entry
→ HVM Watch Write
后续再逐步接:
Callback
IDT
关键 PTE
Token
EPROCESS 字段
其它内核对象
目标是最终让用户不需要知道:
也能使用 HVM。
十五、事件详情页
Watch Hit 建议有独立详情,而不是只往日志里打一行文本。
例如:
Target
Label DriverObject MajorFunction
Requested VA ...
Requested len 8
Physical page ...
Page offset ...
Access WRITE
Effective WRITE
Event
Sequence
Timestamp
CPU
GPA
GLA
GLA valid
Range match
RIP
RSP
CR3
Qualification
Attribution
Module
Module RVA
Symbol
PID
Process image
Confidence
HVM
Watch generation
State
Resident before
Resident after
Event loss status
按钮:
[查看写入者反汇编]
[查看目标内存]
[查看模块]
[重新监视]
[复制证据]
十六、事件丢失必须可见
现有 HVM Event Ring 已经区分:
published
dropped
overwritten
Memory Watch 不应该隐藏这些状态。
如果某个 Watch 已经:
hitCount = 1
state = DISARMED
但对应事件因为 ring contention 没有成功发布,则 UI 应该明确显示:
Watch triggered, event evidence lost
而不是:
否则用户会错误认为目标没有被访问。
因此 Watch 自身至少应保留:
hitCount
lastHitSequence
lastHitStatus
这样 event ring 丢失与“从未命中”能够区分。
十七、与现有 EPT View / Rule 的冲突
P0 不要尝试自动组合复杂规则。
如果目标页已经存在:
CLOAK
HOOK
其它 incompatible EPT Rule
则建立 Watch 时直接返回明确的:
UI 显示:
This physical page is already owned by HVM view/rule #xx.
Remove it before arming Memory Watch.
不要静默覆盖,也不要自动改变现有 view。
同一物理页上的多个 Watch 第一版也可以直接拒绝。
先保证:
one physical page
↓
one clear owner
后续真的有需求再设计规则合并。
十八、HVM 生命周期
Watch 必须绑定:
发生:
STOP_RESIDENT
TEARDOWN
FAULT
RESET
power transition
后,旧 Watch 不允许在下一次 residency 中静默继续生效。
建议:
HVM stop
↓
所有 ARMED Watch -> INVALIDATED
UI 仍可保留历史记录,但需要显示:
重新启动 HVM 后必须显式 Re-arm。
十九、安全边界
该功能是:
观察 / 归因功能。
不是:
安全隔离或不可绕过保护机制。
第一版禁止把 Watch 宣传成:
Memory Protection
Kernel Protection
Anti-rootkit enforcement
Unbypassable guard
它的目标仅仅是:
尤其需要说明:
EPT 是 page-granularity;
DMA 修改不经过 CPU EPT;
VA 映射可能变化;
event ring 可能发生证据丢失;
PID/TID/符号解析属于后处理;
First-touch 不是持续监视;
Watch 不阻止目标访问。
二十、本 ISSUE 明确不包含
以下内容不作为本 ISSUE 的完成条件:
eVMCS;
VPID;
Nested VMX;
VMFUNC 新功能;
HVM 性能调优;
完整 x86 指令模拟器;
无限制 Continuous EPT Watch;
精确 post-instruction New Value;
全量 kernel stack unwind;
强制阻止目标访问;
Anti-PatchGuard / PatchGuard bypass;
把 HVM Watch 做成安全边界。
这些可以独立评估,不应该拖住 First-touch Attribution。
二十一、CLI / 自动化接口
建议同时提供最小 CLI,使测试不依赖 Qt。
例如:
hvm watch add --va FFFFF80112345678 --write --once
hvm watch add --pa 183A45000 --execute --once
hvm watch list
hvm watch events
hvm watch remove 17
hvm watch rearm 17
hvm watch clear
输出必须包含:
watchId
state
requested address
effective physical page
requested/effective access
hitCount
lastHitSequence
这样 VM 靶机自动化测试可以直接判断功能是否真的生效。
二十二、验收测试
1. WRITE First-touch
在测试驱动分配一个稳定的 nonpaged page。
Arm:
随后由测试路径执行一次写入。
要求:
产生一个 Watch Hit;
access 包含 WRITE;
GPA 落在目标物理页;
GLA 有效时指向实际访问地址;
RIP 对应实际测试写入指令;
CPU 编号正确;
Watch 从 ARMED -> TRIGGERED -> DISARMED;
原写入最终成功;
写入后的目标值发生预期变化;
HVM resident processor count 不减少;
不发生 unexpected devirtualization;
第二次写入不会再次产生该 Watch 的事件。
2. READ First-touch
3. EXECUTE First-touch
对测试代码页建立 execute watch;
第一次执行产生事件;
RIP 位于目标页;
自动 disarm 后原函数正常执行;
HVM 保持 resident。
4. Nested Hyper-V
现有已验证的 2-vCPU nested Hyper-V 靶机:
这是 P0 的关键验收项。
5. SMP 同时命中
两个 CPU 尽可能同时访问同一 watched page。
要求:
6. View 冲突
目标页已有 CLOAK / HOOK:
Watch 安装失败;
返回明确 conflict;
原 view 不发生变化。
7. VA 映射变化
Arm 后修改测试 VA 的 backing page:
8. HVM restart
9. Event loss
人为制造 event ring 压力:
二十三、阶段划分
P0:First-touch 可用
完成这一阶段,就已经可以正式把功能称为:
HVM First-touch Attribution
P1:ARK 页面接入
Memory;
Kernel Disassembly;
SSDT / SSSDT;
DriverObject MajorFunction / FastIo;
Callback;
Symbol resolve;
Process best-effort attribution;
Evidence detail / copy / export。
P2:Continuous Watch 可行性研究
单独评估:
MTF
guest TF + intercepted #DB
bounded instruction emulation
其它可靠 re-arm mechanism
只有找到:
不会破坏 guest debug semantics
支持 SMP
nested Hyper-V 可工作
不会制造不可控窗口
的方案后,再增加:
不能为了 UI 上多一个 Continuous 选项而降低正确性要求。
二十四、最终完成定义
这个功能完成的标准不是:
“EPT violation 能打印日志。”
而是用户可以完成下面这个真实工作流:
Ksword 发现某个 DriverObject dispatch 当前正常
↓
用户选择 MajorFunction[IRP_MJ_DEVICE_CONTROL]
↓
右键:HVM Watch Write
↓
继续正常使用系统
↓
某驱动第一次修改所在页
↓
Ksword 捕获 HVM Watch Hit
↓
显示:
时间
CPU
精确 GLA/GPA
RIP
writer module
symbol(如果可用)
CR3 / process context
↓
原写入正常继续
↓
HVM 仍保持 resident
↓
用户点击“查看写入者反汇编”
即:
把 Ksword 从“发现一个东西被改过”,推进到“观察下一次修改,并给出修改者证据”。
这是本 ISSUE 的核心目标。
背景
当前 HVM 已经具备 resident VMM、EPT 4KB split、EPT Rule、EPT Event Ring、CLOAK / HOOK split view,以及多核下的 EPTP-switching 后端。
从底层能力看,现有 EPT Rule 已经可以通过移除页的 R/W/X 权限制造 EPT violation,事件结构里也已经能够记录:
guestPhysicalAddressguestLinearAddressguestRipqualificationCPU group / number
access type
ruleIdtimestamp / sequence
但这些能力目前仍然偏向 HVM 自身的验证、tripwire 和底层诊断,还没有形成一个真正面向 ARK 使用场景的功能。
目前最典型的问题是:
传统快照式检测通常只能得到:
却无法证明中间的修改动作到底来自哪里。
HVM/EPT 的价值不应该只是“再实现一种 Hook”,而应该提供传统 R0 驱动很难稳定提供的低层访问归因能力。
因此建议新增 HVM Memory Watch / First-touch Attribution。
第一阶段目标不是实现无限持续、逐条无损的硬件内存追踪器,而是先可靠解决一个非常明确的问题:
也就是首先把“下一次是谁动了它”做可靠。
一、核心目标
实现一个用户可直接使用的 HVM Watch 功能。
用户可以对指定内核虚拟地址、物理地址或 Ksword 已知内核对象建立:
第一版统一采用:
语义必须明确:
安装 Watch;
对目标物理页设置对应 EPT tripwire;
第一次目标访问产生 EPT violation;
HVM 捕获访问现场;
Watch 原子地从
ARMED进入TRIGGERED;自动恢复该页正常 EPT 权限;
完成必要的 EPT invalidation;
原 RIP 不推进;
VMRESUME;
原访问重新执行并正常完成;
resident HVM 继续运行;
Watch 进入
DISARMED,不会继续产生事件,除非用户主动重新 Arm。最重要的验收语义是:
当前 strict EPT tripwire 命中后通过 devirtualize 来保证 guest 最终能够重新完成访问,这对于底层安全兜底是合理的,但不能作为用户层 Memory Watch 的正常行为。
Memory Watch 命中以后应该只解除这一条 Watch,不应该因为成功抓到一次访问就结束整个 resident monitor。
二、第一版明确要回答的问题
用户建立一次 Watch 后,最终至少应该能够回答:
一个理想的事件展示例如:
这里最重要的是:
它才真正回答“是谁动的”。
三、第一阶段不是 Continuous Watch
需要明确控制范围。
P0 不要求:
第一版只保证:
即:
原因是当前 HVM 在 nested Hyper-V 环境已经实测没有 Monitor Trap Flag。
传统 persistent EPT watch 的典型实现是:
如果依赖 MTF,这条路径在当前 nested Hyper-V 环境不能作为通用方案。
因此本 ISSUE 不应该为了“Continuous”三个字,强行把:
guest TF/#DB 虚拟化;
完整 x86 memory instruction emulation;
新的单步机制;
大规模 decode assist;
一起塞进第一阶段。
第一版的完成条件就是:
Continuous Watch 后续单独评估。
四、监视粒度必须如实展示
EPT 权限是页粒度。
因此第一版 Watch 的真实硬件监视单位必须明确写成:
即使用户从:
这样的 8-byte 字段创建 Watch,真正安装到 EPT 上的仍然是该字段所在的整个 4KB 页。
UI 必须同时保留两套信息:
不能在 UI 上把 EPT page watch 描述成“8 字节硬件断点”。
命中后如果 CPU 提供有效 GLA,则可以进一步判断:
并显示:
或:
但这个判断属于事件归因,不改变第一阶段 EPT 本身仍是 page-granularity 的事实。
五、READ Watch 的架构语义要单独说明
EPT 权限组合存在架构限制。
不能简单假设:
可以作为普通叶项使用。
因此用户请求:
以后,实际生效权限可能同时影响 Write。
协议和 UI 都应该区分:
例如:
如果硬件不支持需要的 execute-only 组合,也应该显示实际归一化后的结果,而不是假装只监视了用户点选的一项。
六、地址模型
P0 支持
优先支持:
Kernel VA 创建 Watch 时:
Watch 内同时保存:
第一版不承诺自动跟踪 VA remap
如果 Watch 建立后:
随后 guest 页表被修改成:
第一版 Watch 仍然监视原来的:
不会声称自己自动跟踪了新的映射。
UI 应该允许重新解析并提示:
这种情况不能静默继续显示成“正在监视该 VA”。
七、建议复用现有 EPT Rule,而不是重新建立一套平行机制
当前已经有:
以及:
因此实现上优先考虑:
而不是再新增一个几乎重复的 EPT page-rule subsystem。
例如逻辑上可以增加:
或等价 flag。
但必须保证:
不能把现有 strict tripwire 的行为悄悄改掉。
Watch 应该是一种新的、显式请求的 action。
八、Watch 状态机
建议不要仅依赖
ruleId exists / not exists表达生命周期。至少具有:
错误时:
删除后:
多核第一次命中必须通过原子状态转换保证:
只有一个 CPU 成为逻辑上的 first hit owner。
其它 CPU 如果在解除权限传播完成前也进入同一页的 EPT violation:
不应该产生第二个独立的 First-touch 事件;
不应该再次修改 Watch 生命周期;
不应该触发全局 devirtualization;
应按照已经处于
TRIGGERED状态的规则安全等待/完成恢复路径。最终用户看到的是:
而不是因为 SMP race 出现若干个看似不同的“第一次”。
九、Watch 命中事件需要补充的现场信息
现有 HVM event 已经有:
建议 Watch Hit 至少再保存:
其中真正必须在 VM-exit 现场保存的是:
不要在 VMX root 里做复杂 Windows 对象解析
VM-exit 热路径里不建议直接解析:
这些应该尽量留给 R0 普通上下文或 R3 做 enrichment。
流程建议:
这样 HVM 负责提供“事实”,Windows-aware 层负责解释事实。
十、RIP 归属必须作为 P0 功能
如果最终只能显示:
那么对普通用户价值仍然有限。
第一版必须至少做到:
有符号时进一步显示:
无符号时:
如果 RIP 不属于任何已知 loaded module,则明确显示:
并提供:
而不能简单显示
Unknown后结束。十一、PID / TID 归因采用 Best-effort,不允许伪造确定性
建议事件记录
guestCR3。用户态或正常 R0 上下文可以尝试:
得到:
但必须考虑:
KVA Shadow;
System address space;
kernel worker thread;
CR3 reuse;
进程退出;
事件和解析之间存在时间差。
因此显示结果需要区分:
例如:
不能因为无法可靠获取 TID 就猜一个出来。
TID / ETHREAD 精确归因可以放到后续阶段。
十二、写入值的语义不要写错
第一版不要承诺:
都是精确的。
EPT violation 发生在导致访问的指令真正完成之前。
因此命中 WRITE 时:
此时可以得到“写之前”的现场,但在没有可靠 post-instruction trap / instruction emulation 的情况下,无法在同一个 VM-exit 中知道该指令最终写进去的完整结果。
所以第一阶段:
可以做
Arm 时保存一个:
命中后允许用户重新读取:
并在 UI 中明确标成:
不应该声称
除非以后有可靠的单指令完成观测机制。
同样,Baseline Snapshot 也需要注明:
十三、UI
HVM 页面新增:
建议表格:
操作:
创建窗口:
下方必须显示:
十四、接入现有页面
功能不能永远只停留在 HVM 实验页。
完成底层和统一 UI API 后,建议增加:
之类的统一入口,使已有页面不需要理解 EPT 细节。
首批建议接入:
Memory
Kernel Disassembly
SSDT / SSSDT
DriverObject / MajorFunction / FastIo
后续再逐步接:
目标是最终让用户不需要知道:
也能使用 HVM。
十五、事件详情页
Watch Hit 建议有独立详情,而不是只往日志里打一行文本。
例如:
按钮:
十六、事件丢失必须可见
现有 HVM Event Ring 已经区分:
Memory Watch 不应该隐藏这些状态。
如果某个 Watch 已经:
但对应事件因为 ring contention 没有成功发布,则 UI 应该明确显示:
而不是:
否则用户会错误认为目标没有被访问。
因此 Watch 自身至少应保留:
这样 event ring 丢失与“从未命中”能够区分。
十七、与现有 EPT View / Rule 的冲突
P0 不要尝试自动组合复杂规则。
如果目标页已经存在:
则建立 Watch 时直接返回明确的:
UI 显示:
不要静默覆盖,也不要自动改变现有 view。
同一物理页上的多个 Watch 第一版也可以直接拒绝。
先保证:
后续真的有需求再设计规则合并。
十八、HVM 生命周期
Watch 必须绑定:
发生:
后,旧 Watch 不允许在下一次 residency 中静默继续生效。
建议:
UI 仍可保留历史记录,但需要显示:
重新启动 HVM 后必须显式 Re-arm。
十九、安全边界
该功能是:
不是:
第一版禁止把 Watch 宣传成:
它的目标仅仅是:
尤其需要说明:
EPT 是 page-granularity;
DMA 修改不经过 CPU EPT;
VA 映射可能变化;
event ring 可能发生证据丢失;
PID/TID/符号解析属于后处理;
First-touch 不是持续监视;
Watch 不阻止目标访问。
二十、本 ISSUE 明确不包含
以下内容不作为本 ISSUE 的完成条件:
eVMCS;
VPID;
Nested VMX;
VMFUNC 新功能;
HVM 性能调优;
完整 x86 指令模拟器;
无限制 Continuous EPT Watch;
精确 post-instruction
New Value;全量 kernel stack unwind;
强制阻止目标访问;
Anti-PatchGuard / PatchGuard bypass;
把 HVM Watch 做成安全边界。
这些可以独立评估,不应该拖住 First-touch Attribution。
二十一、CLI / 自动化接口
建议同时提供最小 CLI,使测试不依赖 Qt。
例如:
输出必须包含:
这样 VM 靶机自动化测试可以直接判断功能是否真的生效。
二十二、验收测试
1. WRITE First-touch
在测试驱动分配一个稳定的 nonpaged page。
Arm:
随后由测试路径执行一次写入。
要求:
产生一个 Watch Hit;
access包含 WRITE;GPA 落在目标物理页;
GLA 有效时指向实际访问地址;
RIP 对应实际测试写入指令;
CPU 编号正确;
Watch 从
ARMED -> TRIGGERED -> DISARMED;原写入最终成功;
写入后的目标值发生预期变化;
HVM resident processor count 不减少;
不发生 unexpected devirtualization;
第二次写入不会再次产生该 Watch 的事件。
2. READ First-touch
第一次读取产生事件;
UI 同时展示 requested / effective access;
原读取最终正常完成;
HVM 保持 resident。
3. EXECUTE First-touch
对测试代码页建立 execute watch;
第一次执行产生事件;
RIP 位于目标页;
自动 disarm 后原函数正常执行;
HVM 保持 resident。
4. Nested Hyper-V
现有已验证的 2-vCPU nested Hyper-V 靶机:
不依赖 Monitor Trap Flag;
WRITE First-touch 可正常 Arm;
第一次写入正常命中;
residentBefore = 2;
residentAfter = 2;
guest 不挂死;
不触发全局 fail-closed。
这是 P0 的关键验收项。
5. SMP 同时命中
两个 CPU 尽可能同时访问同一 watched page。
要求:
无死锁;
无 EPT corruption;
无 unexpected devirtualization;
Watch 只有一个逻辑 first-hit owner;
hitCount/ event 语义确定;最终权限恢复;
两个 CPU 均继续运行。
6. View 冲突
目标页已有 CLOAK / HOOK:
Watch 安装失败;
返回明确 conflict;
原 view 不发生变化。
7. VA 映射变化
Arm 后修改测试 VA 的 backing page:
Watch 仍明确显示自己绑定原 GPA;
UI 能检测当前 VA->GPA 与 Arm 时不同;
不错误声称仍然精确监视当前 VA。
8. HVM restart
STOP_RESIDENT 后 Watch 不继续生效;
下一次 START 不会静默恢复旧 Watch;
UI 将其显示为 stale / invalidated;
用户可以显式 Re-arm。
9. Event loss
人为制造 event ring 压力:
dropped / overwritten 仍可观察;
Watch 命中状态不会因为 event publish 失败而错误保持 ARMED;
能区分“从未命中”和“已命中但详细事件丢失”。
二十三、阶段划分
P0:First-touch 可用
EPT
WATCH_ONCE语义;R/W/X;
命中后自动解除;
原指令继续;
HVM 不退出;
GPA / GLA / RIP / RSP / CR3 / CPU;
RIP -> module;
HVM Memory Watch 页面;
CLI;
2-vCPU nested Hyper-V 验证。
完成这一阶段,就已经可以正式把功能称为:
P1:ARK 页面接入
Memory;
Kernel Disassembly;
SSDT / SSSDT;
DriverObject MajorFunction / FastIo;
Callback;
Symbol resolve;
Process best-effort attribution;
Evidence detail / copy / export。
P2:Continuous Watch 可行性研究
单独评估:
只有找到:
的方案后,再增加:
不能为了 UI 上多一个 Continuous 选项而降低正确性要求。
二十四、最终完成定义
这个功能完成的标准不是:
而是用户可以完成下面这个真实工作流:
即:
这是本 ISSUE 的核心目标。