Skip to content

Commit 5262471

Browse files
committed
feat: 添加 JG-Cursor 1.4.0 mac 版本资源文件
1 parent 5bd21b0 commit 5262471

38 files changed

+746021
-0
lines changed
3.66 MB
Binary file not shown.
8.24 MB
Binary file not shown.
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Cursor Patch 逆向分析报告
2+
3+
## 简介
4+
5+
本文档是对 `bin/cursor_patch` 二进制文件的逆向分析报告。该程序是一个用于修补 Cursor 编辑器的工具,主要功能是绕过 Cursor 的机器ID验证,使得 Cursor 可以在不需要付费订阅的情况下使用全部功能。
6+
7+
## 程序结构
8+
9+
`cursor_patch` 是一个用 Go 语言编写的命令行工具,主要由以下几个部分组成:
10+
11+
1. **main 包**: 包含程序的入口点和主要逻辑流程
12+
2. **cursor_tool_modules 包**: 包含各种功能模块的实现
13+
14+
## 主要功能
15+
16+
程序执行的主要步骤如下:
17+
18+
1. **关闭 Cursor**: 首先关闭所有正在运行的 Cursor 进程
19+
2. **重置机器码**: 重置 Cursor 的机器标识符
20+
3. **禁用自动更新**: 禁用 Cursor 的自动更新功能,防止补丁被覆盖
21+
4. **执行补丁**: 修改 Cursor 的 main.js 文件,替换获取机器ID的相关代码
22+
23+
## 关键函数分析
24+
25+
### `main.main`
26+
27+
主函数是程序的入口点,负责协调整个程序的执行流程。它按顺序执行上述四个步骤,并在执行过程中显示进度信息。每个步骤都有成功和失败的处理逻辑,如果某个步骤失败,程序会立即退出。
28+
29+
### `cursor_tool_modules.PatchMachineID`
30+
31+
这是执行补丁的核心函数,它的主要工作是:
32+
33+
1. 寻找 Cursor 的 main.js 文件
34+
2. 创建备份文件
35+
3. 使用正则表达式替换获取机器ID的相关代码
36+
4. 设置文件权限确保修改成功
37+
38+
关键的替换内容是:
39+
-`async getMachineId(){return ...}` 函数修改为直接返回一个固定值
40+
- 同样修改 Mac 专用的 `getMacMachineID` 函数
41+
42+
## 技术细节
43+
44+
1. **文件路径**: 程序硬编码了 Cursor.app 在 macOS 上的默认安装路径
45+
2. **权限处理**: 程序需要 root 权限运行,并会临时修改文件权限以进行写入
46+
3. **备份机制**: 在修改前会创建原文件的备份,以便在需要时恢复
47+
4. **正则替换**: 使用正则表达式精确定位并替换目标代码,保留原始函数的返回值
48+
49+
## 执行流程图
50+
51+
```
52+
开始
53+
|
54+
v
55+
检查是否有 root 权限
56+
|
57+
v
58+
步骤 1: 关闭 Cursor 进程
59+
|
60+
v
61+
步骤 2: 重置机器码
62+
|
63+
v
64+
步骤 3: 禁用自动更新
65+
|
66+
v
67+
步骤 4: 检查 Cursor 版本并执行补丁
68+
|
69+
v
70+
显示完成通知
71+
|
72+
v
73+
结束
74+
```
75+
76+
## 反编译的代码
77+
78+
通过对二进制文件的反编译,我们提取出了程序的主要结构和逻辑。重建后的代码位于以下文件中:
79+
80+
- `docs/cursor_patch/main/main.go`: 主程序
81+
- `docs/cursor_patch/modules/modules.go`: 功能模块
82+
83+
## 结论
84+
85+
`cursor_patch` 是一个专门为绕过 Cursor 编辑器许可验证而设计的工具。它通过修改 Cursor 的 JavaScript 代码,改变了其获取机器ID的方式,使得 Cursor 始终认为当前机器拥有有效的许可证。程序执行过程设计合理,包含了错误处理和进度显示等用户友好的功能。
86+
87+
需要注意的是,这类修改可能违反 Cursor 的使用条款,仅供学习和研究使用。
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"syscall"
7+
"time"
8+
9+
"github.com/cursor-app/cursor/cursor_tool_modules" // 推测的导入路径
10+
)
11+
12+
// 进度状态映射
13+
var progressSteps = map[int64]struct {
14+
Success bool
15+
Message string
16+
Detail string
17+
}{}
18+
19+
// 步骤描述映射
20+
var stepDescriptions = map[int64]string{
21+
1: "关闭 Cursor",
22+
2: "重置机器码",
23+
3: "禁用自动更新",
24+
4: "执行补丁",
25+
}
26+
27+
// printProgress 打印当前操作的进度
28+
func printProgress(step int, success bool) {
29+
// 实现打印进度的逻辑
30+
if success {
31+
fmt.Printf("步骤 %d (%s): ✅\n", step, stepDescriptions[int64(step)])
32+
} else {
33+
fmt.Printf("步骤 %d (%s): ❌ %s\n", step, stepDescriptions[int64(step)], progressSteps[int64(step)].Detail)
34+
}
35+
}
36+
37+
func main() {
38+
// 检查是否为 root 用户运行
39+
if syscall.Geteuid() != 0 {
40+
fmt.Fprintln(os.Stdout, "需要使用 root 权限运行")
41+
os.Exit(1)
42+
} else {
43+
fmt.Fprintln(os.Stdout, "已获取 root 权限")
44+
}
45+
46+
// 步骤 1: 关闭 Cursor
47+
printProgress(1, false)
48+
if err := cursor_tool_modules.KillCursor(); err != nil {
49+
progressSteps[1] = struct {
50+
Success bool
51+
Message string
52+
Detail string
53+
}{false, "关闭 Cursor 失败步骤 %d (%s): ❌\n", fmt.Sprintf("关闭 Cursor 失败: %v", err)}
54+
fmt.Fprintf(os.Stdout, "\n步骤 1 失败\n\n步骤 2 失败\n\n步骤 3 失败\n")
55+
os.Exit(1)
56+
}
57+
58+
// 标记步骤 1 成功
59+
progressSteps[1] = struct {
60+
Success bool
61+
Message string
62+
Detail string
63+
}{true, "", ""}
64+
printProgress(1, true)
65+
time.Sleep(300 * time.Millisecond)
66+
67+
// 步骤 2: 重置机器码
68+
printProgress(2, false)
69+
if err := cursor_tool_modules.ResetMachineID(); err != nil {
70+
progressSteps[2] = struct {
71+
Success bool
72+
Message string
73+
Detail string
74+
}{false, "重置机器码失败", fmt.Sprintf("重置机器码失败: %v", err)}
75+
fmt.Fprintf(os.Stdout, "\n步骤 2 失败\n\n步骤 3 失败\n")
76+
os.Exit(1)
77+
}
78+
79+
// 标记步骤 2 成功
80+
progressSteps[2] = struct {
81+
Success bool
82+
Message string
83+
Detail string
84+
}{true, "", ""}
85+
printProgress(2, true)
86+
time.Sleep(300 * time.Millisecond)
87+
88+
// 步骤 3: 禁用自动更新
89+
printProgress(3, false)
90+
if err := cursor_tool_modules.DisableUpdate(); err != nil {
91+
progressSteps[3] = struct {
92+
Success bool
93+
Message string
94+
Detail string
95+
}{false, "禁用自动更新失败", fmt.Sprintf("禁用自动更新失败: %v", err)}
96+
fmt.Fprintf(os.Stdout, "\n步骤 3 失败\n")
97+
os.Exit(1)
98+
}
99+
100+
// 标记步骤 3 成功
101+
progressSteps[3] = struct {
102+
Success bool
103+
Message string
104+
Detail string
105+
}{true, "", ""}
106+
printProgress(3, true)
107+
time.Sleep(300 * time.Millisecond)
108+
109+
// 步骤 4: 检查 Cursor 版本并执行补丁
110+
printProgress(4, false)
111+
version, err := cursor_tool_modules.GetCursorVersion()
112+
if err != nil {
113+
progressSteps[4] = struct {
114+
Success bool
115+
Message string
116+
Detail string
117+
}{false, "获取 Cursor 版本失败", fmt.Sprintf("无法获取 Cursor 版本: %v", err)}
118+
fmt.Fprintf(os.Stdout, "\n步骤 4 失败: 无法获取 Cursor 版本 - %v\n", err)
119+
os.Exit(1)
120+
}
121+
122+
// 检查版本是否为 0.45.0,并执行补丁
123+
if version >= "0.45.0" {
124+
if err := cursor_tool_modules.PatchMachineID(); err != nil {
125+
progressSteps[4] = struct {
126+
Success bool
127+
Message string
128+
Detail string
129+
}{false, "补丁执行失败", fmt.Sprintf("补丁执行失败: %v", err)}
130+
fmt.Fprintf(os.Stdout, "\n步骤 4 失败: 补丁执行失败 - %v\n", err)
131+
os.Exit(1)
132+
}
133+
}
134+
135+
// 标记步骤 4 成功
136+
progressSteps[4] = struct {
137+
Success bool
138+
Message string
139+
Detail string
140+
}{true, "", ""}
141+
printProgress(4, true)
142+
time.Sleep(300 * time.Millisecond)
143+
144+
// 显示完成通知
145+
cursor_tool_modules.ShowNotification("", "")
146+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package cursor_tool_modules
2+
3+
import (
4+
"fmt"
5+
"os"
6+
)
7+
8+
// DisableUpdate 禁用 Cursor 的自动更新功能
9+
func DisableUpdate() error {
10+
// 获取更新器目录路径
11+
updaterPath := getUpdaterPath()
12+
13+
// 如果更新器目录不存在,返回错误
14+
if updaterPath == "" {
15+
return fmt.Errorf("不支持的操作系统")
16+
}
17+
18+
// 检查更新器目录是否存在
19+
fileInfo, err := os.Stat(updaterPath)
20+
if err == nil && fileInfo.IsDir() {
21+
// 如果目录存在,尝试删除它
22+
err = os.RemoveAll(updaterPath)
23+
if err != nil {
24+
return fmt.Errorf("删除更新器目录失败: %v", err)
25+
}
26+
}
27+
28+
// 创建一个空文件来代替更新器目录,这样 Cursor 就无法创建自动更新器目录
29+
file, err := os.OpenFile(updaterPath, os.O_CREATE|os.O_RDWR, 0292) // 0292 = 0444 (只读)
30+
if err != nil {
31+
return fmt.Errorf("创建阻止文件失败: %v", err)
32+
}
33+
34+
// 关闭文件
35+
if file != nil {
36+
file.Close()
37+
}
38+
39+
// 设置文件为只读权限
40+
err = os.Chmod(updaterPath, 0292) // 0292 = 0444 (只读)
41+
if err != nil {
42+
return fmt.Errorf("设置文件只读失败: %v", err)
43+
}
44+
45+
return nil
46+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package cursor_tool_modules
2+
3+
import (
4+
"crypto/rand"
5+
"crypto/sha512"
6+
"encoding/hex"
7+
"fmt"
8+
"hash"
9+
)
10+
11+
// generateUUID 生成随机的UUID字符串
12+
func generateUUID() string {
13+
// 生成16字节的随机数
14+
b := make([]byte, 16)
15+
if _, err := rand.Read(b); err != nil {
16+
// 如果随机数生成失败,返回一个固定的UUID
17+
return "00000000-0000-0000-0000-000000000000"
18+
}
19+
20+
// 设置UUID版本和变体
21+
b[6] = (b[6] & 0x0F) | 0x40 // 版本4
22+
b[8] = (b[8] & 0x3F) | 0x80 // 变体1
23+
24+
// 转换为十六进制字符串
25+
return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
26+
}
27+
28+
// generateMachineID 生成机器ID
29+
func generateMachineID() string {
30+
// 生成一个固定的机器ID前缀
31+
return "cursor-" + generateUUID()
32+
}
33+
34+
// generateHash 使用提供的哈希函数生成哈希值
35+
func generateHash(h hash.Hash, size int) string {
36+
// 生成一个固定的输入数据
37+
input := []byte("cursor-machine-id")
38+
39+
// 重置哈希函数
40+
h.Reset()
41+
42+
// 写入数据
43+
h.Write(input)
44+
45+
// 计算哈希值
46+
hashBytes := h.Sum(nil)
47+
48+
// 转换为十六进制字符串
49+
return hex.EncodeToString(hashBytes[:size/2])
50+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package cursor_tool_modules
2+
3+
// GetCursorVersion 获取当前安装的 Cursor 版本
4+
func GetCursorVersion() (string, error) {
5+
// 实现获取版本的逻辑
6+
return "0.45.0", nil
7+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package cursor_tool_modules
2+
3+
import (
4+
"fmt"
5+
"os/exec"
6+
"runtime"
7+
)
8+
9+
// KillCursor 关闭所有正在运行的 Cursor 进程
10+
func KillCursor() error {
11+
var cmd *exec.Cmd
12+
13+
switch runtime.GOOS {
14+
case "darwin":
15+
// macOS: 使用 pkill 命令关闭所有 Cursor 进程
16+
cmd = exec.Command("pkill", "-f", "Cursor")
17+
case "windows":
18+
// Windows: 使用 taskkill 命令关闭所有 Cursor 进程
19+
cmd = exec.Command("taskkill", "/F", "/IM", "Cursor.exe")
20+
case "linux":
21+
// Linux: 使用 pkill 命令关闭所有 Cursor 进程
22+
cmd = exec.Command("pkill", "-f", "Cursor")
23+
default:
24+
return fmt.Errorf("不支持的操作系统: %s", runtime.GOOS)
25+
}
26+
27+
// 执行命令
28+
if err := cmd.Run(); err != nil {
29+
// 如果进程不存在,不返回错误
30+
if cmd.ProcessState.ExitCode() == 1 {
31+
return nil
32+
}
33+
return fmt.Errorf("关闭Cursor进程失败: %v", err)
34+
}
35+
36+
return nil
37+
}

0 commit comments

Comments
 (0)