enXov/steam-leaderboards-finder
GitHub: enXov/steam-leaderboards-finder
该工具通过在运行时 Hook Steam 接口拦截函数调用,自动发现并记录游戏使用的排行榜名称。
Stars: 0 | Forks: 0
# Steam 排行榜查找工具
通过在运行时 Hook `ISteamUserStats` 接口,自动发现任意游戏使用的 Steam 排行榜名称。
## 为什么存在这个项目
要使用 Steam API 的 `UploadLeaderboardScore` 函数,你需要一个排行榜句柄(leaderboard handle)——这需要通过调用 `FindLeaderboard` 并传入**确切的排行榜名称**来获取。但是 Steam 并没有提供列出游戏所有排行榜的方法,而且这些名称只有游戏开发者知道。
这个工具通过拦截游戏自己对 `FindLeaderboard` 的调用并记录其使用的名称来解决这个问题。一旦你获得了这些名称,就可以在自己的项目中使用它们来上传分数、下载条目或以编程方式与排行榜进行交互。
👉 **请参阅 [steam-leaderboards](https://github.com/enXov/steam-leaderboards) 以实际操作上传分数和与排行榜交互。**
## 工作原理
1. 通过一个通常被加载的 Windows DLL 在游戏启动时被加载
2. 修补 `SteamInternal_FindOrCreateUserInterface` 以拦截 `ISteamUserStats` 的创建
3. 将 `FindLeaderboard`(索引 22)和 `FindOrCreateLeaderboard`(索引 21)的 vtable 条目替换为 Hooks
4. 将发现的排行榜名称写入 `leaderboards.txt`
## 输出格式
```
Normal Leaderboard | SortMethod=N/A | DisplayType=N/A
Hard Leaderboard | SortMethod=Ascending | DisplayType=Numeric
```
## 构建
需要 MSVC (x64)。通过 GitHub Actions 构建:
1. 前往 **Actions** → **Build DLL Proxy**
2. 选择 `winmm` 作为 DLL 类型,选择 `runtime` 作为代理方法
3. 下载构建产物
或者在本地构建:
```
cmake -B build -DDLL_TYPE=winmm -DPROXY_METHOD=runtime
cmake --build build --config Release
```
## 使用方法
1. 将构建好的 DLL 放在游戏的可执行文件目录中(紧挨着 `.exe` 文件)
2. 在 Steam 启动选项中添加以下内容:
WINEDLLOVERRIDES="winmm=n,b" %command%
*(在原生 Windows 上,不需要启动选项 —— DLL 会自动加载)*
3. 正常启动游戏
4. 进行游戏(浏览排行榜界面、不同模式等)
5. 在游戏可执行文件旁边的 `leaderboards.txt` 中检查发现的排行榜名称
## 为什么采用这种方法?
`FindLeaderboard` 是一个 C++ 虚方法 —— 它没有固定的地址可以直接进行 Hook。它仅作为指针存在于 `ISteamUserStats` vtable 中。要 Hook 它,首先需要 `ISteamUserStats*` 指针,以便交换其 vtable 条目。
朴素的方法是从后台线程轮询该接口。但这会产生一个**竞态条件**:游戏在主线程上创建 `ISteamUserStats` 并调用 `FindLeaderboard` 的速度非常快,后台线程无法及时安装 Hook。
解决方案是 Hook `SteamInternal_FindOrCreateUserInterface` —— 即*创建* `ISteamUserStats` 的那个函数。这样,当游戏请求该接口的那一刻,我们的 Hook 会首先触发,交换 vtable,并将修改后的接口返回给游戏。等到游戏调用 `FindLeaderboard` 时,我们的 Hook 已经就位了。
```
Game: SteamAPI_Init() → SteamInternal_FindOrCreateUserInterface("STEAMUSERSTATS...")
↓
OUR HOOK → get ISteamUserStats* → swap vtable[22] → return to game
↓
Game: FindLeaderboard("Normal Leaderboard") → hits our hook ✅ → logged to file
```
## 技术细节
- **接口版本**: `STEAMUSERSTATS_INTERFACE_VERSION013`
- **VTable 索引**: `FindOrCreateLeaderboard` 位于 21(偏移量 168),`FindLeaderboard` 位于 22(偏移量 176)
- **Hook 技术**: 对 `SteamInternal_FindOrCreateUserInterface` 执行 Inline hook(x64 绝对 JMP)+ vtable 指针交换
- **SDK**: 仅包含公共头文件用于类型定义 —— 不涉及库链接
## 致谢
本项目构建时使用了 **[dll-proxy](https://github.com/enXov/dll-proxy)**。本 README 不打算详细说明 DLL 注入机制的工作原理 —— 如需了解 DLL 代理概念、导出转发如何工作以及如何在您自己的项目中使用它,请参考该仓库。
## 许可证
MIT —— 详见 [LICENSE](LICENSE)。
标签:API, Bash脚本, C++, CMake, DLL 劫持, DNS解析, Hook, ISteamUserStats, MSVC, Steam, VTable, 云资产清单, 函数拦截, 大语言模型, 安全, 安全意识培训, 客户端加密, 工具, 开源项目, 排行榜, 数据擦除, 游戏开发, 端点可见性, 超时处理, 运行时补丁, 逆向工程