Tatsh/expert-rotary-phone

GitHub: Tatsh/expert-rotary-phone

通过 Ghidra 逆向工程,将 Konami 已停更的 32 位 iOS 音乐游戏「pop'n rhythmin」重构为现代 Objective-C/C++ 源码,使其具备 64 位重编译能力。

Stars: 0 | Forks: 0

# pop'n rhythmin — 源码重构 [![GitHub tag (with filter)](https://img.shields.io/github/v/tag/Tatsh/expert-rotary-phone)](https://github.com/Tatsh/expert-rotary-phone/tags) [![License](https://img.shields.io/github/license/Tatsh/expert-rotary-phone)](https://github.com/Tatsh/expert-rotary-phone/blob/master/LICENSE.txt) [![GitHub commits since latest release (by SemVer including pre-releases)](https://img.shields.io/github/commits-since/Tatsh/expert-rotary-phone/v2.0.3/master)](https://github.com/Tatsh/expert-rotary-phone/compare/v2.0.3...master) [![Dependabot](https://img.shields.io/badge/Dependabot-enabled-blue?logo=dependabot)](https://github.com/dependabot) [![pages-build-deployment](https://static.pigsec.cn/wp-content/uploads/repos/cas/cb/cbfe37aed30c3d39993686ce1959c2a4b9f40ac57057a0431141f1d1a693ea94.svg)](https://tatsh.github.io/expert-rotary-phone/) [![Stargazers](https://img.shields.io/github/stars/Tatsh/expert-rotary-phone?logo=github&style=flat)](https://github.com/Tatsh/expert-rotary-phone/stargazers) [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://github.com/pre-commit/pre-commit) [![Prettier](https://img.shields.io/badge/Prettier-black?logo=prettier)](https://prettier.io/) [![@Tatsh](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fpublic.api.bsky.app%2Fxrpc%2Fapp.bsky.actor.getProfile%2F%3Factor=did%3Aplc%3Auq42idtvuccnmtl57nsucz72&query=%24.followersCount&label=Follow+%40Tatsh&logo=bluesky&style=social)](https://bsky.app/profile/Tatsh.bsky.social) [![Buy Me A Coffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-Tatsh-black?logo=buymeacoffee)](https://buymeacoffee.com/Tatsh) [![Libera.Chat](https://img.shields.io/badge/Libera.Chat-Tatsh-black?logo=liberadotchat)](irc://irc.libera.chat/Tatsh) [![Mastodon Follow](https://img.shields.io/mastodon/follow/109370961877277568?domain=hostux.social&style=social)](https://hostux.social/@Tatsh) [![Patreon](https://img.shields.io/badge/Patreon-Tatsh2-F96854?logo=patreon)](https://www.patreon.com/Tatsh2) 为 **pop'n rhythmin** (`jp.konami.popnmusic`) (Konami 的 iOS 伴侣/音乐节奏游戏)重构的 Objective-C 源码。已发布的二进制文件为**仅 32 位** (`armv7`, `CFBundleShortVersionString` 2.0.3, 基于 iOS 8.1 SDK 构建),因此 在 iOS 11 放弃 32 位支持后它便停止了运行。此代码树的目标是尽最大努力使用现代 Objective-C 重构_原始_应用程序源码,以便能重新编译为 64 位 / 当前版本的 iOS。 ## 出处 - **二进制文件:** `pop'n rhythmin 2.0.3-cracked/Payload/PopnRhythmin.app/PopnRhythmin` (Mach-O, `ARM:LE:32:v8`, image base `0x4000`, 3997 个函数)。 - **Ghidra 项目:** `rb420`, 程序 `PopnRhythmin` (MCP bridge, TCP `127.0.0.1:8091`)。注释中引用的地址均相对于该程序的 image base,且是此处重构内容的真实来源。 - **资源:** `.app` 包中的所有其他内容 (`*.acv`, `*.map`, `*.idx`, `*.m4a`, fonts, `ScoreData.momd`, `DefaultUserData.plist`, `Settings.bundle`)。 ## 重构与非重构内容 **范围内** — 原始应用程序代码:应用程序自身的 Objective-C 类 (view controllers, data models, managers, `ne*` OpenGL 引擎胶水代码) 以及支持它们的普通 C 辅助函数。 **范围外**(根据重构目标,特意_不_重新实现): - 编译器/运行时生成的代码:SjLj 异常 thunks、ARC/`objc_msgSend` stubs、`switchD_*` 跳转表、Obj-C 运行时元数据结构体 (`class_t`, `method_list_t`, `_Rep`, …)、libstdc++ 内部实现。 - 来自工具链或系统 SDK 的静态链接库代码: `CF*`/Foundation/UIKit 内部实现、`libz`、`libstdc++`、`memcpy`/`__stack_chk` 风格的辅助函数。这些内容仅会被引用,绝不重定义。 **打包进二进制文件的第三方 SDK** 既_不_进行重构,也_不_进行 stub 处理。原始 Konami 代码通过其公共头文件引用它们,因此此代码树也照做:它 `#import` 真实的库头文件,并将这些库视为外部依赖。关于列表及各个库的识别方式,请参阅下方的**依赖项**。(唯一的例外是当类名仅仅与某个 SDK _冲突_ 时 —— 例如 Core Data 实体 `TreasureData` 是本地的 sugoroku 存档记录,与 TreasureData 分析 SDK 毫无关联。) ## 约定 - **全面采用现代 Objective-C:** ARC、`@property`/点语法、装箱字面量 (`@[]`, `@{}`, `@(x)`)、`instancetype`、`NSInteger`/`CGFloat`。 - **尽可能使用点语法**进行 property/getter 风格的调用,包括 类 getter:`UIDevice.currentDevice`、`NSUserDefaults.standardUserDefaults`、 `array.count`、`results.lastObject` —— 而不是 `[UIDevice currentDevice]`。括号语法仅保留用于带参数的调用或具有动词副作用的调用。 - **根据语言使用空字面量:** Obj-C 对象 → `nil`;Obj-C++/C++ C 指针 (`.mm`/`.cpp`) → `nullptr`;纯 C (`.c`) → `nullptr` (目标为 **C23**)。C++ 目标为 **C++23**。(避免在旧有上下文之外使用 `NULL`。) - **Include 分组:** 标准库,然后是第三方/Apple 框架, 接着是项目头文件 —— 各组之间用空行分隔(没有组标签注释),每组按字母顺序排序(ASCII/区分大小写,因此 `+`<`.` 且小写排在大写之后 —— 与 clang-format 匹配)。 - **C++ `auto`:** 在 C++/Obj-C++ 代码中,优先使用 `auto`(根据需要加上 `&`/`const`/`*` 限定符)而不是拼写出类型;仅在必要时或确实有助于可读性时才指明具体类型名。 - **使用十进制字面量以提高可读性:** 当十进制更易读时,使用十进制 (`24`, `64`, `31`) 而不是十六进制来编写计数/大小/掩码。十六进制仅保留用于注释/引用 (`@ 0xcae40`) 中的 Ghidra 地址和真实的地址值。 例外:**按位掩码/标志位使用十六进制或二进制**字面量 (`& 0x1f`, `| 0x3`, `1 << n`),因为位模式才是关键。 - **按语言区分的文件扩展名:** - `.m` — 纯 Objective-C。 - `.mm` — Objective-C++ (Obj-C 与 C++ 混合;例如 `ne*` 引擎封装)。 - `.cpp` — 纯 C++ 实现 (`ne` 引擎核心)。 - `.h` — 所有头文件 (C, C++, Obj-C, Obj-C++)。 Obj-C 代码通过 `Engine/NEEngineBridge.h` 中的 `extern "C"` 桥接调用 C++ 引擎,因此仅_调用_引擎的文件仍保持为 `.m`。 - **每个 Obj-C 头文件包含编辑器 modelines:** 每个 `.h` 文件末尾都有 Kate 和 vim modelines,以便编辑器将其视为 Objective-C (或 Objective-C++),因为单纯的 `.h` 扩展名是有歧义的: // kate: hl Objective-C; // vim: set ft=objc : // code: language=Objective-C `code:` 行用于 VSCode 的 _vscode-modelines_ 扩展。Obj-C++ 桥接头文件使用 `hl Objective-C++;` / `ft=objcpp` / `language=Objective-C++`; C++ 头文件使用 `C++` / `cpp` 变体。所有 modelines 还设置了 4 空格的 tab 转空格缩进。 - **头文件保护符:** C++ 头文件使用 `#pragma once`;纯 C 头文件使用 `#ifndef UPPERCASE_NAME_H` (全大写);Obj-C 头文件依赖 `#import` 并且不使用保护符。 - **Ghidra 数据库保持同步:** 当 `FUN_*` 函数被识别后,它们在 `rb420` 数据库中会被重命名以匹配此处使用的名称,并附带一个 plate 注释指回重构后的文件。因此,该数据库是一个实时的交叉引用;像 `Ghidra: NEAppEventCenter_shared (FUN_0000b150)` 这样的引用可以在任一方向上进行解析。 - **Core Data 模型** 位于 `Models/` 中,并且是从 `ScoreData.momd` 满精度恢复的(它们不需要反编译 —— schema 已被序列化)。 - **重命名的 C 函数:** 任何在 Ghidra 中仍为 `FUN_` 并且在此处重新实现的函数都会被赋予一个描述性名称,且其定义包含引用注释,这样回到 Ghidra 的映射就永远不会丢失: // Ghidra: FUN_0000a9cc (project rb420, program PopnRhythmin) // Original: unnamed; renamed here for readability. static PersistentStore *rhythmin_makePersistentStoreCoordinator(void) { ... } 具名的 Objective-C 方法保留其真实的 selector 并引用其地址: `// -[AppDelegate application:didFinishLaunchingWithOptions:] @ 0x8cf0`。 - 该容器**没有 Xcode / Objective-C 编译器**,因此此处的内容均未经过编译检查。代码的编写力求忠实且原则上可构建,并未经过编译器验证。 ## 依赖项 这些内容在此处**不**进行重构 —— 将它们添加到项目中(通过 CocoaPods / Carthage / SPM / vendored 源码),重构后的 `#import` 即可解析。 ### 系统框架(链接 iOS SDK) `Foundation`, `UIKit`, `CoreData`, `CoreGraphics`, `QuartzCore`, `OpenGLES`, `AVFoundation`, `AudioToolbox`, `StoreKit`, `GameKit`, `MapKit`, `CoreLocation`, `Social`, `AdSupport`, `Security`, `libz`, `libstdc++`。(源自 Ghidra 类列表 —— 即 `/System/Library/Frameworks/...` 和 `/usr/lib/...` 条目。) ### 打包的第三方库 — 功能性(vendor 真实的源码/头文件) | Import as | Library | How identified | | --------------------------------------------------------------- | ----------------------------------------------- | ----------------------------------------------------------------------------------------------- | | `CJSONDeserializer.h`, `CJSONSerializer.h`, `CDataScanner.h`, … | **TouchJSON** (Jonathan Wight) | `CJSON*` / `CDataScanner` / `CSerializedJSONData` 类名是 TouchJSON 的确切公共 API。 | | `ZipArchive.h` (a.k.a. `UnZipArchive`) | **ZipArchive / SSZipArchive** (minizip wrapper) | `UnZipArchive` 类 + `libz` 链接。 | 如果确切的上游版本有影响,请固定使用 2014 年中期左右(包的构建日期, 2014-07-18)的发布版本,以匹配发布版本的行为。 ### 广告 / 分析 — 已打桩(STUB),移除依赖 根据项目策略,**不导入或发布任何与广告或分析相关的内容**。 这些依赖项已被移除;在原始代码调用它们的地方,调用点由 `Stubs/` 中的**空操作 stub (no-op stubs)** 提供,因此应用程序仍然可以构建和运行,并且所有的追踪/广告功能均处于无效状态。不要 vendor 真实的 SDK。 | Removed dependency | Kind | Handling | | ------------------------------------------------------------------------- | ----------- | ------------------------------------- | | **TreasureData** 分析 SDK (`TDClient` 等) | analytics | `Stubs/` 中的空操作 stub | | **RewardNetwork** SDK (`RewardNetwork*`, `RewardNetworkResources.bundle`) | 广告奖励 | `Stubs/` 中的空操作 stub | | `ASIdentifierManager` / `AdSupport` (IDFA) | 广告追踪 | 已移除;返回清零/缺失的 IDFA | 应用程序_自身_的交叉推广类 (`Recommend*`) 仍作为 原始源码进行重构,但其网络/广告调用已被中和为空操作,因此它们不会引入任何外部广告服务。 ## 目录结构 此代码树反映了**原始源码结构**,该结构是从内嵌在二进制文件(断言宏)中的 `__FILE__` 字符串恢复而来的。真实的项目根目录曾为 `/Users/usr10013727/Documents/Project/Rhythmin/branches/v203/Project/`,因此此 代码树重现了该 `Project/` 结构: ``` Project/ AppDelegate.{h,mm} confirmed original path System/src/ OpenGL/ neGLES11.cpp -> neIGLES (GL ES abstraction) [pending] Render/ neTextTexture.mm [pending] Sound/ caplayer.mm (CoreAudio AUGraph player) [pending] Aep/ AepManager/AepOrderingTable/AepLyrCtrl.mm [pending] Util/ RhCrypto.{h,c}, NSData+Crypt.{h,m} (crypto helpers) neEngineBridge.h provisional C++ engine singleton interface Game/ Note/ NoteMng.mm, AcNoteMng.mm [pending] Task/ SugorokuMainTask.mm [pending] Util/ Random.cpp [pending] Data/ Chara/ CharaData.mm, SkillData.mm [pending] TreasureMap/ SugorokuMap.mm [pending] Save/ Core Data models + query categories + UserSettingData (save/settings store) (done) Stubs/ No-op replacements for removed ad/analytics SDKs (our addition) ``` 标记为 `[pending` 的路径是已确认属于原始文件名但尚未重构的内容。 `Data/Save/` 是持久化类的临时分组(尚未从字符串中确认它们确切的原始子目录)。 命名遵循原始约定:系统层的 C++ 使用小写的 `ne` 前缀 (`neIGLES`, `neTextTexture`);游戏层的类使用 PascalCase (`NoteMng`, `CharaData`, `SugorokuMap`)。标识符尽可能从内嵌的调试/断言 字符串和 C++ RTTI 中恢复,而不是凭空发明。 有关各类的重构状态看板,请参阅 `HANDOFF.md`。
标签:CVE监控, GitHub Pages, 前端, 游戏, 源码重构, 音乐游戏