プリンスオブペルシャのソースコードとコピー保護の分析

画像






パート1:はじめに



2012年4月17日に、ジョーダンメックナープリンスオブペルシャのソースコードを公開しました



これは6502プロセッサのアセンブリ言語で書かれたApple IIのバージョンですが、この伝説的なゲームのコードに飛び込むのはとてもうれしいことです。 いつものように、私は多くのソフトウェアの利益を待っていました。



明らかにゲームの弱いプログラミング環境であるApple IIは、比類のない革新と創造性の基盤でした。つまり、自己修正コード、内部ブートローダー、スマートフロッピーディスクフォーマット、オフセット検索テーブルです。 Prince Of Persiaの各モジュールには、エンジニアリングの宝が保存されています。



ソースコードを読むことで、80年代のゲーム開発プロセスについてより多くを学ぶことができただけでなく、今日では自然と考えられているものに再び感謝の気持ちを抱かせました。



いつものように、詳細なメモを保管し、それに基づいてこの記事を作成しました。 彼女がソースコードを読んで開発スキルを向上させるように他の人を奮い立たせることを願っています。



謝辞:知識を共有してくれた6502.orgとRoland Gustafsson(RWTS18の著者)のMiles.Jに感謝します。



どこから始めますか?



ソースコードはGitHubのリポジトリから入手でき、1つのコマンドでダウンロードできます。



git clone git://github.com/jmechner/Prince-of-Persia-Apple-II.git
      
      





興味深い部分は、 /Prince-of-Persia-Apple-II/01 POP Source/Source/



フォルダーです。このフォルダーには、多くの.S



ファイルで構成されるゲームエンジンが含まれています。



これは、プログラマーが当時持っていなかった最初のものです。高品質のコンパイラーを備えた高レベル言語です。 優れた速度を実現するために、開発者はアセンブリ言語6502のハードウェアを直接操作する必要がありました。これにより、これらの.S



ファイルが構成されます。







ジョーダン・メックナーの著書『メイキング・オブ・プリンス・オブ・ペルシャ』によると、マーリンのアセンブラーはPoPで使用されていました。



Merlinの優れた機能の1つは、 ORG



ディレクティブです。これにより、アセンブラはRAMのどこに命令をロードするかを指示できます。PoPでは、 ORG



は各ファイルの先頭にあります。



興味深い事実: ORG



ディレクティブは実際には単なるガイドラインでした。 Apple IIには、オペレーティングシステムもリンカーもブートローダーもありませんでした。開発者自身が、なんとかしてフロッピーディスクから適切な場所に命令を転送する必要がありました。



PoPを一般的に理解するために理解する必要がある2番目の重要な点は、モジュール間で情報が交換される方法です。 その時点ではファイル間リンカー(および最終的な実行可能ファイル、フラグメントのみ)がなかったため、モジュールはデータを交換し、他のモジュールが配置されるvoid ...への移行を行う必要があります。







この例は、ブートローダーBOOT.S



138行 BOOT.S



で確認できます。



 jmp $ee00
      
      





そして、これはかなり神秘的です。



指示の流れに従うには、 $ee00



内容を把握する必要があります。 小さなgrepコマンドをHIRES.S



と、 HIRES.S



と移行でorg = $ee00



確認できます。



リンカがなかったため、80年代の開発者はエンジンのメモリスキームを知り、RAMの制限を理解する必要がありました。 ほとんどの専門家はガベージコレクターまたは自動サイズ変更機能付きベクターの使用に依存しているため、これは現在では非常にまれです。



アセンブラー6502



全体像を紹介し、サブシステム間の移行がどのように実行されるかについて説明します。 各モジュールの内容を理解するには、中央処理装置に少し精通する必要があります。 幸いなことに、6502は3つのレジスタのみを備えた単純な16ビットプロセッサであり、64 KBのRAMをアドレス指定できます(スイッチングバンクはこの量を128 KBに拡張しました)。







図は、すべてがいかに単純かを示しています。





ほとんどの操作は、レジスタをロードおよび保存するように設計されており、XおよびYレジスタには簡単な命令があり、ドライブ(A)はもう少し複雑ですが、一般的に非常に簡単でよく文書化されています。



今日残念ながら絶版となっている2つの素晴らしい本は、 Apple II Reference ManualInside the Apple IIeです。







出発点



80年代には、 main



メソッドを備えたIDEとCソースファイルがなかったため、プログラムがどこから始まったかを知ることはできません。 読み始める場所を理解するには、Apple IIの起動方法を知る必要があります。



  1. フロッピーディスクからトラック0のセクター0の最初のバイトXを読み取ります。
  2. Xセクターをトラック0からRAMに$800



    ダウンロードします。
  3. $800



    コードの実行を開始します。


開始点を見つけるには、 ORG



ディレクティブを検索して、 $800



実行するように指示されているモジュールを判別する必要があります。



  fabiensanglard$ find . -name "*.S" -exec grep -H "org = \$800" {} \; ./01 POP Source/Source/BOOT.S:org = $800 ./02 POP Disk Routines/CP.525/POPBOOT0.S:org = $800 ./03 Disk Protection/POPBOOT0.S:org = $800 ./04 Support/MakeDisk/DRAZ/DRAZ.S:org = $800 ./04 Support/MakeDisk/S/BOOT.S:org = $800
      
      





そのため、開始点はBOOT.S



ます。このファイルには、後で説明するように、PoPローダーが含まれています。



推奨読書



ジョーダン・メックナーは自分の日記を出版しました(本またはPDFとして購入できます)。 これは、ゲーム開発者がゲームを作成するときに経験しなければならないこと、つまり疑念、プレッシャー、絶望、希望、喜びについての非常に正確な説明です。







技術的な部分について詳しく理解するには、Atari / Amiga / PCの開発者向けの開発者向けメモを調べてください(これらのポートでの作業はそれほど難しくありませんでしたが、雑誌「Make Of」の重要性を損ないません)。



















ヨルダンの日記で言及されたロトスコーピングとティナラドー(プリンセス)を知るための伝説的なプロセスのビデオ。









注: Jordan Meknerは、2013年1月にRedditで開催されたAMAに参加しました。



パート2:ブートローダー



RAMとコンピューティングリソースを節約するために、Apple IIゲーム開発者はコンピューターに付属のオペレーティングシステムを使用しませんでした。 したがって、ゲームエンジンをフロッピーディスクからRAMにロードする小さなプログラムである、独自のブートローダーを作成する必要がありました。



Apple II ROMにある手順はこれに本当に役立ちました。RWTS16はフロッピーディスクを制御し、35トラックのトラックあたり256バイトの16セクターを読み書きできるようにする命令のセットでした。 合計で、ディスクあたり140 KBでした。



しかし、BrøderbundゲームはRWTS16を使用しませんでした。 彼らはより良いフォーマットを見つけました。RWTS18はより多くのデータを提供し、信頼できるコピー保護メカニズムであることが証明されました。



従来のブートローダー







違いに注目する前に、ビデオゲーム業界で通常行われていることをリストします。



コンピューターが起動すると、3つのコンポーネントが相互作用します。









Apple IIを起動するとき:



  1. コンピューターは、Apple ROMのブート指示に指示ポインターをインストールしました
  2. Appleのブート手順では、RWTS16を使用して、フロッピーディスクからRAMに$800



    セクターをロードしました。
  3. これらのセクターにはゲームローダーが含まれていました。
  4. その後、Apple IIの起動手順は$800



    移行しました。






この時点から、ゲームローダーはゲームエンジンをフロッピーディスクからRAMにロードする役割を果たしました。



  1. Apple IIのRWTS16手順の使用...
  2. 彼はゲームエンジンをフロッピーディスクからRAMに移し......
  3. そして、彼はエンジンに移りました。


RWTS16







RWTS16は、Apple IIに付属のフロッピーディスクフォーマットでした。 これは、 Beneath Apple DOSという素晴らしい本に詳しく説明されています。 つまり、ディスクドライブを制御してトラックごとに16セクタを読み書きするROMの一連の手順で構成されていました。



次のように、トラックごとに256バイトのセクターが記録されました。







ドライブは精度に欠けていたため、重複することなく消去/再起動を保証するために、セクター間に大きなギャップを残す必要がありました。



下の図でわかるように、ドライブヘッドは「理想的な」位置の少し前または後に記録できます。 これらの不正確さを補うギャップ:







RWTS18







RWTS18は、BrøderbundのためにRoland Gustafssonによって作成されたフロッピーディスクフォーマットです。 RWTS16とは完全に異なり、より多くのストレージを提供するだけでなく、ハッカーの生活を非常に複雑にしました。



RWTS18の容量の増加は重要な観察によって提供されました。ゲームを開発するとき、それは主に書き込みではなくデータの読み取りを使用していました。 RWTS18は、セクターの概念をほぼ完全に放棄しました。彼はトラック全体を記録し、より大きなサイズのセクターを読み取りました。



このようなスキームにより、RWTS16がセクター間で持つ必要があったギャップのほとんどを取り除くことができました:セクター間はXXXの自己同期バイトのみでした。







その結果、RWTS18は、RWTS16で使用可能な140 KBではなく、6セクターのそれぞれに768バイトのストレージとディスクあたり157 KBのストレージを提供しました。



しかし、RWTS18の利点は容量の増加だけではありませんでした。 彼はコピー保護メカニズムも作成しました。





注: RWTS18は、次の2つの理由でセクターを完全に放棄しませんでした。





注: Roland Gustafssonはコメントを追加しました:



仕様によると、ディスクを読み取るとき、18セクターはRAMの18の異なるページに転送され、結果の順序で18セクター($ 1200バイト)の順次読み取りだけではありません。 この方法は現在、ハードドライブに使用されており、「スキャッターリード」と呼ばれているようです(それから、私にとっては素晴らしいアイデアのように思えました!)。



使用した自己修正コードにより、6回ではなく4回の循環読み取りを実行でき、2サイクルの読み取り/書き込みを節約できました。 さらに、各セクター/ページが必ずしも必要ではない場合、読み取り操作を「破棄」できました。 必要なすべてのバリエーションを制御するAPIがありました。 内部トラックの読み取りおよび書き込みサイクルは非常にタイトでした。 実際、記録手順では、1回転で記録するために、データを少し前処理する必要がありました。 間違っていなければ、在庫はわずか20%でした。


興味深い事実:ローランド・グスタフソンはApple IIが大好きだったため、車のナンバープレート「 D5 AA 96



」を作成しました(これは3バイトのプロローグマーカーRWTS16に対応します。







興味深い事実: RWTS18 ソースコードは、テキストファイルだけでなく、マークアップされたファイル形式のLISAアセンブラを使用して作成されました。 ローランドは、ソースコードを抽出でき次第、公開する予定です。 これを行う方法を知っているなら、彼を助けてください。



興味深い事実: RWTS18は解読するのが非常に難しく、奇妙な伝説が生まれました。以前は、RWTS18ディスクを作成するには低速のディスクドライブが必要であると考えられていました。



興味深い事実:ハッカーは依然としてプリンスオブペルシャをハッキングすることができました...しかし、さらに配布するためには、ゲームをリバースエンジニアリングし、RWTS16でフォーマットされた3つのディスクに書き込む必要がありました。 PoPのオリジナルバージョンは、RWTS18を搭載した2つのディスクで販売されていました。 Apple IIエミュレーターでも、ハッキングされたPrince Of Persiaのバージョンしか実行できません!



Prince Of Persiaダウンローダー







これで、PoPブートローダーの処理を開始するためのすべての情報が得られました。



PoPは通常の方法でロードを開始しました。最初のトラックはRWTS16でフォーマットされていたため、Apple IIのブート手順によりPoPブートローダーがRAMにロードされました。







次に、RWTS16を使用するPoPローダーは、トラック0の残りからRWTS18プロシージャをロードしました。







次に、ブートローダーはRWTS18を使用して、RWTS18でフォーマットされた他のトラックからゲームエンジンをロードしました。



ブートローダーはゲームエンジンに移り、ゲームエンジンはRWTS18プロシージャを使用してゲームリソースをロードしました。



ローランド・グスタフソンへのインタビュー



ローランドは、いくつかの質問に答えることに同意しました。インタビューは次のとおりです。



Fabien Sanglar:こんにちは、ローランド、あなた自身について少し話してください。生まれたとき、どこで育ち、学校が好きで、プログラマーになったのですか?



ローランド・グスタフソン:私はスウェーデンで生まれましたが、生涯カリフォルニアで過ごしました。 私は学校があまり好きではありませんでしたが、高校を卒業しました。その時、私はすでに17年間でプログラムを作成し、よく暮らしていました。 (だから大学に行かなかった。大学では、コンピューターサイエンスの教育は「パーソナルコンピューター」と呼ばれる興味深い新しいマシンとはまったく関係がなかった。それは70年代後半だった。)



FS: 80年代にBrøderbundで働き始めたきっかけは? どれくらい働いていますか? RWTS18のアイデアはどのようにして得たのですか、なぜそれを書いたのですか? RWTS18以外にブレーダーバンドで他に取り組んだことはありますか?



RG:私は一度もブローダーバンドの従業員になったことはありません。本当の仕事はありませんでした。私は常にフリーランサーでした。



RW18のアイデアは、必然的に生まれました。 標準の16セクタードライブに適合しないBank Street製品(Bank Street Writerの後)がありました。 以前は手品をしなければならなかったので、より多くのデータを保存する何かを考え出すことができるかどうか尋ねられました。 何年もの間、私はコピー保護に取り組み、箱の外で考え、Disk IIドライブの機能を完全に理解しました。 少し考えた後、私は思いついた最も効果的な方法に来ました。 日本へ向かう途中の飛行機で起こったので、紙と鉛筆で多くの時間を過ごしました。 私の友人Corey Kosakは、19セクター(理論上の制限)を保存する方法を見つけたと確信していましたが、弱い6502では対応できないほど高価な数学的計算を使用していました。 ニブルを管理するための数学ではベース64を使用しますが、ベース78などで簡単に作業できる場合はより多くのデータを保存できましたが、覚えていません。 数学は少しst迷。 もちろん、Base 64での作業は、バイナリシステムは非常に簡単でした。



FS: Brøderbundとはどのように仕事をしましたか(スケジュール、給料、あなたのような情熱的な人々に興味があります)? その経験を現在の労働条件と比較できますか?



RG:私は本当の仕事を持っていませんでしたし、望んでいませんでした。オフィスが好きではありません。



FS:プリンスオブペルシャで働いていましたか? ゲームの開発者を助けましたか、それともアセンブラとマニュアルにソースコードを渡すことで終わりましたか?



WP: Jordan Meknerと直接協力して、RW18とコピー防止の実装を行いました。 コピーを複雑にする迂回方法を思いついたとき、私たちはしばしば面白い瞬間を経験しました。 場合によっては、ゲームは機能しているように見えましたが、その結果、プレイできなくなりました。 他のほとんどのゲームの場合、それらが完了し、コピー防止機能を追加した後に動作するように設定しました。 例外はRW18プログラムで、開発段階で実装する必要がありました! 簡単に使用できるように、簡単なガイドを作成しました。



FS:本「ハッカー:コンピューター革命の英雄」(「ハッカー:コンピューター革命の英雄」)には、SpirradiscとSierra On-Lineの海賊行為との戦いに関する章があります。 振り返ってみると、RWTS18をゲームの海賊行為からブロードバンドを保護する効果的な方法と名づけることはできますか? 他の出版社(Spiradisc)のコピー防止メカニズムを研究しましたか? もしそうなら、あなたはそれらをどう思いますか?



WP:私が注意深く研究した唯一のコピー防止機能は、Microsoft Flight Simulatorのカセットバージョンです。 その後、コピー防止機能があることに気付きました。 その瞬間から、私はセキュリティシステムを開発し、他の人がしていることをほとんど研究しませんでした。 私自身はスパイラルディスクで保護の概念に到達し、多くのゲームBrøderbundとGebelliでそれを使用しました。 誰もが18セクターのテクノロジーを考えているかどうかは知りませんでしたが、何年も後に、誰かがこの方法を自分でコピーまたは到達したと聞きました。 しかし、私はまだよくわかりません。 RW18が私によって発明されたことは確かです。



FS:ソフトウェア著作権侵害との闘いのテーマ継続します。RWTS18を改善するために、相手のテクニックに従っていますか? 敵は時々、彼らが戦う人々のスキルに敬意を表します:海賊ができたことに感銘を受けたことはありますか(たとえば、3つのRWTS16ディスク上のPoPの海賊版コピー)。



WP:はい。少なくとも、Locksmith、Nibbles Away、およびその他のコピー用ソフトウェアを勉強し、ハードウェアに関するトピックも読みました。 ハードウェアのコピーから保護するためのコードを追加しましたが、それは非常によくできていたので、Appleはその当時は要求されていない秘密のApple // eでもそれを保護する方法を理解できませんでした そこで彼らはこのコンピューターを私の家に持ち込み、私は保護作業を行いました。 Apple // eが発表されてリリースされるまで、かなりの時間隠れました。



正直なところ、RW18で2枚組のゲーム用に3枚組のバージョンを作成するというアイデアは愚かで、あまり印象的ではなかったと思います。 このRW18形式を完全に再作成し、正確なコピーを作成するコピーシステムを作成する方が良いでしょう! ゲームははるかに良く、速くなります...



FS:ソフトウェア開発の歴史の中で、最もハッキングと考えているハックは何ですか?



RG:何も思い浮かびません。 誰かが独創的な思考を必要とする複雑な問題に対する驚くほど賢明な解決策を見つけたとき、それは常に認識に値すると言えます。



FS:どのゲームが一番好きですか?

WP:長い間プレイしていませんでしたが、GameBoyのTetrisのオリジナルバージョンは、プレイヤーが互いに戦うときに「ネットワーク」ゲームと呼ぶことができます。 私はBrøderbundで非常に一生懸命演奏しました。



FS:コンピューター業界の個人的なヒーローであるロールモデルはありますか?



WP: Steve WozniakがオリジナルのApple II ROMのソースコードの公開を主張したという事実は、私のトレーニングにとって非常に重要でした。 サンフランシスコで開催されたAppleユーザーミーティングで彼に会った後、彼と話をして、Disk IIに関する詳細な情報を得ることができました。これにより、コピー防止が可能になりました。



FS:ソフトウェアエンジニアとして最も誇りに思う瞬間は何ですか?



RG: 「うさぎを帽子から出して」という期待を超えることができたときはいつでも、これらは素晴らしい瞬間です。 私は今でもRW18を私の最高のトリックの1つと考えています。



FS:今は何に取り組んでいますか?



WP:私はOceanhouse Mediaのテクニカルディレクターです。モバイルアプリケーションを開発しています。 AppleはiOSとアプリケーション開発で真のブレークスルーを達成しました! また、他のモバイル市場向けに開発を進めており、まだまだ多くのことが行われています。 はい、私はまだAppleの大ファンです。



推奨読書







Beneath Apple DOS 」は、Apple IIコンピューターの内部構造を説明する優れた本です。 RWTS16およびブロードキャスト6 + 2を理解するのに非常に役立ちます。







Hackers:Heroes of the Computer Revolutionには、Sierra On-Lineに関する章と、 Spiradisc 、Mark Duchaineauを開発した子供の天才アンチハッカーとの複雑な関係があります。



必要なすべての知識が得られたので、実際にコードに突入し、各ファイルが信じられないほどのカオスのどこにあるかを把握できます。これがRAM Apple IIの構造です。



パート3:ブートローダーの詳細



ソースコードの詳細なコメント付きバージョンはGitHubにあります



以下に、この悪名高いRAMの図を示します。







BOOT.S



BOOT.S



は、 $01



を命令ストリームに出力することから始まります( 行:21 )。これにより、Appleファームウェアは1つのセクターをトラック0からアドレスのRAMに自動的にロードし、$800



そこに行きます:







複数のソフトウェアスイッチをインストールした後、BOOT.S



RWTS16を使用して、オフセットテーブルを使用して一連のセクターをRAMにロードします(行:79)。これらのセクターには残りの手順BOOT.S



とRWTS18 が含まれていることが判明ました:







RWTS18の手順をアドレスの別のバンクに移動した後$D000



(使いやすさのため)、RWTS18を使用してトラック1全体をアドレス$E000



行:136にダウンロードし、謎の1つに進み$ee00



ます。







採用情報



何がトラック1にあったのか、このデータがアドレスにあるべきかどうかはわかりません$ee00







ただし、grepを使用してこれを把握できます。



  fabiensanglard$ find . -name "*.S" -exec grep -H "org = \$ee00" {} \; ./01 POP Source/Source/HIRES.S:org = $ee00 ./01 POP Source/Source/MOVER.S:org = $ee00
      
      





コードを少し調べたところ、興味があることがわかりましたHIRES.S











HIRES.S



:トランジションの最初に別の謎のアドレスに私たちをもたらした、テーブルを含んでいる$f880



13行)。



MASTER.S



そして再び、私たちは何がその住所にあるべきかを知りません$f880







しかし、もう一度grepを使用して調べることができます。



  fabiensanglard$ find . -name "*.S" -exec grep -H "org = \$f880" {} \; ./01 POP Source/Source/MASTER.S:org = $f880 ./04 Support/MakeDisk/S/MASTER.S:org = $f880 ./04 Support/MakeDisk/S/MASTER525.S:org = $f880
      
      





したがって、アドレス$f880



はcontent MASTER.S



です。メモリ割り当てテーブルを編集できます。







MASTER.S



次の内容があります。



  jmp FIRSTBOOT jmp LOADLEVEL jmp RELOAD jmp LoadStage2 jmp RELOAD jmp ATTRACTMODE jmp CUTPRINCESS jmp SAVEGAME jmp LOADGAME jmp DOSTARTGAME jmp EPILOG jmp LOADALTSET
      
      





この段階で、ゲームエンジンがRAMにロードされ、伝説的なDOUBLE-HIGHスプラッシュスクリーンをロードする準備ができました。







[注 .: . , , , - .]



All Articles