feat(vm): 神谕钩子 —— 在真 VM 中按 PC 快照寄存器 (定位/校验任意值)

做了什么:
- tools/tdc_probe.js 注入自包含钩子(window.__H): 记录 PC 轨迹, 并在指定 PC
  dump 指定寄存器 (默认 9109 / E[7]), 通过 report.__xtea / report.__pc_len 回传
- tools/tdc_keytrace.js 同步支持 TARGET_PC 钩子

为什么:
- 需要"某个值在哪段字节码诞生"的运行时神谕(AGENTS.md §3.2 第3条: 与运行时观测对齐)
- 钩子自包含写在沙箱 window 上(沙箱内没有 globalThis)

怎么验证(本轮的关键结论):
- 命中: @9109 入口 E[7] = [[1817655617,1381395306,1245924197,1767660346]];
  其后 PC 序列 tail = [...9021,9022,9023,9024,9026,9028,9030,9109]
  -> 说明 XTEA 闭包是在 @9030 CALL_FUNC[2] 被调用的
- 交叉验证: 用 extract_xtea_key 的密钥解密 probe 的 collect -> {"cd":[0,10,"top",...
  (真明文) => extract_xtea_key 正确;
  而 E[7] 解不开 => E[7] 是"基字", 不是生效密钥
- 结构确认: real[0]-cap[0]=855311, real[3]-cap[3]=723726 (XTEA 轮里的可见立即数)
  => 有效密钥 = 脚本基字 + 两个轮加盐
This commit is contained in:
yml2213
2026-10-11 22:21:53 +08:00
parent 9c889215f2
commit 5c949090c1
2 changed files with 35 additions and 4 deletions
+22 -3
View File
@@ -87,7 +87,20 @@ globalThis.__SCAN = function (E) {
} catch (e) { /* ignore */ }
};
src = src.replace(needle, "M=(globalThis.__PC.push(H),globalThis.__SCAN(E),G[z[H++]]())");
const TARGET_PC = parseInt(process.env.TARGET_PC || "9109", 10);
globalThis.__XTEA = null;
globalThis.__HOOK = function (H, E) {
if (H === TARGET_PC && !globalThis.__XTEA) {
const cell = E[7];
globalThis.__XTEA = {
at: H,
r7_cell: (Array.isArray(cell) ? JSON.stringify(cell).slice(0, 400) : String(cell)),
r7_val: (cell && typeof cell[0] === "object") ? JSON.stringify(cell[0]).slice(0, 400) : String(cell && cell[0]),
prev_pcs: globalThis.__PC.slice(-300),
};
}
};
src = src.replace(needle, "M=(globalThis.__PC.push(H),globalThis.__HOOK(H,E),G[z[H++]]())");
globalThis.window = globalThis;
globalThis.document = { cookie: "", referrer: "", createElement: () => ({ getContext: () => null, toDataURL: () => "", style: {} }), getElementById: () => null };
@@ -111,7 +124,8 @@ try {
process.stderr.write("[keytrace] 调用 TDC.getData(true) 驱动...\n");
globalThis.__PC.push(-1);
const c = globalThis.TDC.getData(true);
process.stderr.write(`[keytrace] getData 返回长度=${c ? c.length : 0}\n`);
globalThis.__COLLECT = c;
process.stderr.write(`[keytrace] getData 返回长度=${c ? c.length : 0} 头部=${String(c).slice(0,90)}\n`);
} else {
process.stderr.write("[keytrace] 未找到 TDC.getData\n");
}
@@ -122,4 +136,9 @@ let out = globalThis.__HITS[0] || null;
if (out) {
process.stderr.write(`[keytrace] 命中寄存器 r${out.reg}, 密钥=${JSON.stringify(out.key)}, ASCII=${out.ascii}, 命中时 PC=@${out.pc}\n`);
}
process.stdout.write(JSON.stringify(out));
const pcs=globalThis.__PC;
const uniq=new Set(pcs);
const inRange=[...uniq].filter(x=>x>=9000&&x<=9600);
process.stdout.write(JSON.stringify({ key_hit: out, xtea: globalThis.__XTEA,
pc_total: pcs.length, pc_unique: uniq.size, min: Math.min(...pcs), max: Math.max(...pcs),
has_9109: uniq.has(9109), range9000_9600: inRange.sort((a,b)=>a-b).slice(0,40) }));
+13 -1
View File
@@ -80,7 +80,17 @@ function createVirtualDate(initialTime) {
}
function probeTdc(tdcFilePath, options = {}) {
const tdcCode = options.tdcCode || fs.readFileSync(tdcFilePath, "utf-8");
let tdcCode = options.tdcCode || fs.readFileSync(tdcFilePath, "utf-8");
// ---- 神谕钩子(自包含, 写在沙箱内的 window 上): 记录 PC, 并在进入 XTEA 例程时 dump 密钥寄存器 ----
const TARGET_PC = parseInt(process.env.XTEA_PC || "9109", 10);
const HOOK = "window.__PC=window.__PC||[];window.__H=function(H,E){window.__PC.push(H);"
+ "if(H===" + TARGET_PC + "&&!window.__XT){var c=E[7];window.__XT={at:H,"
+ "r7:Array.isArray(c)?JSON.stringify(c).slice(0,300):String(c),prev:window.__PC.slice(-260)};}};";
const NEEDLE = "M=G[z[H++]]()";
if (tdcCode.includes(NEEDLE)) {
tdcCode = HOOK + tdcCode.replace(NEEDLE, "M=(window.__H(H,E),G[z[H++]]())");
}
const accesses = new Set();
let mouseHandler = null;
@@ -295,6 +305,8 @@ function probeTdc(tdcFilePath, options = {}) {
eksPreview: eks ? eks.slice(0, 80) : null,
accessCount: accesses.size,
accesses: Array.from(accesses).sort(),
__pc_len: (sandbox.__PC || []).length,
__xtea: sandbox.__XT || null,
};
return result;