Mode Pengembang Balik Hewan yang Menyeberang

Menggunakan kode pada GameCube nyata

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 .

fungsi game_move_first

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".

mode format string zuru

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?

zerumode_check_keycheck

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?

cek zurumode_flag

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":

Dolphin debugger nopping

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.

Mode surat debug.  D

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:

Cabang di zzz_DebugDrawPrint

Setelah memasukkan NOP alih-alih beberapa konstruksi percabangan lainnya, saya mulai melihat berbagai hal menarik di layar:

Lebih banyak hal debug yang ditambahkan

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. "

tampilan nomor pesan

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:

Pesan 687 di editor tabel string

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 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:

Layar judul dengan mode zuru

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 // set last bit } else { osAppNMIBuffer[0x3c] = x & ~1 // clear last bit } 

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:

  1. Bit 26 diatur ke 0x3C(osAppNMIBuffer)
  2. Bit 25 diatur ke 0x3C(osAppNMIBuffer) dan pengontrol terhubung ke port 2
  3. 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.

Pengaturan bit 26

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:

ID versi gim 0x99

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?

Bit 25 dan 28

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:

zerumode_check_keycheck

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.

tombol periksa ujung

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 hasil
XOR dari 1 akan menjadi 1 Jika nilainya 1, maka hasilnya adalah 0. Lihat tabel kebenaran untuk XOR.)

tombol periksa ujung

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.

Pengaturan r5 ke 0xb

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

Menelusuri jalur kode

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 sama

old_vals = old_vals XOR new_vals
old_vals = old_vals AND new_vals


r0

r00x1000

r50xA. 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:

  • 8040ed50
  • 8040ed00
  • 8040ed38

8040ed38

  • 8040ed34: nilainya r0harus sama 0x4000(tombol B ditekan)
  • 8040ebe0: nilai r5harus sama0x5b
  • 8040eba4: nilai r5harus lebih besar0x7
  • maka semuanya berjalan seperti sebelumnya ...

r5 harus dimulai dengan 0x5b

8040ed00

  • 8040ecfc: nilai r0harus sama 0xC000(A dan B ditekan)
  • 8040ebf8: nilai r5harus> = 9
  • 8040ebf0: nilai r5harus kurang dari 10
  • 8040ebe4: nilai r5harus lebih kecil0x5b
  • 8040eba4: r5harus lebih0x7
  • maka semuanya berjalan seperti sebelumnya ...

r5 harus dimulai jam 9

8040ed50

  • 8040ed4c: nilai r0harus sama 0x8000(tombol A ditekan)
  • 8040ec04: nilai r5harus lebih kecil0x5d
  • 8040ebe4: nilai r5harus lebih besar0x5b
  • 8040eba4: nilai r5harus lebih besar0x7
  • maka semuanya berjalan seperti sebelumnya ...

r5harus 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 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, MULAI

Sebelum 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 0x10dan 0x20). Selain itu, ATAS / BAWAH / KIRI / KANAN adalah tombol D-pad, bukan stik analog.

Kode curang


Kombo lengkap terlihat seperti ini:

  1. Pegang bumper L + R dan tekan Z
  2. D-up
  3. C-BAWAH
  4. C-up
  5. D-down
  6. D-kiri
  7. C-kiri
  8. C-BENAR
  9. D-KANAN
  10. A + B
  11. 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.

Menggunakan kode pada GameCube nyata

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:

JUTConsole karakter sampah

Setelah melakukan semua ini, saya menemukan bahwa masuk ke mode debug dengan menambal ID
versi 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.

Layar pilih peta


Selain itu, saya akan menerbitkan artikel tentang rekayasa terbalik sistem dialog, acara, dan pencarian dengan tujuan menciptakan mod.

Source: https://habr.com/ru/post/id413967/


All Articles