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:
+22
-3
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user