『SimTower』のリバースエンジニアリング

2026/04/29 2:41

『SimTower』のリバースエンジニアリング

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

towers.world プロジェクトは、オリジナルのエンジンソースコードへのアクセスなしで古いバイナリをリバースエンジニアリングするという課題を克服することで、伝説的なゲーム SimTower を成功裡に甦らせました。初期の試みにおいて、大規模言語モデル(LLM)が静的解析を用いて失敗しました。これは、雑多なディスアセンブルから早合点を行い、 verbose なコンテキストウィンドウにより精度を失い、上位レベルの設計と下位レベルの実装とを混同させたためです。開発チームは最終的に動的解析ワークフローへ切り替えることで成功しました。レガシーの Windows 3.1 API をエミュレートする Unicorn ベースのエミュレータを組み込むことで、自律的なコード実行ループを実現しました。LLM エージェント("Claude Code")を用いて、チームはこのエミュレータを約 30 分で構築し、8 時間動作させることに成功しました。これにより、ステートマッチングや乱数発生器のパリティに関するバグ(例:スラブアロケータの再現パターン)などを自律的に修正することが可能となりました。この実績は、雑多なディスアセンブルを持つ複雑なレガシーバイナリにおいて、AI によるリバースエンジニアリングが静的解析のみへの依存や抽象的なクリーンルーム設計に頼るのではなく、動的検証ループを最優先すべきことを示しています。これにより、特定のソフトウェアの動作を再現するために必要な時間と資源を大幅に削減できます。

本文

2026 年 4 月 28 日(火)、午後 5 時 05 分

ある日の朝、私はこう自問しました:「大規模言語モデル(LLM)が、私が愛してやまない幼少期のビデオゲームのモダンなクローン版を逆エンジニアリングすることはできるでしょうか?」そして、実際に行ってみました。本日、「towers.world」が公開され、オリジナルの完璧なクローン版における協力プレイ(Co-op 動作)を可能にしています。

クローン版とオリジナル

この回顧記事への感謝です。

本作の核心はエレベータシミュレーションにあります。塔の高さが増し、スイマー(キャラクター)たちが望む場所に移動しようと競い合うようになると、ゲームは困難さを増していきます。例えば、オフィス棟が塔を最も急速に成長させますが、それに伴って 9 時〜17 時の同期スケジュールを持つスイマーが 6 体も登場し、エレベーターに甚大な負荷をかけます。その結果、各エレベーターがどのような階へ行き、いつ行くのかを非常に厳密に管理する必要があるのです。

残念ながら、現在はエミュレータなしにはこのゲームを実際に遊ぶことがほぼ不可能になっています。もしエンジンがどこかで完全に説明されていれば再実装も可能だったでしょうが、そのような情報は存在しません。当初の私のアイデアは、LLM がバイナリを完全な仕様に逆エンジニアリングし、その仕様に基づいてゲームを再実装することでした。サイモン・ウィリソン氏のプログラムを別の言語へ翻訳するに関する投稿に触発されました。畢竟、アセンブリ言語も他のプログラミング言語の一つであり、明確に定義されたセマンティクスを持っています。そして、協力機能やより良い UI(主に部屋のグリッドを作成する機能)などの機能を追加したいと考えたのです。

そして、私はその道を選択しました。私が構築してきた一般的なバイナリ逆エンジニアリングフレームワーク「reaper」から始めました。これは静的解析のためにコーディングエージェントを囲むシンプルなハネスです。「ディスアセンブルされたコードを読み取ることで、このバイナリについて何を知ることができるか」という問いかけに対して答えを出します。

静的解析の時代

「reaper」は、プロンプトテンプレートセットと Ghidra に接続するためのスキルを持ち込み、選択した AI を使用させます。複数のプロンプトセッションを通じて、AI はバイナリに対する理解を深めていきます。最初は低レベルで容易に識別可能な関数やデータ構造から始め、それらがより高レベルのロジックを構成するようになる過程を経て、理解が積み上がります。このプロセスは私の手元でも较小的プログラムで成功しており、その出力をクリーンルーム仕様の基礎として利用しようと考えていました。

しかし、これは私の理論に過ぎませんでした。実際には、完全な仕様の複雑さを著しく過小評価していました。各部屋のスイマーには 10〜15 個の可能な状態があり、それらが持つ遷移関数は情報の精密な追跡を必要とします。また当時の最適化の要件により、ゲームはできる限り計算結果を激进的にキャッシュ・保存しており、パッキングされたビットフィールドや他の奇妙な構造体をよく使用していました。その結果でしょうか?機能するシミュレーションに近い形にはなったと言っても過言ではありませんが、プレイ可能な状態には決して至らず、ましてや振る舞いの同等性(behavioral parity)に達することはできませんでした。

静的解析を通じて、現在の AI の 3 つの具体的な失敗パターンを学ぶことができました。

第一に、AI はサブシステムについて premature な結論を drawn し、それを記録してしまう一方で、それ以前の推測をいつ放棄すべきかを見出せないまま苦悩しています。さらに深刻なのは、どの程度の詳細さ(specifcity)で記述すべきかのバランスを取るのが困難であることです。「runtime entity」といった奇妙な抽象用語を使ってスイマーを表したり、「queued-car continuation」という言葉でエレベータの列に並ぶ状態を説明したりすることが頻繁に見られました。最初のパスにおいて、マルチフロアのロビーコードを見つけ、「lower-atrium band」と命名しましたが、今なお Ghidra データベースやノート書(どこにでも散らばっています)から完全に除去できていません。

第二に、結論の記録について安易になりがちで、指示通りパラメータやローカル変数の名称付けを行うことをしばしば怠ります。私のプロンプトは極めて明確に、「関数単位で解析し、すべてのローカル変数とパラメータを命名すること」を求めています。しかし、それが実行されることはほとんどありません。モデル側はこの点において各イテレーションで徐々に向上していますが、まだ到達点には至っていません。

第三に、仕様の構築においては、シミュレーションの概念的な設計バイナリの実装詳細から切り離すことに苦戦しました。私はデータ構造のレイアウトの説明ではなく、クリーンルームの設計仕様を求めていたにもかかわらず、バイナリ詳細の含まないよう指示すると、再実装には不十分なほど抽象的な概念レベルへと移行してしまいました。

これらの課題の多くは、コンテキストウィンドウを管理するためのツールが不足していることによるものです。ディスアセンブルやデコンパイラの出力は、LLM がゼロから始めるにはあまりにも冗長です。確かに探索をより LLM ネイティブな手法にすることでこれを扱う方法があるかもしれませんが、単一の Ghidra データベースで作業する環境自体、LLM にとっては困難であると言えます。度々、LLM がコンパクト化・要約化されすぎて、直前に探査した詳細を忘却させる様子を観察させられました。テキスト処理タスクとは異なり、逆エンジニアリングでは正確な詳細情報をワーキングメモリに保持する必要があります。コンパクト化されたサマリーでは不充分です。

それでも私は諦めず進めました。LLM に仕様の洗練、誤り推測の棄却、そして書き直したシミュレーション向けのテスト構築を指導するために約 1 週間費やしました。欠落している具体的な不足点を指摘し、仕様を見直し改善するよう繰り返し求めましたが、目標に達することはできませんでした。

動的解析の時代

では次にどうすればよいでしょうか?友人から紹介されたこの 2 月の投稿が示唆的でした。そこでは SimCity の機能単位でのポート(移植)をオリジナルと比較するための入出力(I/O)比較手法について、エンジニア Christopher Ehrlich の取り組みが記されていました。Ehrlich のツイートはさらに banteg というユーザーによるゲーム『Crimsonland』の投稿を参照していました。

しかし、私は関数単位のポートを実行することに乗りたがりませんでした。まず第一に、API は著作権の対象となり得ます。バイナリと極めて類似したものをコピーすることは、クリーンルーム設計に近いアプローチよりも著作権上の問題を招く可能性があります。しかし、再実装における LLM の学習対象である「ヒル(傾斜面)」を提供するためには、元のバイナリからの何らかのフィードバックが必要であることを認識しなければなりませんでした。

直ちに直面した問題:このプロジェクトの根本的な理由は、SimTower を現代ハードウェアで実行できないことにあるためです。banteg プロジェクトが WinDbg を使用したのに対し、我々は何らかのエミュレータを必要とします。市販のホールのシステムエミュレータは最適な選択肢ではありません。なぜなら、操作系の数百万行の冗長コードの中から関心のあるプログラム動作を篩い出す必要があるからです。素早い検索が Unicorn というエミュレーションフレームワークの存在に気づかせてくれました。Unicorn は QEMU の JIT コード生成ロジックを利用し、任意のエミュレーションパイプラインを可能にするのです。

Claude Code にゲームが呼び出している Windows 3.1 API 関数の 195 つそれぞれに対して独自の実装を持つモック(マウス)を組み込んだ Unicorn エミュレータを作成させる指示を出しました。私は Claude に対するプロンプトは、ほぼ次の文章程度のものでした:「ご教授ください」。この作業には合計約半時間しかかかりませんでした。出来上がりは 99% 正解で、 loaders に存在する一つの問題点(後ほど Claude が発見し修正)を除けば完璧でした。私自身、ほとんど何も作業せずに行いました。正直に申し上げますと、ほぼゼロのガイド仅提供下でのこのような成果は、LLM の進歩に対する又一つの衝撃的な瞬間と感じています。

その後、Claude Code に複数の小規模な塔構成を指定させ、エミュレータされたバイナリ内の関数を呼び出して部屋を作成し、数ゲームティックごとに塔の状態のスナップショットを記録させるように指示しました。状態トレースを取得した以降、AI に再実装とエミュレータされたバイナリの動作間の乖離を引き起こす問題を自律的に修正させるよう指示を出しました。

もちろん、これはあらゆる詳細が精密に一致していることを確保することを意味します。特に面倒なのは、RNG(乱数ジェネレーター)や各ステップでのスイマーの処理順序です。RNG 的一致性とは、RNG を使用するすべての関数が同じ順序で実行される必要があり、例えば誤ったスイマーがディスパッチされると、連鎖的に状態が不一致となってしまいます。元のバイナリはスラブアロケータのような機構を使ってスイマーを割り当てており、一部の部屋はそのテーブルから空間を「獲得」した後、解放します。RNG 的一致性を得るためには、スイマーの反復によって誘発される RNG の呼び出しが同じ順序で発生するように、そのパターンをどこかで再現する必要があります。

そこから先は、トレーステストのカバー範囲の繰り返し改善と、Claude Code を長時間実行させるだけの作業となりました(私がプロンプトなしに最も長い実行時間は約 8 時間であり、その間に自律的に 5 つのパリティバグを修正しコミットしました)。

教訓

私がより深く進めるにつれ、ゲームはオリジナルバイナリの構造に近い再現へと収束していき、当初の「関数単位の移植ではない」という制約に違反することになりました。しかし、これは問題ありません。コメントや命名された関数・変数を備えた高レベル言語における完全な再現が得られれば、その後再び AI を使って翻訳し直すことも可能です。

素晴らしいのは、エミュレーションと状態一致(state-matching)が優れた検証ターゲットを提供できることです。トレースの一致が進むにつれ、LLM は段階的にヒルクライミングを行いながら、コードについて十分な知識を持ち、自律的にデバッグや問題解決を行うことができます。大きな教訓は一つです:これは私が何度も学び直さなければならない点ですが、複雑なタスクを実行する際には LLM を閉じたループ(closed loop)に置く必要があるということです。静的解析からのクリーンルーム設計という抽象的なタスクを LLM が確実に実行できる能力はまだ備わっていません。「改善せよ」と繰り返すだけでは問題解決にはなりません。裏側で動的解析による検証が必要です。

また、いくつか具体的なハネスパターンが役立つことがわかりました。現在の LLM を自律的に動作させるための最良の方法の一つは、長期間実行される高レベルの調整スレッドと、特定タスクのための低レベルサブエージェントを組み合わせることです。

このプロジェクトで使用されたトークン量は非常に多かったと言えます。Claude Code の $200/月のプランへアップグレードし、午前 8 時から午後 2 時のピーク使用時間(2 倍)を厳重に避ける必要がありました。自律的なヒルクライミングは LLM にとっては優れたパターンですが、安価には実行できません。LLM は実験を試み、プロジェクトから知る必要があるかもしれない情報をコンテキストウィンドウに埋めようとします。これらに対して非常に注意深く回避策を講じることができますが、多くの避けられないコストが存在します。学術文献にはディスアセンブルに関する興味深いアプローチ(例えば冗長性を減らすための独自フォーマットなど)がありますが、根本的な問題に対応するものはありません。

結論:私はこれを成し遂げました。あなたもできるようになります!マシ語からモダンな言語へコードを翻訳することが可能です。世界中にテラバイト単位の放棄されたマシネコードが存在します。初めて、それを経済的に修正・再利用できる持続可能な方法を持つツールが登場しました。これは驚異的な進歩です。

「towers.world」は現在利用可能です。ぜひプレイしてください!

補足 この全ての作業は、Recursion Center の参加者として行いました。NYC にあるプログラマのためのリトリートであり、私にとって世界で最も好きな場所の一つです。応募するか迷っている方は、ぜひ申し込んでください!

同じ日のほかのニュース

一覧に戻る →

2026/05/01 4:40

リンクedin は、拡張機能を 6,278 つスキャンし、その結果を全てのリクエストに暗号化して含めています。

## Japanese Translation: LinkedIn は、同意なく特定の Chrome 拡張機能を検出し処罰するために、ユーザーのブラウザを秘密裏にスキャンしており、基本的なプライバシー原則違反となっています。2026 年 4 月現在、そのスキャンカタログには 6,278 の拡張機能エントリが含まれており、少なくとも 2017 年から(当初は 38 から)積極的に維持されています。各拡張機能について、LinkedIn は chrome-extension:// URL に対して fetch() リクエストを發行し、失敗した場合はエラーがログに記録され、成功した場合は無視されて解決し、1 回の訪問あたり最大 6,278 のデータポイントが発生します。~1.6 MB の minified(圧縮された)かつ部分的に暗号化された JavaScript ファイルには、ハードコードされた拡張機能 ID と特定の web_accessible_resources パスが埋め込まれています。スキャンは 2 つのモードで実行されます:Promise.allSettled() を使用した同時並列リクエストと、設定可能な遅延( 때로는 requestIdleCallback に委譲される場合もあり)を持つ順次リクエストであり、パフォーマンスへの影響を隠蔽するためです。二次的なシステム「Spectroscopy」は、ハードコードされたリストに含まれていなくても chrome-extension:// URL を参照するアクティブなインタラクションを検出するために、独立して DOM ツリーを行進します。 拡張機能のみならず、LinkedIn の APFC/DNA ファフィンガープリントでは、キャンバスフィンガープリント、WebGL レンダラー、音声処理、インストール済みフォント、画面解像度、ピクセル比率、ハードウェア並列性、デバイスメモリ、バッテリーレベル、WebRTC によるローカル IP、タイムゾーン、言語など 48 の特性を収集し、これらを開示なしに収穫します。検出された拡張機能 ID は AedEvent および SpectroscopyEvent オブジェクトにパッケージ化され、RSA 公開鍵で暗号化され、LinkedIn の li/track エンドポイントに送信され、セッション中の後続のすべての API リクエストにおいて HTTP ヘッダーとして注入されます。 これらの実践により、求職ツール、政治コンテンツ拡張機能、宗教活動ツール、障害者支援ソフトウェア、神経多様性関連アプリケーションへの執行措置が可能となり、また LinkedIn は個人の詳細(例:アクティブな求職活動)を推測し、従業員間の組織ツールおよびワークフローをマッピングすることが可能です。この暗黙的なスキャンは LinkedIn のプライバシーポリシーに開示されておらず、EU デジタル市場法に違反しており、ゲートキーパーであるマイクロソフト(2024 年に指定)に対し、サードパーティツールを許可し、差別的な執行を禁止することを求めています。browsergate.eu によって公開準備が整っている完全な裁判所文書を通じて、法律当局——バイエルン州中央サイバー犯罪捜査庁(バーミング)など——は刑事調査を開始しました。ユーザーおよび企業は今後、プライバシー侵害とセキュリティ構成の暴露に対するリスクが高まっています。

2026/05/01 1:09

PyTorch Lightning の AI トレーニングライブラリに、神話上の風化獣「シャイ・フールード」をテーマにしたマルウェアが検出された

## Japanese Translation: 人気の PyPI パッケージ「lightning」の脆弱なバージョン 2(2.6.2 および 2.6.3)が、2026 年 4 月 30 日に公開されたことが、"Shai-Hulud"というテーマのオブフスクエードされた JavaScript 負荷を含むサプライチェーン攻撃で利用されました。マルウェアはモジュールをインポートするだけで自動的に実行され、認証情報、認証トークン、環境変数、クラウドシークレット(AWS、Azure Key Vault、GCP Secret Manager)、およびローカルファイルシステムの認証情報ファイルを盗みます。また、「EveryBoiWeBuildIsaWormBoi」という特定の命名規則と、"EveryBoiWeBuildIsAWormyBoi"で始まるコミットメッセージを用いて、公開の GitHub リポジトリを毒付けようとし、さらに C2 サーバーへの HTTPS POST、二重 base64 符号化されたトークンを伴う GitHub コミット検索デッドドロップ、攻撃者による公開リポジトリの利用、および `ghs_` トークンを用いて被害者のリポジトリに直接プッシュする、4 つの並列データ流出チャネルを利用しています。 この攻撃は、悪用された npm 認証情報を使用して公開されるあらゆるパッケージに対して、14.8 MB の `setup.mjs` ドロッパー(Bun ランタイム v1.3.13 をブートストアップする)と `router_runtime.js` ファイルを注入することで、PyPI から npm へと感染を広げます。永続性を確保するために、マルウェアは人気のある開発ツール設定ファイルにフックを注入します:Claude Code の `.claude/settings.json` への "SessionStart"フックと、VS Code の `.vscode/tasks.json` への `runOn: folderOpen` タスクです。攻撃者が書込みアクセス権を持っている場合、「Formatter」という名前の悪意のある GitHub Actions ワークフローがプッシュされ、「format-results」というダウンロード可能なアーティファクトとしてシークレットがダンプされます。さらに、`_runtime/`ディレクトリや `start.py`のようなファイルに隠れたフックも注入されます。 セキュリティ企業 Semgrep は、特定の検出規則を含む緊急のアドバースを発表しており、詳細は https://semgrep.dev/orgs/-/advisories で入手できます。影響を受けたユーザーは、直ちにすべての盗まれた認証情報(GitHub トークン、クラウドキー、API キー)の再発行を行い、`.claude/`、`.vscode/`、`_runtime/`ディレクトリなどに注入された悪意のあるスクリプトを含むプロジェクトを監査し、将来のサプライチェーン侵害を防ぐために厳格な依存関係フィルタを実装する必要があります。

2026/05/01 5:33

アップル、第四半期業績を発表

## Japanese Translation: アップルは、2026 年 3 月 28 日に終了した fiscal second quarter(第 2 四半期)で史上最高益を記録し、売上高は 1,112 億ドル(前年同期比 17% 増)、一株当たり利益は 2.01 ドル(同 22% 増)となりました。この業績は、iPhone 17 シリーズ(新 iPhone 17e を含む)への特異な需要から生じた iPhone 売上高の歴代最高記録、サービスの歴史的な成長、そして M4チップ搭載 iPad Air と MacBook Neo の成功した発売によって牽引されました。稼働キャッシュフローは四半期史上最高の 280 億ドルを超え、アップルの既存基盤はすべての主要製品カテゴリーおよび地域で史上最高に達しました。このモメンタムを報いるため、アップルは一株当たり 0.27 ドルの配当(4% 増)を宣告し、2026 年 5 月 14 日に記録日(レコードデー)として 2026 年 5 月 11 日の株主に対して支払い可能にするほか、追加の 1,000 億ドル規模の自社株式買回プログラムを承認しました。アップルの利益発表会合は、2026 年 4 月 30 日午後 2 時(太平洋標準時間)にライブストリーミング開始され、約 2 週間後のリプレイも利用可能です。詳細は apple.com/investor/earnings-call で確認できます。同社は堅調な財務体質とすべての主要セグメントにおける消費者の積極的な関与を強調しました。

『SimTower』のリバースエンジニアリング | そっか~ニュース