mirror of
https://github.com/yuaotian/go-cursor-help.git
synced 2026-03-07 22:33:39 +00:00
```
feat(cursor-hook): 添加machineGuid和会话标识符支持并优化设备识别绕过方案 添加了新的标识符字段包括machineGuid、macAddress、sessionId和firstSessionDate, 实现对注册表MachineGuid/IOPlatformUUID的模拟。增强了ID配置的向后兼容性, 当配置文件缺失字段时自动补全并更新。 优化了设备识别绕过方案为三重保护机制: - 方案A: someValue占位符替换(稳定锚点) - 方案B: b6 定点重写(机器码源函数) - 方案C: Loader Stub + 外置 Hook(支持在线下载) 改进了模块劫持逻辑,兼容node:前缀,并增加了execFileSync的支持。 同时在Linux脚本中添加了相应的ID生成和配置文件部署功能。 ```
This commit is contained in:
@@ -110,9 +110,14 @@ var __cursor_hook_config__ = {
|
||||
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()}}`
|
||||
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;
|
||||
@@ -123,6 +128,32 @@ var __cursor_hook_config__ = {
|
||||
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;
|
||||
}
|
||||
@@ -133,10 +164,13 @@ var __cursor_hook_config__ = {
|
||||
// 生成新的 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()
|
||||
};
|
||||
|
||||
@@ -153,6 +187,8 @@ var __cursor_hook_config__ = {
|
||||
|
||||
// 加载 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 ====================
|
||||
@@ -164,42 +200,44 @@ var __cursor_hook_config__ = {
|
||||
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(id)) {
|
||||
return hookedModules.get(id);
|
||||
if (hookedModules.has(normalizedId)) {
|
||||
return hookedModules.get(normalizedId);
|
||||
}
|
||||
|
||||
let hooked = result;
|
||||
|
||||
// Hook child_process 模块
|
||||
if (id === 'child_process') {
|
||||
if (normalizedId === 'child_process') {
|
||||
hooked = hookChildProcess(result);
|
||||
}
|
||||
// Hook os 模块
|
||||
else if (id === 'os') {
|
||||
else if (normalizedId === 'os') {
|
||||
hooked = hookOs(result);
|
||||
}
|
||||
// Hook crypto 模块
|
||||
else if (id === 'crypto') {
|
||||
else if (normalizedId === 'crypto') {
|
||||
hooked = hookCrypto(result);
|
||||
}
|
||||
// Hook @vscode/deviceid 模块
|
||||
else if (id === '@vscode/deviceid') {
|
||||
else if (normalizedId === '@vscode/deviceid') {
|
||||
hooked = hookDeviceId(result);
|
||||
}
|
||||
// Hook @vscode/windows-registry 模块
|
||||
else if (id === '@vscode/windows-registry') {
|
||||
else if (normalizedId === '@vscode/windows-registry') {
|
||||
hooked = hookWindowsRegistry(result);
|
||||
}
|
||||
|
||||
// 缓存 Hook 结果
|
||||
if (hooked !== result) {
|
||||
hookedModules.set(id, hooked);
|
||||
log(`已 Hook 模块: ${id}`);
|
||||
hookedModules.set(normalizedId, hooked);
|
||||
log(`已 Hook 模块: ${normalizedId}`);
|
||||
}
|
||||
|
||||
|
||||
return hooked;
|
||||
};
|
||||
|
||||
@@ -207,6 +245,7 @@ var __cursor_hook_config__ = {
|
||||
|
||||
function hookChildProcess(cp) {
|
||||
const originalExecSync = cp.execSync;
|
||||
const originalExecFileSync = cp.execFileSync;
|
||||
|
||||
cp.execSync = function(command, options) {
|
||||
const cmdStr = String(command).toLowerCase();
|
||||
@@ -215,13 +254,13 @@ var __cursor_hook_config__ = {
|
||||
if (cmdStr.includes('reg') && cmdStr.includes('machineguid')) {
|
||||
log('拦截 MachineGuid 查询');
|
||||
// 返回格式化的注册表输出
|
||||
return Buffer.from(`\r\n MachineGuid REG_SZ ${__cursor_ids__.machineId.substring(0, 36)}\r\n`);
|
||||
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" = "${__cursor_ids__.machineId.substring(0, 36).toUpperCase()}"`);
|
||||
return Buffer.from(`"IOPlatformUUID" = "${getMachineGuid().toUpperCase()}"`);
|
||||
}
|
||||
|
||||
// 拦截 machine-id 读取 (Linux)
|
||||
@@ -233,6 +272,30 @@ var __cursor_hook_config__ = {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -347,7 +410,7 @@ var __cursor_hook_config__ = {
|
||||
// 拦截 MachineGuid 读取
|
||||
if (name === 'MachineGuid' || path.includes('Cryptography')) {
|
||||
log('拦截注册表 MachineGuid 读取');
|
||||
return __cursor_ids__.machineId.substring(0, 36);
|
||||
return getMachineGuid();
|
||||
}
|
||||
return originalGetStringRegKey?.apply(this, arguments) || '';
|
||||
}
|
||||
@@ -439,7 +502,7 @@ var __cursor_hook_config__ = {
|
||||
}
|
||||
if (name === 'MachineGuid' || path?.includes('Cryptography')) {
|
||||
log('动态导入: 拦截 MachineGuid');
|
||||
return __cursor_ids__.machineId.substring(0, 36);
|
||||
return getMachineGuid();
|
||||
}
|
||||
return originalGetStringRegKey?.apply(this, arguments) || '';
|
||||
}
|
||||
@@ -459,6 +522,7 @@ var __cursor_hook_config__ = {
|
||||
|
||||
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);
|
||||
|
||||
@@ -474,4 +538,3 @@ if (typeof module !== 'undefined' && module.exports) {
|
||||
if (typeof globalThis !== 'undefined') {
|
||||
globalThis.__cursor_hook_config__ = __cursor_hook_config__;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ BACKUP_DIR="$CURSOR_CONFIG_DIR/User/globalStorage/backups"
|
||||
|
||||
# 共享ID(用于配置与JS注入保持一致)
|
||||
CURSOR_ID_MACHINE_ID=""
|
||||
CURSOR_ID_MACHINE_GUID=""
|
||||
CURSOR_ID_MAC_MACHINE_ID=""
|
||||
CURSOR_ID_DEVICE_ID=""
|
||||
CURSOR_ID_SQM_ID=""
|
||||
@@ -529,6 +530,7 @@ PY
|
||||
# 仅用于JS注入的ID生成(不写配置)
|
||||
generate_ids_for_js_only() {
|
||||
CURSOR_ID_MACHINE_ID=$(openssl rand -hex 32)
|
||||
CURSOR_ID_MACHINE_GUID=$(generate_uuid)
|
||||
CURSOR_ID_MAC_MACHINE_ID=$(openssl rand -hex 32)
|
||||
CURSOR_ID_DEVICE_ID=$(generate_uuid)
|
||||
CURSOR_ID_SQM_ID="{$(generate_uuid | tr '[:lower:]' '[:upper:]')}"
|
||||
@@ -787,10 +789,12 @@ find_cursor_js_files() {
|
||||
local js_patterns=(
|
||||
"resources/app/out/vs/workbench/api/node/extensionHostProcess.js"
|
||||
"resources/app/out/main.js"
|
||||
"resources/app/out/vs/code/electron-utility/sharedProcess/sharedProcessMain.js"
|
||||
"resources/app/out/vs/code/node/cliProcessMain.js"
|
||||
# 添加其他可能的路径模式
|
||||
"app/out/vs/workbench/api/node/extensionHostProcess.js" # 如果资源目录是 app 的父目录
|
||||
"app/out/main.js"
|
||||
"app/out/vs/code/electron-utility/sharedProcess/sharedProcessMain.js"
|
||||
"app/out/vs/code/node/cliProcessMain.js"
|
||||
)
|
||||
|
||||
@@ -841,13 +845,13 @@ find_cursor_js_files() {
|
||||
}
|
||||
|
||||
# 修改Cursor的JS文件
|
||||
# 🔧 修改Cursor内核JS文件实现设备识别绕过(增强版 Hook 方案)
|
||||
# 🔧 修改Cursor内核JS文件实现设备识别绕过(增强版三重方案)
|
||||
# 方案A: someValue占位符替换 - 稳定锚点,不依赖混淆后的函数名
|
||||
# 方案B: 深度 Hook 注入 - 从底层拦截所有设备标识符生成
|
||||
# 方案C: Module.prototype.require 劫持 - 拦截 child_process, crypto, os 等模块
|
||||
# 方案B: b6 定点重写 - 机器码源函数直接返回固定值
|
||||
# 方案C: Loader Stub + 外置 Hook - 主/共享进程仅加载外置 Hook 文件
|
||||
modify_cursor_js_files() {
|
||||
log_info "🔧 [内核修改] 开始修改Cursor内核JS文件实现设备识别绕过..."
|
||||
log_info "💡 [方案] 使用增强版 Hook 方案:深度模块劫持 + someValue替换"
|
||||
log_info "💡 [方案] 使用增强版三重方案:占位符替换 + b6 定点重写 + Loader Stub + 外置 Hook"
|
||||
|
||||
# 先查找需要修改的JS文件
|
||||
if ! find_cursor_js_files; then
|
||||
@@ -861,6 +865,7 @@ modify_cursor_js_files() {
|
||||
|
||||
# 生成或复用设备标识符(优先使用配置中读取的值)
|
||||
local machine_id="${CURSOR_ID_MACHINE_ID:-}"
|
||||
local machine_guid="${CURSOR_ID_MACHINE_GUID:-}"
|
||||
local device_id="${CURSOR_ID_DEVICE_ID:-}"
|
||||
local mac_machine_id="${CURSOR_ID_MAC_MACHINE_ID:-}"
|
||||
local sqm_id="${CURSOR_ID_SQM_ID:-}"
|
||||
@@ -873,6 +878,10 @@ modify_cursor_js_files() {
|
||||
machine_id=$(openssl rand -hex 32)
|
||||
ids_missing=true
|
||||
fi
|
||||
if [ -z "$machine_guid" ]; then
|
||||
machine_guid=$(generate_uuid)
|
||||
ids_missing=true
|
||||
fi
|
||||
if [ -z "$device_id" ]; then
|
||||
device_id=$(generate_uuid)
|
||||
ids_missing=true
|
||||
@@ -901,6 +910,7 @@ modify_cursor_js_files() {
|
||||
fi
|
||||
|
||||
CURSOR_ID_MACHINE_ID="$machine_id"
|
||||
CURSOR_ID_MACHINE_GUID="$machine_guid"
|
||||
CURSOR_ID_DEVICE_ID="$device_id"
|
||||
CURSOR_ID_MAC_MACHINE_ID="$mac_machine_id"
|
||||
CURSOR_ID_SQM_ID="$sqm_id"
|
||||
@@ -910,6 +920,7 @@ modify_cursor_js_files() {
|
||||
|
||||
log_info "🔑 [准备] 设备标识符已就绪"
|
||||
log_info " machineId: ${machine_id:0:16}..."
|
||||
log_info " machineGuid: ${machine_guid:0:16}..."
|
||||
log_info " deviceId: ${device_id:0:16}..."
|
||||
log_info " macMachineId: ${mac_machine_id:0:16}..."
|
||||
log_info " sqmId: $sqm_id"
|
||||
@@ -923,16 +934,75 @@ modify_cursor_js_files() {
|
||||
cat > "$ids_config_path" << EOF
|
||||
{
|
||||
"machineId": "$machine_id",
|
||||
"machineGuid": "$machine_guid",
|
||||
"macMachineId": "$mac_machine_id",
|
||||
"devDeviceId": "$device_id",
|
||||
"sqmId": "$sqm_id",
|
||||
"macAddress": "$mac_address",
|
||||
"sessionId": "$session_id",
|
||||
"firstSessionDate": "$first_session_date",
|
||||
"createdAt": "$first_session_date"
|
||||
}
|
||||
EOF
|
||||
chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$ids_config_path" 2>/dev/null || true
|
||||
log_info "💾 [保存] 新的 ID 配置已保存到: $ids_config_path"
|
||||
|
||||
# 部署外置 Hook 文件(供 Loader Stub 加载,支持多域名备用下载)
|
||||
local hook_target_path="$HOME/.cursor_hook.js"
|
||||
local script_dir
|
||||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
local hook_source_path="$script_dir/../hook/cursor_hook.js"
|
||||
local hook_download_urls=(
|
||||
"https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/hook/cursor_hook.js"
|
||||
"https://down.npee.cn/?https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/hook/cursor_hook.js"
|
||||
"https://xget.xi-xu.me/gh/yuaotian/go-cursor-help/refs/heads/master/scripts/hook/cursor_hook.js"
|
||||
"https://gh-proxy.com/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/hook/cursor_hook.js"
|
||||
"https://gh.chjina.com/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/hook/cursor_hook.js"
|
||||
)
|
||||
|
||||
if [ -f "$hook_source_path" ]; then
|
||||
if cp "$hook_source_path" "$hook_target_path"; then
|
||||
chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$hook_target_path" 2>/dev/null || true
|
||||
log_info "✅ [Hook] 外置 Hook 已部署: $hook_target_path"
|
||||
else
|
||||
log_warn "⚠️ [Hook] 本地 Hook 复制失败,尝试在线下载..."
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -f "$hook_target_path" ]; then
|
||||
local hook_downloaded=false
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
for url in "${hook_download_urls[@]}"; do
|
||||
if curl -fsSL "$url" -o "$hook_target_path"; then
|
||||
chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$hook_target_path" 2>/dev/null || true
|
||||
log_info "✅ [Hook] 外置 Hook 已在线下载: $hook_target_path"
|
||||
hook_downloaded=true
|
||||
break
|
||||
else
|
||||
rm -f "$hook_target_path"
|
||||
log_warn "⚠️ [Hook] 外置 Hook 下载失败: $url"
|
||||
fi
|
||||
done
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
for url in "${hook_download_urls[@]}"; do
|
||||
if wget -qO "$hook_target_path" "$url"; then
|
||||
chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$hook_target_path" 2>/dev/null || true
|
||||
log_info "✅ [Hook] 外置 Hook 已在线下载: $hook_target_path"
|
||||
hook_downloaded=true
|
||||
break
|
||||
else
|
||||
rm -f "$hook_target_path"
|
||||
log_warn "⚠️ [Hook] 外置 Hook 下载失败: $url"
|
||||
fi
|
||||
done
|
||||
else
|
||||
log_warn "⚠️ [Hook] 未检测到 curl/wget,无法在线下载 Hook"
|
||||
fi
|
||||
if [ "$hook_downloaded" != true ] && [ ! -f "$hook_target_path" ]; then
|
||||
log_warn "⚠️ [Hook] 外置 Hook 全部下载失败"
|
||||
fi
|
||||
fi
|
||||
|
||||
local modified_count=0
|
||||
local file_modification_status=()
|
||||
|
||||
@@ -1041,102 +1111,66 @@ EOF
|
||||
replaced=true
|
||||
fi
|
||||
|
||||
# ========== 方法B: 增强版深度 Hook 注入 ==========
|
||||
local inject_code='// ========== Cursor Hook 注入开始 ==========
|
||||
# ========== 方法B: b6 定点重写(机器码源函数,仅 main.js) ==========
|
||||
local b6_patched=false
|
||||
if [ "$(basename "$file")" = "main.js" ]; then
|
||||
if command -v python3 >/dev/null 2>&1; then
|
||||
local b6_result
|
||||
b6_result=$(python3 - "$file" "$machine_guid" "$machine_id" <<'PY'
|
||||
import re, sys
|
||||
path, machine_guid, machine_id = sys.argv[1], sys.argv[2], sys.argv[3]
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
data = f.read()
|
||||
pattern = re.compile(r'async function (\\w+)\\((\\w+)\\)\\{.*?createHash\\(\"sha256\"\\).*?return \\w+\\?\\w+:\\w+\\}', re.S)
|
||||
def repl(m):
|
||||
name = m.group(1)
|
||||
param = m.group(2)
|
||||
return f"async function {name}({param}){{return {param}?\\\"{machine_guid}\\\":\\\"{machine_id}\\\";}}"
|
||||
new_data, count = pattern.subn(repl, data, count=1)
|
||||
if count:
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
f.write(new_data)
|
||||
print("PATCHED")
|
||||
else:
|
||||
print("NOT_FOUND")
|
||||
PY
|
||||
)
|
||||
if [ "$b6_result" = "PATCHED" ]; then
|
||||
log_info " ✓ [方案B] 已重写 b6 特征函数"
|
||||
b6_patched=true
|
||||
else
|
||||
log_warn "⚠️ [方案B] 未定位到 b6 特征函数"
|
||||
fi
|
||||
else
|
||||
log_warn "⚠️ [方案B] 未检测到 python3,跳过 b6 定点重写"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ========== 方法C: Loader Stub 注入 ==========
|
||||
local inject_code='// ========== Cursor Hook Loader 开始 ==========
|
||||
;(async function(){/*__cursor_patched__*/
|
||||
"use strict";
|
||||
if(globalThis.__cursor_patched__)return;
|
||||
if(globalThis.__cursor_hook_loaded__)return;
|
||||
globalThis.__cursor_hook_loaded__=true;
|
||||
|
||||
// 兼容 ESM:确保可用的 require(部分版本 main.js 可能是纯 ESM,不保证存在 require)
|
||||
var __require__=typeof require==="function"?require:null;
|
||||
if(!__require__){
|
||||
try{
|
||||
try{
|
||||
var __require__=typeof require==="function"?require:null;
|
||||
if(!__require__){
|
||||
var __m__=await import("module");
|
||||
__require__=__m__.createRequire(import.meta.url);
|
||||
}catch(e){
|
||||
// 无法获得 require 时直接退出,避免影响主进程启动
|
||||
return;
|
||||
}
|
||||
var fs=__require__("fs");
|
||||
var path=__require__("path");
|
||||
var os=__require__("os");
|
||||
var hookPath=path.join(os.homedir(), ".cursor_hook.js");
|
||||
if(fs.existsSync(hookPath)){
|
||||
__require__(hookPath);
|
||||
}
|
||||
}catch(e){
|
||||
// 失败静默,避免影响启动
|
||||
}
|
||||
|
||||
globalThis.__cursor_patched__=true;
|
||||
|
||||
var __ids__={
|
||||
machineId:"'"$machine_id"'",
|
||||
macMachineId:"'"$mac_machine_id"'",
|
||||
devDeviceId:"'"$device_id"'",
|
||||
sqmId:"'"$sqm_id"'",
|
||||
macAddress:"'"$mac_address"'"
|
||||
};
|
||||
|
||||
globalThis.__cursor_ids__=__ids__;
|
||||
|
||||
var Module=__require__("module");
|
||||
var _origReq=Module.prototype.require;
|
||||
var _hooked=new Map();
|
||||
|
||||
Module.prototype.require=function(id){
|
||||
var result=_origReq.apply(this,arguments);
|
||||
if(_hooked.has(id))return _hooked.get(id);
|
||||
var hooked=result;
|
||||
|
||||
if(id==="child_process"){
|
||||
var _origExecSync=result.execSync;
|
||||
result.execSync=function(cmd,opts){
|
||||
var cmdStr=String(cmd).toLowerCase();
|
||||
if(cmdStr.includes("machine-id")||cmdStr.includes("hostname")){
|
||||
return Buffer.from(__ids__.machineId.substring(0,32));
|
||||
}
|
||||
return _origExecSync.apply(this,arguments);
|
||||
};
|
||||
hooked=result;
|
||||
}
|
||||
else if(id==="os"){
|
||||
result.networkInterfaces=function(){
|
||||
return{"eth0":[{address:"192.168.1.100",netmask:"255.255.255.0",family:"IPv4",mac:__ids__.macAddress,internal:false}]};
|
||||
};
|
||||
hooked=result;
|
||||
}
|
||||
else if(id==="crypto"){
|
||||
var _origCreateHash=result.createHash;
|
||||
var _origRandomUUID=result.randomUUID;
|
||||
result.createHash=function(algo){
|
||||
var hash=_origCreateHash.apply(this,arguments);
|
||||
if(algo.toLowerCase()==="sha256"){
|
||||
var _origDigest=hash.digest.bind(hash);
|
||||
var _origUpdate=hash.update.bind(hash);
|
||||
var inputData="";
|
||||
hash.update=function(data,enc){inputData+=String(data);return _origUpdate(data,enc);};
|
||||
hash.digest=function(enc){
|
||||
if(inputData.includes("machine-id")||(inputData.length>=32&&inputData.length<=40)){
|
||||
return enc==="hex"?__ids__.machineId:Buffer.from(__ids__.machineId,"hex");
|
||||
}
|
||||
return _origDigest(enc);
|
||||
};
|
||||
}
|
||||
return hash;
|
||||
};
|
||||
if(_origRandomUUID){
|
||||
var uuidCount=0;
|
||||
result.randomUUID=function(){
|
||||
uuidCount++;
|
||||
if(uuidCount<=2)return __ids__.devDeviceId;
|
||||
return _origRandomUUID.apply(this,arguments);
|
||||
};
|
||||
}
|
||||
hooked=result;
|
||||
}
|
||||
else if(id==="@vscode/deviceid"){
|
||||
hooked={...result,getDeviceId:async function(){return __ids__.devDeviceId;}};
|
||||
}
|
||||
|
||||
if(hooked!==result)_hooked.set(id,hooked);
|
||||
return hooked;
|
||||
};
|
||||
|
||||
console.log("[Cursor ID Modifier] 增强版 Hook 已激活 - 煎饼果子(86) 公众号【煎饼果子卷AI】");
|
||||
})();
|
||||
// ========== Cursor Hook 注入结束 ==========
|
||||
// ========== Cursor Hook Loader 结束 ==========
|
||||
|
||||
'
|
||||
|
||||
@@ -1153,19 +1187,22 @@ console.log("[Cursor ID Modifier] 增强版 Hook 已激活 - 煎饼果子(86)
|
||||
}
|
||||
{ print }
|
||||
' "$file" > "$temp_file"
|
||||
log_info " ✓ [方案B] 增强版 Hook 代码已注入(版权声明后)"
|
||||
log_info " ✓ [方案C] Loader Stub 已注入(版权声明后)"
|
||||
else
|
||||
echo "$inject_code" > "$temp_file"
|
||||
cat "$file" >> "$temp_file"
|
||||
log_info " ✓ [方案B] 增强版 Hook 代码已注入(文件开头)"
|
||||
log_info " ✓ [方案C] Loader Stub 已注入(文件开头)"
|
||||
fi
|
||||
|
||||
if mv "$temp_file" "$file"; then
|
||||
local summary="Hook加载器"
|
||||
if [ "$replaced" = true ]; then
|
||||
log_info "✅ [成功] 增强版混合方案修改成功(someValue替换 + 深度Hook)"
|
||||
else
|
||||
log_info "✅ [成功] 增强版 Hook 修改成功"
|
||||
summary="someValue替换 + $summary"
|
||||
fi
|
||||
if [ "$b6_patched" = true ]; then
|
||||
summary="b6定点重写 + $summary"
|
||||
fi
|
||||
log_info "✅ [成功] 增强版方案修改成功($summary)"
|
||||
((modified_count++))
|
||||
file_modification_status+=("'$(basename "$file")': Success")
|
||||
|
||||
@@ -1191,9 +1228,10 @@ console.log("[Cursor ID Modifier] 增强版 Hook 已激活 - 煎饼果子(86)
|
||||
fi
|
||||
|
||||
log_info "🎉 [完成] 成功修改 $modified_count 个JS文件"
|
||||
log_info "💡 [说明] 使用增强版 Hook 方案:"
|
||||
log_info "💡 [说明] 使用增强版三重方案:"
|
||||
log_info " • 方案A: someValue占位符替换(稳定锚点,跨版本兼容)"
|
||||
log_info " • 方案B: 深度模块劫持(child_process, crypto, os, @vscode/*)"
|
||||
log_info " • 方案B: b6 定点重写(机器码源函数)"
|
||||
log_info " • 方案C: Loader Stub + 外置 Hook(cursor_hook.js)"
|
||||
log_info "📁 [配置] ID 配置文件: $ids_config_path"
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -755,6 +755,7 @@ BACKUP_DIR="$TARGET_HOME/Library/Application Support/Cursor/User/globalStorage/b
|
||||
|
||||
# 共享ID(用于配置与JS注入保持一致)
|
||||
CURSOR_ID_MACHINE_ID=""
|
||||
CURSOR_ID_MACHINE_GUID=""
|
||||
CURSOR_ID_MAC_MACHINE_ID=""
|
||||
CURSOR_ID_DEVICE_ID=""
|
||||
CURSOR_ID_SQM_ID=""
|
||||
@@ -1434,31 +1435,10 @@ _show_troubleshooting_info() {
|
||||
echo
|
||||
}
|
||||
|
||||
# 智能设备识别绕过(优先MAC地址修改,失败则JS注入)
|
||||
# 智能设备识别绕过(已移除 MAC 地址修改,仅保留 JS 注入)
|
||||
run_device_bypass() {
|
||||
log_info "🔧 [设备识别] 开始执行智能设备识别绕过..."
|
||||
log_info "🔧 [设备识别] 已禁用 MAC 地址修改,直接执行 JS 内核注入..."
|
||||
|
||||
local wifi_interface=""
|
||||
wifi_interface=$(networksetup -listallhardwareports | awk '/Hardware Port: Wi-Fi/{getline; print $2; exit}')
|
||||
local mac_success=false
|
||||
|
||||
if [ -n "$wifi_interface" ]; then
|
||||
log_info "📡 [接口] 检测到 Wi-Fi 接口: $wifi_interface"
|
||||
if _change_mac_for_one_interface "$wifi_interface"; then
|
||||
mac_success=true
|
||||
else
|
||||
log_warn "⚠️ [MAC] Wi-Fi 接口 MAC 地址修改失败或未生效"
|
||||
fi
|
||||
else
|
||||
log_warn "⚠️ [MAC] 未找到 Wi-Fi 接口,改用 JS 注入"
|
||||
fi
|
||||
|
||||
if [ "$mac_success" = true ]; then
|
||||
log_info "✅ [MAC] MAC 地址修改成功,跳过 JS 注入"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_info "🔧 [JS] 开始执行 JS 内核注入..."
|
||||
if modify_cursor_js_files; then
|
||||
log_info "✅ [JS] JS 内核注入完成"
|
||||
return 0
|
||||
@@ -1572,13 +1552,13 @@ protect_storage_file() {
|
||||
fi
|
||||
}
|
||||
|
||||
# 🔧 修改Cursor内核JS文件实现设备识别绕过(增强版 Hook 方案)
|
||||
# 🔧 修改Cursor内核JS文件实现设备识别绕过(增强版三重方案)
|
||||
# 方案A: someValue占位符替换 - 稳定锚点,不依赖混淆后的函数名
|
||||
# 方案B: 深度 Hook 注入 - 从底层拦截所有设备标识符生成
|
||||
# 方案C: Module.prototype.require 劫持 - 拦截 child_process, crypto, os 等模块
|
||||
# 方案B: b6 定点重写 - 机器码源函数直接返回固定值
|
||||
# 方案C: Loader Stub + 外置 Hook - 主/共享进程仅加载外置 Hook 文件
|
||||
modify_cursor_js_files() {
|
||||
log_info "🔧 [内核修改] 开始修改Cursor内核JS文件实现设备识别绕过..."
|
||||
log_info "💡 [方案] 使用增强版 Hook 方案:深度模块劫持 + someValue替换"
|
||||
log_info "💡 [方案] 使用增强版三重方案:占位符替换 + b6 定点重写 + Loader Stub + 外置 Hook"
|
||||
echo
|
||||
|
||||
# 检查Cursor应用是否存在
|
||||
@@ -1589,6 +1569,7 @@ modify_cursor_js_files() {
|
||||
|
||||
# 生成或复用设备标识符(优先使用配置中生成的值)
|
||||
local machine_id="${CURSOR_ID_MACHINE_ID:-}"
|
||||
local machine_guid="${CURSOR_ID_MACHINE_GUID:-}"
|
||||
local device_id="${CURSOR_ID_DEVICE_ID:-}"
|
||||
local mac_machine_id="${CURSOR_ID_MAC_MACHINE_ID:-}"
|
||||
local sqm_id="${CURSOR_ID_SQM_ID:-}"
|
||||
@@ -1601,6 +1582,10 @@ modify_cursor_js_files() {
|
||||
machine_id=$(openssl rand -hex 32)
|
||||
ids_missing=true
|
||||
fi
|
||||
if [ -z "$machine_guid" ]; then
|
||||
machine_guid=$(uuidgen | tr '[:upper:]' '[:lower:]')
|
||||
ids_missing=true
|
||||
fi
|
||||
if [ -z "$device_id" ]; then
|
||||
device_id=$(uuidgen | tr '[:upper:]' '[:lower:]')
|
||||
ids_missing=true
|
||||
@@ -1629,6 +1614,7 @@ modify_cursor_js_files() {
|
||||
fi
|
||||
|
||||
CURSOR_ID_MACHINE_ID="$machine_id"
|
||||
CURSOR_ID_MACHINE_GUID="$machine_guid"
|
||||
CURSOR_ID_DEVICE_ID="$device_id"
|
||||
CURSOR_ID_MAC_MACHINE_ID="$mac_machine_id"
|
||||
CURSOR_ID_SQM_ID="$sqm_id"
|
||||
@@ -1638,6 +1624,7 @@ modify_cursor_js_files() {
|
||||
|
||||
log_info "🔑 [准备] 设备标识符已就绪"
|
||||
log_info " machineId: ${machine_id:0:16}..."
|
||||
log_info " machineGuid: ${machine_guid:0:16}..."
|
||||
log_info " deviceId: ${device_id:0:16}..."
|
||||
log_info " macMachineId: ${mac_machine_id:0:16}..."
|
||||
log_info " sqmId: $sqm_id"
|
||||
@@ -1652,18 +1639,78 @@ modify_cursor_js_files() {
|
||||
cat > "$ids_config_path" << EOF
|
||||
{
|
||||
"machineId": "$machine_id",
|
||||
"machineGuid": "$machine_guid",
|
||||
"macMachineId": "$mac_machine_id",
|
||||
"devDeviceId": "$device_id",
|
||||
"sqmId": "$sqm_id",
|
||||
"macAddress": "$mac_address",
|
||||
"sessionId": "$session_id",
|
||||
"firstSessionDate": "$first_session_date",
|
||||
"createdAt": "$first_session_date"
|
||||
}
|
||||
EOF
|
||||
log_info "💾 [保存] 新的 ID 配置已保存到: $ids_config_path"
|
||||
|
||||
# 目标JS文件列表(只修改 main.js)
|
||||
# 部署外置 Hook 文件(供 Loader Stub 加载,支持多域名备用下载)
|
||||
local hook_target_path="$TARGET_HOME/.cursor_hook.js"
|
||||
local script_dir
|
||||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
local hook_source_path="$script_dir/../hook/cursor_hook.js"
|
||||
local hook_download_urls=(
|
||||
"https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/hook/cursor_hook.js"
|
||||
"https://down.npee.cn/?https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/hook/cursor_hook.js"
|
||||
"https://xget.xi-xu.me/gh/yuaotian/go-cursor-help/refs/heads/master/scripts/hook/cursor_hook.js"
|
||||
"https://gh-proxy.com/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/hook/cursor_hook.js"
|
||||
"https://gh.chjina.com/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/hook/cursor_hook.js"
|
||||
)
|
||||
|
||||
if [ -f "$hook_source_path" ]; then
|
||||
if cp "$hook_source_path" "$hook_target_path"; then
|
||||
chown "$TARGET_USER":"$(id -g -n "$TARGET_USER")" "$hook_target_path" 2>/dev/null || true
|
||||
log_info "✅ [Hook] 外置 Hook 已部署: $hook_target_path"
|
||||
else
|
||||
log_warn "⚠️ [Hook] 本地 Hook 复制失败,尝试在线下载..."
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -f "$hook_target_path" ]; then
|
||||
local hook_downloaded=false
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
for url in "${hook_download_urls[@]}"; do
|
||||
if curl -fsSL "$url" -o "$hook_target_path"; then
|
||||
chown "$TARGET_USER":"$(id -g -n "$TARGET_USER")" "$hook_target_path" 2>/dev/null || true
|
||||
log_info "✅ [Hook] 外置 Hook 已在线下载: $hook_target_path"
|
||||
hook_downloaded=true
|
||||
break
|
||||
else
|
||||
rm -f "$hook_target_path"
|
||||
log_warn "⚠️ [Hook] 外置 Hook 下载失败: $url"
|
||||
fi
|
||||
done
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
for url in "${hook_download_urls[@]}"; do
|
||||
if wget -qO "$hook_target_path" "$url"; then
|
||||
chown "$TARGET_USER":"$(id -g -n "$TARGET_USER")" "$hook_target_path" 2>/dev/null || true
|
||||
log_info "✅ [Hook] 外置 Hook 已在线下载: $hook_target_path"
|
||||
hook_downloaded=true
|
||||
break
|
||||
else
|
||||
rm -f "$hook_target_path"
|
||||
log_warn "⚠️ [Hook] 外置 Hook 下载失败: $url"
|
||||
fi
|
||||
done
|
||||
else
|
||||
log_warn "⚠️ [Hook] 未检测到 curl/wget,无法在线下载 Hook"
|
||||
fi
|
||||
if [ "$hook_downloaded" != true ] && [ ! -f "$hook_target_path" ]; then
|
||||
log_warn "⚠️ [Hook] 外置 Hook 全部下载失败"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 目标JS文件列表(main + shared process)
|
||||
local js_files=(
|
||||
"$CURSOR_APP_PATH/Contents/Resources/app/out/main.js"
|
||||
"$CURSOR_APP_PATH/Contents/Resources/app/out/vs/code/electron-utility/sharedProcess/sharedProcessMain.js"
|
||||
)
|
||||
|
||||
local modified_count=0
|
||||
@@ -1791,106 +1838,66 @@ EOF
|
||||
replaced=true
|
||||
fi
|
||||
|
||||
# ========== 方法B: 增强版深度 Hook 注入 ==========
|
||||
# 创建注入代码
|
||||
local inject_code='// ========== Cursor Hook 注入开始 ==========
|
||||
# ========== 方法B: b6 定点重写(机器码源函数,仅 main.js) ==========
|
||||
local b6_patched=false
|
||||
if [ "$(basename "$file")" = "main.js" ]; then
|
||||
if command -v python3 >/dev/null 2>&1; then
|
||||
local b6_result
|
||||
b6_result=$(python3 - "$file" "$machine_guid" "$machine_id" <<'PY'
|
||||
import re, sys
|
||||
path, machine_guid, machine_id = sys.argv[1], sys.argv[2], sys.argv[3]
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
data = f.read()
|
||||
pattern = re.compile(r'async function (\\w+)\\((\\w+)\\)\\{.*?createHash\\(\"sha256\"\\).*?return \\w+\\?\\w+:\\w+\\}', re.S)
|
||||
def repl(m):
|
||||
name = m.group(1)
|
||||
param = m.group(2)
|
||||
return f"async function {name}({param}){{return {param}?\\\"{machine_guid}\\\":\\\"{machine_id}\\\";}}"
|
||||
new_data, count = pattern.subn(repl, data, count=1)
|
||||
if count:
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
f.write(new_data)
|
||||
print("PATCHED")
|
||||
else:
|
||||
print("NOT_FOUND")
|
||||
PY
|
||||
)
|
||||
if [ "$b6_result" = "PATCHED" ]; then
|
||||
log_info " ✓ [方案B] 已重写 b6 特征函数"
|
||||
b6_patched=true
|
||||
else
|
||||
log_warn "⚠️ [方案B] 未定位到 b6 特征函数"
|
||||
fi
|
||||
else
|
||||
log_warn "⚠️ [方案B] 未检测到 python3,跳过 b6 定点重写"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ========== 方法C: Loader Stub 注入 ==========
|
||||
local inject_code='// ========== Cursor Hook Loader 开始 ==========
|
||||
;(async function(){/*__cursor_patched__*/
|
||||
"use strict";
|
||||
if(globalThis.__cursor_patched__)return;
|
||||
if(globalThis.__cursor_hook_loaded__)return;
|
||||
globalThis.__cursor_hook_loaded__=true;
|
||||
|
||||
// 兼容 ESM:确保可用的 require(部分版本 main.js 可能是纯 ESM,不保证存在 require)
|
||||
var __require__=typeof require==="function"?require:null;
|
||||
if(!__require__){
|
||||
try{
|
||||
try{
|
||||
var __require__=typeof require==="function"?require:null;
|
||||
if(!__require__){
|
||||
var __m__=await import("module");
|
||||
__require__=__m__.createRequire(import.meta.url);
|
||||
}catch(e){
|
||||
// 无法获得 require 时直接退出,避免影响主进程启动
|
||||
return;
|
||||
}
|
||||
var fs=__require__("fs");
|
||||
var path=__require__("path");
|
||||
var os=__require__("os");
|
||||
var hookPath=path.join(os.homedir(), ".cursor_hook.js");
|
||||
if(fs.existsSync(hookPath)){
|
||||
__require__(hookPath);
|
||||
}
|
||||
}catch(e){
|
||||
// 失败静默,避免影响启动
|
||||
}
|
||||
|
||||
globalThis.__cursor_patched__=true;
|
||||
|
||||
var __ids__={
|
||||
machineId:"'"$machine_id"'",
|
||||
macMachineId:"'"$mac_machine_id"'",
|
||||
devDeviceId:"'"$device_id"'",
|
||||
sqmId:"'"$sqm_id"'",
|
||||
macAddress:"'"$mac_address"'"
|
||||
};
|
||||
|
||||
globalThis.__cursor_ids__=__ids__;
|
||||
|
||||
var Module=__require__("module");
|
||||
var _origReq=Module.prototype.require;
|
||||
var _hooked=new Map();
|
||||
|
||||
Module.prototype.require=function(id){
|
||||
var result=_origReq.apply(this,arguments);
|
||||
if(_hooked.has(id))return _hooked.get(id);
|
||||
var hooked=result;
|
||||
|
||||
if(id==="child_process"){
|
||||
var _origExecSync=result.execSync;
|
||||
result.execSync=function(cmd,opts){
|
||||
var cmdStr=String(cmd).toLowerCase();
|
||||
if(cmdStr.includes("ioreg")&&cmdStr.includes("ioplatformexpertdevice")){
|
||||
return Buffer.from("\"IOPlatformUUID\" = \""+__ids__.machineId.substring(0,36).toUpperCase()+"\"");
|
||||
}
|
||||
if(cmdStr.includes("machine-id")||cmdStr.includes("hostname")){
|
||||
return Buffer.from(__ids__.machineId.substring(0,32));
|
||||
}
|
||||
return _origExecSync.apply(this,arguments);
|
||||
};
|
||||
hooked=result;
|
||||
}
|
||||
else if(id==="os"){
|
||||
result.networkInterfaces=function(){
|
||||
return{"en0":[{address:"192.168.1.100",netmask:"255.255.255.0",family:"IPv4",mac:__ids__.macAddress,internal:false}]};
|
||||
};
|
||||
hooked=result;
|
||||
}
|
||||
else if(id==="crypto"){
|
||||
var _origCreateHash=result.createHash;
|
||||
var _origRandomUUID=result.randomUUID;
|
||||
result.createHash=function(algo){
|
||||
var hash=_origCreateHash.apply(this,arguments);
|
||||
if(algo.toLowerCase()==="sha256"){
|
||||
var _origDigest=hash.digest.bind(hash);
|
||||
var _origUpdate=hash.update.bind(hash);
|
||||
var inputData="";
|
||||
hash.update=function(data,enc){inputData+=String(data);return _origUpdate(data,enc);};
|
||||
hash.digest=function(enc){
|
||||
if(inputData.includes("IOPlatformUUID")||(inputData.length>=32&&inputData.length<=40)){
|
||||
return enc==="hex"?__ids__.machineId:Buffer.from(__ids__.machineId,"hex");
|
||||
}
|
||||
return _origDigest(enc);
|
||||
};
|
||||
}
|
||||
return hash;
|
||||
};
|
||||
if(_origRandomUUID){
|
||||
var uuidCount=0;
|
||||
result.randomUUID=function(){
|
||||
uuidCount++;
|
||||
if(uuidCount<=2)return __ids__.devDeviceId;
|
||||
return _origRandomUUID.apply(this,arguments);
|
||||
};
|
||||
}
|
||||
hooked=result;
|
||||
}
|
||||
else if(id==="@vscode/deviceid"){
|
||||
hooked={...result,getDeviceId:async function(){return __ids__.devDeviceId;}};
|
||||
}
|
||||
|
||||
if(hooked!==result)_hooked.set(id,hooked);
|
||||
return hooked;
|
||||
};
|
||||
|
||||
console.log("[Cursor ID Modifier] 增强版 Hook 已激活 - 煎饼果子(86) 公众号【煎饼果子卷AI】");
|
||||
})();
|
||||
// ========== Cursor Hook 注入结束 ==========
|
||||
// ========== Cursor Hook Loader 结束 ==========
|
||||
|
||||
'
|
||||
|
||||
@@ -1908,32 +1915,36 @@ console.log("[Cursor ID Modifier] 增强版 Hook 已激活 - 煎饼果子(86)
|
||||
{ print }
|
||||
' "$file" > "${file}.new"
|
||||
mv "${file}.new" "$file"
|
||||
log_info " ✓ [方案B] 增强版 Hook 代码已注入(版权声明后)"
|
||||
log_info " ✓ [方案C] Loader Stub 已注入(版权声明后)"
|
||||
else
|
||||
# 注入到文件开头
|
||||
echo "$inject_code" > "${file}.new"
|
||||
cat "$file" >> "${file}.new"
|
||||
mv "${file}.new" "$file"
|
||||
log_info " ✓ [方案B] 增强版 Hook 代码已注入(文件开头)"
|
||||
log_info " ✓ [方案C] Loader Stub 已注入(文件开头)"
|
||||
fi
|
||||
|
||||
# 清理临时文件
|
||||
rm -f "${file}.tmp"
|
||||
|
||||
local summary="Hook加载器"
|
||||
if [ "$replaced" = true ]; then
|
||||
log_info "✅ [成功] 增强版混合方案修改成功(someValue替换 + 深度Hook)"
|
||||
else
|
||||
log_info "✅ [成功] 增强版 Hook 修改成功"
|
||||
summary="someValue替换 + $summary"
|
||||
fi
|
||||
if [ "$b6_patched" = true ]; then
|
||||
summary="b6定点重写 + $summary"
|
||||
fi
|
||||
log_info "✅ [成功] 增强版方案修改成功($summary)"
|
||||
((modified_count++))
|
||||
done
|
||||
|
||||
if [ $modified_count -gt 0 ]; then
|
||||
log_info "🎉 [完成] 成功修改 $modified_count 个JS文件"
|
||||
log_info "💾 [备份] 原始文件备份位置: $backup_dir"
|
||||
log_info "💡 [说明] 使用增强版 Hook 方案:"
|
||||
log_info "💡 [说明] 使用增强版三重方案:"
|
||||
log_info " • 方案A: someValue占位符替换(稳定锚点,跨版本兼容)"
|
||||
log_info " • 方案B: 深度模块劫持(child_process, crypto, os, @vscode/*)"
|
||||
log_info " • 方案B: b6 定点重写(机器码源函数)"
|
||||
log_info " • 方案C: Loader Stub + 外置 Hook(cursor_hook.js)"
|
||||
log_info "📁 [配置] ID 配置文件: $ids_config_path"
|
||||
return 0
|
||||
else
|
||||
@@ -2855,7 +2866,7 @@ main() {
|
||||
echo -e "${BLUE} 5️⃣ 等待配置文件生成完成(最多45秒)${NC}"
|
||||
echo -e "${BLUE} 6️⃣ 关闭Cursor进程${NC}"
|
||||
echo -e "${BLUE} 7️⃣ 修改新生成的机器码配置文件${NC}"
|
||||
echo -e "${BLUE} 8️⃣ 智能设备识别绕过(MAC地址修改或JS内核修改)${NC}"
|
||||
echo -e "${BLUE} 8️⃣ 智能设备识别绕过(仅 JS 内核注入)${NC}"
|
||||
echo -e "${BLUE} 9️⃣ 禁用自动更新${NC}"
|
||||
echo -e "${BLUE} 🔟 显示操作完成统计信息${NC}"
|
||||
echo
|
||||
@@ -2865,7 +2876,7 @@ main() {
|
||||
echo -e "${YELLOW} • 执行完成后需要重新启动Cursor${NC}"
|
||||
echo -e "${YELLOW} • 原配置文件会自动备份到backups文件夹${NC}"
|
||||
echo -e "${YELLOW} • 需要Python3环境来处理JSON配置文件${NC}"
|
||||
echo -e "${YELLOW} • MAC地址修改是临时的,重启后恢复${NC}"
|
||||
echo -e "${YELLOW} • 已移除 MAC 地址修改,仅保留 JS 注入方案${NC}"
|
||||
fi
|
||||
echo
|
||||
|
||||
@@ -2964,10 +2975,10 @@ main() {
|
||||
# 🛠️ 修改机器码配置
|
||||
modify_machine_code_config
|
||||
|
||||
# 🔧 智能设备识别绕过(MAC地址修改或JS内核修改)
|
||||
# 🔧 智能设备识别绕过(仅 JS 内核注入)
|
||||
echo
|
||||
log_info "🔧 [设备识别] 开始智能设备识别绕过..."
|
||||
log_info "💡 [说明] 将优先尝试 MAC 地址修改,失败则使用 JS 内核注入"
|
||||
log_info "💡 [说明] 已移除 MAC 地址修改,直接使用 JS 内核注入"
|
||||
if ! run_device_bypass; then
|
||||
log_warn "⚠️ [设备识别] 智能设备识别绕过未完全成功,请查看日志"
|
||||
fi
|
||||
|
||||
@@ -27,11 +27,11 @@ function Generate-RandomString {
|
||||
# 🔧 修改Cursor内核JS文件实现设备识别绕过(增强版三重方案)
|
||||
# 方案A: someValue占位符替换 - 稳定锚点,不依赖混淆后的函数名
|
||||
# 方案B: b6 定点重写 - 机器码源函数直接返回固定值
|
||||
# 方案C: 深度 Hook + 共享进程注入 - 拦截 child_process/crypto/os/@vscode 等模块
|
||||
# 方案C: Loader Stub + 外置 Hook - 主/共享进程仅加载外置 Hook 文件
|
||||
function Modify-CursorJSFiles {
|
||||
Write-Host ""
|
||||
Write-Host "$BLUE🔧 [内核修改]$NC 开始修改Cursor内核JS文件实现设备识别绕过..."
|
||||
Write-Host "$BLUE💡 [方案]$NC 使用增强版三重方案:占位符替换 + b6 定点重写 + 共享进程 Hook"
|
||||
Write-Host "$BLUE💡 [方案]$NC 使用增强版三重方案:占位符替换 + b6 定点重写 + Loader Stub + 外置 Hook"
|
||||
Write-Host ""
|
||||
|
||||
# Windows版Cursor应用路径
|
||||
@@ -125,6 +125,46 @@ function Modify-CursorJSFiles {
|
||||
$idsConfig | ConvertTo-Json | Set-Content -Path $idsConfigPath -Encoding UTF8
|
||||
Write-Host "$GREEN💾 [保存]$NC 新的 ID 配置已保存到: $idsConfigPath"
|
||||
|
||||
# 部署外置 Hook 文件(供 Loader Stub 加载,支持多域名备用下载)
|
||||
$hookTargetPath = "$env:USERPROFILE\.cursor_hook.js"
|
||||
$hookSourceCandidates = @(
|
||||
(Join-Path $PSScriptRoot "..\hook\cursor_hook.js"),
|
||||
(Join-Path (Get-Location) "scripts\hook\cursor_hook.js")
|
||||
)
|
||||
$hookSourcePath = $hookSourceCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1
|
||||
$hookDownloadUrls = @(
|
||||
"https://wget.la/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/hook/cursor_hook.js",
|
||||
"https://down.npee.cn/?https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/hook/cursor_hook.js",
|
||||
"https://xget.xi-xu.me/gh/yuaotian/go-cursor-help/refs/heads/master/scripts/hook/cursor_hook.js",
|
||||
"https://gh-proxy.com/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/hook/cursor_hook.js",
|
||||
"https://gh.chjina.com/https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/hook/cursor_hook.js"
|
||||
)
|
||||
if ($hookSourcePath) {
|
||||
try {
|
||||
Copy-Item -Path $hookSourcePath -Destination $hookTargetPath -Force
|
||||
Write-Host "$GREEN✅ [Hook]$NC 外置 Hook 已部署: $hookTargetPath"
|
||||
} catch {
|
||||
Write-Host "$YELLOW⚠️ [Hook]$NC 本地 Hook 复制失败,尝试在线下载..."
|
||||
}
|
||||
}
|
||||
if (-not (Test-Path $hookTargetPath)) {
|
||||
foreach ($url in $hookDownloadUrls) {
|
||||
try {
|
||||
Invoke-WebRequest -Uri $url -OutFile $hookTargetPath -UseBasicParsing -ErrorAction Stop
|
||||
Write-Host "$GREEN✅ [Hook]$NC 外置 Hook 已在线下载: $hookTargetPath"
|
||||
break
|
||||
} catch {
|
||||
Write-Host "$YELLOW⚠️ [Hook]$NC 外置 Hook 下载失败: $url"
|
||||
if (Test-Path $hookTargetPath) {
|
||||
Remove-Item -Path $hookTargetPath -Force
|
||||
}
|
||||
}
|
||||
}
|
||||
if (-not (Test-Path $hookTargetPath)) {
|
||||
Write-Host "$YELLOW⚠️ [Hook]$NC 外置 Hook 全部下载失败"
|
||||
}
|
||||
}
|
||||
|
||||
# 目标JS文件列表(Windows路径,按优先级排序)
|
||||
$jsFiles = @(
|
||||
"$cursorAppPath\resources\app\out\main.js",
|
||||
@@ -258,7 +298,8 @@ function Modify-CursorJSFiles {
|
||||
# ========== 方法B: b6 定点重写(机器码源函数,仅 main.js) ==========
|
||||
# 说明:b6(t) 是 machineId 的核心生成函数,t=true 返回原始值,t=false 返回哈希
|
||||
if ((Split-Path $file -Leaf) -eq "main.js") {
|
||||
$b6Pattern = '(?s)async function b6\(\w+\)\{.*?return \w+\?\w+:\w+\}'
|
||||
# 使用特征锚点定位(createHash("sha256") + return t?e:i),避免依赖函数名
|
||||
$b6Pattern = '(?s)async function \w+\(\w+\)\{.*?createHash\("sha256"\).*?return \w+\?\w+:\w+\}'
|
||||
$b6Replacement = "async function b6(t){return t?'$machineGuid':'$machineId';}"
|
||||
$b6Regex = [regex]::new($b6Pattern)
|
||||
if ($b6Regex.IsMatch($content)) {
|
||||
@@ -270,200 +311,45 @@ function Modify-CursorJSFiles {
|
||||
}
|
||||
}
|
||||
|
||||
# ========== 方法C: 增强版深度 Hook 注入 ==========
|
||||
# 从底层拦截所有设备标识符的生成:
|
||||
# 1. Module.prototype.require 劫持 - 拦截 child_process, crypto, os 等模块
|
||||
# 2. child_process.execSync - 拦截 REG.exe 查询 MachineGuid
|
||||
# 3. crypto.createHash - 拦截 SHA256 哈希计算
|
||||
# 4. crypto.randomUUID - 拦截 UUID 生成
|
||||
# 5. os.networkInterfaces - 拦截 MAC 地址获取
|
||||
# 6. @vscode/deviceid - 拦截 devDeviceId 获取
|
||||
# 7. @vscode/windows-registry - 拦截注册表读取
|
||||
# ========== 方法C: Loader Stub 注入 ==========
|
||||
# 说明:主/共享进程仅注入加载器,具体 Hook 逻辑由外置 cursor_hook.js 维护
|
||||
|
||||
$injectCode = @"
|
||||
// ========== Cursor Hook 注入开始 ==========
|
||||
// ========== Cursor Hook Loader 开始 ==========
|
||||
;(async function(){/*__cursor_patched__*/
|
||||
'use strict';
|
||||
if (globalThis.__cursor_patched__) return;
|
||||
globalThis.__cursor_patched__ = true;
|
||||
if (globalThis.__cursor_hook_loaded__) return;
|
||||
globalThis.__cursor_hook_loaded__ = true;
|
||||
|
||||
try {
|
||||
// 固定的设备标识符(与 PowerShell 生成保持一致)
|
||||
var __ids__ = {
|
||||
machineId:'$machineId',
|
||||
machineGuid:'$machineGuid',
|
||||
macMachineId:'$macMachineId',
|
||||
devDeviceId:'$deviceId',
|
||||
sqmId:'$sqmId',
|
||||
macAddress:'$macAddress',
|
||||
sessionId:'$sessionId',
|
||||
firstSessionDate:'$firstSessionDateValue'
|
||||
};
|
||||
|
||||
// 暴露到全局,便于共享进程复用
|
||||
globalThis.__cursor_ids__ = __ids__;
|
||||
|
||||
// 兼容 ESM:尝试获取 require
|
||||
var __require__ = typeof require === 'function' ? require : null;
|
||||
if (!__require__) {
|
||||
try {
|
||||
var __m__ = await import('module');
|
||||
__require__ = __m__.createRequire(import.meta.url);
|
||||
} catch (e) {
|
||||
// 无法获得 require 时仅做全局 crypto 兜底,避免影响启动
|
||||
if (globalThis.crypto && typeof globalThis.crypto.randomUUID === 'function') {
|
||||
var __origGlobalUUID__ = globalThis.crypto.randomUUID;
|
||||
var __uuidCount__ = 0;
|
||||
globalThis.crypto.randomUUID = function(){
|
||||
__uuidCount__++;
|
||||
if (__uuidCount__ <= 2) return __ids__.devDeviceId;
|
||||
return __origGlobalUUID__.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
return;
|
||||
}
|
||||
var __m__ = await import('module');
|
||||
__require__ = __m__.createRequire(import.meta.url);
|
||||
}
|
||||
|
||||
// 处理 node: 前缀模块名
|
||||
function __normalizeId__(id){
|
||||
return (typeof id === 'string' && id.indexOf('node:') === 0) ? id.slice(5) : id;
|
||||
var fs = __require__('fs');
|
||||
var path = __require__('path');
|
||||
var os = __require__('os');
|
||||
var hookPath = path.join(os.homedir(), '.cursor_hook.js');
|
||||
if (fs.existsSync(hookPath)) {
|
||||
__require__(hookPath);
|
||||
}
|
||||
|
||||
// 先覆盖全局 crypto.randomUUID(满足直调用)
|
||||
if (globalThis.crypto && typeof globalThis.crypto.randomUUID === 'function') {
|
||||
var __origGlobalUUID2__ = globalThis.crypto.randomUUID;
|
||||
var __uuidCount2__ = 0;
|
||||
globalThis.crypto.randomUUID = function(){
|
||||
__uuidCount2__++;
|
||||
if (__uuidCount2__ <= 2) return __ids__.devDeviceId;
|
||||
return __origGlobalUUID2__.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
// Hook Module.prototype.require
|
||||
var Module = __require__('module');
|
||||
var _origReq = Module.prototype.require;
|
||||
var _hooked = new Map();
|
||||
|
||||
Module.prototype.require = function(id){
|
||||
var normalized = __normalizeId__(id);
|
||||
var result = _origReq.apply(this, arguments);
|
||||
if (_hooked.has(normalized)) return _hooked.get(normalized);
|
||||
var hooked = result;
|
||||
|
||||
// Hook child_process(拦截注册表/平台查询)
|
||||
if (normalized === 'child_process') {
|
||||
var _origExecSync = result.execSync;
|
||||
var _origExecFileSync = result.execFileSync;
|
||||
if (typeof _origExecSync === 'function') {
|
||||
result.execSync = function(cmd, opts){
|
||||
var cmdStr = String(cmd).toLowerCase();
|
||||
if (cmdStr.includes('reg') && cmdStr.includes('machineguid')) {
|
||||
return Buffer.from('\r\n MachineGuid REG_SZ ' + __ids__.machineGuid + '\r\n');
|
||||
}
|
||||
if (cmdStr.includes('ioreg') && cmdStr.includes('ioplatformexpertdevice')) {
|
||||
return Buffer.from('\"IOPlatformUUID\" = \"' + __ids__.machineGuid.toUpperCase() + '\"');
|
||||
}
|
||||
return _origExecSync.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
if (typeof _origExecFileSync === 'function') {
|
||||
result.execFileSync = function(file, args, opts){
|
||||
var cmdStr = [file].concat(args || []).join(' ').toLowerCase();
|
||||
if (cmdStr.includes('reg') && cmdStr.includes('machineguid')) {
|
||||
return Buffer.from('\r\n MachineGuid REG_SZ ' + __ids__.machineGuid + '\r\n');
|
||||
}
|
||||
if (cmdStr.includes('ioreg') && cmdStr.includes('ioplatformexpertdevice')) {
|
||||
return Buffer.from('\"IOPlatformUUID\" = \"' + __ids__.machineGuid.toUpperCase() + '\"');
|
||||
}
|
||||
return _origExecFileSync.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
hooked = result;
|
||||
}
|
||||
// Hook os(MAC 地址)
|
||||
else if (normalized === 'os') {
|
||||
var _origNI = result.networkInterfaces;
|
||||
result.networkInterfaces = function(){
|
||||
return {'Ethernet':[{'address':'192.168.1.100','netmask':'255.255.255.0','family':'IPv4','mac':__ids__.macAddress,'internal':false}]};
|
||||
};
|
||||
hooked = result;
|
||||
}
|
||||
// Hook crypto(hash/uuid)
|
||||
else if (normalized === 'crypto') {
|
||||
var _origCreateHash = result.createHash;
|
||||
var _origRandomUUID = result.randomUUID;
|
||||
if (typeof _origCreateHash === 'function') {
|
||||
result.createHash = function(algo){
|
||||
var hash = _origCreateHash.apply(this, arguments);
|
||||
var algoName = String(algo).toLowerCase();
|
||||
if (algoName === 'sha256') {
|
||||
var _origDigest = hash.digest.bind(hash);
|
||||
var _origUpdate = hash.update.bind(hash);
|
||||
var inputData = '';
|
||||
hash.update = function(data, enc){ inputData += String(data); return _origUpdate(data, enc); };
|
||||
hash.digest = function(enc){
|
||||
var text = inputData.toLowerCase();
|
||||
var looksGuid = /^[0-9a-f-]{32,36}$/.test(text);
|
||||
if (looksGuid || text.includes('machineguid') || text.includes('ioplatformuuid')) {
|
||||
return enc === 'hex' ? __ids__.machineId : Buffer.from(__ids__.machineId, 'hex');
|
||||
}
|
||||
return _origDigest(enc);
|
||||
};
|
||||
}
|
||||
return hash;
|
||||
};
|
||||
}
|
||||
if (typeof _origRandomUUID === 'function') {
|
||||
var uuidCount = 0;
|
||||
result.randomUUID = function(){
|
||||
uuidCount++;
|
||||
if (uuidCount <= 2) return __ids__.devDeviceId;
|
||||
return _origRandomUUID.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
hooked = result;
|
||||
}
|
||||
// Hook @vscode/deviceid
|
||||
else if (normalized === '@vscode/deviceid') {
|
||||
hooked = Object.assign({}, result, {
|
||||
getDeviceId: async function(){ return __ids__.devDeviceId; }
|
||||
});
|
||||
}
|
||||
// Hook @vscode/windows-registry
|
||||
else if (normalized === '@vscode/windows-registry') {
|
||||
var _origGetReg = result.GetStringRegKey;
|
||||
hooked = Object.assign({}, result, {
|
||||
GetStringRegKey: function(hive, path, name){
|
||||
var p = String(path || '').toLowerCase();
|
||||
if (name === 'MachineId' || p.includes('sqmclient')) return __ids__.sqmId;
|
||||
if (name === 'MachineGuid' || p.includes('cryptography')) return __ids__.machineGuid;
|
||||
return _origGetReg ? _origGetReg.apply(this, arguments) : '';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (hooked !== result) _hooked.set(normalized, hooked);
|
||||
return hooked;
|
||||
};
|
||||
|
||||
console.log('[Cursor ID Modifier] Hook 已激活(占位符 + b6 + 共享进程)');
|
||||
} catch (e) {
|
||||
try { console.warn('[Cursor ID Modifier] 注入异常:' + (e && e.message ? e.message : e)); } catch (_) {}
|
||||
// 失败静默,避免影响启动
|
||||
}
|
||||
})();
|
||||
// ========== Cursor Hook 注入结束 ==========
|
||||
// ========== Cursor Hook Loader 结束 ==========
|
||||
|
||||
"@
|
||||
|
||||
# 找到版权声明结束位置并在其后注入
|
||||
if ($content -match '(\*/\s*\n)') {
|
||||
$content = $content -replace '(\*/\s*\n)', "`$1$injectCode"
|
||||
Write-Host " $GREEN✓$NC [方案C] 增强版 Hook 代码已注入(版权声明后)"
|
||||
Write-Host " $GREEN✓$NC [方案C] Loader Stub 已注入(版权声明后)"
|
||||
} else {
|
||||
# 如果没有找到版权声明,则注入到文件开头
|
||||
$content = $injectCode + $content
|
||||
Write-Host " $GREEN✓$NC [方案C] 增强版 Hook 代码已注入(文件开头)"
|
||||
Write-Host " $GREEN✓$NC [方案C] Loader Stub 已注入(文件开头)"
|
||||
}
|
||||
|
||||
# 写入修改后的内容
|
||||
@@ -473,7 +359,7 @@ try {
|
||||
$summaryParts = @()
|
||||
if ($replaced) { $summaryParts += "someValue替换" }
|
||||
if ($replacedB6) { $summaryParts += "b6定点重写" }
|
||||
$summaryParts += "深度Hook"
|
||||
$summaryParts += "Hook加载器"
|
||||
$summaryText = ($summaryParts -join " + ")
|
||||
Write-Host "$GREEN✅ [成功]$NC 增强版方案修改成功($summaryText)"
|
||||
$modifiedCount++
|
||||
@@ -497,7 +383,7 @@ try {
|
||||
Write-Host "$BLUE💡 [说明]$NC 使用增强版三重方案:"
|
||||
Write-Host " • 方案A: someValue占位符替换(稳定锚点,跨版本兼容)"
|
||||
Write-Host " • 方案B: b6 定点重写(机器码源函数)"
|
||||
Write-Host " • 方案C: 深度模块劫持 + 共享进程注入(child_process/crypto/os/@vscode/*)"
|
||||
Write-Host " • 方案C: Loader Stub + 外置 Hook(cursor_hook.js)"
|
||||
Write-Host "$BLUE📁 [配置]$NC ID 配置文件: $idsConfigPath"
|
||||
return $true
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user