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_flagke 0
- Memeriksa beberapa bit di osAppNMIBuffer
- Menyimpan pointer ke fungsi zurumode_callbackdalam strukturpadmgr
- 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_classitu sendiri
- 0x4(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 38c00001Ini 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, 28Ini 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]=0x00000078Semua 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 r3hanya dengan melihat nilai apa yang diberikan padanya sebelum memanggil fungsi ini.Di alamat, 8040ed88nilainya r4dituliskan 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 r5harus sama 0xbsebelum instruksi cabang yang berjalan sebelum breakpoint ( 8040ed74). Dari banyak jalur berbeda yang mengarah ke blok ini, hanya satu yang memberikan r5nilai 0xbdi depannya di alamat 8040ed68.Perhatikan bahwa untuk mencapai blok yang menetapkan r5nilai 0xB, nilainya r0harus 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 r5harus sama0xB
- 8040ed60: nilai r0harus sama0x1000
- 8040ebe8: nilai r5harus sama0xA
- 8040ebe4: nilai r5harus lebih kecil0x5B
- 8040eba4: nilai r5harus lebih besar0x7
- 8040eb94: nilai r6harus 1
- 8040eb5c: nilai r0tidak boleh 0
- 8040eb74: nilai tombol port 2 harus berubah

old_vals = old_vals XOR new_vals
old_vals = old_vals AND new_valsr0r00x1000r50xA. r5dan r6dimuat 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 r5nilainya diberikan 0xA:8040ed38
- 8040ed34: nilainya- r0harus sama- 0x4000(tombol B ditekan)
- 8040ebe0: nilai- r5harus sama- 0x5b
- 8040eba4: nilai- r5harus lebih besar- 0x7
- maka semuanya berjalan seperti sebelumnya ...
r5 harus dimulai dengan 0x5b8040ed00
- 8040ecfc: nilai- r0harus sama- 0xC000(A dan B ditekan)
- 8040ebf8: nilai- r5harus> = 9
- 8040ebf0: nilai- r5harus kurang dari 10
- 8040ebe4: nilai- r5harus lebih kecil- 0x5b
- 8040eba4:- r5harus lebih- 0x7
- maka semuanya berjalan seperti sebelumnya ...
r5 harus dimulai jam 98040ed50
- 8040ed4c: nilai- r0harus sama- 0x8000(tombol A ditekan)
- 8040ec04: nilai- r5harus lebih kecil- 0x5d
- 8040ebe4: nilai- r5harus lebih besar- 0x5b
- 8040eba4: nilai- r5harus lebih besar- 0x7
- maka semuanya berjalan seperti sebelumnya ...
r5harus mulai dengan 0x5cTampaknya 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 r5nilai ke 9, maka sebuah pola muncul: r5- itu adalah nilai yang meningkat yang dapat meningkat ketika r0nilai yang cocok ditemukan, atau nol. Kasus paling aneh saat ini bukan nilai dalam rentang dari 0x0hingga0xB, 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:- r5mengambil nilai 9 saat KANAN ditekan pada alamat- 8040ece8.
- r5mengambil nilai 8 saat tombol kanan C pada alamat ditekan- 8040eccc.
- r5mengambil nilai 7 ketika tombol kiri C ditekan pada alamat- 8040ecb0.
- r5mengambil nilai 6 ketika KIRI ditekan di alamat- 8040ec98.
- r5mengambil nilai 5 (dan r6 mengambil nilai 1) ketika BAWAH ditekan pada alamat- 8040ec7c.
- r5mengambil nilai 4 saat tombol atas C di alamat ditekan- 8040ec64.
- r5mengambil nilai 3 saat tombol bawah C pada alamat ditekan- 8040ec48.
- r5mengambil nilai 2 saat UP ditekan di alamat- 8040ec30.
- r5mengambil nilai 1 (dan- r6mengambil 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 sama0x2030: bumper kiri dan kanan juga harus ditekan (mereka memiliki nilai 0x10dan 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_callbackdigunakan 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 r6nilai 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_scrolldapat 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 0x99sudah 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.