Skip to content

从 MP2/EasyTool Hook 到 Health Percentage:SM2268XT2 的可观测性与健康度机制

  • 数据时间:2026-06-25 Asia/Shanghai
  • 研究对象:SMI SM2268XT2 Secondary MPTool、EasyTool、MPISP、Health Percentage 与系统块读写路径
  • 报告类型:存储芯片逆向与健康度机制研究博客
  • 资料来源:smi_mp2_patchersmi_nvme_mpisp_patcher 包内源码与文档、IDA 静态分析记录、EasyTool/MPTool hook 实测记录

样本边界:

  • 本文讨论的是 SM2268XT2 Secondary MP2 / EasyTool 这条工作线,不自动外推到 SM2262、SM2267XT、SM2269XT 或其它厂商主控。
  • MP2 hook 与 EasyTool hook 默认定位是可观测、只读取证和受控实验。写入、擦除、Health 修复都必须以目标盘自身 dump、spare/checksum 复现、写后完整 readback 和断电后验证为前提。
  • 文中提到的地址、opcode 和函数名来自当前样本的逆向命名。它们是工程坐标,不是公开 ABI;换固件、换 MPTool 版本或换 NAND 后必须重新验证。

核心结论

这轮工程的重点已经越过“再做一个 Clear SMART 补丁”,转向把 SMI NVMe 设备现场拆成三层可审计链路:

工具形态作用边界
MP2 host hooksmi_hook.dll / smi_hook_launcher.exe观察 Secondary MPTool 的 phase、runmode、vendor command、buffer、MessageBox、进程退出默认 observe-only,不改返回值,不吞失败
MPISP patcherpatched MPISP2268XT2.bin + host trigger在 MPISP window 内触发自定义 payload,验证 RAM source 或后续设备侧路径host trigger 只负责触发,Health 语义必须在 MPISP/ISP 侧成立
EasyTool EZT hookezt_hook.dll + loopback JSON-RPC/MCP复用 EasyTool 官方 Flash RW helper,自动化 listSysBlocks / readBlock / command capture当前主线只使用只读 dump;写/擦需要完整备份、校验与授权

Health Percentage 的研究也已经从“SMART byte 5 是哪个字段”推进到“谁在生成这个百分比”。当前结论很克制:0x1028504C 确实是 SMART rebuild 会读取的参数输入,但它不是当前 Percentage Used = 3% 的充分持久来源。更强的闭环来自 C2/0x53 的 erase count 表、D1 telemetry 和 endurance PE 基准:

text
C2/0x53[0x0000..0x073f]  = 全盘 data block 16-bit erase count 表
C2/0x53[0x3000..0x300a]  = 主 ISP 按区域现场计算的 6 个 PE/EC summary

avgTLC = 23
avgSLC/MLC = 285
maxTLC = 38
minTLC = 9
maxSLC/MLC = 286
minSLC/MLC = 281

InfoBlk.bin + 0x338 = 10000
ceil(285 * 100 / 10000) = 3
ceil(286 * 100 / 10000) = 3

这解释了为什么原生 Clear SMART 返回成功,CrystalDiskInfo 仍显示已用寿命 3%。普通 SMART counter 被清了,但 EC / PE / endurance 来源没有变;下一次 Get Log Page 或 SMART rebuild 仍会把旧的磨损状态带回来。

MP2 Hook:先把黑箱流程变成事件流

Secondary MPTool 的问题在于 UI 上只显示“Update MPInfo”“Back to ISP mode fail”一类结果,真正关键的状态藏在 host wrapper、vendor command 和设备 runmode 之间。MP2 hook 的第一目标就是把这些瞬间落成事件,而不是靠弹窗猜测。

统一 hook runtime 的输出是三类文件:

text
events.jsonl
summary.json
buffers/*.bin

事件模型按 hostmpispispuiprocess 分层,记录 phase、call site、opcode、CDW、runmode、返回值和动作。第一版 hook 覆盖 ExitProcessTerminateProcessMessageBoxA/W、通用 vendor passthrough sub_481D40 和 runmode/status read sub_4838B0。当 inline 观察打开时,buffer dump 会记录 MPISP download chunk、MPISP debug/status readback、SysBlk flash R/W payload、NVMe SMART / D1 telemetry return buffer。

这件事的价值很直接:过去“程序走一会直接退出”只能截图,现在可以问:

  • 最后一条 vendor command 是什么?
  • 设备当时在 ISP mode 还是 MPISP mode?
  • host 下载的 MPISP chunk hash 是否等于包内当前 MPISP?
  • 失败发生在 C1/0x99 SSDINFO route、C2/0x88 debug/status readback,还是 reset/back-to-ISP?
  • 进程退出前有没有 MessageBox、异常或 caller RVA?

MP2 hook 的默认目标不是绕过失败。它默认不修改返回值、不跳过 call、不注入命令。override 只能作为单独 profile 下的实验策略;正常工作流先拿证据,再决定应该改 host、MPISP payload、系统块,还是放弃这条假设。

Host Trigger 与 MPISP Patch 的分工

SM2268XT2 Secondary 的原生 Clear SMART 不在 MPISP window 内执行。主流程大致是:

text
Force ROM
Download MPISP
Set MPISP mode
Update MPInfo / InfoBlock / ISPBlock
Reset drive
Back to ISP
Clear SMART & Unformat

原生 Clear SMART & Unformat 调用 sub_442EA0,下发的是:

text
opcode = 0xC0
CDW12  = 0x0E
data   = none

但它发生在 reset/back-to-ISP 之后,设备已经不在 MPISP window。于是 host trigger patch 的插入点选在 Reset drive 之前:先读 runmode,如果 status[4] == 1,说明仍在 MPISP mode,就额外发送一次 C0/0E + CDW13,再恢复原始 reset 流程。

这里要分清职责:

部分做什么不做什么
Secondary MPTool host trigger在正确时机发一次 C0/0E + CDW13不在 host 里伪造 Health 成功,不直接写 SMART log
MPISP payload接住 CDW13=0/1/2/3,执行 probe 或 RAM source 清零实验不自动证明 NAND/metadata 已持久改变
主 ISP正常返回 NVMe SMART / D1 / C2/0x53当前不是可直接 patch 的目标二进制

早期 payload 的 CDW13 分层仍有诊断价值:

CDW13定位
0x00probe:确认 payload 被触发,检查运行态 base 是否可用
0x01health-source:清 0x1028504C 并读回
0x02production 实验:清 0x1028504C 和一组 SLC/endurance RAM 来源
0x03full-state 实验:再清 state/archive mirror

但实机结果已经说明:RAM source 清零即使返回成功,也不足以让 Health Percentage 持久归零。这条路线现在被降级为诊断层,不能包装成最终修复方案。

EasyTool Hook:把 SysBlk 读写变成可脚本化接口

MP2 hook 解决的是 Secondary MPTool 的生产流程取证;EasyTool hook 解决的是另一个问题:如何复用官方 EasyTool 已有的 Flash RW 能力,自动化系统块读取和证据打包。

ezt_hook 注入 EasyTool 后,会在本机 loopback 端口启动 JSON-RPC 服务,默认端口是:

text
127.0.0.1:22682

控制台窗口标题为 EZT Hook JSON-RPC Trace,会同步打印 hook 事件、rpc/requestrpc/response。大块 dataHexinputHexoutputHex 会折叠,避免一次 16 KiB 或 32 KiB 读包刷爆窗口。

当前直接方法包括:

方法用途默认使用边界
ping / info确认 hook 版本、PID、direct methods 是否可用安全
ui.tree / ui.click / ui.comboSelect / ui.getText复用 EasyTool UI 控件适合验证 UI 链路
captures.list / captures.get查看 DeviceIoControl / command capture只读取证
ioctl.raw重放或构造底层 IOCTL需要严格限制
listSysBlocks读取系统块索引/可选项只读
readBlock复用 EasyTool 内部 Flash read helper当前主线
writeBlock / eraseBlock复用 EasyTool 内部 Flash write/erase helper只有完整备份、校验和授权后才允许

这套接口也明确排除了一个常见误解:EasyTool UI 里的 DRAM RW 不等于能直接读写控制器 SRAM。当前 hook 不暴露 ram.read / ram.write,也不把 ISP 内的 0x1028xxxx 地址当作 EasyTool 进程地址。Health RAM source 验证仍要回到 MPISP payload 或已证明的 vendor RAM opcode;ezt_hook 继续聚焦 SysBlk/NAND block 自动化和 host command 取证。

Health Percentage 不是静态 SMART 字节

NVMe SMART/Health log 的 byte 5 看起来只是一个字节,实际不是 host 写进去的静态字段。设备在 Get Log Page 或 rebuild 时会重新生成它。

ISP 里可以看到多条 rebuild 路径读取:

text
0x1028504C = 0x10284C00 + 0x44C

再经过转换 helper,把结果写到 [base]+0x1005,也就是 SMART byte 5 的输出位置。原生 Clear SMART sub_C408C 会清 power cycles、unsafe shutdowns 等普通 backing counter,然后调用 rebuild;但它没有清 0x1028504C,也没有清 EC / SLC / endurance 来源簇。

更重要的是,当前盘的反证已经把 0x1028504C 从“唯一来源”降级为“参数输入之一”:8 份 E1/Info page 0x72data[0x44C] 都是 0x00,但设备 NVMe SMART Percentage Used0x03。这说明当前 3% 不能只由 page72+0x44C 解释。

更强的解释来自这条链:

text
0x10193E3C RAM EC table
  -> C2/0x53 输出 0x740 字节 EC table
  -> 0x3000..0x300A 现场计算 avg/max/min summary
  -> D1 telemetry 中的 erase count / endurance PE 字段
  -> Percentage Used ~= ceil(SLC_EC * 100 / MaxSlcEndurancePE)

所以现在的最小验证顺序变成:

  1. 读 D1 telemetry 和 C2/0x53,确认 SLC/TLC avg/max EC 与 endurance PE。
  2. 读 NVMe SMART LID 0x02 offset 0x05,确认当前 Percentage Used。
  3. 观察 selector 0x1Asub_A6920/sub_6A920 与 EC summary 的依赖,而不是只盯 0x1028504C
  4. 找到 EC table / type=3 metadata backing 或原厂 erase-count edit 入口。
  5. 写后同时读 D1、C2/0x53、LID 0x02,并在 reset/back-to-ISP 后复测,确认没有回弹。

为什么 C1/0x97C1/0x99C2/0x56 都不能当主线

这轮研究里几个看起来像入口的点已经被降级。

C1/0x97 曾经被怀疑是 0x2000 MPInfo 写入路径。force-heavy 实验确实抓到了 buffer,但内容偏 SN、Model、FW、NQN、MPINFO 等静态身份信息,没有命中 Health、Wear、SLC endurance 或 Percentage Used = 3 的明显模式。它不是当前 Health 动态来源。

C1/0x99 是当前 Update MPInfo fast route 会走到的 SSDINFO / Clear SMART 相关路径。MP2 日志里它会返回成功,但 ISP 侧复核显示 Clear SMART handler 仍是 C0/0E -> sub_C408C,没有新的 0x99 metadata writer。它证明 MPTool 流程跑通,不证明 Health backing 被改。

C2/0x56 静态上能触发 selector 0x24 -> sub_119690,而 sub_119690 会编辑 RAM EC table 0x10193E3C。但实测设备 probe 的 host-visible 行为和 length 相关:Length=0 长忙,非零 length 返回 UNKNOWN,reconnect 后 C2/0x53 summary 不变。因此它只能保留为 selector 静态证据,不能写成 F8 -> 56 或任何可执行清零 recipe。

MPISP window 里的 C2/0x53 也被证伪为读 EC 主线:当前 MPISP mode 下返回 UNKNOWN,EasyTool Read Telemetry 和 FA Prog/Erase Count 也都是全 0。EC / telemetry builder 依赖主 ISP / FTL runtime,不是在 MPISP window 里随时可读。

落盘逻辑:从 RAM EC 表到 metadata record

OpcodeC2.bin 不是 NAND 上某个系统块文件的 raw backing。它是主 ISP 从 RAM 0x10193E3C 现场导出的 host buffer:前 0x740 字节是全盘 data block EC table,尾部 0x3000 起是现场计算出的 summary。

持久化主线现在更像这样:

text
0x10140000..0x10197FFF metadata arena
  -> 0x10193E3C RAM EC table
  -> sub_6025C()
     copy 0x10193E3C..0x1019457B
     to   0x101C9080..0x101C97BF
  -> E1 / type=3 metadata record body
  -> NAND system block / metadata pages

这解释了几个看似矛盾的现象:

  • C2/0x53 能看到完整 EC table,不代表某个 LogBlock.bin 里会直接出现同样的 0x740 字节。
  • LogBlock.bin+0x418 偶然出现 0x011E,它等于 maxSLC=286,但这更像 0x20-byte metadata header 里的 EC snapshot,不是完整 EC table。
  • 直接改某个 header snapshot 不能证明 D1、C2/0x53 和 SMART byte 5 会一起变化。
  • 真正要改的是 type=3 metadata body / EC table backing,并处理 checksum、多副本、spare 和写回顺序。

系统块读写入口目前选择复用原厂路径,而不是直接移植主 ISP 内部 descriptor queue。EasyTool 普通 Flash RW 的 Read SysBlk 下拉框会从 device info / parameter table 里取系统块线性地址,再按 NAND 几何拆成 Block、Page、CH、Plane、CE、Option 等字段。Secondary MPTool 的系统块 dump/write 流程同样依赖 SM2268PARA 参数表,不是硬编码物理块。

读写 opcode 层面可以概括为:

操作原厂 helper底层语义
Read sysblock/pagesub_47BA84 / Secondary read wrapperopcode 0x4E
Write sysblock/pagesub_47BC84 / Secondary write wrapperopcode 0x83
Erase blockerase wrapperopcode 0x03,常见 option 0x84

Secondary 原厂 writer 还会检查 first-page spare ID:Info-like block 期待 0xE1,ISP block 期待 0xE4。但这里也有坑:当前复核显示它的内部 readback compare 可能最多只比较 1 byte,因此写回方案不能依赖工具 UI 上的“compare pass”。必须额外 dump 回同一个 sysblock,由本地工具对 data+spare 做完整 hash / byte compare。

证据打包:manifest 比截图更重要

有了 EasyTool hook 之后,系统块采集不应停留在“我读到了一个 bin”。每个 dump 都需要机器可读 manifest:

text
sysblk label: 1st Info / 2nd Info / 3rd Info / 1st ISP / MPInfo / Log
option:       C5 00 / 95 00 / 85 00
address:      Block, Page, 2KChunk, CH, CE, Plane, Sec size
raw:          raw page data path, size, sha256
spare:        spare path or inline spare hex, size, sha256
status:       DW0, SCT/SC
notes:        是否 Read SysBlk、是否 Physical Access、是否 Plane Base Read

sm2268xt2-sysblk-dump-manifest 的意义就在这里:它把 EasyTool/MPTool UI 地址字段、hook events.jsonl 里的 0x4E/0x83 buffer dump、raw/spare hash、以及 health-block-scan 结果绑到同一个 JSON。扫描器会查三类东西:

  • OpcodeC2.bin[0x3000..0x300B] 的 6 个 summary 是否作为连续序列出现。
  • OpcodeC2.bin[0..0x73F] 的 EC table 是否 exact hit 或 fuzzy hit。
  • 是否存在保守的 type=3 metadata record header 候选。

现有负结论同样重要:LogBlock.bin 没有 EC table hit,没有 summary hit,也没有 type=3 record hit;只出现单个 0x011E 不能升级成 backing 证据。这个 stop sign 防止我们把一个看起来像的数值写坏成“修复方案”。

当前工程路线

现在比较稳的路线是四步。

第一步,MP2 观察。用 observe-only hook 跑 Secondary MPTool,保存 events.jsonlsummary.json 和关键 buffers。确认 host 下载的 MPISP 是否是当前包、C1/0x99 / C2/0x88 / reset/back-to-ISP 是否成功、原生 Clear SMART 是否返回 0。

第二步,只读基线。主 ISP mode 下读三套事实:NVMe SMART LID 0x02、EasyTool D1 telemetry、C2/0x53 PE/EC summary。不要用 MPISP window 的全 0 telemetry 或 UNKNOWN 结果替代主 ISP 基线。

第三步,系统块取证。用 EasyTool hook 的 listSysBlocks / readBlock 或 UI 复用链路 dump Info、ISP、MPInfo、Log 和相邻 page,保留 raw+spare,生成 manifest 和 scan bundle。OpcodeC2.bin 作为 baseline,不作为待写文件。

第四步,谨慎写回。只有当 type=3 body、checksum/spare、多副本和原厂 writer 行为都闭合后,才在目标盘自己的 dump 副本上 patch 最小字段。写回后必须立即 readback 完整比较,再 power cycle / reconnect,重新读取 D1、C2/0x53、LID 0x02

这条路线慢,但它避免了最危险的误判:把 SMART output buffer 当成来源,把 page72+0x44C 当成当前 3% 的持久字段,把 LogBlock.bin+0x418 当成完整 EC table,或者把一个 host 返回成功当成设备状态已经持久改变。

当前结论

SM2268XT2 的 Health Percentage 研究已经从“哪个按钮能清 SMART”进入到“磨损来源如何被重建、汇总和落盘”的阶段。MP2 hook 让 Secondary MPTool 的生产流程可观测,EasyTool hook 让官方 SysBlk 读写能力可脚本化,MPISP patcher 则保留了设备侧诊断入口。三者合起来,是为了让每一步都有日志、hash、buffer 和可复核边界。

当前最强模型是:Percentage Used = 3% 更接近 EC / PE summary 与 endurance PE 的换算结果,而不是某个静态 SMART 字节。0x1028504C 仍是 SMART rebuild 输入,但不是当前寿命值的充分来源;0x10193E3C RAM EC table、0x101C9080 metadata image 和 E1/type=3 metadata record 才是后续持久化研究的主线。

对健康度机制研究和受控实验来说,这个结论很实用:不要急着写。先用 hook 把现场变成事件流,用 JSON-RPC 把系统块读成可追溯证据,用 D1 / C2/0x53 / SMART 三重读回验证每个假设。能被复现、能被回读、能过断电验证的改动,才算真正靠近了 Health Percentage 的落盘逻辑。