Sejak artikel terakhir saya, sangat mengejutkan saya, membuat Anda tertarik. Saya memutuskan untuk menambah hasilnya, versi yang diretas dari permainan "Contra (J) [T + Rus_Chronix]", dengan sedikit fungsionalitas, pada saat yang sama menampilkan "injeksi kode" pada NES. Kali ini saya akan membuat para pemain memulai permainan dengan Spreadgun yang dipompa, untuk mendapatkannya dalam permainan Anda harus memilih ikon "S", diikuti oleh "R".

Semua tertarik selamat datang di bawah kucing.
Secara tradisional:
rekaman video proses yang membosankan dan menjemukan Dan kami secara tradisional merencanakan urutan tindakan.
- Temukan Alamat
- Cari tahu nilai Spreadgun yang dipompa
- Cari tahu apa yang dia tulis ke alamat-alamat ini di awal permainan
- Tulis ulang ROM
- Easyway - ubah nilai senjata dasar menjadi spreadgan yang dipompa
- Hardway - gunakan injeksi kode lengkap jika cara mudah gagal
- simpan hasilnya ke file baru
Untuk mencari alamat, kami menggunakan metode yang dijelaskan sebelumnya, tetapi mengingat bahwa nyawa berada di alamat tetangga, kami hanya akan mencari senjata dari pemain pertama dengan harapan bahwa pemain kedua akan berada di dekatnya. Membuka jendela "Ram watch" setelah dimulainya level pertama, kami mencari nilai yang tidak diketahui. Saya percaya senjata dasar diatur ke 0, tapi saya tidak tahu pasti.
Kami berlari di sepanjang level tanpa berlari ke depan, menembak ke segala arah dan menyingkirkan nilai yang berubah. Senjata itu belum berubah.
Mari kita gunakan opsi jendela lain, atau lebih tepatnya, di bidang "Bandingkan dengan / Dengan", menyoroti frekuensi radio "Jumlah Perubahan", masukkan dalam bidang 0. Jenis perbandingan tentu saja "Setara dengan". Senjata itu masih tidak berubah.
Jadi melompat dari opsi "sama dengan nilai sebelumnya", ke opsi "jumlah perubahan adalah 0", Anda dapat mencapai sekitar 10.000 alamat. Ketika skrining lebih lanjut akan mengurangi daftar alamat terlalu sedikit atau tidak sama sekali, seseorang dapat maju cukup jauh untuk merobohkan senjata pertama.
Setelah mengambilnya, kami segera menggunakan metode pencarian "tidak sama dengan nilai sebelumnya", dan selanjutnya mengurangi daftar dengan mencari "jumlah perubahan adalah 1", senjata berubah tepat sekali.
Di tempat kami mengambil senjata pertama kami, penguat senjata juga muncul. Setelah memilih dan mengambilnya, Anda dapat mengurangi jumlah alamat menjadi 1, tetapi jika itu tidak berhasil, bunuh saja karakter Anda dan ubah senjatanya lagi. (Jangan lupa tentang pencarian setelah setiap perubahan).
Dengan penguat senjata, ada beberapa risiko bahwa itu tidak akan mengubah nilai senjata itu sendiri, tetapi bendera di tempat lain dalam memori, tetapi mari kita berharap bahwa penulis permainan menyimpan memori dan instruksi. Dan, saya beruntung bonus "R" mengubah nilai senjata dan alamatnya berada di koordinat AA 16 . (Saya bisa saja salah, tetapi saya berulang kali memonitor senjata pahlawan di berbagai versi permainan Contra, seperti di mana-mana alamat ini adalah AA 16 ).
Saya juga memperhatikan bahwa bonus "R" meningkatkan nilai dalam alamat dengan 16 10 atau 10 16 , yaitu, meningkat 1 digit pertama dari angka heksadesimal.
Setelah restart di jendela "Ram watch", dapat dilihat bahwa nilai dasarnya benar-benar 00 16 , bonus "M" meningkatkan digit kedua sebesar 1, dan bonus "R" yang pertama.
Anda bisa menggunakan spreadgan, pasti akan bertemu di level ini, atau Anda dapat mengubah nilai alamat untuk melihat angka apa, senjata apa yang mereka buat. Secara empiris, saya menemukan bahwa, 01 16 adalah "Machinegun", 02 16 adalah "Fire", 03 16 adalah "Spreadgun", dan 04 16 adalah "Laser". Ketika Anda memasukkan nilai-nilai lain di digit kedua, berbagai gangguan terjadi.
Setelah mengatur ulang permainan dan memasukkan nilai 1x 16 , (di mana "x" adalah salah satu opsi yang dapat diterima) sebelum memilih bonus "Cepat", Anda dapat mengetahui bahwa memilih kembali bonus tidak mengubah apa pun.
Sekarang Anda dapat memulai kembali gim, memulai gim untuk dua dan mencoba mengubah alamat yang berdekatan dengan AA 16 . (Ada dua dari mereka, pencarian tidak akan lama) Setelah menembak pemain kedua, saya dengan cepat menemukan bahwa senjata pemain kedua benar-benar disimpan di dekat alamat 16 AB. Dan sekarang kita tahu alamat yang menarik bagi kita dan nilai yang harus diletakkan di sana, saatnya untuk mencari tahu apa yang dia tulis ke alamat ini.
Melempar breakpoint pada catatan alamat ini, saya menemukan bahwa rekaman terjadi di sana beberapa kali dan salah satunya setelah splash screen. Kode berikut membuat entri ini:
Alamat | Opcode | Mnemonik | Argumen | A | X |
---|
C307 | A2 28 | LDX | # $ 28 | ?? | ?? |
C309 | A9 00 | Lda | # $ 00 | ?? | 28 atau 29 atau ... atau F0 |
C30B | 95 00 | STA | $ 00, X | 00 | 28 atau 29 atau ... atau F0 |
C30d | E8 | Inx | | 00 | 28 atau 29 atau ... atau F0 |
C30e | E0 F0 | CPX | # $ F0 | 00 | 29 atau 30 atau ... atau F0 |
C310 | D0 F9 | Bne | $ C30B | 00 | 29 atau 30 atau ... atau F0 |
Jika Anda dengan cermat membaca game di sini nol rentang rentang alamat dari 0028 16 hingga 00F0 16 , jelas kedua alamat yang menarik bagi kami dalam kisaran. Jadi tidak akan ada cara mudah. Saya harus menggunakan "Kode Injeksi" dan solusi paling sederhana yang saya lihat untuk mencari tahu dari mana kita dapatkan dari sini, mengarahkan ulang eksekusi ke suatu tempat yang bebas dari kode dan data dalam memori, menulis di sana versi saya loop yang menempati seluruh jajaran kecuali alamat 00AA 16 dan 00AB 16 dan mengembalikan kereta eksekusi kembali. Omong-omong, ini adalah versi injeksi paling klasik. Anda juga dapat berasumsi bahwa kita sampai di sini dari instruksi JSR (Jump to SubRoutine), ini mudah untuk diperiksa dengan stack.
Bagaimana cara kerja tumpukan?Dalam 6502 prosesor, tumpukan selalu berada di kisaran alamat 0100 16 - 01FF 16 untuk semua komputer yang didasarkan pada prosesor ini, dan tumbuh dari alamat yang lebih besar ke yang lebih kecil. Ada register terpisah yang menunjuk ke atas tumpukan, awalnya itu sama dengan FF 16 karena byte yang lebih signifikan tidak pernah berubah. Register itu sendiri selalu menunjukkan byte tertinggi tidak dihuni dengan data yang berguna.
Emulator debugger tidak menunjukkan nilai register "Stack Pointer", melainkan menunjukkan alamat yang dirujuk register dan saat ini adalah 01F2 16 , perhitungan sederhana menunjukkan bahwa data terakhir pada stack adalah C3 16 dan C2 16 , yang dapat menyebabkan Saya berpikir tentang alamat C3C2 16 tetapi 6502 adalah prosesor tipe "Little Endian", dan karena itu, ketika menjalankan instruksi dan menyimpan alamat dalam memori atau di stack, byte yang kurang signifikan ditulis terlebih dahulu. Dan jika alamatnya benar-benar ada di atas tumpukan, ini adalah alamat C2C3 16 . Dan ini adalah alamat dari argumen terakhir dari instruksi JSR, jika lagi, ini adalah alamatnya. Sangat mudah untuk memeriksa, lihat saja apa yang ditulis dua byte di atas alamat C2C3 16 .
Alamat | Opcode | Mnemonik | Argumen |
---|
C2C1 | 20 07 C3 | Jsr | $ C307 |
Seperti yang Anda lihat, ini adalah instruksi JSR ke C307 16 , yang berarti asumsi subrutin benar.
Sekarang Anda perlu menulis kode injeksi dengan benar, menemukan tempat yang cocok untuk itu, menulisnya ke tempat ini dan mengarahkan instruksi JSR ke injeksi ini.
Untuk ini, sangat nyaman menggunakan notepad, saya punya Visual Studio Code untuk itu. Setiap orang memiliki gaya penulisan mereka sendiri, secara pribadi, saya adalah orang pertama yang menulis instruksi JSR dengan alamatnya, untuk mengetahui di mana harus berubah dan opcode lengkap, untuk mengetahui apa yang harus diubah.
Setelah beberapa indentasi, saya menduplikasi kode loop, itu sudah dapat digunakan tanpa alamat, tetapi sangat berguna untuk melihat mnemonik dengan argumen selain opcode, dan berguna untuk mengambil instruksi mengikuti loop ini bersama dengan alamat untuk mengetahui di mana harus kembali dari injeksi.
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
Beberapa indentasi di bawah ini Anda dapat menulis kode injeksi itu sendiri, sebenarnya itu adalah duplikat dari siklus itu sendiri dengan beberapa tambahan.
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
Untuk lebih jelasnya, saya menunjukkan indentasi alih-alih alamat lokasi lompat.
Jika Anda tidak dapat membaca kode iniBerikut ini adalah siklus yang sama, tetapi dibagi menjadi tiga bagian, pada siklus pertama kami membandingkan register X dengan nilai AA 16 , karena kita perlu nol semua alamat ke alamat 00AA 16 , setelah kita memasukkan 13 16 di register A, nilai spreadgan yang dipompa dan tulis siklus kedua ke alamat 00AC 16 mulai dari yang sisa rentang harus di-nolkan lagi. Kami kembali untuk mendaftarkan A nol dan nol sisa rentang.
Sangat penting untuk menyelesaikan instruksi pengembalian injeksi di akhir.
E0 F0 CPX #$F0 D0 F9 BNE -7 4C 12 C3 JMP $C312
Sekarang, untuk kenyamanan, saya lebih suka menulis opcodes di bawah dalam file.
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
Dan setelah menghitung opcodes, mudah untuk mengetahui bahwa ada 32 dari mereka. Oleh karena itu, Anda perlu menemukan 20 16 alamat kosong di ROM. Sebagai aturan, alamat yang tidak dihuni adalah ruang besar dengan nilai yang sama, paling sering nol atau FF 16. Itu hanya bagian besar yang perlu ditemukan, harus setidaknya 35 10 alamat sehingga ada beberapa margin.
Dalam "Hex Editor" saya menemukan kisaran seperti itu di B29E 16 -BFFF 16 . Menggunakan awal situs gratis semacam itu untuk injeksi bisa berbahaya, oleh karena itu saya menyarankan Anda untuk menulis kode injeksi di akhir. Alamat yang paling nyaman untuk memulai injeksi adalah BFE0 16 , tetapi ini adalah alamat di memori konsol, untuk mencari tahu di mana ia berada dalam file ROM, klik kanan padanya dan pilih "Go Here In ROM File".
Sekarang Anda dapat menyalin-tempel seluruh opcode di sini (32 nilai). Petunjuk perubahan sentuhan akhir
C2C1:20 07 C3 JSR $C307
untuk melompat ke alamat injeksi yang saya miliki adalah BFE0 16 .
C2C1:20 E0 BF JSR $BFE0
Tentu saja, menemukan tempat pengajaran yang benar pada ROM.
Jawaban atas pertanyaan para profesional yang lalai.Alamat instruksi JSR berada di tumpukan, oleh karena itu, terlepas dari tempat lompatan, alamat pengirim yang sama akan ada di sana, dan dari injeksi kami kembali ke kode dengan instruksi JMP yang tidak mempengaruhi tumpukan dengan cara apa pun. Dengan demikian, instruksi RTS bekerja di tempat yang sama tanpa injeksi, dan kembali ke tempat yang sama tanpa injeksi. Akibatnya, injeksi ini tidak mematahkan tumpukan.
PS Untuk selamanya, Anda masih perlu memastikan bahwa setelah kematian karakter-karakter tersebut terlahir kembali dengan spread yang dipompa, tetapi saya yakin dengan pengetahuan yang Anda dapat tangani sendiri. Saya akan mengalihkan pandangan saya ke hal lain. Mesin persatuan misalnya.