/** * 完整反混淆 provider.js * 使用 RC4 + 非标准 Base64 解码 */ const fs = require('fs'); const path = require('path'); // 非标准 Base64 字母表(小写在前) const BASE64_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/='; /** * 非标准 Base64 解码 */ function base64Decode(input) { let output = ''; let buffer = 0; let bitsCollected = 0; for (let i = 0; i < input.length; i++) { const char = input[i]; if (char === '=') break; const value = BASE64_CHARS.indexOf(char); if (value === -1) continue; buffer = (buffer << 6) | value; bitsCollected += 6; if (bitsCollected >= 8) { bitsCollected -= 8; output += String.fromCharCode((buffer >> bitsCollected) & 0xFF); } } return output; } /** * RC4 解密 */ function rc4Decrypt(data, key) { const s = []; let j = 0; let result = ''; // 初始化 S-box for (let i = 0; i < 256; i++) { s[i] = i; } // 密钥调度 for (let i = 0; i < 256; i++) { j = (j + s[i] + key.charCodeAt(i % key.length)) % 256; [s[i], s[j]] = [s[j], s[i]]; } // 生成密钥流并解密 let i = 0; j = 0; for (let k = 0; k < data.length; k++) { i = (i + 1) % 256; j = (j + s[i]) % 256; [s[i], s[j]] = [s[j], s[i]]; const keyByte = s[(s[i] + s[j]) % 256]; result += String.fromCharCode(data.charCodeAt(k) ^ keyByte); } return result; } /** * 解码单个字符串 */ function decodeString(encoded, key) { try { const base64Decoded = base64Decode(encoded); const decrypted = rc4Decrypt(base64Decoded, key); return decrypted; } catch (e) { return null; } } /** * 从代码中提取字符串数组 */ function extractStringArray(code) { // 找到字符串数组函数 const arrayMatch = code.match(/function\s+_0x[a-f0-9]+\(\)\s*\{\s*const\s+_0x[a-f0-9]+\s*=\s*\(function\(\)\s*\{\s*return\s*\[vip,([\s\S]*?)\]\.concat/); if (!arrayMatch) { console.log('未找到字符串数组,尝试其他模式...'); // 尝试直接匹配数组内容 const directMatch = code.match(/return\s*\[\s*vip\s*,\s*'([^']+)'/); if (directMatch) { console.log('找到数组起始'); } return null; } console.log('找到字符串数组定义'); // 提取所有字符串 const arrayContent = arrayMatch[1]; const strings = ['cursor']; // vip = 'cursor' // 匹配所有字符串 const stringRegex = /'([^'\\]*(?:\\.[^'\\]*)*)'/g; let match; while ((match = stringRegex.exec(arrayContent)) !== null) { strings.push(match[1]); } console.log(`提取了 ${strings.length} 个字符串`); return strings; } /** * 动态执行提取字符串数组 */ function extractStringArrayDynamic(code) { console.log('使用动态方法提取字符串数组...'); // 提取 _0x4ff4 或类似函数 const funcMatch = code.match(/(function\s+(_0x[a-f0-9]+)\(\)\s*\{[\s\S]*?return\s+_0x[a-f0-9]+;\s*\})/); if (!funcMatch) { console.log('未找到字符串数组函数'); return null; } const funcName = funcMatch[2]; console.log(`找到函数: ${funcName}`); // 提取完整的数组定义部分 // 找到 concat 链的结束 let depth = 0; let start = code.indexOf('return[vip,'); if (start === -1) start = code.indexOf("return [vip,"); if (start === -1) { console.log('未找到数组起始'); return null; } let end = start; let inString = false; let stringChar = ''; for (let i = start; i < code.length; i++) { const char = code[i]; if (!inString) { if (char === '"' || char === "'") { inString = true; stringChar = char; } else if (char === '[') { depth++; } else if (char === ']') { depth--; if (depth === 0) { // 检查后面是否还有 .concat const after = code.slice(i + 1, i + 20); if (!after.match(/^\s*\.\s*concat/)) { end = i + 1; break; } } } } else { if (char === stringChar && code[i-1] !== '\\') { inString = false; } } } // 构建可执行代码 const arrayCode = ` var vip = 'cursor'; ${code.slice(start, end)}; `; try { const result = eval(arrayCode); console.log(`动态提取了 ${result.length} 个字符串`); return result; } catch (e) { console.log('动态执行失败:', e.message); return null; } } /** * 手动解析提取字符串数组 */ function extractStringsManual(code) { console.log('使用手动解析方法...'); const strings = ['cursor']; // 找到所有在数组中的字符串字面量 // 模式: 'xxxxx' 在数组上下文中 const regex = /\[vip,([\s\S]*?)\]\.concat\(\(function\(\)/g; let match; while ((match = regex.exec(code)) !== null) { const content = match[1]; const strRegex = /'([^'\\]*(?:\\.[^'\\]*)*)'/g; let strMatch; while ((strMatch = strRegex.exec(content)) !== null) { strings.push(strMatch[1].replace(/\\'/g, "'")); } } // 继续查找 concat 中的字符串 const concatRegex = /return\s*\[([\s\S]*?)\](?:\s*;\s*\}|\s*\.\s*concat)/g; while ((match = concatRegex.exec(code)) !== null) { const content = match[1]; if (content.includes('vip')) continue; // 跳过第一个 const strRegex = /'([^'\\]*(?:\\.[^'\\]*)*)'/g; let strMatch; while ((strMatch = strRegex.exec(content)) !== null) { const str = strMatch[1].replace(/\\'/g, "'"); if (!strings.includes(str)) { strings.push(str); } } } console.log(`手动提取了 ${strings.length} 个字符串`); return strings; } /** * 在沙盒中执行代码提取字符串数组 */ function extractWithSandbox(code) { console.log('尝试沙盒执行...'); // 找到字符串数组函数名 const funcNameMatch = code.match(/function\s+(_0x[a-f0-9]+)\(\)\s*\{\s*const\s+_0x[a-f0-9]+\s*=\s*\(function\(\)\s*\{/); if (!funcNameMatch) { console.log('未找到数组函数'); return null; } const funcName = funcNameMatch[1]; console.log(`数组函数名: ${funcName}`); // 提取整个函数定义 const funcStart = code.indexOf(`function ${funcName}()`); let braceCount = 0; let funcEnd = funcStart; let started = false; for (let i = funcStart; i < code.length; i++) { if (code[i] === '{') { braceCount++; started = true; } else if (code[i] === '}') { braceCount--; if (started && braceCount === 0) { funcEnd = i + 1; break; } } } const funcCode = code.slice(funcStart, funcEnd); // 执行并获取结果 const execCode = ` var vip = 'cursor'; ${funcCode} ${funcName}(); `; try { const result = eval(execCode); console.log(`沙盒执行成功,获取 ${result.length} 个字符串`); return result; } catch (e) { console.log('沙盒执行失败:', e.message); return null; } } /** * 主函数 */ async function main() { console.log('╔════════════════════════════════════════════════════╗'); console.log('║ Provider.js 完整反混淆工具 ║'); console.log('╚════════════════════════════════════════════════════╝'); const inputPath = 'D:/temp/破解/cursorpro-0.4.5/原版本/extension/out/webview/provider.js'; const outputPath = 'D:/temp/破解/cursorpro-0.4.5/deobfuscated_full/extension/out/webview/provider.js'; // 读取文件 console.log('\n[1] 读取文件...'); let code = fs.readFileSync(inputPath, 'utf8'); console.log(`文件大小: ${(code.length / 1024).toFixed(2)} KB`); // 提取字符串数组 console.log('\n[2] 提取字符串数组...'); let stringArray = extractWithSandbox(code); if (!stringArray || stringArray.length < 100) { console.log('沙盒方法失败,尝试手动解析...'); stringArray = extractStringsManual(code); } if (!stringArray || stringArray.length < 10) { console.log('错误:无法提取字符串数组'); return; } console.log(`成功提取 ${stringArray.length} 个编码字符串`); // 找到解码器函数名和密钥 console.log('\n[3] 分析解码器...'); const decoderMatch = code.match(/const\s+(_0x[a-f0-9]+)\s*=\s*(_0x[a-f0-9]+);/); let decoderName = '_0x56bd'; let decoderAlias = '_0xa6d6ac'; if (decoderMatch) { decoderAlias = decoderMatch[1]; decoderName = decoderMatch[2]; console.log(`解码器: ${decoderName}, 别名: ${decoderAlias}`); } // 构建解码映射 console.log('\n[4] 解码字符串...'); const decodeMap = new Map(); let decodedCount = 0; // 找到所有解码器调用: _0x56bd(0x123, 'key') 或 _0xa6d6ac(0x123, 'key') const callPattern = new RegExp( `(?:${decoderName}|${decoderAlias})\\s*\\(\\s*(0x[a-f0-9]+)\\s*,\\s*'([^']*)'\\s*\\)`, 'gi' ); const calls = new Set(); let callMatch; while ((callMatch = callPattern.exec(code)) !== null) { calls.add(JSON.stringify([callMatch[0], callMatch[1], callMatch[2]])); } console.log(`找到 ${calls.size} 个唯一的解码器调用`); // 解码每个调用 const baseIndex = 0x107; // 从混淆代码中提取的基准索引 for (const callStr of calls) { const [fullMatch, indexHex, key] = JSON.parse(callStr); const index = parseInt(indexHex, 16) - baseIndex; if (index >= 0 && index < stringArray.length) { const encoded = stringArray[index]; const decoded = decodeString(encoded, key); if (decoded && decoded.length > 0 && !decoded.includes('\x00')) { decodeMap.set(fullMatch, decoded); decodedCount++; } } } console.log(`成功解码 ${decodedCount} 个字符串`); // 替换代码中的调用 console.log('\n[5] 替换代码...'); let newCode = code; let replaceCount = 0; for (const [pattern, decoded] of decodeMap) { // 转义特殊字符用于字符串 let replacement; if (decoded.includes('\n') || decoded.includes('\r') || decoded.includes('`')) { // 使用 JSON.stringify 处理复杂字符串 replacement = JSON.stringify(decoded); } else if (decoded.includes("'") && !decoded.includes('"')) { replacement = `"${decoded}"`; } else { replacement = `'${decoded.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`; } const before = newCode.length; newCode = newCode.split(pattern).join(replacement); if (newCode.length !== before) { replaceCount++; } } console.log(`替换了 ${replaceCount} 个模式`); // 清理代码 console.log('\n[6] 清理代码...'); // 简化属性访问 newCode = newCode.replace(/\['([a-zA-Z_$][a-zA-Z0-9_$]*)'\]/g, '.$1'); // 替换布尔值 newCode = newCode.replace(/!!\[\]/g, 'true'); newCode = newCode.replace(/!\[\]/g, 'false'); // 保存 console.log('\n[7] 保存文件...'); const outputDir = path.dirname(outputPath); if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir, { recursive: true }); } fs.writeFileSync(outputPath, newCode); console.log(`保存到: ${outputPath}`); console.log(`新文件大小: ${(newCode.length / 1024).toFixed(2)} KB`); // 保存解码映射供调试 const mapPath = 'D:/temp/破解/cursorpro-0.4.5/provider_decode_map.json'; const mapObj = {}; for (const [k, v] of decodeMap) { if (v.length < 500) { // 只保存较短的字符串 mapObj[k] = v; } } fs.writeFileSync(mapPath, JSON.stringify(mapObj, null, 2)); console.log(`解码映射保存到: ${mapPath}`); console.log('\n✅ 完成!'); } main().catch(console.error);