/** * 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 地址获取 * * 📦 使用方式: * 将此代码注入到 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; 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 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; } // ==================== 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) { // 拦截 MachineId 读取 if (name === 'MachineId' || path.includes('SQMClient')) { log('拦截注册表 MachineId/SQMClient 读取'); return __cursor_ids__.sqmId; } // 拦截 MachineGuid 读取 if (name === 'MachineGuid' || path.includes('Cryptography')) { log('拦截注册表 MachineGuid 读取'); return getMachineGuid(); } return originalGetStringRegKey?.apply(this, arguments) || ''; } }; } // ==================== 动态 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) { if (name === 'MachineId' || path?.includes('SQMClient')) { log('动态导入: 拦截 SQMClient'); return __cursor_ids__.sqmId; } if (name === 'MachineGuid' || path?.includes('Cryptography')) { log('动态导入: 拦截 MachineGuid'); return getMachineGuid(); } return originalGetStringRegKey?.apply(this, arguments) || ''; } }; hookedDynamicModules.set('@vscode/windows-registry', hooked); return hooked; }; // 将 Hook 函数暴露到全局,供后续使用 globalThis.__cursor_hook_dynamic__ = { crypto: hookDynamicCrypto, deviceId: hookDynamicDeviceId, windowsRegistry: hookDynamicWindowsRegistry, 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__; }