objval/osu-helper
GitHub: objval/osu-helper
一个面向 osu!lazer 的 Relax 游戏辅助引擎,通过读取游戏内存和解析谱面来实现拟人的自动按键。
Stars: 0 | Forks: 0
# osu-helper
**一个用于 osu!lazer 的合法 relax 工具**
从内存中读取游戏状态,从磁盘解析 beatmap,并注入
类似人类的按键操作,具有可配置的 timing jitter、hold durations、
error injection 和 fatigue simulation。
## 功能
| 功能 | 描述 |
|---------|-------------|
| **类似人类的 timing** | 带有提前偏置的 Gaussian jitter、BPM scaling 和 fatigue |
| **可变 holds** | 因按键和 BPM 而异的 Skewed-normal hold 持续时间 |
| **智能交替** | 具有感知 BPM 的 Z/X 交替,并以 singletap 作为后备 |
| **Error injection** | 5% 的几率出现“bad hits”,以模仿人类的不稳定性 |
| **Fatigue simulation** | 在长时间游玩中 timing 会有轻微下降 |
| **Scancode injection** | 使用 KEYEVENTF_SCANCODE,而不是 virtual keys |
| **字符串混淆** | 编译时的 XOR —— 二进制文件中没有敏感字符串 |
| **配置热重载** | 游玩时编辑 config.ini,2 秒内自动重载 |
| **Debug 日志** | 可选的 debug.log,用于诊断 timing 和按键操作 |
| **最小足迹** | 3 个 DLL 导入,387KB 的二进制文件,无 overlay,无 hooks |
## 架构
```
┌─────────────┐ ┌──────────────┐ ┌──────────────┐
│ main.cpp │────▶│ lazer.h │────▶│ process.h │
│ (game loop)│ │ (pointer │ │ (memory │
│ │ │ chain) │ │ reading) │
└──────┬──────┘ └──────────────┘ └──────────────┘
│
▼
┌──────────────┐ ┌──────────────┐
│ relax.h │────▶│ beatmap.h │
│ (key sched │ │ (.osu file │
│ + timing) │ │ parser) │
└──────────────┘ └──────────────┘
```
**数据流:**
1. `process.h` 找到 osu!.exe 的 PID 并打开一个只读句柄
2. `lazer.h` 扫描 anchor pattern,遍历 .NET 指针链以找到游戏基地址
3. `lazer.h` 从内存中读取游戏时间、beatmap 信息和游玩状态
4. `beatmap.h` 从磁盘解析当前的 .osu 文件(lazer 的 content-addressed store)
5. `relax.h` 在 beatmap 物件时间点以类似人类的 timing 调度按键操作
6. `relax.h` 通过带有 scancode 的 SendInput 注入按键
## 构建
### 前置条件
- Windows 10/11
- Visual Studio 2022(任意版本)包含 C++ 桌面开发工作负载
- 无外部依赖(所有库均为 Windows SDK)
### 构建
```
build.bat
```
这会调用 `vcvarsall.bat x64`,然后使用以下参数进行编译:
- `/O2` — 速度优化
- `/GL /LTCG` — 全程序与链接时优化
- `/EHsc /MT` — 静态 CRT,无 DLL 依赖
- `/GS-` — 禁用安全 cookies(更小的二进制文件)
- `/DNDEBUG` — 无 debug 断言
输出:`AppHelper.exe` (387KB)
## 用法
1. 构建项目
2. 打开 osu!lazer
3. 运行 `AppHelper.exe`(控制台会自动隐藏)
4. 开始一张地图 —— **只需用鼠标瞄准,bot 会按下 Z/X**
5. 在游玩时编辑 `config.ini` —— 更改将在 2 秒内自动重载
### 控制
| 按键 | 动作 |
|-----|--------|
| `Insert` | 暂停 / 恢复(暂停时释放所有按键) |
## 配置参考
所有设置都在 `config.ini` 中。可以在游玩时编辑 —— 会自动重载。
### Timing
| 键 | 类型 | 默认值 | 描述 |
|-----|------|---------|-------------|
| `hit_jitter_ms` | float | `12` | 基础 timing jitter(±ms,Gaussian)。数值越低 = 越紧凑 |
| `timing_bias_ms` | float | `-2` | Timing 偏置。负数 = 提前击打(人类玩家会这样做) |
| `bpm_jitter_scale` | float | `0.002` | BPM 增加 jitter 的程度。`0.002` = 每 100 BPM 增加 +0.2ms |
### Hold 持续时间
| 键 | 类型 | 默认值 | 描述 |
|-----|------|---------|-------------|
| `hold_center_k1` | float | `65` | K1 hold 持续时间中心(ms) |
| `hold_spread_k1` | float | `15` | K1 hold 持续时间散布(Gaussian) |
| `hold_center_k2` | float | `75` | K2 hold 持续时间中心(ms) |
| `hold_spread_k2` | float | `14` | K2 hold 持续时间散布(Gaussian) |
| `hold_floor` | float | `25` | 最小 hold 时间(ms) |
| `hold_ceiling` | float | `120` | 最大 hold 时间(ms) |
| `bpm_hold_scale` | float | `0.001` | BPM 缩短 hold 的程度。`0.001` = 每 100 BPM 减少 -10ms |
### Error Injection
| 键 | 类型 | 默认值 | 描述 |
|-----|------|---------|-------------|
| `error_chance` | float | `0.05` | 出现“bad hit”的几率(5%)。使 timing 分布更宽 |
| `error_multiplier` | float | `2.5` | bad hit 的严重程度(2.5倍更宽的 jitter) |
### Release
| 键 | 类型 | 默认值 | 描述 |
|-----|------|---------|-------------|
| `release_jitter_ms` | float | `4` | 按键 release timing 的 jitter(±ms)。增加真实感 |
### 全局
| 键 | 类型 | 默认值 | 描述 |
|-----|------|---------|-------------|
| `manual_offset_ms` | int | `0` | 全局 timing 偏移。负数 = 更早,正数 = 更晚 |
| `bpm_alternate_threshold` | int | `120` | 高于该 BPM 则始终进行交替按键 |
| `singletap_mode` | bool | `false` | 强制 singletap(除非 BPM > 阈值,否则仅使用 K1) |
### Fatigue
| 键 | 类型 | 默认值 | 描述 |
|-----|------|---------|-------------|
| `fatigue_rate` | float | `0.0001` | 每游玩一秒增加的 jitter |
| `fatigue_max` | float | `1.5` | 最大 fatigue 乘数(1.5 = 多 50% 的 jitter) |
### 按键
| 键 | 类型 | 默认值 | 描述 |
|-----|------|---------|-------------|
| `left_key` | int | `90` | 左键 VK 码(90=Z, 67=C) |
| `right_key` | int | `88` | 右键 VK 码(88=X, 86=V) |
### 系统
| 键 | 类型 | 默认值 | 描述 |
|-----|------|---------|-------------|
| `tick_ms` | int | `2` | 主循环 sleep 时间(ms)。2 = ~500Hz |
| `tick_jitter_ms` | int | `1` | sleep 时的随机 jitter(±ms) |
## 推荐配置
### 紧凑(看起来像高熟练度玩家)
```
hit_jitter_ms=8
timing_bias_ms=-3
hold_center_k1=55
hold_spread_k1=10
hold_center_k2=60
hold_spread_k2=10
error_chance=0.03
```
### 默认(平衡的类人表现)
```
hit_jitter_ms=12
timing_bias_ms=-2
hold_center_k1=65
hold_spread_k1=15
hold_center_k2=75
hold_spread_k2=14
error_chance=0.05
```
### 宽松(看起来像休闲玩家)
```
hit_jitter_ms=18
timing_bias_ms=-1
hold_center_k1=75
hold_spread_k1=20
hold_center_k2=85
hold_spread_k2=18
error_chance=0.08
```
## 检测分析
### Import Table
```
KERNEL32.dll — OpenProcess, ReadProcessMemory, VirtualQueryEx
USER32.dll — SendInput, GetCursorPos, GetForegroundWindow, MapVirtualKeyA
SHELL32.dll — SHGetFolderPathW
```
没有 D3D11,没有 ImGui,没有 hooks,没有 VirtualAlloc,没有 WriteProcessMemory。
### 反检测措施
| 措施 | 状态 |
|---------|--------|
| 编译时字符串 XOR | 所有敏感字符串均已混淆 |
| 只读进程访问 | 仅限 VM_READ + QUERY_INFO |
| Scancode injection | KEYEVENTF_SCANCODE,而非 virtual keys |
| 零 dwExtraInfo | SendInput 上无注入指纹 |
| 隐藏控制台 | 启动时 SW_HIDE |
| 静态 CRT | /MT —— 无 MSVCRT 依赖 |
| 无 overlay | 无 D3D11,无 DXGI,无窗口创建 |
| 无 hooks | 无 WH_MOUSE_LL,无 WH_KEYBOARD_LL |
| 配置热重载 | 无需重启即可更改设置 |
### 残余风险
| 风险 | 级别 | 缓解措施 |
|------|-------|------------|
| 进程句柄 | 低 | 许多合法工具也会打开 osu! 句柄 |
| 内存读取 | 低 | 每 tick 2-3 次指针读取,足迹极小 |
| SendInput | 中 | Scancode injection,类人 timing |
| 统计分析 | 低 | Gaussian jitter,error injection,fatigue |
## 项目结构
```
osu-helper/
├── README.md ← this file
├── ARCHITECTURE.md ← full technical map
├── config.ini ← runtime settings
├── build.bat ← MSVC build script
├── .gitignore
└── src/
├── main.cpp ← entry point, game loop
├── config.h ← INI parser, hot-reload
├── process.h ← process attachment, memory reading
├── lazer.h ← lazer pointer chain, game state
├── beatmap.h ← .osu file parser
├── relax.h ← relax bot engine
├── obf.h ← compile-time string obfuscation
├── dbg.h ← debug logging
├── playfield.h ← coordinate projection
├── human.h ← human-like mouse movement
└── aim.h ← aim assist engine (unused)
```
## 工作原理
### 指针链 (osu!lazer 2026.518.0)
```
1. Scan for anchor: 1024.0f, 768.0f as floats in memory
2. Go back 0x24 bytes → ExternalLinkOpener pointer
3. Read ExternalLinkOpener + 536 → APIAccess pointer
4. Read APIAccess + 784 → OsuGameBase pointer
5. Read OsuGameBase + 1232 → BeatmapClock → CurrentTime
6. Read OsuGameBase + 1104 → Beatmap → BeatmapInfo
```
### Timing 分布
```
Human player: ████░░░░░░ (Gaussian, centered slightly early)
Blatant relax: ██████████ (uniform, perfect timing every hit)
osu-helper: █████░░░░░ (Gaussian, early bias, 5% error injection)
```
### Hold 持续时间
```
Fixed: ██████████ (same duration every hit)
osu-helper: █████░░░░░ (skewed-normal, BPM-scaled, per-key variation)
```
## 致谢
- [osu!](https://osu.ppy.sh) 作者 peppy
- [osu!lazer](https://github.com/ppy/osu) —— 开源客户端
- osu! 社区提供的 beatmap 格式文档
## 许可证
本项目仅供教育目的使用。标签:C++, osu!, 内存读取, 安全意识培训, 按键注入, 数据擦除, 游戏外挂, 游戏辅助, 端点可见性