// 纯算加密服务:调用快手 captcha 的 Jose VM 生成 verifyParam。 // // 加密管线(从 iframe bundle d702 模块还原): // verifyParam = base64( Jose.$encrypt( utf8(JSON.stringify(payload)), KEY ) ) // KEY = "c7b645db-65e8-401f-b38c-4c07c5fff247" (硬编码, iframe bundle d702) // Jose = encrypt.js 的字节码 VM; $encrypt 内含随机 IV. // // 用法 (CLI): // node tools/jose_encrypt.js '{"captchaSn":"...","relativeX":123,...}' // -> stdout: verifyParam(base64) // // 关键: 沙箱必须是【单 realm】——不能注入外层 String/Object/Uint8Array 等, // 否则 VM 对宿主基本类型字符串的 .charCodeAt 方法派发失败 (跨 realm 原型链查不到)。 const fs = require("fs"), vm = require("vm"), path = require("path"); const ENC_PATH = path.join(__dirname, "..", "out", "captcha_net", "js_07_rm_static_captcha_js_encrypt_ee7d2a41_js.js"); const KEY = "c7b645db-65e8-401f-b38c-4c07c5fff247"; function makeBox() { const sandbox = { console: { log: () => {}, error: () => {}, warn: () => {} }, setTimeout, clearTimeout, setImmediate, queueMicrotask, Buffer, btoa: (s) => Buffer.from(s, "binary").toString("base64"), atob: (s) => Buffer.from(s, "base64").toString("binary"), }; vm.createContext(sandbox); // 让 context 自带 intrinsic sandbox.window = sandbox; sandbox.self = sandbox; sandbox.global = sandbox; const src = fs.readFileSync(ENC_PATH, "utf-8"); vm.runInContext(src, sandbox, { filename: "encrypt.js", timeout: 30000 }); const factory = sandbox.webpackJsonp[0][1]["088e"]; const rq = (id) => id === "b639" ? { Buffer } : id === "dd40" ? (x) => x : {}; const mod = { exports: {} }; factory(mod, mod.exports, rq); if (!sandbox.Jose) throw new Error("Jose 未加载"); return sandbox; } // 预置 in-sandbox 辅助 + 加密入口(全单 realm) function primeBox(sandbox) { vm.runInContext(` globalThis.__enc = function(payloadStr){ var u8 = new Uint8Array(Array.prototype.map.call(payloadStr, function(c){return c.charCodeAt(0);})); globalThis.__out=null; globalThis.__done=null; Jose.call("$encrypt", [u8, ${JSON.stringify(KEY)}, { suc: function(v){ var s=""; for(var i=0;i { const t0 = Date.now(); const iv = setInterval(() => { if (sandbox.__done !== null || Date.now() - t0 > 5000) { clearInterval(iv); resolve(sandbox.__done === "ok" ? sandbox.__out : (sandbox.__out || "ERR:timeout")); } }, 5); }); } module.exports = { makeBox, primeBox, encrypt, KEY }; // ---- CLI ---- if (require.main === module) { const arg = process.argv[2]; if (!arg) { console.error("usage: node jose_encrypt.js ''"); process.exit(2); } const box = makeBox(); primeBox(box); let payload; try { payload = JSON.parse(arg); } catch (e) { console.error("payload JSON parse 失败:", e.message); process.exit(2); } encrypt(box, payload).then((out) => { if (out && out.indexOf("ERR:") === 0) { console.error(out); process.exit(1); } process.stdout.write(out || ""); }); }