最初にスプレッドガノムを使用したDendyまたはContraでの古典的なゲームのハッキングの物語

私の最後の記事以来、私の驚いたことに、あなたに興味を持っていました。 その結果を補足することにしました。ハッキングされたゲーム「Contra(J)[T + Rus_Chronix]」は、NESで「コードインジェクション」を示しながら、少しの機能を備えています。 今回は、プレイヤーがポンピングされたSpreadgunでゲームを開始するようにします。ゲームでそれを取得するには、アイコン「S」、次に「R」を選択する必要があります。













猫の下ですべての興味のある歓迎。







従来:







退屈なプロセスビデオ


そして、私たちは伝統的に一連の行動を計画しています。







  1. 住所を検索
  2. ポンプ式Spreadgunの価値をご覧ください
  3. ゲームの始めに彼がこれらのアドレスに書いたものを見つけてください
  4. ROMの書き換え

    • Easyway-基本的な武器の値をポンピングスプレッドガンに変更する
    • ハードウェイ-簡単な方法が失敗した場合、完全なコードインジェクションを使用する
  5. 結果を新しいファイルに保存します


住所を検索するには、前述の方法を使用しますが、生活は近隣の住所にあったことを覚えて、2番目のプレイヤーが近くにいることを期待して最初のプレイヤーからの武器のみを探します。 最初のレベルの開始後に「Ram watch」ウィンドウを開いて、未知の値を探しています。 基本武器は0だと思いますが、確かなことはわかりません。

前方に走ることなくレベルに沿って走り、すべての方向に撃ち、変化する値を取り除きます。 武器はまだ変更されていません。







別のウィンドウオプションを使用するか、フィールド "Compare To / By"でラジオ周波数 "Number of Changes"を強調表示し、フィールド0に入れます。比較のタイプはもちろん "Equals to"です。 武器はまだ変わりませんでした。







したがって、「以前の値と等しい」オプションから「変更の数が0」というオプションにジャンプすると、約10,000個のアドレスに到達できます。 さらにスクリーニングを行うと、アドレスリストがわずかに減少するか、まったく減少しない場合、最初の武器をノックアウトするのに十分なほど前進できます。







それを取得したら、すぐに「前の値と等しくない」検索方法を使用し、「変更数が1」である武器を一度だけ変更して検索することでリストをさらに減らします。







最初の武器を拾う場所には、武器アンプも表示されます。 アドレスを選択して選択したら、アドレスの数を1に減らすことができますが、うまくいかない場合は、キャラクターを殺して武器を再度変更します。 (各変更後の検索を忘れないでください)。







武器アンプを使用すると、武器自体の値は変更されず、メモリの他の場所のフラグが変更される可能性がありますが、ゲームの作成者がメモリと指示を保存することを期待しましょう。 そして、幸運なボーナス「R」が武器の価値を変え、アドレスは座標AA 16にありました 。 (私は間違っている可能性がありますが、このアドレスがAA 16であるように、ゲームコントラの異なるバージョンでヒーローの武器を繰り返し監視しました)。







また、ボーナス "R"によってアドレスの値が16 10または10 16増加したこと、つまり、16進数の最初の桁が1増加したことにも気付きました。







「Ram watch」ウィンドウでの再起動後、基本値が実際に00 16であり、ボーナス「M」が2桁目を1増加させ、ボーナス「R」が最初に増加したことがわかります。







あなたはスプレッガンに行くことができます、それは間違いなくこのレベルで会うでしょう、またはあなたはどの数字、どんな武器を作るかを見るためにアドレスの値を変えることができます。 経験的に、01 16は「Machinegun」、02 16は「Fire」、03 16は「Spreadgun」、04 16は「Laser」であることがわかりました。 2桁目に他の値を入力すると、さまざまなグリッチが発生します。







ゲームをリセットし、値1x 16を入力した後(「x」は受け入れ可能なオプションのいずれか)、「Rapid」ボーナスを選択する前に、ボーナスを再選択しても何も変わらないことがわかります。







これで、ゲームを再起動し、2人でゲームを開始して、AA 16に隣接するアドレスを変更することができます。 (そのうちの2つがあり、検索は長くはありません)2番目のプレイヤーを撃ったところ、2番目のプレイヤーの武器が実際にアドレスAB 16の近くに保存されていることがすぐにわかりました。 そして今、私たちは私たちにとって興味のあるアドレスとそこに置かれるべき価値を知っています、それは彼がこれらのアドレスに書いているものを見つける時です。







このアドレスの記録にブレークポイントを投げると、記録が複数回発生し、そのうちの1つはスプラッシュ画面の後に発生することがわかりました。 次のコードはこのエントリを作成します。







住所 オペコード ニーモニック 引数 A X
C307 A2 28 LDX #$ 28
C309 A9 00 LDA #$ 00 28または29または...またはF0
C30b 95 00 STA $ 00、X 00 28または29または...またはF0
C30d E8 Inx 00 28または29または...またはF0
C30E E0 F0 CPX #$ F0 00 29または30または...またはF0
C310 D0 F9 ブネ $ C30b 00 29または30または...またはF0


ここでゲームを注意深く読んだ場合、アドレス範囲が0028 16から00F0 16にゼロになっているので、明らかにその範囲内の両方のアドレスに興味があります。 簡単な方法はありません。 「コードインジェクション」と最も簡単なソリューションを使用して、ここからどこに到達するかを調べ、メモリ内のコードやデータのない場所に実行をリダイレクトし、アドレス00AA 16と00AB 16を除く範囲全体を占めるループのバージョンを記述し、キャリッジを返す必要があります実行バック。 ちなみに、これは注射の最も古典的なバージョンです。 JSR(Jump to SubRoutine)命令からここに到達したと仮定することもできます。これはスタックで簡単に確認できます。







スタックはどのように機能しますか?

6502プロセッサでは、スタックは常にこのプロセッサに基づくすべてのコンピュータのアドレス範囲0100 16-01FF 16にあり、大きいアドレスから小さいアドレスに拡大します。 スタックの最上部を指す個別のレジスタがあります。最初は、より重要なバイトが変更されないため、FF 16に等しくなります。 レジスタ自体は、有用なデータで占有されていない最上位バイトを常に示します。







エミュレータデバッガは「スタックポインタ」レジスタの値を表示せず、代わりにレジスタが参照するアドレスを表示し、現在は01F2 16です 。簡単な計算では、スタックの最後のデータがC3 16およびC2 16であり、アドレスC3C2 16が6502プロセッサタイプ「リトルエンディアン」を考えているため、命令を実行してメモリまたはスタックにアドレスを格納するとき、下位バイトが最初に書き込まれます。 そして、アドレスが本当にスタックの一番上にある場合、これはアドレスC2C3 16です。 そして、これはJSR命令の最後の引数のアドレスです。これもアドレスです。 チェックは非常に簡単です。アドレスC2C3 16の 2バイト上に書き込まれているものを見てください。







住所 オペコード ニーモニック 引数
C2C1 20 07 C3 JSR $ C307


ご覧のとおり、これはC307 16の JSR命令です。つまり、サブルーチンの仮定が正しいことを意味します。







ここで、注入コードを正しく記述し、適切な場所を見つけて、この場所に書き込み、JSR命令をこの注入にリダイレクトする必要があります。







ヘルプサイト

オペコード指示6502アセンブリに関する多くの情報。







これを行うには、メモ帳を使用すると非常に便利です。VisualStudio Codeが用意されています。 誰もが独自の記述スタイルを持っています。個人的には、どこで変更すべきか、そして何を変更すべきかを知るために完全なオペコードを知るために、そのアドレスでJSR命令を書くのは私が初めてです。







数回インデントした後、ループコードを複製します。アドレスなしで既に使用できますが、オペコード以外の引数を持つニーモニックを確認することは非常に便利です。インジェクションから戻る場所を知るために、このループに続く命令をアドレスとともに取得すると便利です。







C2C1:20 07 C3 JSR $C307 A2 28 LDX #$28 A9 00 LDA #$00 95 00 STA $00,X E8 INX E0 F0 CPX #$F0 D0 F9 BNE $C30B C312:A2 07 LDX #$07
      
      





以下のいくつかのインデントは、インジェクション自体のコードを書くことができます。実際には、いくつかの追加を加えたサイクル自体の複製です。







 C312:A2 07 LDX #$07 A2 28 LDX #$28 A9 00 LDA #$00 95 00 STA $00,X E8 INX E0 AA CPX #$AA D0 F9 BNE -7 A9 13 LDA #$13 95 00 STA $00,X E8 INX E0 AC CPX #$AC D0 F9 BNE -7 A9 00 LDA #$00 95 00 STA $00,X E8 INX E0 F0 CPX #$F0 D0 F9 BNE -7
      
      





わかりやすくするために、ジャンプロケーションアドレスの代わりにインデントを指定しました。







このコードを読むことができなかった場合

同じサイクルですが、3つの部分に分かれています。最初のサイクルでは、レジスタXを値AA 16と比較します。レジスタAに13 16を入れた後、すべてのアドレスをアドレス00AA 16にゼロにする必要があるためです。それをアドレス00AC 16に開始し、そこから残りの範囲を再びゼロにする必要があります。 レジスタAにゼロを返し、範囲の残りをゼロにします。







最後に注入戻り指示を完了する必要があります。







 E0 F0 CPX #$F0 D0 F9 BNE -7 4C 12 C3 JMP $C312
      
      





さて、便宜上、以下のオペコードをファイルに書き込むことを好みます。







 4C 12 C3 JMP $C312 A2 28 A9 00 95 00 E8 E0 AA D0 F9 A9 13 95 00 E8 E0 AC D0 F9 A9 00 95 00 E8 E0 F0 D0 F9 4C 12 C3
      
      





そして、オペコードを数えてみると、32個あることが簡単にわかります。 したがって、20 16個の未使用アドレスをROMで見つける必要があります。 原則として、空いているアドレスは同じ値の大きなスペースであり、ほとんどの場合はゼロまたはFF 16です。見つける必要があるのは非常に大きな部分であり、少なくとも35 10個のアドレスである必要があります。







「Hex Editor」では、B29E 16 -BFFF 16にそのような範囲があります。 そのような無料サイトの先頭を注射に使用するのは危険な場合があるため、最後に注射コードを書くことをお勧めします。 インジェクションを開始するための最も便利なアドレスはBFE0 16ですが、これはコンソールメモリ内のアドレスです。ROMファイル内の場所を確認するには、それを右クリックして[ROMファイルに移動]を選択する必要があります。







ここで、オペコード全体(32個の値)をコピーして貼り付けることができます。 最終タッチ変更手順







 C2C1:20 07 C3 JSR $C307
      
      





私が持っている注入アドレスにジャンプするのはBFE0 16です。







 C2C1:20 E0 BF JSR $BFE0
      
      





もちろん、ROMで命令の真の場所を見つけます。







不注意な専門家の質問に対する答え。

JSR命令のアドレスはスタック上にあるため、ジャンプの場所に関係なく、同じリターンアドレスがそこにあり、インジェクションから、スタックに影響を与えないJMP命令でコードに戻ります。 したがって、RTS命令は注入なしと同じ場所で機能し、注入なしと同じ場所に戻ります。 結果として、この注入はスタックを破壊しません。







PS PS 私は何か他のものに目を向けます。 たとえば、Unityエンジン。








All Articles