备份: 完整开发状态(含反混淆脚本和临时文件)

This commit is contained in:
ccdojox-crypto
2025-12-17 17:18:02 +08:00
parent 9e2333c90c
commit 7e9ea173a7
2872 changed files with 326818 additions and 249 deletions

120
extension/out/ANALYSIS.md Normal file
View File

@@ -0,0 +1,120 @@
# CursorPro 反混淆分析报告
## 项目结构
```
deobfuscated/
├── extension.js # 扩展主入口
├── api/
│ └── client.js # API 客户端
├── utils/
│ ├── account.js # 账号管理工具
│ └── sqlite.js # SQLite 数据库操作
└── webview/
└── provider.js # Webview 提供者
```
## 功能分析
### 1. extension.js - 扩展入口
- **cleanServiceWorkerCache()**: 清理 Cursor 的 Service Worker 缓存
- **activate()**: 注册 webview provider 和状态栏
- **updateUsageStatusBar()**: 更新状态栏显示使用量
### 2. api/client.js - API 客户端
与远程服务器通信,主要 API
| 函数 | 端点 | 说明 |
|------|------|------|
| `verifyKey()` | POST /api/verify | 验证激活码 |
| `switchAccount()` | POST /api/switch | 切换账号 |
| `getSeamlessStatus()` | GET /api/seamless/status | 获取无缝模式状态 |
| `injectSeamless()` | POST /api/seamless/inject | 注入无缝模式 |
| `getProxyConfig()` | GET /api/proxy-config | 获取代理配置 |
**默认 API 服务器**: `https://api.cursorpro.com` (从混淆代码中提取)
### 3. utils/account.js - 账号管理
**getCursorPaths()** - 返回 Cursor 配置路径:
| 平台 | 数据库路径 |
|------|-----------|
| Windows | `%APPDATA%/Cursor/User/globalStorage/state.vscdb` |
| macOS | `~/Library/Application Support/Cursor/User/globalStorage/state.vscdb` |
| Linux | `~/.config/Cursor/User/globalStorage/state.vscdb` |
**writeAccountToLocal()** - 写入账号数据到本地:
- 修改 SQLite 数据库中的认证 token
- 更新 storage.json 中的设备 ID
- 写入 machineid 文件
- Windows: 写入注册表
**关键数据库字段**
```
cursorAuth/accessToken - 访问令牌
cursorAuth/refreshToken - 刷新令牌
cursorAuth/WorkosCursorSessionToken - WorkOS 会话令牌
cursorAuth/cachedEmail - 缓存邮箱
cursorAuth/stripeMembershipType - 会员类型
telemetry.serviceMachineId - 服务机器ID
telemetry.devDeviceId - 设备ID
```
### 4. utils/sqlite.js - SQLite 操作
通过 `sqlite3` 命令行工具直接操作 Cursor 的 VSCode 状态数据库:
- `sqliteGet()` - 读取单个值
- `sqliteSet()` - 写入单个值
- `sqliteSetBatch()` - 批量写入 (使用事务)
### 5. webview/provider.js - Webview 界面
实现侧边栏 UI提供
- 激活码验证界面
- 使用统计显示
- 无缝模式配置
- 代理设置
- 账号切换功能
## 工作原理
```
┌─────────────────────────────────────────────────────────────┐
│ CursorPro 工作流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 用户输入激活码 │
│ ↓ │
│ 2. 发送到远程 API 服务器验证 │
│ ↓ │
│ 3. 服务器返回账号数据 (token, email, 设备ID等) │
│ ↓ │
│ 4. 写入本地 Cursor 配置文件: │
│ - state.vscdb (SQLite 数据库) │
│ - storage.json │
│ - machineid │
│ ↓ │
│ 5. 提示重启 Cursor 生效 │
│ │
└─────────────────────────────────────────────────────────────┘
```
## 安全风险分析
1. **远程服务器控制**: 所有账号数据来自 `api.cursorpro.com`
2. **本地文件修改**: 直接操作 Cursor 数据库和配置文件
3. **设备指纹伪造**: 替换 machineId, devDeviceId 等标识
4. **进程控制**: 可强制关闭 Cursor 进程
## 混淆技术分析
原代码使用了以下混淆技术:
1. **字符串数组 + 解密函数**: 所有字符串存储在数组中,通过 RC4 算法解密
2. **十六进制变量名**: `_0x50c5e9`, `_0x2b0b`
3. **控制流平坦化**: 使用 switch-case 打乱代码执行顺序
4. **死代码注入**: 插入无用的条件分支
5. **Base64 + RC4 双重编码**: 字符串先 Base64 再 RC4 加密
---
*此分析仅供安全研究和学习目的*

File diff suppressed because one or more lines are too long

263
extension/out/seamless.js Normal file
View File

@@ -0,0 +1,263 @@
'use strict';
// ============================================
// CursorPro 无感换号模块 - 详细分析
// ============================================
const vscode = require('vscode');
const client = require('./api/client');
const account = require('./utils/account');
/**
* ============================================
* 无感换号 (Seamless Mode) 工作原理
* ============================================
*
* 核心思路:
* 1. 用户配置一个"账号池",包含多个 Cursor 账号的 token
* 2. 当检测到当前账号额度用尽或即将用尽时
* 3. 自动从账号池中选择下一个可用账号
* 4. 无缝切换到新账号,用户无感知
*
* 关键 API 端点:
* - /api/seamless/status 获取无缝模式状态
* - /api/seamless/config 获取/更新无缝配置
* - /api/seamless/inject 注入无缝模式到本地
* - /api/seamless/restore 恢复原始设置
* - /api/seamless/accounts 获取账号池列表
* - /api/seamless/token 获取指定账号的 token
* - /api/seamless/switch 切换到指定账号
*/
// ============================================
// 无缝模式配置结构
// ============================================
/**
* @typedef {Object} SeamlessConfig
* @property {boolean} enabled - 是否启用无缝模式
* @property {string} mode - 切换模式: 'auto' | 'manual'
* @property {number} switchThreshold - 切换阈值 (剩余额度百分比)
* @property {string[]} accountPool - 账号池 (userKey 列表)
* @property {number} currentIndex - 当前使用的账号索引
*/
const defaultSeamlessConfig = {
enabled: false,
mode: 'auto', // 自动切换
switchThreshold: 10, // 当剩余额度低于 10% 时切换
accountPool: [],
currentIndex: 0
};
// ============================================
// 无缝模式核心函数
// ============================================
/**
* 获取无缝模式状态
* 检查服务端是否支持无缝模式,以及当前用户是否有权使用
*/
async function getSeamlessStatus() {
return client.request('/api/seamless/status');
}
/**
* 获取无缝模式配置
* 从服务端获取用户的无缝模式配置
*/
async function getSeamlessConfig() {
return client.request('/api/seamless/config');
}
/**
* 更新无缝模式配置
* @param {SeamlessConfig} config - 新的配置
*/
async function updateSeamlessConfig(config) {
return client.request('/api/seamless/config', 'POST', config);
}
/**
* 获取用户切换状态
* 检查指定用户当前的使用状态,判断是否需要切换
* @param {string} userKey - 用户标识
*/
async function getUserSwitchStatus(userKey) {
return client.request('/api/seamless/user-status?key=' + encodeURIComponent(userKey));
}
/**
* 注入无缝模式
* 将无缝模式的配置写入本地 Cursor
*
* 这是无感换号的核心!
* 它会修改 Cursor 的认证配置,使其指向一个代理服务器
* 代理服务器会自动处理账号切换
*
* @param {string} apiUrl - 无缝模式的 API 代理地址
* @param {string} userKey - 用户标识
*/
async function injectSeamless(apiUrl, userKey) {
const result = await client.request('/api/seamless/inject', 'POST', {
api_url: apiUrl,
user_key: userKey
});
if (result.success && result.data) {
// 将返回的账号数据写入本地
// 这里的关键是:写入的 token 是代理服务器的 token
// 代理服务器会根据使用情况自动切换真实账号
await account.writeAccountToLocal(result.data);
}
return result;
}
/**
* 恢复原始设置
* 移除无缝模式,恢复到单账号模式
*/
async function restoreSeamless() {
return client.request('/api/seamless/restore', 'POST');
}
/**
* 获取账号池列表
* 返回用户配置的所有账号
*/
async function getSeamlessAccounts() {
return client.request('/api/seamless/accounts');
}
/**
* 同步账号池
* 将本地账号列表同步到服务端
* @param {Array} accounts - 账号列表
*/
async function syncSeamlessAccounts(accounts) {
return client.request('/api/seamless/accounts', 'POST', { accounts });
}
/**
* 获取指定账号的 Token
* @param {string} userKey - 用户标识
*/
async function getSeamlessToken(userKey) {
return client.request('/api/seamless/token?key=' + encodeURIComponent(userKey));
}
/**
* 手动切换到指定账号
* @param {string} userKey - 要切换到的账号标识
*/
async function switchSeamlessToken(userKey) {
const result = await client.request('/api/seamless/switch', 'POST', {
mode: 'seamless',
userKey: userKey
});
if (result.success && result.data) {
await account.writeAccountToLocal(result.data);
}
return result;
}
// ============================================
// 无感换号流程图
// ============================================
/**
*
* ┌─────────────────────────────────────────────────────────────────┐
* │ 无感换号工作流程 │
* ├─────────────────────────────────────────────────────────────────┤
* │ │
* │ ┌──────────────┐ │
* │ │ 用户请求 │ │
* │ │ (使用 Cursor) │ │
* │ └──────┬───────┘ │
* │ │ │
* │ ▼ │
* │ ┌──────────────┐ ┌──────────────┐ │
* │ │ Cursor 客户端 │────▶│ 代理服务器 │ (CursorPro API) │
* │ │ (本地修改后) │ │ │ │
* │ └──────────────┘ └──────┬───────┘ │
* │ │ │
* │ ▼ │
* │ ┌──────────────┐ │
* │ │ 检查当前账号 │ │
* │ │ 额度是否充足 │ │
* │ └──────┬───────┘ │
* │ │ │
* │ ┌───────────────┼───────────────┐ │
* │ │ │ │ │
* │ ▼ ▼ ▼ │
* │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
* │ │ 账号 A │ │ 账号 B │ │ 账号 C │ (账号池) │
* │ │ 额度:5% │ │ 额度:80% │ │ 额度:60% │ │
* │ └─────────┘ └────┬────┘ └─────────┘ │
* │ │ │
* │ ▼ │
* │ ┌──────────────┐ │
* │ │ 使用账号 B │ (额度最充足) │
* │ │ 转发请求 │ │
* │ └──────┬───────┘ │
* │ │ │
* │ ▼ │
* │ ┌──────────────┐ │
* │ │ Cursor API │ │
* │ │ (官方服务器) │ │
* │ └──────┬───────┘ │
* │ │ │
* │ ▼ │
* │ ┌──────────────┐ │
* │ │ 返回结果给 │ │
* │ │ 用户 │ │
* │ └──────────────┘ │
* │ │
* │ 用户全程无感知,只要账号池中有任一账号有额度,就能继续使用 │
* │ │
* └─────────────────────────────────────────────────────────────────┘
*
*/
// ============================================
// 无感换号的技术实现细节
// ============================================
/**
* 关键技术点:
*
* 1. 代理注入
* - 修改本地 Cursor 的 API 端点指向代理服务器
* - 所有请求先经过代理,代理决定使用哪个真实账号
*
* 2. Token 管理
* - 代理服务器维护账号池的所有 token
* - 根据各账号的额度情况动态选择
*
* 3. 切换策略
* - 自动模式:当前账号额度 < 阈值时自动切换
* - 手动模式:用户手动选择要使用的账号
*
* 4. 本地写入的数据
* - accessToken: 代理服务器生成的特殊 token
* - refreshToken: 用于刷新代理 token
* - 设备 ID: 统一使用代理分配的 ID避免被检测
*/
const seamlessModule = {
getSeamlessStatus,
getSeamlessConfig,
updateSeamlessConfig,
getUserSwitchStatus,
injectSeamless,
restoreSeamless,
getSeamlessAccounts,
syncSeamlessAccounts,
getSeamlessToken,
switchSeamlessToken
};
module.exports = seamlessModule;