| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374 |
- // 终极尝试:用当前 V8 dummy 的整个 header 覆盖 996box .jsc 的 header(保留 996box 的 bytecode payload)
- const fs = require('fs');
- const vm = require('vm');
- const v8 = require('v8');
- v8.setFlagsFromString('--no-lazy');
- v8.setFlagsFromString('--no-flush-bytecode');
- // 1. 生成当前 V8 的 dummy header (使用 urlCreator 长度 1245 字符以匹配 sourceHash)
- const sourceLen = 1245;
- const dummyCode = '"' + '\u200b'.repeat(sourceLen - 2) + '"';
- const dummyScript = new vm.Script(dummyCode, { produceCachedData: true });
- const dummyBuf = dummyScript.cachedData;
- console.log('Dummy size:', dummyBuf.length);
- console.log('Dummy header:', dummyBuf.subarray(0, 32).toString('hex'));
- // 2. 读 996box .jsc,剥掉 0xa4 0x05 wrapper
- const raw = fs.readFileSync(process.argv[2]);
- const v8bc = raw.subarray(2);
- console.log('996box v8bc size:', v8bc.length);
- console.log('996box v8bc header:', v8bc.subarray(0, 32).toString('hex'));
- // 3. 复制 dummy 的 header(0..N) 到 v8bc 的 0..N,然后接 v8bc 的 payload
- // V8 bytecode header 是前多少字节?
- // V8 ScriptData 头部根据版本不同大小不同
- // dummyBuf.length = 256, 996box v8bc = 2086, payload 远大于 dummy,所以应该用 v8bc 的 payload + dummy 的 metadata header
- // 但 v8bc 整个 buffer 已经是 V8 字节码格式,需要找到 magic 后面才是真实数据
- // 试验:用 v8bc 自己的 header 0..32 + dummy 0..0 替换,看看哪个版本可被接受
- // 实际上 bytenode 1.3.6 的 fixBytecode patch 的是 byte 12-16 (flagHash)
- // 1.6.0 同样的 patch
- // 让我看 dummy header 字节 12-16,直接 patch 到 996box
- const fixed = Buffer.from(v8bc);
- const dummyHeader12_16 = dummyBuf.subarray(12, 16);
- console.log('Dummy flagHash:', dummyHeader12_16.toString('hex'));
- console.log('996box flagHash:', fixed.subarray(12, 16).toString('hex'));
- dummyHeader12_16.copy(fixed, 12);
- // 也 patch read-only checksum (16-20)
- const dummyHeader16_20 = dummyBuf.subarray(16, 20);
- dummyHeader16_20.copy(fixed, 16);
- console.log('Patched 996box header:', fixed.subarray(0, 32).toString('hex'));
- // 4. 尝试加载
- try {
- const s = new vm.Script(dummyCode, { cachedData: fixed });
- console.log('Result: rejected =', s.cachedDataRejected);
- if (!s.cachedDataRejected) {
- const result = s.runInThisContext();
- console.log('Ran! result:', result);
- }
- } catch (e) {
- console.log('ERR:', e.code, e.message);
- }
- // 5. 也试不同 header 长度替换
- for (let headerSize of [0, 4, 8, 12, 16, 20, 24, 32]) {
- if (headerSize > dummyBuf.length) break;
- const patched = Buffer.from(v8bc);
- dummyBuf.copy(patched, 0, 0, headerSize);
- try {
- const s = new vm.Script(dummyCode, { cachedData: patched });
- if (!s.cachedDataRejected) {
- console.log(`[hsize=${headerSize}] ACCEPTED!`);
- break;
- } else {
- console.log(`[hsize=${headerSize}] rejected`);
- }
- } catch (e) {
- console.log(`[hsize=${headerSize}] ERR:`, e.code, e.message);
- }
- }
|