Musim panas lalu, saya mulai merekayasa balik Animal Crossing untuk GameCube. Saya ingin menjelajahi kemungkinan membuat mod untuk game ini. Selain itu, saya ingin mendokumentasikan proses untuk membuat tutorial untuk orang-orang yang tertarik pada peretasan ROM dan rekayasa balik. Dalam posting ini, saya akan berbicara tentang fitur debugging pengembang yang masih ada dalam permainan, dan juga berbagi bagaimana saya menemukan cheat combo yang dapat digunakan untuk membuka kuncinya.
new_Debug_mode
Mempelajari simbol debug yang tersisa, saya perhatikan nama-nama fungsi dan variabel yang mengandung kata "debug", dan memutuskan bahwa akan menarik untuk melihat apakah ada fungsi debugging yang tersisa dalam permainan. Jika saya berhasil mengaktifkan fungsi debugging atau pengembangan, ini akan membantu saya dalam proses membuat mod.
Fungsi pertama yang saya perhatikan adalah
new_Debug_mode
. Ini disebut dengan fungsi
entry
, yang dimulai segera setelah layar logo Nintendo selesai. Yang dia lakukan adalah menempatkan struktur byte
0x1C94
dan menyimpan pointer ke sana.
Setelah dipanggil
entry
dalam struktur yang dihosting di offset
0xD4
segera sebelum memanggil
mainproc
nilai 0 diatur.
Untuk melihat apa yang terjadi ketika nilainya tidak nol, saya menambal instruksi
li r0, 0
di
80407C8C
, menggantinya dengan
li r0, 1
. Byte mentah dari instruksi
li r0, 0
adalah
38 00 00 00
mana nilai yang diberikan adalah di akhir instruksi, jadi saya hanya bisa mengganti byte dengan
38 00 00 01
dan mendapatkan
li r0, 1
. Sebagai cara yang lebih andal untuk membuat instruksi, Anda dapat menggunakan sesuatu seperti
kstool
:
$ kstool ppc32be "li 0, 1"
li 0, 1 = [ 38 00 00 01 ]
Di emulator Dolphin, tambalan ini dapat diterapkan dengan masuk ke tab "Tambalan" di properti gim dan memasukkannya sebagai berikut:
Setelah menetapkan nilai 1, grafik yang menarik muncul di bagian bawah layar:
Itu tampak seperti indikator kinerja: bilah-bilah kecil di bagian bawah layar dapat naik atau turun. (Kemudian, ketika saya melihat nama-nama fungsi yang menggambar grafik ini, saya menemukan bahwa mereka benar-benar menampilkan metrik penggunaan CPU dan memori.)
Itu hebat, tetapi tidak terlalu membantu. Setelah menetapkan nilai 1, kota saya berhenti memuat, jadi tidak ada lagi yang bisa dilakukan di sini.
Mode zuru
Saya kembali mencari referensi lain untuk fungsi debugging, dan beberapa kali menemukan sesuatu yang disebut "mode zuru". Cabang-cabang blok kode dengan fungsi debug sering memeriksa variabel
zurumode_flag
.
zzz_LotsOfDebug
(nama yang saya buat sendiri) di fungsi
game_move_first
ditunjukkan di atas disebut hanya ketika
zurumode_flag
tidak sama dengan nol.
Mencari fungsi yang terkait dengan nilai ini, saya menemukan ini:
zurumode_init
zurumode_callback
zurumode_update
zurumode_cleanup
Sekilas, tujuan mereka misterius, mereka menyulap bit dalam offset variabel yang disebut
osAppNMIBuffer
.
Berikut adalah cara kerja fungsi-fungsi ini pada pandangan pertama:
zurumode_init
- Setel
zurumode_flag
ke 0 - Memeriksa beberapa bit di
osAppNMIBuffer
- Menyimpan pointer ke fungsi
zurumode_callback
dalam struktur padmgr
- Panggilan
zurumode_update
zurumode_update
- Memeriksa beberapa bit di
osAppNMIBuffer
- Tergantung pada nilai bit ini, pembaruan
zurumode_flag
- Mencetak string format ke konsol OS.
Ini biasanya berguna untuk memberikan konteks pada kode, tetapi ada banyak karakter yang tidak dapat dicetak pada baris tersebut. Satu-satunya teks yang dikenali adalah "zurumode_flag" dan "% d".
Dengan asumsi itu bisa berupa teks Jepang dengan pengkodean karakter multibyte, saya melewati string melalui alat pengenalan pengkodean dan menemukan bahwa string itu dikodekan dengan Shift-JIS. Dalam terjemahan, baris itu berarti "Nilai zurumode_flag telah berubah dari% d menjadi% d." Ini tidak memberi kita banyak informasi baru, tetapi sekarang kita tahu bahwa Shift-JIS digunakan: dalam file biner dan tabel baris ada lebih banyak baris dalam pengkodean ini.
zurumode_callback
- Panggilan
zerumode_check_keycheck
- Memeriksa beberapa bit di
osAppNMIBuffer
- Nilai
zurumode_flag
- Panggilan
zurumode_update
zerumode_check_keycheck
sampai kami bertemu karena ejaan yang berbeda ... apa itu?
Fungsi rumit yang sangat besar yang bekerja lebih banyak pada bit dengan nilai yang tidak disebutkan namanya.
Pada titik ini, saya memutuskan untuk mengambil langkah mundur dan mempelajari fungsi dan variabel debugging lainnya, karena saya tidak yakin tentang pentingnya mode zuru. Selain itu, saya tidak mengerti apa artinya "pemeriksaan kunci" di sini. Mungkinkah ini adalah kunci kriptografi?
Kembali ke debugging
Sekitar waktu ini, saya melihat ada masalah dengan cara saya memuat simbol debugging di IDA. File
foresta.map
pada disk game berisi banyak alamat dan nama fungsi dan variabel. Pada awalnya, saya tidak melihat bahwa alamat untuk setiap bagian mulai lagi dari awal, jadi saya menulis skrip sederhana yang menambahkan entri nama untuk setiap baris file.
Saya menulis skrip IDA baru untuk memperbaiki tabel simbol pemuatan untuk bagian program yang berbeda:
.rodata
,
.rodata
,
.bss
dan
.bss
. Bagian
.text
berisi semua fungsi, jadi saya membuatnya sehingga saat ini ketika saya menetapkan nama, skrip akan secara otomatis mengenali fungsi di setiap alamat.
Di bagian data, dia sekarang membuat segmen untuk setiap objek biner (misalnya,
m_debug.o
, yang seharusnya merupakan kode yang dikompilasi untuk sesuatu yang disebut
m_debug
), dan mengatur ruang dan nama untuk setiap bagian data.
Ini memberi saya lebih banyak informasi, tetapi saya harus secara manual mengatur tipe data untuk setiap bagian data, karena saya mendefinisikan setiap objek data sebagai array byte sederhana. (Melihat ke belakang, saya mengerti bahwa akan lebih baik untuk mengasumsikan bahwa fragmen 4 byte berisi bilangan bulat 32-bit, karena ada banyak, dan banyak berisi alamat fungsi dan data yang penting untuk membangun referensi silang.)
Mempelajari segmen
.bss
baru untuk
m_debug_mode.o
, saya menemukan beberapa variabel dari form
quest_draw_status
dan
event_status
. Ini menarik karena saya ingin informasi yang berguna, bukan hanya grafik kinerja, untuk ditampilkan dalam mode debug. Untungnya, dari catatan data ini ada referensi silang ke sepotong besar kode yang memeriksa
debug_print_flg
.
Menggunakan debugger di Dolphin emulator, saya menetapkan breakpoint di lokasi fungsi tempat
debug_print_flg
diperiksa (pada
8039816C
) untuk memahami cara kerja pemeriksaan ini. Namun program tersebut tidak pernah sekalipun melewati breakpoint ini.
Mari kita
game_debug_draw_last
mengapa ini terjadi: fungsi ini dipanggil oleh
game_debug_draw_last
. Tebak nilai apa yang diperiksa sebelum panggilan kondisional?
zurumode_flag
! Apa yang sedang terjadi?
Saya menetapkan breakpoint pada cek ini (
80404E18
) dan langsung bekerja. Nilai
zurumode_flag
adalah nol, jadi dalam eksekusi normal, program akan melewatkan panggilan ke fungsi ini. Saya memasukkan instruksi cabang NOP sebagai gantinya (menggantinya dengan instruksi yang tidak melakukan apa-apa) untuk memeriksa apa yang terjadi ketika fungsi dipanggil.
Di Dolphin debugger, ini bisa dilakukan dengan menjeda game, mengklik kanan pada instruksi dan memilih "Sisipkan nop":
Tidak ada yang terjadi. Kemudian saya memeriksa apa yang terjadi di dalam fungsi dan menemukan konstruksi percabangan lain yang menghindari segala sesuatu yang menarik terjadi pada
803981a8
. Saya juga memasukkan NOP, dan huruf "D" muncul di sudut kanan atas layar.
Dalam fungsi ini di
8039816C
(saya menyebutnya
zzz_DebugDrawPrint
), masih ada banyak kode yang menarik, tetapi tidak dipanggil. Jika Anda melihat fungsi ini dalam bentuk grafik, Anda dapat melihat bahwa ada serangkaian operator percabangan yang melewati blok kode di seluruh fungsi:
Setelah memasukkan NOP alih-alih beberapa konstruksi percabangan lainnya, saya mulai melihat berbagai hal menarik di layar:
Pertanyaan selanjutnya adalah bagaimana cara mengaktifkan fungsi debugging ini tanpa mengubah kode.
Selain itu, di beberapa konstruksi cabang,
zurumode_flag
muncul lagi di fungsi undian debug ini. Saya menambahkan tambalan lain sehingga dalam
zurumode_update
bendera
zurumode_update
selalu diberi nilai 2, karena ketika tidak dibandingkan dengan 0, itu dibandingkan secara khusus dengan nilai 2.
Setelah memulai kembali permainan, saya melihat di sudut kanan atas layar pesan seperti itu "Pesan. tidak. "
Nomor 687 adalah pengidentifikasi catatan dari pesan yang terakhir ditampilkan. Saya memeriksanya menggunakan program tabel viewer yang saya tulis di awal analisis, tetapi Anda juga dapat memeriksanya menggunakan
editor tabel string dengan GUI lengkap , yang saya tulis untuk meretas ROM. Seperti apa tampilan pos di editor:
Pada titik ini, menjadi jelas bahwa studi tentang mode zuru tidak lagi diambil - itu terkait langsung dengan fungsi debugging game.
Kembali ke mode Zuru lagi
zurumode_init
menginisialisasi beberapa hal:
0xC(padmgr_class)
diberikan nilai alamat zurumode_callback
0x10(padmgr_class)
diberikan nilai alamat padmgr_class
itu sendiri0x4(zuruKeyCheck)
diberikan nilai bit terakhir dalam kata yang dimuat dari 0x3C(osAppNMIBuffer)
.
Saya mencari tahu apa itu
padmgr
, singkatan dari "gamepad manager". Ini berarti bahwa mungkin ada kombinasi tombol (tombol) khusus yang dapat dimasukkan pada gamepad untuk mengaktifkan mode zuru, atau semacam perangkat debugging atau fungsi konsol pengembang yang dapat digunakan untuk mengirim sinyal untuk mengaktifkannya.
zurumode_init
dijalankan hanya ketika game pertama kali dimuat (ketika tombol reset ditekan, itu tidak bekerja).
Setelah menetapkan breakpoint di alamat
8040efa4
, di mana nilai
0x4(zuruKeyCheck)
ditetapkan
0x4(zuruKeyCheck)
, kita dapat melihat bahwa ketika memuat tanpa menekan tombol, nilainya diatur ke 0. Jika Anda menggantinya dengan 1, hal menarik terjadi:
Huruf "D" muncul lagi di sudut kanan atas (kali ini berwarna hijau, bukan kuning), dan beberapa informasi perakitan juga ditampilkan:
[CopyDate: 02/08/01 00:16:48 ]
[Date: 02-07-31 12:52:00]
[Creator:SRD@SRD036J]
Sebuah tambalan yang selalu menetapkan
0x4(zuruKeyCheck)
ke 1 di awal terlihat seperti ini:
8040ef9c 38c00001
Ini sepertinya cara yang benar untuk menginisialisasi mode zuru. Setelah ini, berbagai tindakan mungkin diperlukan untuk mencapai tampilan informasi debugging tertentu. Memulai permainan, berjalan-jalan di atasnya dan berbicara dengan penduduk desa, kita tidak akan melihat pesan apa pun yang disebutkan di atas (kecuali untuk huruf "D" di sudut).
Tersangka yang paling mungkin adalah
zurumode_update
dan
zurumode_callback
.
zurumode_update
zurumode_update
pertama kali disebut dalam
zurumode_init
dan kemudian secara konstan dipanggil oleh
zurumode_callback
.
Lagi memeriksa bit terakhir
0x3C(osAppNMIBuffer)
dan kemudian, berdasarkan nilai ini, pembaruan
zurumode_flag
.
Jika bitnya nol, maka flag diset ke nol.
Jika tidak, pernyataan berikut dijalankan, dengan nilai penuh
0x3c(osAppNMIBuffer)
menjadi
r5
:
extrwi r3, r5, 1, 28
Ini mengekstrak bit ke-28 dari
r5
dan menyimpannya di
r3
.
Kemudian 1 ditambahkan ke hasil, yaitu, hasil akhir selalu 1 atau 2.
Kemudian
zurumode_flag
dibandingkan dengan hasil sebelumnya, tergantung pada berapa banyak bit ke-28 dan terakhir diatur ke
0x3c(osAppNMIBuffer)
: 0, 1 atau 2.
Nilai ini ditulis ke
zurumode_flag
. Jika tidak mengubah apa pun, fungsi keluar dan mengembalikan nilai bendera saat ini. Jika itu mengubah nilainya, maka rantai blok kode yang jauh lebih kompleks dijalankan.
Sebuah pesan ditampilkan dalam bahasa Jepang: “nilai zurumode_flag yang sama berubah dari% d menjadi% d”, yang kita bicarakan di atas.
Kemudian serangkaian fungsi dipanggil dengan argumen yang berbeda, tergantung pada apakah bendera telah menjadi sama dengan nol atau tidak. Kode assembler dari bagian ini monoton, jadi saya akan menunjukkan kodesemu:
if (flag_changed_to_zero) { JC_JUTAssertion_changeDevice(2) JC_JUTDbPrint_setVisible(JC_JUTDbPrint_getManager(), 0) } else if (BIT(nmiBuffer, 25) || BIT(nmiBuffer, 31)) { JC_JUTAssertion_changeDevice(3) JC_JUTDbPrint_setVisible(JC_JUTDbPrint_getManager(), 1) }
Perhatikan bahwa jika flagnya nol, maka argumen 0 diteruskan ke JC_JUTDbPrint_setVisible.
Jika flag tidak sama dengan nol. Dan bit 25 atau bit 31 diatur ke
0x3C(osAppNMIBuffer)
, maka
setVisible
diteruskan argumen 1.
Ini adalah kunci pertama untuk mengaktifkan mode
0x3C(osAppNMIBuffer)
bit terakhir
0x3C(osAppNMIBuffer)
harus disetel ke 1 untuk menampilkan informasi debug dan mengatur
zurumode_flag
bukan nol.
zurumode_callback
zurumode_callback
terletak di
8040ee74
dan mungkin disebut dengan fungsi yang terkait dengan gamepad. Setelah memasukkan breakpoint dalam debugger Dolphin, tumpukan panggilan menunjukkan kepada kita bahwa itu sebenarnya dipanggil dari
padmgr_HandleRetraceMsg
.
Salah satu tindakan pertamanya adalah mengeksekusi
zerucheck_key_check
. Fungsi ini kompleks, tetapi tampaknya secara umum dirancang untuk membaca dan memperbarui nilai
zuruKeyCheck
. Sebelum beralih ke fungsi cek kunci, saya memutuskan untuk memeriksa bagaimana nilai ini digunakan di sisa fungsi panggilan balik.
Kemudian lagi memeriksa beberapa bit dalam
0x3c(osAppNMIBuffer)
. Jika bit 26 diatur, atau jika bit 25 diatur dan
padmgr_isConnectedController(1)
mengembalikan nilai bukan nol, maka bit terakhir dalam
0x3c(osAppNMIBuffer)
ke 1!
Jika tidak ada bit ini yang diatur, atau bit 25 yang ditetapkan, tetapi
padmgr_isConnectedController(1)
mengembalikan 0, maka fungsi memeriksa apakah byte pada alamat
0x4(zuruKeyCheck)
sama dengan nol. Jika sama, maka akan mereset bit terakhir dalam nilai asli dan menulisnya kembali ke
0x3c(osAppNMIBuffer)
. Jika tidak, maka bit terakhir masih tetap 1.
Dalam kode pseudo, tampilannya seperti ini:
x = osAppNMIBuffer[0x3c] if (BIT(x, 26) || (BIT(x, 25) && isConnectedController(1)) || zuruKeyCheck[4] != 0) { osAppNMIBuffer[0x3c] = x | 1
Setelah itu, jika bit 26 tidak disetel, fungsi melanjutkan ke memanggil
zurumode_update
, dan kemudian keluar.
Jika bit diatur, maka jika
0x4(zuruKeyCheck)
tidak sama dengan nol, maka ia memuat string format yang menampilkan berikut ini: "ZURU% d /% d".
Untuk meringkas subtotal
Inilah yang terjadi:
padmgr_HandleRetraceMsg
memanggil
zurumode_callback
. Saya berasumsi bahwa “handle retrace message” ini berarti hanya memindai penekanan tombol pada pengontrol. Dengan setiap pemindaian, ini dapat menyebabkan serangkaian panggilan balik yang berbeda.
Ketika
zurumode_callback
dijalankan
zurumode_callback
ia memeriksa penekanan tombol saat ini (tombol). Sepertinya dia sedang memeriksa tombol atau kombinasi tombol tertentu.
Bit terakhir dalam Buffer NMI diperbarui tergantung pada bit spesifik dalam nilai saat ini, serta pada nilai salah satu byte
0x4(zuruKeyCheck)
).
Kemudian
zurumode_update
dan periksa bit ini. Jika 0, maka flag mode zuru diatur ke 0. Jika itu 1, maka flag mode berubah menjadi 1 atau 2, tergantung pada apakah bit 28 diatur.
Ada tiga cara untuk mengaktifkan mode zuru:- Bit 26 diatur ke
0x3C(osAppNMIBuffer)
- Bit 25 diatur ke
0x3C(osAppNMIBuffer)
dan pengontrol terhubung ke port 2 0x4(zuruKeyCheck)
bukan nol
osAppNMIBuffer
Tertarik dengan apa arti
osAppNMIBuffer
, saya mulai mencari "NMI" dan menemukan tautan dalam konteks Nintendo untuk "non-maskable interrupt". Ternyata nama variabel ini sepenuhnya disebutkan dalam dokumentasi pengembang untuk Nintendo 64:
osAppNMIBuffer adalah buffer 64-byte yang dihapus pada restart dingin. Jika sistem reboot karena NMI, status buffer ini tidak berubah.
Sebenarnya, ini adalah sebagian kecil dari memori yang disimpan selama restart "lunak" (dengan tombol reset). Gim ini dapat menggunakan buffer ini untuk menyimpan data apa pun saat konsol ada di jaringan. Animal Crossing asli dirilis pada Nintendo 64, jadi masuk akal jika sesuatu yang serupa muncul di kode.
Jika kita masuk ke file
boot.dol
biner (semua yang ditunjukkan di atas ada di
foresta.rel
), maka fungsi
main
memiliki banyak tautan ke
osAppNMIBuffer
. Tampilan cepat menunjukkan bahwa ada serangkaian pemeriksaan yang dapat menyebabkan
0x3c(osAppNMIBuffer)
nilai bit yang berbeda
0x3c(osAppNMIBuffer)
menggunakan operasi OR.
Nilai ATAU operan berikut mungkin menarik:
- Bit 31: 0x01
- Bit 30: 0x02
- Bit 29: 0x04
- Bit 28: 0x08
- Bit 27: 0x10
- Bit 26: 0x20
Kita ingat bahwa bit 25, 26 dan 28 sangat menarik: 25 dan 26 menentukan apakah mode zuru aktif, dan bit 28 menentukan level bendera (1 atau 2).
Bit 31 juga menarik, tetapi sepertinya akan berubah tergantung pada nilai yang lain.
Bit 26
Pertama-tama: pada alamat
800062e0
ada instruksi
ori r0, r0, 0x20
dengan nilai buffer
0x3c
. Set bit 26, yang selalu mengaktifkan mode zuru.
Agar bit diset, byte kedelapan yang dikembalikan dari
DVDGetCurrentDiskID
harus
0x99
. Pengidentifikasi ini terletak di awal gambar disk gim, dan dimuat ke dalam memori pada
80000000
. Dalam rilis ritel game reguler, ID terlihat seperti ini:
47 41 46 45 30 31 00 00 GAFE01..
Mengganti byte terakhir dari pengidentifikasi dengan
0x99
untuk
0x99
, kita mendapatkan gambar berikut saat memulai permainan:
Dan berikut ini ditampilkan di konsol OS:
06:43:404 HW\EXI_DeviceIPL.cpp:339 N[OSREPORT]: ZURUMODE2 ENABLE
08:00:288 HW\EXI_DeviceIPL.cpp:339 N[OSREPORT]: osAppNMIBuffer[15]=0x00000078
Semua tambalan lain dapat dihapus, setelah itu huruf D muncul lagi di sudut kanan atas layar, tetapi tidak ada pesan debug yang diaktifkan lagi.
Bit 25
Bit 25 digunakan bersama dengan cek port pengontrol 2. Apa yang menyebabkannya hidup?
Ternyata ia harus menggunakan cek yang sama dengan bit 28: versi harus lebih besar dari atau sama dengan
0x90
. Jika bit 26 diatur (ID adalah
0x99
), maka kedua bit ini juga akan ditetapkan, dan mode zuru akan tetap diaktifkan.
Namun, jika versi berada dalam kisaran dari
0x98
hingga
0x98
, maka mode
0x98
tidak langsung menyala. Ingat cek yang dilakukan di
zurumode_callback
- mode akan diaktifkan hanya jika bit 25 diatur
dan padmgr_isConnectedController(1)
mengembalikan nilai bukan nol.
Setelah pengontrol terhubung ke port 2 (argumennya
isConnectedController
memiliki pengindeksan nol), mode zuru diaktifkan. Huruf D dan informasi tentang perakitan muncul di layar awal, dan kami ... dapat mengontrol tampilan debugging menggunakan tombol-tombol pada pengontrol kedua!
Beberapa tombol melakukan tindakan yang tidak hanya mengubah tampilan, tetapi juga, misalnya, meningkatkan kecepatan permainan.
zerucheck_key_check
Misteri terakhir tetap
0x4(zuruKeyCheck)
. Ternyata nilai ini diperbarui dengan fungsi kompleks besar yang saya perlihatkan di atas:
Menggunakan debugger emulator Dolphin, saya dapat menentukan bahwa nilai yang diperiksa oleh fungsi ini adalah sekumpulan bit yang sesuai dengan penekanan tombol pada pengontrol kedua.
Pelacakan klik tombol disimpan dalam nilai 16-bit pada
0x2(zuruKeyCheck)
. Ketika controller tidak terhubung, nilainya
0x7638
.
2 byte yang berisi flags dari penekanan tombol pengontrol diunduh dan kemudian diperbarui pada awal
zerucheck_key_check
. Nilai baru diteruskan dengan register
r4
fungsi
padmgr_HandleRetraceMsg
ketika ia memanggil fungsi callback.
Menjelang akhir
zerucheck_key_check
ada tempat lain di mana
0x4(zuruKeyCheck)
diperbarui
0x4(zuruKeyCheck)
.
Itu tidak muncul dalam daftar referensi silang karena digunakan sebagai alamat dasar r3
, dan kita dapat mengetahui nilainya r3
hanya dengan melihat nilai apa yang diberikan padanya sebelum memanggil fungsi ini.Di alamat, 8040ed88
nilainya r4
dituliskan ke 0x4(zuruKeyCheck)
. Tepat sebelum itu, tetapi ditulis dari tempat yang sama dan kemudian XOR dari 1. Tugas operasi ini adalah untuk mengubah nilai byte (dan sebenarnya bit terakhir) antara 0 dan 1. (Jika nilainya 0, maka hasilXOR dari 1 akan menjadi 1 Jika nilainya 1, maka hasilnya adalah 0. Lihat tabel kebenaran untuk XOR.)Sebelumnya, ketika saya mempelajari nilai-nilai dalam memori, saya tidak melihat perilaku ini, tetapi saya akan mencoba untuk memecah instruksi ini di debugger untuk memahami apa yang terjadi. Nilai asli dimuat di 8040ed7c
.Tanpa menyentuh tombol pengontrol, saya tidak akan sampai ke breakpoint ini di layar awal. Untuk masuk ke blok kode ini, nilai r5
harus sama 0xb
sebelum instruksi cabang yang berjalan sebelum breakpoint ( 8040ed74
). Dari banyak jalur berbeda yang mengarah ke blok ini, hanya satu yang memberikan r5
nilai 0xb
di depannya di alamat 8040ed68
.Perhatikan bahwa untuk mencapai blok yang menetapkan r5
nilai 0xB
, nilainya r0
harus sama persis sebelum itu 0x1000
. Dengan mengikuti blok rantai hingga awal fungsi, kita bisa melihat semua batasan yang diperlukan untuk mencapai blok ini:- 8040ed74: nilai
r5
harus sama0xB
- 8040ed60: nilai
r0
harus sama0x1000
- 8040ebe8: nilai
r5
harus sama0xA
- 8040ebe4: nilai
r5
harus lebih kecil0x5B
- 8040eba4: nilai
r5
harus lebih besar0x7
- 8040eb94: nilai
r6
harus 1 - 8040eb5c: nilai
r0
tidak boleh 0 - 8040eb74: nilai tombol port 2 harus berubah

Di sini kita telah mencapai titik di mana nilai-nilai tombol yang lama dimuat dan nilai-nilai baru disimpan. Kemudian datang beberapa operasi yang diterapkan pada nilai-nilai baru dan lama: Operasi XOR menandai semua bit yang telah berubah di antara dua nilai. Kemudian, operasi DAN menyembunyikan input baru untuk mengatur semua bit yang saat ini tidak diatur ke status 0. Hasilnya adalah seperangkat bit baru (penekanan tombol) pada nilai baru. Jika tidak kosong, maka kita berada di jalur yang benar. Untuk membuat perbedaan , tombol pelacakan keempat dari 16 bit harus berubah. Setelah memasukkan breakpoint setelah operasi XOR / AND, saya menemukan bahwa tombol START memicu keadaan ini. Pertanyaan selanjutnya adalah bagaimana cara agar awalnya samaold_vals = old_vals XOR new_vals
old_vals = old_vals AND new_vals
r0
r0
0x1000
r5
0xA
. r5
dan r6
dimuat dari 0x0(zuruKeyCheck)
awal fungsi uji kunci dan diperbarui lebih dekat ke akhir, ketika kita tidak masuk ke dalam blok kode yang termasuk 0x4(zuruKeyCheck)
.Ada beberapa tempat sebelum ini di mana r5
nilainya diberikan 0xA
:8040ed38
8040ed34
: nilainya r0
harus sama 0x4000
(tombol B ditekan)8040ebe0
: nilai r5
harus sama0x5b
8040eba4
: nilai r5
harus lebih besar0x7
- maka semuanya berjalan seperti sebelumnya ...
r5
harus dimulai dengan 0x5b
8040ed00
8040ecfc
: nilai r0
harus sama 0xC000
(A dan B ditekan)8040ebf8
: nilai r5
harus> = 98040ebf0
: nilai r5
harus kurang dari 108040ebe4
: nilai r5
harus lebih kecil0x5b
8040eba4
: r5
harus lebih0x7
- maka semuanya berjalan seperti sebelumnya ...
r5
harus dimulai jam 98040ed50
8040ed4c
: nilai r0
harus sama 0x8000
(tombol A ditekan)8040ec04
: nilai r5
harus lebih kecil0x5d
8040ebe4
: nilai r5
harus lebih besar0x5b
8040eba4
: nilai r5
harus lebih besar0x7
- maka semuanya berjalan seperti sebelumnya ...
r5
harus mulai dengan 0x5c
Tampaknya ada semacam keadaan di antara penekanan tombol, setelah itu Anda harus memasukkan urutan kombo tertentu dari tombol, diakhiri dengan menekan MULAI. Sepertinya A dan / atau B harus tepat sebelum MULAI.Jika Anda melacak jalur kode yang menetapkan r5
nilai ke 9, maka sebuah pola muncul: r5
- itu adalah nilai yang meningkat yang dapat meningkat ketika r0
nilai yang cocok ditemukan, atau nol. Kasus paling aneh saat ini bukan nilai dalam rentang dari 0x0
hingga0xB
, terjadi ketika memproses langkah-langkah dengan beberapa tombol, misalnya, ketika A dan B ditekan secara bersamaan. Seseorang yang mencoba memasukkan kombo ini biasanya tidak dapat menekan kedua tombol pada waktu yang sama persis saat melacak gamepad, jadi Anda harus memproses tombol yang ditekan yang pertama.Kami terus menjelajahi jalur kode yang berbeda:r5
mengambil nilai 9 saat KANAN ditekan pada alamat 8040ece8
.r5
mengambil nilai 8 saat tombol kanan C pada alamat ditekan 8040eccc
.r5
mengambil nilai 7 ketika tombol kiri C ditekan pada alamat 8040ecb0
.r5
mengambil nilai 6 ketika KIRI ditekan di alamat 8040ec98
.r5
mengambil nilai 5 (dan r6 mengambil nilai 1) ketika BAWAH ditekan pada alamat 8040ec7c
.r5
mengambil nilai 4 saat tombol atas C di alamat ditekan 8040ec64
.r5
mengambil nilai 3 saat tombol bawah C pada alamat ditekan 8040ec48
.r5
mengambil nilai 2 saat UP ditekan di alamat 8040ec30
.r5
mengambil nilai 1 (dan r6
mengambil nilai 1) ketika Z ditekan di alamat 8040ec1c
.
Urutan saat ini adalah:Z, ATAS, C-BAWAH, C-ATAS, BAWAH, KIRI, C-KIRI, C-KANAN, KANAN, A + B, MULAISebelum memeriksa Z, satu lagi kondisi diperiksa: walaupun tombol baru harus ditekan Z, bendera saat ini harus sama 0x2030
: bumper kiri dan kanan juga harus ditekan (mereka memiliki nilai 0x10
dan 0x20
). Selain itu, ATAS / BAWAH / KIRI / KANAN adalah tombol D-pad, bukan stik analog.Kode curang
Kombo lengkap terlihat seperti ini:- Pegang bumper L + R dan tekan Z
- D-up
- C-BAWAH
- C-up
- D-down
- D-kiri
- C-kiri
- C-BENAR
- D-KANAN
- A + B
- MULAI
Itu berhasil! Hubungkan controller ke port kedua dan masukkan kode, setelah itu informasi debug muncul. Setelah itu, Anda dapat mulai menekan tombol pada pengontrol kedua (atau bahkan ketiga) untuk melakukan berbagai tindakan.Kombo ini akan berfungsi tanpa menambal nomor versi gim. Itu bahkan dapat digunakan dalam salinan eceran game secara reguler tanpa alat curang atau mod konsol. Memasukkan kembali kombo menonaktifkan mode zuru.Pesan "ZURU% d /% d" zurumode_callback
digunakan untuk menampilkan status kombinasi ini jika Anda memasukkannya ketika ID disk sudah sama 0x99
(mungkin untuk men-debug kode cheat itu sendiri). Angka pertama adalah posisi Anda saat ini dalam urutan, sesuai r5
. Yang kedua mengambil nilai 1, ketika tombol tertentu dari urutan dipegang, mereka dapat sesuai dengan ketika r6
nilai diberikan 1.Sebagian besar pesan tidak menjelaskan apa yang mereka lakukan di layar, jadi untuk memahami tujuannya, Anda perlu menemukan fungsi yang memprosesnya. Misalnya, garis panjang bintang biru dan merah di bagian atas layar adalah penampung untuk menampilkan status berbagai pencarian. Ketika pencarian aktif, beberapa angka muncul di sana, melaporkan status pencarian.Layar hitam yang ditampilkan dengan menekan Z adalah konsol untuk menampilkan pesan debug, khususnya untuk aspek tingkat rendah, seperti alokasi memori, kesalahan tumpukan dan pengecualian buruk lainnya. Secara perilaku, fault_callback_scroll
dapat diasumsikan bahwa ini digunakan untuk menampilkan kesalahan ini sebelum sistem restart. Itu tidak meluncurkan kesalahan ini, tetapi dapat menyebabkan mereka untuk mencetak beberapa karakter sampah dengan beberapa NOP. Saya pikir di masa depan akan sangat berguna untuk menampilkan pesan debug Anda sendiri:Setelah melakukan semua ini, saya menemukan bahwa masuk ke mode debug dengan menambal IDversi 0x99
sudah diketahui orang lain: https://tcrf.net/Animal_Crossing#Debug_Mode . (Juga ada catatan bagus pada tautan yang menunjukkan berbagai pesan, dan berbicara tentang hal-hal lain yang dapat dilakukan dengan controller di port 3.) Namun, sejauh yang saya tahu, belum ada yang menerbitkan kombinasi cheat.Itu saja.
Ada fitur pengembang lain yang ingin saya jelajahi, seperti layar debug kartu dan layar pemilihan emulator NES, dan cara mengaktifkannya tanpa menggunakan patch.Selain itu, saya akan menerbitkan artikel tentang rekayasa terbalik sistem dialog, acara, dan pencarian dengan tujuan menciptakan mod.