/** * Cursor 设备标识符 Hook 模块 * * 🎯 功能:从底层拦截所有设备标识符的生成,实现一劳永逸的机器码修改 * * 🔧 Hook 点: * 1. child_process.execSync - 拦截 REG.exe 查询 MachineGuid * 2. crypto.createHash - 拦截 SHA256 哈希计算 * 3. @vscode/deviceid - 拦截 devDeviceId 获取 * 4. @vscode/windows-registry - 拦截注册表读取 * 5. os.networkInterfaces - 拦截 MAC 地址获取 * 6. fs.writeFileSync/writeFile - 拦截 storage.json 写入,保护 telemetry 字段 * * 📦 使用方式: * 将此代码注入到 main.js 文件顶部(Sentry 初始化之后) * * ⚙️ 配置方式: * 1. 环境变量:CURSOR_MACHINE_ID, CURSOR_MAC_MACHINE_ID, CURSOR_DEV_DEVICE_ID, CURSOR_SQM_ID * 2. 配置文件:~/.cursor_ids.json * 3. 自动生成:如果没有配置,则自动生成并持久化 */ // ==================== 配置区域 ==================== // 使用 var 确保在 ES Module 环境中也能正常工作 var __cursor_hook_config__ = { // 是否启用 Hook(设置为 false 可临时禁用) enabled: true, // 是否输出调试日志(设置为 true 可查看详细日志) debug: false, // 配置文件路径(相对于用户目录) configFileName: '.cursor_ids.json', // 标记:防止重复注入 injected: false }; // ==================== Hook 实现 ==================== // 使用 IIFE 确保代码立即执行 (function() { 'use strict'; // 防止重复注入 if (globalThis.__cursor_patched__ || __cursor_hook_config__.injected) { return; } globalThis.__cursor_patched__ = true; __cursor_hook_config__.injected = true; // 调试日志函数 const log = (...args) => { if (__cursor_hook_config__.debug) { console.log('[CursorHook]', ...args); } }; // ==================== ID 生成和管理 ==================== // 生成 UUID v4 const generateUUID = () => { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { const r = Math.random() * 16 | 0; const v = c === 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); }; // 生成 64 位十六进制字符串(用于 machineId) const generateHex64 = () => { let hex = ''; for (let i = 0; i < 64; i++) { hex += Math.floor(Math.random() * 16).toString(16); } return hex; }; // 生成 MAC 地址格式的字符串 const generateMacAddress = () => { const hex = '0123456789ABCDEF'; let mac = ''; for (let i = 0; i < 6; i++) { if (i > 0) mac += ':'; mac += hex[Math.floor(Math.random() * 16)]; mac += hex[Math.floor(Math.random() * 16)]; } return mac; }; // 加载或生成 ID 配置 // 注意:该 Hook 由脚本注入的 Loader 通过 CommonJS(require) 方式加载, // 为避免出现 import.meta 等仅 ESM 支持的语法导致 Cursor 启动期解析失败,这里保持纯 CommonJS 写法。 const loadOrGenerateIds = () => { const fs = require('fs'); const path = require('path'); const os = require('os'); const configPath = path.join(os.homedir(), __cursor_hook_config__.configFileName); let ids = null; // 尝试从环境变量读取 if (process.env.CURSOR_MACHINE_ID) { ids = { machineId: process.env.CURSOR_MACHINE_ID, // machineGuid 用于模拟注册表 MachineGuid/IOPlatformUUID machineGuid: process.env.CURSOR_MACHINE_GUID || generateUUID(), macMachineId: process.env.CURSOR_MAC_MACHINE_ID || generateHex64(), devDeviceId: process.env.CURSOR_DEV_DEVICE_ID || generateUUID(), sqmId: process.env.CURSOR_SQM_ID || `{${generateUUID().toUpperCase()}}`, macAddress: process.env.CURSOR_MAC_ADDRESS || generateMacAddress(), sessionId: process.env.CURSOR_SESSION_ID || generateUUID(), firstSessionDate: process.env.CURSOR_FIRST_SESSION_DATE || new Date().toISOString() }; log('从环境变量加载 ID 配置'); return ids; } // 尝试从配置文件读取 try { if (fs.existsSync(configPath)) { const content = fs.readFileSync(configPath, 'utf8'); ids = JSON.parse(content); // 补全缺失字段,保持向后兼容 let updated = false; // 🔧 补齐核心 ID 字段(用于 Hook 与 storage.json 保护) if (!ids.machineId || typeof ids.machineId !== 'string') { ids.machineId = generateHex64(); updated = true; } if (!ids.macMachineId || typeof ids.macMachineId !== 'string') { ids.macMachineId = generateHex64(); updated = true; } if (!ids.devDeviceId || typeof ids.devDeviceId !== 'string') { ids.devDeviceId = generateUUID(); updated = true; } if (!ids.sqmId || typeof ids.sqmId !== 'string') { ids.sqmId = `{${generateUUID().toUpperCase()}}`; updated = true; } if (!ids.machineGuid) { ids.machineGuid = generateUUID(); updated = true; } if (!ids.macAddress) { ids.macAddress = generateMacAddress(); updated = true; } if (!ids.sessionId) { ids.sessionId = generateUUID(); updated = true; } if (!ids.firstSessionDate) { ids.firstSessionDate = new Date().toISOString(); updated = true; } if (updated) { try { fs.writeFileSync(configPath, JSON.stringify(ids, null, 2), 'utf8'); log('已补全并更新 ID 配置:', configPath); } catch (e) { log('补全配置文件失败:', e.message); } } log('从配置文件加载 ID 配置:', configPath); return ids; } } catch (e) { log('读取配置文件失败:', e.message); } // 生成新的 ID ids = { machineId: generateHex64(), machineGuid: generateUUID(), macMachineId: generateHex64(), devDeviceId: generateUUID(), sqmId: `{${generateUUID().toUpperCase()}}`, macAddress: generateMacAddress(), sessionId: generateUUID(), firstSessionDate: new Date().toISOString(), createdAt: new Date().toISOString() }; // 保存到配置文件 try { fs.writeFileSync(configPath, JSON.stringify(ids, null, 2), 'utf8'); log('已生成并保存新的 ID 配置:', configPath); } catch (e) { log('保存配置文件失败:', e.message); } return ids; }; // 加载 ID 配置 const __cursor_ids__ = loadOrGenerateIds(); // 统一获取 MachineGuid,缺失时回退到 machineId 的前 36 位 const getMachineGuid = () => __cursor_ids__.machineGuid || __cursor_ids__.machineId.substring(0, 36); log('当前 ID 配置:', __cursor_ids__); // ==================== Module Hook ==================== const Module = require('module'); const originalRequire = Module.prototype.require; // 缓存已 Hook 的模块 const hookedModules = new Map(); Module.prototype.require = function(id) { // 兼容 node: 前缀 const normalizedId = (typeof id === 'string' && id.startsWith('node:')) ? id.slice(5) : id; const result = originalRequire.apply(this, arguments); // 如果已经 Hook 过,直接返回缓存 if (hookedModules.has(normalizedId)) { return hookedModules.get(normalizedId); } let hooked = result; // Hook child_process 模块 if (normalizedId === 'child_process') { hooked = hookChildProcess(result); } // Hook os 模块 else if (normalizedId === 'os') { hooked = hookOs(result); } // Hook fs 模块 (新增:保护 storage.json) else if (normalizedId === 'fs') { hooked = hookFs(result); } // Hook crypto 模块 else if (normalizedId === 'crypto') { hooked = hookCrypto(result); } // Hook @vscode/deviceid 模块 else if (normalizedId === '@vscode/deviceid') { hooked = hookDeviceId(result); } // Hook @vscode/windows-registry 模块 else if (normalizedId === '@vscode/windows-registry') { hooked = hookWindowsRegistry(result); } // 缓存 Hook 结果 if (hooked !== result) { hookedModules.set(normalizedId, hooked); log(`已 Hook 模块: ${normalizedId}`); } return hooked; }; // ==================== child_process Hook ==================== function hookChildProcess(cp) { const originalExecSync = cp.execSync; const originalExecFileSync = cp.execFileSync; cp.execSync = function(command, options) { const cmdStr = String(command).toLowerCase(); // 拦截 MachineGuid 查询 if (cmdStr.includes('reg') && cmdStr.includes('machineguid')) { log('拦截 MachineGuid 查询'); // 返回格式化的注册表输出 return Buffer.from(`\r\n MachineGuid REG_SZ ${getMachineGuid()}\r\n`); } // 拦截 ioreg 命令 (macOS) if (cmdStr.includes('ioreg') && cmdStr.includes('ioplatformexpertdevice')) { log('拦截 IOPlatformUUID 查询'); return Buffer.from(`"IOPlatformUUID" = "${getMachineGuid().toUpperCase()}"`); } // 拦截 machine-id 读取 (Linux) if (cmdStr.includes('machine-id') || cmdStr.includes('hostname')) { log('拦截 machine-id 查询'); return Buffer.from(__cursor_ids__.machineId.substring(0, 32)); } return originalExecSync.apply(this, arguments); }; // 兼容 execFileSync(部分版本会直接调用可执行文件) if (typeof originalExecFileSync === 'function') { cp.execFileSync = function(file, args, options) { const cmdStr = [file].concat(args || []).join(' ').toLowerCase(); if (cmdStr.includes('reg') && cmdStr.includes('machineguid')) { log('拦截 MachineGuid 查询(execFileSync)'); return Buffer.from(`\r\n MachineGuid REG_SZ ${getMachineGuid()}\r\n`); } if (cmdStr.includes('ioreg') && cmdStr.includes('ioplatformexpertdevice')) { log('拦截 IOPlatformUUID 查询(execFileSync)'); return Buffer.from(`"IOPlatformUUID" = "${getMachineGuid().toUpperCase()}"`); } if (cmdStr.includes('machine-id') || cmdStr.includes('hostname')) { log('拦截 machine-id 查询(execFileSync)'); return Buffer.from(__cursor_ids__.machineId.substring(0, 32)); } return originalExecFileSync.apply(this, arguments); }; } return cp; } // ==================== os Hook ==================== function hookOs(os) { const originalNetworkInterfaces = os.networkInterfaces; os.networkInterfaces = function() { log('拦截 networkInterfaces 调用'); // 返回虚拟的网络接口,使用固定的 MAC 地址 return { 'Ethernet': [{ address: '192.168.1.100', netmask: '255.255.255.0', family: 'IPv4', mac: __cursor_ids__.macAddress || '00:00:00:00:00:00', internal: false }] }; }; return os; } // ==================== fs Hook (新增) ==================== // 🔧 拦截 storage.json 写入操作,保护 telemetry 字段不被覆盖 // 需要保护的 telemetry 字段列表 const PROTECTED_TELEMETRY_KEYS = [ 'telemetry.machineId', 'telemetry.macMachineId', 'telemetry.devDeviceId', 'telemetry.sqmId' ]; // 规范化 filePath(兼容 string/Buffer/URL 等) function normalizeFilePath(filePath) { try { if (filePath === undefined || filePath === null) return ''; if (typeof filePath === 'string') return filePath; if (Buffer.isBuffer(filePath)) return filePath.toString('utf8'); // WHATWG URL (fs 支持 URL 对象) if (typeof filePath === 'object' && typeof filePath.href === 'string') { // 优先将 file:// URL 转为本地路径,避免传递 "file:///..." 字符串导致 existsSync/readFileSync 失败 if (typeof filePath.protocol === 'string' && filePath.protocol === 'file:') { try { const url = require('url'); if (url && typeof url.fileURLToPath === 'function') { return url.fileURLToPath(filePath); } } catch (_) { // ignore } } return filePath.href; } return String(filePath); } catch (_) { return ''; } } function previewValue(value) { try { const s = String(value); return s.length > 16 ? s.slice(0, 16) + '...' : s; } catch (_) { return ''; } } // 将写入内容转为 utf8 文本,并提供回写为“同类类型”的包装器 function coerceContentToUtf8Text(content) { try { if (typeof content === 'string') { return { text: content, wrap: (s) => s }; } if (Buffer.isBuffer(content)) { return { text: content.toString('utf8'), wrap: (s) => Buffer.from(s, 'utf8') }; } // TypedArray / DataView if (content && typeof content === 'object') { if (content instanceof Uint8Array) { // Buffer 也属于 Uint8Array,但已在上面处理 const buf = Buffer.from(content); return { text: buf.toString('utf8'), wrap: (s) => new Uint8Array(Buffer.from(s, 'utf8')) }; } if (typeof ArrayBuffer !== 'undefined' && content instanceof ArrayBuffer) { const buf = Buffer.from(content); return { text: buf.toString('utf8'), wrap: (s) => Buffer.from(s, 'utf8') }; } if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' && ArrayBuffer.isView(content)) { const buf = Buffer.from(content.buffer, content.byteOffset, content.byteLength); return { text: buf.toString('utf8'), wrap: (s) => Buffer.from(s, 'utf8') }; } } } catch (_) { // ignore } return null; } // 检查路径是否为 storage.json function isStorageJsonPath(filePath) { const raw = normalizeFilePath(filePath); if (!raw) return false; const normalized = raw.replace(/\\/g, '/').toLowerCase(); return normalized.includes('globalstorage/storage.json'); } // 保护 storage.json 中的 telemetry 字段 function protectStorageJson(content, filePath) { if (!isStorageJsonPath(filePath)) return content; try { const fs = require('fs'); const coerced = coerceContentToUtf8Text(content); if (!coerced) return content; let newData; try { newData = JSON.parse(coerced.text); } catch (_) { return content; } // 如果写入的内容不是有效的 JSON 对象,直接返回 if (typeof newData !== 'object' || newData === null) { return content; } // 保护值优先级: // 1) __cursor_ids__(Hook 配置/环境变量/自动生成) // 2) 现有 storage.json 中已存在的值 // 3) 本次写入值(最低) const protectedValues = { 'telemetry.machineId': __cursor_ids__ && __cursor_ids__.machineId, 'telemetry.macMachineId': __cursor_ids__ && __cursor_ids__.macMachineId, 'telemetry.devDeviceId': __cursor_ids__ && __cursor_ids__.devDeviceId, 'telemetry.sqmId': __cursor_ids__ && __cursor_ids__.sqmId }; // 仅当 Hook 配置不完整时,才读取旧文件值作为二级兜底 let existingProtected = {}; const needExisting = PROTECTED_TELEMETRY_KEYS.some((k) => !(typeof protectedValues[k] === 'string' && protectedValues[k])); if (needExisting) { try { if (fs.existsSync(filePath)) { const existingText = fs.readFileSync(filePath, 'utf8'); const existing = JSON.parse(existingText); if (existing && typeof existing === 'object') { for (const key of PROTECTED_TELEMETRY_KEYS) { if (typeof existing[key] === 'string' && existing[key]) { existingProtected[key] = existing[key]; } } } } } catch (_) { // ignore } } let modified = false; for (const key of PROTECTED_TELEMETRY_KEYS) { const fromIds = protectedValues[key]; const desired = (typeof fromIds === 'string' && fromIds) ? fromIds : (typeof existingProtected[key] === 'string' && existingProtected[key]) ? existingProtected[key] : undefined; if (desired === undefined) { continue; } // 方案B:无论写入内容是否包含该字段,都确保最终值稳定(缺失则补齐) if (newData[key] !== desired) { log(`[fs Hook] 固定 ${key}: ${previewValue(newData[key])} -> ${previewValue(desired)}`); newData[key] = desired; modified = true; } } if (modified) { log('[fs Hook] storage.json telemetry 字段已保护'); const nextText = JSON.stringify(newData, null, '\t'); return coerced.wrap(nextText); } } catch (e) { const msg = e && e.message ? e.message : String(e); log('[fs Hook] 处理 storage.json 失败:', msg); } return content; } function hookFs(fsModule) { const originalWriteFileSync = fsModule.writeFileSync; const originalWriteFile = fsModule.writeFile; const originalAppendFileSync = fsModule.appendFileSync; const originalAppendFile = fsModule.appendFile; const originalCreateWriteStream = fsModule.createWriteStream; const originalOpenSync = fsModule.openSync; const originalOpen = fsModule.open; const originalCloseSync = fsModule.closeSync; const originalClose = fsModule.close; // fd 追踪:覆盖 open/close 路径(仅用于 storage.json) const storageJsonFds = new Map(); let inFdFix = false; const fixStorageJsonFile = (filePath) => { if (inFdFix) return; inFdFix = true; try { const current = fsModule.readFileSync(filePath, 'utf8'); const next = protectStorageJson(current, filePath); if (typeof next === 'string' && next !== current) { originalWriteFileSync.call(fsModule, filePath, next, 'utf8'); log('[fs Hook] close-fix: storage.json telemetry 字段已重新保护'); } } catch (e) { const msg = e && e.message ? e.message : String(e); log('[fs Hook] close-fix 失败:', msg); } finally { inFdFix = false; } }; // Hook writeFileSync fsModule.writeFileSync = function(filePath, data, options) { const protectedData = protectStorageJson(data, filePath); return originalWriteFileSync.call(this, filePath, protectedData, options); }; // Hook writeFile (异步版本) fsModule.writeFile = function(filePath, data, options, callback) { // 处理参数重载: writeFile(path, data, callback) 或 writeFile(path, data, options, callback) if (typeof options === 'function') { callback = options; options = undefined; } const protectedData = protectStorageJson(data, filePath); return originalWriteFile.call(this, filePath, protectedData, options, callback); }; // Hook promises API (fs.promises.writeFile) if (fsModule.promises) { const originalPromisesWriteFile = fsModule.promises.writeFile; fsModule.promises.writeFile = async function(filePath, data, options) { const protectedData = protectStorageJson(data, filePath); return originalPromisesWriteFile.call(this, filePath, protectedData, options); }; if (typeof fsModule.promises.appendFile === 'function') { const originalPromisesAppendFile = fsModule.promises.appendFile; fsModule.promises.appendFile = async function(filePath, data, options) { const protectedData = protectStorageJson(data, filePath); return originalPromisesAppendFile.call(this, filePath, protectedData, options); }; } } // Hook appendFileSync if (typeof originalAppendFileSync === 'function') { fsModule.appendFileSync = function(filePath, data, options) { const protectedData = protectStorageJson(data, filePath); return originalAppendFileSync.call(this, filePath, protectedData, options); }; } // Hook appendFile (异步版本) if (typeof originalAppendFile === 'function') { fsModule.appendFile = function(filePath, data, options, callback) { if (typeof options === 'function') { callback = options; options = undefined; } const protectedData = protectStorageJson(data, filePath); return originalAppendFile.call(this, filePath, protectedData, options, callback); }; } // Hook createWriteStream(仅对 storage.json:保持原生 WriteStream,但 close 后做补救性修正) if (typeof originalCreateWriteStream === 'function') { fsModule.createWriteStream = function(filePath, options) { const stream = originalCreateWriteStream.apply(this, arguments); if (isStorageJsonPath(filePath) && stream && typeof stream.on === 'function') { stream.on('close', () => { try { fixStorageJsonFile(filePath); } catch (_) { // ignore } }); } return stream; }; } // Hook open/openSync:追踪 storage.json 的 fd if (typeof originalOpenSync === 'function') { fsModule.openSync = function(filePath) { const fd = originalOpenSync.apply(this, arguments); try { if (!inFdFix && isStorageJsonPath(filePath)) { storageJsonFds.set(fd, filePath); } } catch (_) { // ignore } return fd; }; } if (typeof originalOpen === 'function') { fsModule.open = function(filePath, flags, mode, callback) { if (typeof mode === 'function') { callback = mode; mode = undefined; } const wrapped = function(err, fd) { try { if (!err && !inFdFix && isStorageJsonPath(filePath)) { storageJsonFds.set(fd, filePath); } } catch (_) { // ignore } if (typeof callback === 'function') { return callback.apply(this, arguments); } }; if (mode === undefined) { return originalOpen.call(this, filePath, flags, wrapped); } return originalOpen.call(this, filePath, flags, mode, wrapped); }; } // Hook close/closeSync:关闭后再做一次“落盘后修正”(覆盖 fd 写入路径) if (typeof originalCloseSync === 'function') { fsModule.closeSync = function(fd) { const filePath = storageJsonFds.get(fd); const ret = originalCloseSync.apply(this, arguments); if (filePath !== undefined) { storageJsonFds.delete(fd); fixStorageJsonFile(filePath); } return ret; }; } if (typeof originalClose === 'function') { fsModule.close = function(fd, callback) { const filePath = storageJsonFds.get(fd); const wrapped = function(err) { try { if (!err && filePath !== undefined) { storageJsonFds.delete(fd); fixStorageJsonFile(filePath); } } catch (_) { // ignore } if (typeof callback === 'function') { return callback.apply(this, arguments); } }; return originalClose.call(this, fd, wrapped); }; } log('[fs Hook] 已启用 storage.json 写入保护'); return fsModule; } // ==================== crypto Hook ==================== function hookCrypto(crypto) { const originalCreateHash = crypto.createHash; const originalRandomUUID = crypto.randomUUID; // Hook createHash - 用于拦截 machineId 的 SHA256 计算 crypto.createHash = function(algorithm) { const hash = originalCreateHash.apply(this, arguments); if (algorithm.toLowerCase() === 'sha256') { const originalUpdate = hash.update.bind(hash); const originalDigest = hash.digest.bind(hash); let inputData = ''; hash.update = function(data, encoding) { inputData += String(data); return originalUpdate(data, encoding); }; hash.digest = function(encoding) { // 检查是否是 machineId 相关的哈希计算 if (inputData.includes('MachineGuid') || inputData.includes('IOPlatformUUID') || inputData.length === 32 || inputData.length === 36) { log('拦截 SHA256 哈希计算,返回固定 machineId'); if (encoding === 'hex') { return __cursor_ids__.machineId; } return Buffer.from(__cursor_ids__.machineId, 'hex'); } return originalDigest(encoding); }; } return hash; }; // Hook randomUUID - 用于拦截 devDeviceId 生成 if (originalRandomUUID) { let uuidCallCount = 0; crypto.randomUUID = function() { uuidCallCount++; // 第一次调用返回固定的 devDeviceId if (uuidCallCount <= 2) { log('拦截 randomUUID 调用,返回固定 devDeviceId'); return __cursor_ids__.devDeviceId; } return originalRandomUUID.apply(this, arguments); }; } return crypto; } // ==================== @vscode/deviceid Hook ==================== function hookDeviceId(deviceIdModule) { log('Hook @vscode/deviceid 模块'); return { ...deviceIdModule, getDeviceId: async function() { log('拦截 getDeviceId 调用'); return __cursor_ids__.devDeviceId; } }; } // ==================== @vscode/windows-registry Hook ==================== function hookWindowsRegistry(registryModule) { log('Hook @vscode/windows-registry 模块'); const originalGetStringRegKey = registryModule.GetStringRegKey; return { ...registryModule, GetStringRegKey: function(hive, path, name) { const pathStr = (typeof path === 'string') ? path : ''; // 拦截 MachineId 读取 if (name === 'MachineId' || pathStr.includes('SQMClient')) { log('拦截注册表 MachineId/SQMClient 读取'); return __cursor_ids__.sqmId; } // 拦截 MachineGuid 读取 if (name === 'MachineGuid' || pathStr.includes('Cryptography')) { log('拦截注册表 MachineGuid 读取'); return getMachineGuid(); } if (typeof originalGetStringRegKey === 'function') { return originalGetStringRegKey.apply(this, arguments) || ''; } return ''; } }; } // ==================== 动态 import Hook ==================== // Cursor 使用动态 import() 加载模块,我们需要 Hook 这些模块 // 由于 ES Module 的限制,我们通过 Hook 全局对象来实现 // 存储已 Hook 的动态导入模块 const hookedDynamicModules = new Map(); // Hook crypto 模块的动态导入 const hookDynamicCrypto = (cryptoModule) => { if (hookedDynamicModules.has('crypto')) { return hookedDynamicModules.get('crypto'); } const hooked = { ...cryptoModule }; // Hook createHash if (cryptoModule.createHash) { const originalCreateHash = cryptoModule.createHash; hooked.createHash = function(algorithm) { const hash = originalCreateHash.apply(this, arguments); if (algorithm.toLowerCase() === 'sha256') { const originalDigest = hash.digest.bind(hash); let inputData = ''; const originalUpdate = hash.update.bind(hash); hash.update = function(data, encoding) { inputData += String(data); return originalUpdate(data, encoding); }; hash.digest = function(encoding) { // 检测 machineId 相关的哈希 if (inputData.includes('MachineGuid') || inputData.includes('IOPlatformUUID') || (inputData.length >= 32 && inputData.length <= 40)) { log('动态导入: 拦截 SHA256 哈希'); return encoding === 'hex' ? __cursor_ids__.machineId : Buffer.from(__cursor_ids__.machineId, 'hex'); } return originalDigest(encoding); }; } return hash; }; } hookedDynamicModules.set('crypto', hooked); return hooked; }; // Hook @vscode/deviceid 模块的动态导入 const hookDynamicDeviceId = (deviceIdModule) => { if (hookedDynamicModules.has('@vscode/deviceid')) { return hookedDynamicModules.get('@vscode/deviceid'); } const hooked = { ...deviceIdModule, getDeviceId: async () => { log('动态导入: 拦截 getDeviceId'); return __cursor_ids__.devDeviceId; } }; hookedDynamicModules.set('@vscode/deviceid', hooked); return hooked; }; // Hook @vscode/windows-registry 模块的动态导入 const hookDynamicWindowsRegistry = (registryModule) => { if (hookedDynamicModules.has('@vscode/windows-registry')) { return hookedDynamicModules.get('@vscode/windows-registry'); } const originalGetStringRegKey = registryModule.GetStringRegKey; const hooked = { ...registryModule, GetStringRegKey: function(hive, path, name) { const pathStr = (typeof path === 'string') ? path : ''; if (name === 'MachineId' || pathStr.includes('SQMClient')) { log('动态导入: 拦截 SQMClient'); return __cursor_ids__.sqmId; } if (name === 'MachineGuid' || pathStr.includes('Cryptography')) { log('动态导入: 拦截 MachineGuid'); return getMachineGuid(); } if (typeof originalGetStringRegKey === 'function') { return originalGetStringRegKey.apply(this, arguments) || ''; } return ''; } }; hookedDynamicModules.set('@vscode/windows-registry', hooked); return hooked; }; // Hook fs 模块的动态导入 (新增:保护 storage.json) const hookDynamicFs = (fsModule) => { if (hookedDynamicModules.has('fs')) { return hookedDynamicModules.get('fs'); } const hooked = { ...fsModule }; const originalWriteFileSync = fsModule.writeFileSync; const originalWriteFile = fsModule.writeFile; const originalAppendFileSync = fsModule.appendFileSync; const originalAppendFile = fsModule.appendFile; const originalCreateWriteStream = fsModule.createWriteStream; const originalOpenSync = fsModule.openSync; const originalOpen = fsModule.open; const originalCloseSync = fsModule.closeSync; const originalClose = fsModule.close; const storageJsonFds = new Map(); let inFdFix = false; const fixStorageJsonFile = (filePath) => { if (inFdFix) return; inFdFix = true; try { const current = fsModule.readFileSync(filePath, 'utf8'); const next = protectStorageJson(current, filePath); if (typeof next === 'string' && next !== current) { originalWriteFileSync.call(fsModule, filePath, next, 'utf8'); log('动态导入: close-fix storage.json telemetry 字段已重新保护'); } } catch (e) { const msg = e && e.message ? e.message : String(e); log('动态导入: close-fix 失败:', msg); } finally { inFdFix = false; } }; hooked.writeFileSync = function(filePath, data, options) { const protectedData = protectStorageJson(data, filePath); return originalWriteFileSync.call(this, filePath, protectedData, options); }; hooked.writeFile = function(filePath, data, options, callback) { if (typeof options === 'function') { callback = options; options = undefined; } const protectedData = protectStorageJson(data, filePath); return originalWriteFile.call(this, filePath, protectedData, options, callback); }; // Hook promises API if (fsModule.promises) { const originalPromisesWriteFile = fsModule.promises.writeFile; hooked.promises = { ...fsModule.promises, writeFile: async function(filePath, data, options) { const protectedData = protectStorageJson(data, filePath); return originalPromisesWriteFile.call(this, filePath, protectedData, options); } }; if (typeof fsModule.promises.appendFile === 'function') { const originalPromisesAppendFile = fsModule.promises.appendFile; hooked.promises.appendFile = async function(filePath, data, options) { const protectedData = protectStorageJson(data, filePath); return originalPromisesAppendFile.call(this, filePath, protectedData, options); }; } } if (typeof originalAppendFileSync === 'function') { hooked.appendFileSync = function(filePath, data, options) { const protectedData = protectStorageJson(data, filePath); return originalAppendFileSync.call(this, filePath, protectedData, options); }; } if (typeof originalAppendFile === 'function') { hooked.appendFile = function(filePath, data, options, callback) { if (typeof options === 'function') { callback = options; options = undefined; } const protectedData = protectStorageJson(data, filePath); return originalAppendFile.call(this, filePath, protectedData, options, callback); }; } if (typeof originalCreateWriteStream === 'function') { hooked.createWriteStream = function(filePath, options) { const stream = originalCreateWriteStream.apply(this, arguments); if (isStorageJsonPath(filePath) && stream && typeof stream.on === 'function') { stream.on('close', () => { try { fixStorageJsonFile(filePath); } catch (_) { // ignore } }); } return stream; }; } if (typeof originalOpenSync === 'function') { hooked.openSync = function(filePath) { const fd = originalOpenSync.apply(this, arguments); try { if (!inFdFix && isStorageJsonPath(filePath)) { storageJsonFds.set(fd, filePath); } } catch (_) { // ignore } return fd; }; } if (typeof originalOpen === 'function') { hooked.open = function(filePath, flags, mode, callback) { if (typeof mode === 'function') { callback = mode; mode = undefined; } const wrapped = function(err, fd) { try { if (!err && !inFdFix && isStorageJsonPath(filePath)) { storageJsonFds.set(fd, filePath); } } catch (_) { // ignore } if (typeof callback === 'function') { return callback.apply(this, arguments); } }; if (mode === undefined) { return originalOpen.call(this, filePath, flags, wrapped); } return originalOpen.call(this, filePath, flags, mode, wrapped); }; } if (typeof originalCloseSync === 'function') { hooked.closeSync = function(fd) { const filePath = storageJsonFds.get(fd); const ret = originalCloseSync.apply(this, arguments); if (filePath !== undefined) { storageJsonFds.delete(fd); fixStorageJsonFile(filePath); } return ret; }; } if (typeof originalClose === 'function') { hooked.close = function(fd, callback) { const filePath = storageJsonFds.get(fd); const wrapped = function(err) { try { if (!err && filePath !== undefined) { storageJsonFds.delete(fd); fixStorageJsonFile(filePath); } } catch (_) { // ignore } if (typeof callback === 'function') { return callback.apply(this, arguments); } }; return originalClose.call(this, fd, wrapped); }; } log('动态导入: 已 Hook fs 模块'); hookedDynamicModules.set('fs', hooked); return hooked; }; // 将 Hook 函数暴露到全局,供后续使用 globalThis.__cursor_hook_dynamic__ = { crypto: hookDynamicCrypto, deviceId: hookDynamicDeviceId, windowsRegistry: hookDynamicWindowsRegistry, fs: hookDynamicFs, // 新增 fs Hook ids: __cursor_ids__ }; log('Cursor Hook 初始化完成'); log('machineId:', __cursor_ids__.machineId.substring(0, 16) + '...'); log('machineGuid:', getMachineGuid().substring(0, 16) + '...'); log('devDeviceId:', __cursor_ids__.devDeviceId); log('sqmId:', __cursor_ids__.sqmId); })(); // ==================== 导出配置(供外部使用) ==================== if (typeof module !== 'undefined' && module.exports) { module.exports = { __cursor_hook_config__ }; } // ==================== ES Module 兼容性 ==================== // 如果在 ES Module 环境中,也暴露配置 if (typeof globalThis !== 'undefined') { globalThis.__cursor_hook_config__ = __cursor_hook_config__; }