danielcho02/win_minesweeper_hack
GitHub: danielcho02/win_minesweeper_hack
通过 IDA 静态分析和运行时内存读取,逆向验证经典 Windows 扫雷的棋盘结构并实现自动胜利的逆向工程学习项目。
Stars: 0 | Forks: 0
# 扫雷破解
**通过 IDA 静态分析和运行时内存读取,验证经典扫雷的棋盘结构并实现自动胜利的项目**





在 `9 x 9` 初级棋盘中读取了 10 个地雷,仅自动点开 71 个安全格以确认胜利状态。
## 项目概述
本项目在不修改提供的 `winmine.exe` 的前提下,从以下两个角度进行分析。
1. 在 IDA 中追踪随机数初始化、地雷布置、棋盘初始化、点击处理及胜利处理例程。
2. 读取运行中进程的棋盘数组,仅点击没有地雷位的格子,以验证分析结果。
核心在于地雷位置以明文形式保存在全局棋盘数组中。只需检查每个格子的 `0x80` 位即可区分是否有雷。
## 核心分析结果
| 项目 | 结果 |
|---|---|
| ImageBase | `0x01000000` |
| 棋盘起始地址 | `0x01005340` |
| 棋盘访问公式 | `board[32 * row + col]` |
| 行 stride | `32 bytes` |
| 地雷判定 | `cell & 0x80 != 0` |
| 已开格判定 | `cell & 0x40 != 0` |
| 关闭的普通格 | `0x0F` |
| 关闭的地雷格 | `0x8F` |
| 胜利后的地雷格 | `0x8E` |
```
cell = *(uint8_t *)(0x01005340 + 32 * row + col)
```
屏幕点击坐标在消息处理例程中使用以下公式进行转换。
```
client_x = 16 * col + 4
client_y = 16 * row + 47
```
## 分析流程
```
flowchart LR
A["GetTickCount()"] --> B["srand(seed)"]
B --> C["rand() % width / height"]
C --> D["board[32 * row + col] |= 0x80"]
D --> E["ReadProcessMemory"]
E --> F{"cell & 0x80"}
F -->|지뢰| G["클릭 제외"]
F -->|안전| H["마우스 메시지 전송"]
H --> I["안전 칸 71개 개방"]
I --> J["face_state = 3 / won = true"]
```
## 主要函数
| 地址 | 作用 |
|---|---|
| `0x01003AB0` | 使用 `GetTickCount()` 和 `srand()` 进行随机数初始化 |
| `0x01003940` | `rand() % n` 随机数封装 |
| `0x0100367A` | 设置新游戏并布置地雷 |
| `0x01002ED5` | 棋盘初始化与外围边界设置 |
| `0x01001BC9` | 窗口消息及坐标转换处理 |
| `0x010037E1` | 确认点击处理 |
| `0x01003008` | 点开安全格并计算相邻地雷数 |
| `0x0100347C` | 游戏结束及胜利状态处理 |
详细的分析内容可以在[分析报告](docs/analysis-report.md)中查看。
## 动态验证结果
| 验证项目 | 值 |
|---|---|
| 难度 | 初级 |
| 棋盘大小 | `9 x 9` |
| 地雷数 | `10` |
| 发送的安全点击数 | `71` |
| 最终打开的格子 | `71 / 71` |
| `face_state` | `3` |
| `game_flags` | `0x00000010` |
| 最终判定 | `won = true` |
原始验证数据保存在 [dynamic_verification.json](analysis/dynamic_verification.json) 中。
## 仓库结构
```
.
├── README.md
├── docs/
│ └── analysis-report.md
├── analysis/
│ ├── dynamic_verification.json
│ └── winmine_verification.png
├── tools/
│ ├── dynamic_verify_winmine.py
│ ├── ida_collect_board.py
│ ├── ida_collect_winmine.py
│ └── build_report_pdf.py
└── requirements.txt
```
## 复现方法
### 1. 准备分析目标
本仓库不会重新发布原始可执行文件。请将通过合法途径获取的目标文件放置在仓库根目录下,并命名为 `winmine.exe`。
脚本在运行前会检查以下 SHA256 哈希值。
```
D1A612A1791614B628A5C99F03B60FF1B979B8D1F088E99228893CB000C5DAF4
```
如果哈希值不一致,则无法保证地址和数据结构匹配,脚本将中止运行。
### 2. 准备 Python 环境
```
py -3 -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
```
Pillow 仅用于捕获胜利画面。即使未安装,也会执行内存读取和自动点击。
### 3. 动态验证
```
python tools\dynamic_verify_winmine.py
```
如果目标文件位于其他位置,请将路径作为参数传递。
```
python tools\dynamic_verify_winmine.py C:\path\to\winmine.exe
```
运行后将生成以下文件。
- `analysis/dynamic_verification.json`:初始地雷坐标和最终游戏状态
- `analysis/winmine_verification.png`:自动点击后的胜利画面
### 4. 收集 IDA 静态分析
在 IDA Professional 9.0 中完成自动分析后,运行提供的 IDAPython 脚本。
```
$env:WINMINE_ANALYSIS_DIR = "$PWD\analysis"
& "C:\path\to\IDA Professional 9.0\idat64.exe" -A -S"tools\ida_collect_winmine.py" winmine.exe
& "C:\path\to\IDA Professional 9.0\idat64.exe" -A -S"tools\ida_collect_board.py" winmine.exe
```
在无法使用 Hex-Rays 反编译器的环境中,依然可以收集反汇编和引用信息。
## 不包含原始可执行文件的原因
- 重新发布分析对象的权限尚不明确。
- 部分安全产品可能会将旧版可执行文件归类为可疑文件。
- 仅公开准确的 SHA256 也可以验证是否为相同的二进制文件。
- 可以防止仓库访问者在非预期的情况下下载可执行文件。
因此,`winmine.exe`、IDA 数据库(`*.i64`)以及本地临时文件已通过 `.gitignore` 排除。
## 范围与注意事项
- 这是一个用于教育目的的本地分析项目。
- 自动化脚本仅支持与上述 SHA256 匹配的 32 位目标。
- 地址基于该 PE 映像的固定布局。
- 建议在隔离的 Windows 环境中进行动态验证。
## License
分析和自动化代码采用 [MIT License](LICENSE)。分析对象可执行文件本身不受此许可证约束,也不包含在仓库中。
在 `9 x 9` 初级棋盘中读取了 10 个地雷,仅自动点开 71 个安全格以确认胜利状态。
标签:IDA Pro, Python, 云资产清单, 内存读取, 无后门, 端点可见性, 网络调试, 自动化, 逆向工具, 逆向工程