وضع مطور معبر الحيوانات عكس الهندسة

باستخدام الكود على GameCube حقيقي

في الصيف الماضي ، بدأت الهندسة العكسية لعبور الحيوانات في GameCube. أردت استكشاف إمكانية إنشاء تعديلات لهذه اللعبة. بالإضافة إلى ذلك ، أردت توثيق العملية لإنشاء دروس تعليمية للأشخاص المهتمين باختراق الأقراص المضغوطة والهندسة العكسية. في هذا المنشور ، سأتحدث عن ميزات تصحيح أخطاء المطورين التي بقيت في اللعبة ، وسأشارك أيضًا كيف اكتشفت مجموعات الغش التي يمكن استخدامها لفتحها.

new_Debug_mode


عند دراسة رموز التصحيح المتبقية ، لاحظت أسماء الوظائف والمتغيرات التي تحتوي على كلمة "debug" ، وقررت أنه سيكون من المثير للاهتمام معرفة ما إذا كانت هناك أي وظيفة تصحيح في اللعبة. إذا تمكنت من تنشيط وظائف التصحيح أو التطوير ، فسيساعدني هذا في عملية إنشاء التعديلات.

الوظيفة الأولى التي لاحظتها كانت new_Debug_mode . يتم استدعاؤها بواسطة وظيفة entry ، والتي تبدأ فور انتهاء شاشة شعار Nintendo. كل ما تفعله هو وضع بنية بايت 0x1C94 وحفظ مؤشر لها.

بعد أن يتم استدعاؤه في entry في البنية المستضافة عند الإزاحة 0xD4 مباشرة قبل استدعاء mainproc يتم تعيين القيمة 0.


لمعرفة ما يحدث عندما لا تكون القيمة صفرًا ، قمت بتصحيح تعليمة li r0, 0 عند 80407C8C ، واستبدالها بـ li r0, 1 . البايتات الخام للتعليمات li r0, 0 هي 38 00 00 00 حيث تكون القيمة المعينة في نهاية التعليمات ، لذا يمكنني استبدال البايتات بـ 38 00 00 01 والحصول على li r0, 1 . كطريقة أكثر موثوقية لبناء التعليمات ، يمكنك استخدام شيء مثل kstool :

$ kstool ppc32be "li 0, 1"
li 0, 1 = [ 38 00 00 01 ]


في محاكي Dolphin ، يمكن تطبيق هذا التصحيح بالانتقال إلى علامة التبويب "التصحيحات" في خصائص اللعبة وإدخالها كما يلي:


بعد تعيين القيمة 1 ، ظهر رسم بياني مثير للاهتمام أسفل الشاشة:



بدا الأمر كمؤشر للأداء: الأشرطة الصغيرة في أسفل الشاشة إما زادت أو انخفضت. (لاحقًا ، عندما نظرت إلى أسماء الوظائف التي ترسم هذا الرسم البياني ، وجدت أنها تعرض بالفعل مقاييس استخدام وحدة المعالجة المركزية والذاكرة.)

كانت رائعة ، لكنها ليست مفيدة بشكل خاص. بعد تعيين القيمة 1 ، توقفت تحميل مدينتي ، لذلك لا يمكن فعل أي شيء آخر هنا.

وضع زورو


بدأت مرة أخرى في البحث عن مراجع أخرى لوظائف تصحيح الأخطاء ، وقد صادفت عدة مرات ما يسمى "وضع zuru". غالبًا ما zurumode_flag فروع كتل التعليمات البرمجية مع وظيفة التصحيح من المتغير zurumode_flag .

دالة game_move_first

zzz_LotsOfDebug (الاسم الذي توصلت إليه بنفسي) في دالة game_move_first الموضحة أعلاه يتم استدعاؤه فقط عندما لا يكون zurumode_flag مساوياً للصفر.

بحثًا عن الوظائف المرتبطة بهذه القيمة ، وجدت ما يلي:

  • zurumode_init
  • zurumode_callback
  • zurumode_update
  • zurumode_cleanup

للوهلة الأولى ، غرضهم غامض ، فهم osAppNMIBuffer في تعويضات متغير يسمى osAppNMIBuffer .

هنا كيف بدا عمل هذه الوظائف للوهلة الأولى:

zurumode_init


  • لتعيين zurumode_flag على 0
  • يتحقق عدة بت في osAppNMIBuffer
  • يحفظ zurumode_callback لوظيفة zurumode_callback في بنية padmgr
  • المكالمات zurumode_update

zurumode_update


  • يتحقق عدة بت في osAppNMIBuffer
  • اعتمادا على قيمة هذه البتات ، تحديثات zurumode_flag
  • لطباعة سلسلة تنسيق إلى وحدة تحكم نظام التشغيل.

هذا مفيد عادة لإعطاء سياق للشفرة ، ولكن كان هناك الكثير من الأحرف غير القابلة للطباعة في السطر. كان النص الوحيد المعترف به هو "zurumode_flag" و "٪ d".

سلسلة تنسيق وضع zuru

بافتراض أنه يمكن أن يكون نصًا يابانيًا مع ترميز الأحرف متعددة البايت ، مررت السلسلة من خلال أداة التعرف على التشفير واكتشفت أن السلسلة تم ترميزها باستخدام Shift-JIS. في الترجمة ، يعني السطر ببساطة "تغيرت قيمة zurumode_flag من٪ d إلى٪ d." هذا لا يعطينا الكثير من المعلومات الجديدة ، لكننا نعلم الآن أنه يتم استخدام Shift-JIS: في الملفات الثنائية وجداول الصفوف هناك المزيد من الأسطر في هذا الترميز.

zurumode_callback


  • المكالمات zerumode_check_keycheck
  • يتحقق عدة بت في osAppNMIBuffer
  • يتم zurumode_flag قيمة zurumode_flag
  • المكالمات zurumode_update

zerumode_check_keycheck حتى التقينا بسبب تهجئة مختلفة ... ما هو؟

zerumode_check_keycheck

وظيفة معقدة ضخمة تقوم بالكثير من العمل على البتات بقيم غير مسماة.

عند هذه النقطة ، قررت التراجع خطوة بخطوة ودراسة وظائف ومتغيرات تصحيح الأخطاء الأخرى ، لأنني لم أكن متأكدًا من أهمية وضع zuru. بالإضافة إلى ذلك ، لم أفهم معنى "التحقق من المفاتيح" هنا. هل من الممكن أن يكون هذا مفتاح تشفير؟

عودة إلى التصحيح


في هذا الوقت ، لاحظت وجود مشكلة في طريقي في تحميل رموز تصحيح الأخطاء في المؤسسة الدولية للتنمية. يحتوي ملف foresta.map على قرص اللعبة على العديد من العناوين وأسماء الوظائف والمتغيرات. في البداية ، لم أر أن عناوين كل قسم تبدأ مرة أخرى من البداية ، لذا كتبت نصًا بسيطًا يضيف إدخال اسم لكل سطر من الملف.

قمت بكتابة نصوص برمجية جديدة للمؤسسة الدولية للتنمية لإصلاح جداول رموز التحميل لأقسام مختلفة من البرنامج: .data و. .bss و .bss و .bss . يحتوي قسم .text على جميع الوظائف ، لذلك قمت بها بحيث يتعرف البرنامج النصي هذه الوظائف تلقائيًا عند كل عنوان عند تعيين الاسم.

في أقسام البيانات ، قام الآن بإنشاء مقطع لكل كائن ثنائي (على سبيل المثال ، m_debug.o ، الذي كان من المفترض أن يتم تجميعه برمز لشيء يسمى m_debug ) ، وتعيين المساحة والأسماء لكل قطعة من البيانات.

أعطاني هذا المزيد من المعلومات ، ولكن كان عليّ تعيين نوع البيانات يدويًا لكل قطعة من البيانات ، لأنني عرّفت كل كائن بيانات على أنه صفيف بايت بسيط. (بالنظر إلى الوراء ، أفهم أنه سيكون من الأفضل أن نفترض أن أجزاء من 4 بايت تحتوي على أعداد صحيحة 32 بت ، لأن هناك العديد والعديد من عناوين الوظائف والبيانات الهامة لبناء المراجع التبادلية.)

من خلال دراسة مقطع .bss الجديد لـ m_debug_mode.o ، وجدت العديد من المتغيرات في النموذج quest_draw_status و event_status . هذا مثير للاهتمام لأنني أردت عرض معلومات مفيدة ، وليس مجرد رسم بياني للأداء ، في وضع التصحيح. لحسن الحظ ، من سجلات البيانات هذه كانت هناك إشارات مرجعية إلى جزء كبير من التحقق من التعليمات البرمجية debug_print_flg .

باستخدام مصحح أخطاء في محاكي Dolphin ، قمت بتعيين نقطة توقف في موقع الوظيفة حيث debug_print_flg فحص 8039816C (عند 8039816C ) لفهم كيفية عمل هذا الفحص. لكن البرنامج لم يمر مرة واحدة إلى نقطة التوقف هذه.

دعنا game_debug_draw_last سبب حدوث ذلك: يتم استدعاء هذه الوظيفة بواسطة game_debug_draw_last . تخمين ما هي القيمة المحددة قبل المكالمة الشرطية؟ zurumode_flag ! ماذا يجري بحق الجحيم؟

الاختيار zurumode_flag

قمت بتعيين نقطة توقف على هذا الشيك ( 80404E18 ) وعملت على الفور. كانت قيمة zurumode_flag صفرًا ، لذلك في التنفيذ العادي ، كان البرنامج قد فاته الاستدعاء لهذه الوظيفة. قمت بإدراج تعليمات فرع NOP بدلاً من ذلك (استبدلتها بإرشادات لا تفعل شيئًا) للتحقق مما يحدث عندما يتم استدعاء الوظيفة.

في مصحح Dolphin ، يمكن القيام بذلك عن طريق إيقاف اللعبة مؤقتًا ، والنقر بزر الماوس الأيمن على التعليمات واختيار "Insert nop":

دولفين مصحح الأخطاء

لم يحدث شيء. ثم راجعت ما يجري داخل الوظيفة واكتشفت بنية متفرعة أخرى تحايلت على كل شيء مثير للاهتمام يحدث في 803981a8 . قمت أيضًا بإدراج NOP بدلاً من ذلك ، وظهر الحرف "D" في الزاوية العلوية اليمنى من الشاشة.

حرف وضع التصحيح D

في هذه الوظيفة عند 8039816C ( zzz_DebugDrawPrint ) ، لا يزال هناك مجموعة من التعليمات البرمجية المثيرة للاهتمام ، ولكن لم يتم استدعاؤها. إذا نظرت إلى هذه الوظيفة في شكل رسم بياني ، يمكنك أن ترى أن هناك سلسلة من عوامل التفرع التي تتخطى كتل التعليمات البرمجية في جميع أنحاء الوظيفة:

الفروع في zzz_DebugDrawPrint

بعد أن أدخلت NOP بدلاً من العديد من الإنشاءات المتفرعة الأخرى ، بدأت أرى أشياء متنوعة مثيرة للاهتمام على الشاشة:

طباعة المزيد من عناصر التصحيح

كان السؤال التالي هو كيفية تنشيط وظيفة التصحيح هذه دون تغيير التعليمات البرمجية.

بالإضافة إلى ذلك ، في بعض zurumode_flag الفروع ، zurumode_flag مرة أخرى في وظيفة سحب التصحيح هذه. أضفت رقعة أخرى بحيث في zurumode_update zurumode_flag دائمًا تعيين علامة zurumode_update للقيمة 2 ، لأنه عندما لا تتم مقارنتها مع 0 ، يتم مقارنتها تحديدًا بالقيمة 2.

بعد إعادة تشغيل اللعبة ، رأيت في الزاوية اليمنى العليا من الشاشة مثل هذه الرسالة "msg. لا ".

عرض رقم الرسالة

الرقم 687 هو معرف السجل لآخر رسالة معروضة. لقد راجعتها باستخدام برنامج عارض الجدول الذي كتبته في بداية التحليل ، ولكن يمكنك أيضًا التحقق منه باستخدام محرر جدول السلسلة بواجهة مستخدم رسومية كاملة ، والتي كتبتها لقرصنة ROM. إليك ما تبدو عليه المشاركة في المحرر:

687 الرسالة في محرر جدول السلسلة

عند هذه النقطة ، أصبح من الواضح أن دراسة وضع zuru لم تعد تؤخذ - فهي مرتبطة مباشرة بوظائف تصحيح الأخطاء في اللعبة.

العودة إلى وضع زورو مرة أخرى


zurumode_init بتهيئة عدة أشياء:

  • 0xC(padmgr_class) تعيين 0xC(padmgr_class) قيمة عنوان zurumode_callback
  • 0x10(padmgr_class) تعيين قيمة عنوان padmgr_class نفسها
  • 0x4(zuruKeyCheck) تعيين 0x4(zuruKeyCheck) قيمة البت الأخير في الكلمة التي تم تحميلها من 0x3C(osAppNMIBuffer) .

اكتشفت ما padmgr ، اختصار لـ "مدير padmgr ". هذا يعني أنه قد يكون هناك مجموعة خاصة من المفاتيح (الأزرار) التي يمكن إدخالها على لوحة الألعاب لتنشيط وضع zuru ، أو نوع من جهاز التصحيح أو وظيفة وحدة تحكم المطور التي يمكن استخدامها لإرسال إشارة لتنشيطها.

يتم تنفيذ zurumode_init فقط في أول تمهيد للعبة (عند الضغط على زر إعادة الضبط ، فإنه لا يعمل).

بعد تعيين نقطة توقف على العنوان 8040efa4 ، حيث يتم تعيين القيمة 0x4(zuruKeyCheck) ، يمكننا أن نرى أنه عند التحميل بدون الضغط على المفاتيح ، يتم تعيين القيمة على 0. إذا قمت باستبدالها بـ 1 ، يحدث شيء مثير للاهتمام:

شاشة العنوان مع وضع zuru

يظهر الحرف "D" مرة أخرى في الزاوية العلوية اليمنى (هذه المرة باللون الأخضر وليس الأصفر) ، كما يتم عرض بعض معلومات التجميع:

[CopyDate: 02/08/01 00:16:48 ]
[Date: 02-07-31 12:52:00]
[Creator:SRD@SRD036J]


التصحيح الذي يضبط دائمًا 0x4(zuruKeyCheck) على 1 في البداية يبدو كالتالي:

8040ef9c 38c00001

يبدو أن هذه هي الطريقة الصحيحة لتهيئة وضع zuru. بعد ذلك ، قد تكون هناك حاجة إلى إجراءات مختلفة لتحقيق عرض بعض معلومات التصحيح. عند بدء اللعبة ، والتنزه فيها والتحدث إلى أحد القرويين ، لن نرى أيًا من الرسائل المذكورة أعلاه (باستثناء الحرف "D" في الزاوية).

من المرجح أن المشتبه بهم هم zurumode_update و zurumode_callback .

zurumode_update


يسمى zurumode_update لأول مرة في zurumode_init ثم يتم استدعاؤه باستمرار بواسطة zurumode_callback .

يتحقق مرة أخرى من البت الأخير 0x3C(osAppNMIBuffer) ثم ، بناءً على هذه القيمة ، يقوم بتحديث zurumode_flag .

إذا كان البت صفرًا ، يتم تعيين العلم على صفر.

إذا لم يكن الأمر كذلك ، يتم تنفيذ العبارة التالية ، مع القيمة الكاملة 0x3c(osAppNMIBuffer) هي r5 :

extrwi r3, r5, 1, 28

يستخرج البت 28 من r5 ويخزنه في r3 .

ثم تتم إضافة 1 إلى النتيجة ، أي أن النتيجة النهائية دائمًا تكون 1 أو 2.

ثم zurumode_flag مقارنة zurumode_flag بالنتيجة السابقة ، اعتمادًا على عدد البتات 28 والأخيرة التي تم تعيينها على 0x3c(osAppNMIBuffer) : 0 أو 1 أو 2.

هذه القيمة مكتوبة على zurumode_flag . إذا لم يغير أي شيء ، تخرج الدالة وتعيد قيمة العلم الحالي. إذا غيرت القيمة ، فسيتم تنفيذ سلسلة أكثر تعقيدًا من كتل التعليمات البرمجية.

يتم عرض رسالة باللغة اليابانية: تغيرت نفس قيمة "zurumode_flag من٪ d إلى٪ d" ، والتي تحدثنا عنها أعلاه.

ثم يتم استدعاء سلسلة من الوظائف مع وسيطات مختلفة ، اعتمادًا على ما إذا كان العلم أصبح يساوي الصفر أم لا. كود المجمع لهذا الجزء رتيب ، لذلك سوف أعرض رمزه الكاذب:

 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) } 

لاحظ أنه إذا كانت العلامة صفر ، فسيتم تمرير الوسيطة 0 إلى JC_JUTDbPrint_setVisible.

إذا لم يكن العلم يساوي صفرًا. وتم تعيين بت 25 أو 31 بت على 0x3C(osAppNMIBuffer) ، setVisible تمرير setVisible الوسيطة 1.

هذا هو المفتاح الأول لتنشيط وضع zuru: يجب تعيين البت الأخير 0x3C(osAppNMIBuffer) على 1 لعرض معلومات التصحيح وتعيين zurumode_flag قيمة غير صفرية.

zurumode_callback


يقع 8040ee74 في 8040ee74 وربما يتم استدعاؤه بواسطة دالة تتعلق 8040ee74 . بعد إدراج نقطة توقف في مصحح أخطاء Dolphin ، يوضح لنا مكدس الاستدعاء أنه يتم استدعاؤه بالفعل من padmgr_HandleRetraceMsg .

كان من أول إجراءاتها تنفيذ zerucheck_key_check . هذه الوظيفة معقدة ، ولكن يبدو أنها مصممة بشكل عام لقراءة وتحديث قيمة zuruKeyCheck . قبل الانتقال إلى وظيفة التحقق من المفاتيح ، قررت التحقق من كيفية استخدام هذه القيمة في بقية وظيفة رد الاتصال.

ثم يتحقق مرة أخرى لبعض البتات في 0x3c(osAppNMIBuffer) . إذا تم تعيين بت 26 ، أو إذا تم تعيين بت 25 وإعادة padmgr_isConnectedController(1) قيمة غير صفرية ، ثم يتم تعيين البت الأخير في 0x3c(osAppNMIBuffer) إلى 1!

إذا لم يتم تعيين أي من هذه البتات ، أو تم تعيين البت 25 ، ولكن padmgr_isConnectedController(1) ترجع 0 ، فإن الوظيفة تتحقق مما إذا كان البايت في العنوان 0x4(zuruKeyCheck) يساوي صفر. إذا كان يساوي ، فإنه يعيد تعيين آخر بت في القيمة الأصلية 0x3c(osAppNMIBuffer) مرة أخرى إلى 0x3c(osAppNMIBuffer) . إذا لم يكن كذلك ، فلا يزال يضبط البت الأخير على 1.

في الكود الزائف ، يبدو كما يلي:

 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 } 

بعد ذلك ، إذا لم يتم تعيين البت 26 ، تستمر الوظيفة في استدعاء zurumode_update ، ثم تخرج.

إذا تم تعيين البت ، ثم إذا كان 0x4(zuruKeyCheck) لا يساوي الصفر ، فإنه يقوم بتحميل سلسلة تنسيق يعرض فيها ما يلي: "ZURU٪ d /٪ d".

لتلخيص المجموع الفرعي


إليك ما يحدث:

padmgr_HandleRetraceMsg مكالمات zurumode_callback . أفترض أن هذه "رسالة معالجة التصحيح" تعني أنها ببساطة تقوم بمسح ضغطات مفاتيح وحدة التحكم. مع كل مسح ، يمكن أن يسبب سلسلة من عمليات الاستدعاء المختلفة.

عندما zurumode_callback تنفيذ zurumode_callback فإنه يفحص ضغطات المفاتيح (الأزرار) الحالية. يبدو أنها تتحقق من زر معين أو مجموعة من الأزرار.

يتم تحديث البت الأخير في NMI Buffer اعتمادًا على وحدات البت المحددة في قيمته الحالية ، بالإضافة إلى قيمة أحد وحدات بايت zuruKeyCheck ( 0x4(zuruKeyCheck) ).

ثم يتم zurumode_update ويتحقق من هذا البت. إذا كان الرقم 0 ، يتم تعيين علامة وضع zuru على 0. إذا كانت 1 ، تتغير علامة الوضع إلى 1 أو 2 ، اعتمادًا على ما إذا تم تعيين البت 28.

هناك ثلاث طرق لتنشيط وضع zuru:

  1. يتم تعيين بت 26 إلى 0x3C(osAppNMIBuffer)
  2. يتم تعيين بت 25 إلى 0x3C(osAppNMIBuffer) ووحدة التحكم متصلة بالمنفذ 2
  3. 0x4(zuruKeyCheck) ليس صفرًا

osAppNMIBuffer


مهتمة بما يعنيه osAppNMIBuffer ، بدأت في البحث عن "NMI" ووجدت روابط في سياق Nintendo إلى "مقاطعة غير قابلة للإخفاء". اتضح أن اسم هذا المتغير مذكور تمامًا في وثائق المطور لـ Nintendo 64:

osAppNMIBuffer هو مخزن مؤقت 64 بايت يتم مسحه عند إعادة التشغيل البارد. إذا تم إعادة تمهيد النظام بسبب NMI ، لا تتغير حالة هذا المخزن المؤقت.

في الواقع ، هذه جزء صغير من الذاكرة يتم حفظه أثناء إعادة التشغيل "الناعم" (باستخدام زر إعادة الضبط). يمكن للعبة استخدام هذا المخزن المؤقت لتخزين أي بيانات أثناء وجود وحدة التحكم على الشبكة. تم إصدار لعبة Cross Crossing الأصلية على Nintendo 64 ، لذا فمن المنطقي أن يظهر شيء مشابه في الشفرة.

إذا انتقلنا إلى ملف boot.dol الثنائي (كل شيء موضح أعلاه كان في foresta.rel ) ، فإن وظيفته main بها الكثير من الروابط إلى osAppNMIBuffer . يظهر نظرة سريعة أن هناك سلسلة من عمليات التحقق التي يمكن أن تؤدي إلى 0x3c(osAppNMIBuffer) قيم بتات مختلفة 0x3c(osAppNMIBuffer) باستخدام عمليات OR.

قد تكون قيم المعاملات OR التالية مثيرة للاهتمام:

  • بت 31: 0x01
  • بت 30: 0x02
  • بت 29: 0x04
  • بت 28: 0x08
  • بت 27: 0x10
  • بت 26: 0x20

نتذكر أن البتات 25 و 26 و 28 مثيرة للاهتمام بشكل خاص: 25 و 26 تحدد ما إذا كان وضع zuru قيد التشغيل ، ويحدد البت 28 مستوى العلم (1 أو 2).
بت 31 مثير للاهتمام أيضًا ، ولكن يبدو أنه يتغير اعتمادًا على قيم الآخرين.

بت 26

بادئ 800062e0 : في العنوان 800062e0 هناك تعليمات ori r0, r0, 0x20 بقيمة عازلة 0x3c . يقوم بتعيين 26 بت ، والذي يقوم دائمًا بتشغيل وضع zuru.

ضبط 26 بت

لتعيين DVDGetCurrentDiskID يجب أن يكون البايت الثامن الذي تم إرجاعه من DVDGetCurrentDiskID 0x99 . يقع هذا المعرف في بداية صورة قرص اللعبة ، ويتم تحميله في الذاكرة عند 80000000 . في إصدار التجزئة المنتظم للعبة ، يبدو المعرف كما يلي:

47 41 46 45 30 31 00 00 GAFE01..

باستبدال البايت الأخير من المعرف 0x99 ، نحصل على الصورة التالية عند بدء اللعبة:

معرف إصدار اللعبة 0x99

ويتم عرض ما يلي في وحدة تحكم نظام التشغيل:

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


يمكن إزالة جميع التصحيحات الأخرى ، وبعد ذلك يظهر الحرف D مرة أخرى في الزاوية العلوية اليمنى من الشاشة ، ولكن لم يعد يتم تنشيط رسائل التصحيح.

بت 25

يتم استخدام بت 25 مع فحص منفذ وحدة التحكم 2. ما الذي يجعلها قيد التشغيل؟

بت 25 و 28

اتضح أنه يجب عليه استخدام نفس التحقق مثل البت 28: يجب أن يكون الإصدار أكبر من أو يساوي 0x90 . إذا تم تعيين البت 26 (المعرف 0x99 ) ، فسيتم أيضًا تعيين كل من هذه البتات ، وسيستمر تنشيط وضع zuru.

ومع ذلك ، إذا كان الإصدار في النطاق من 0x98 إلى 0x98 ، فلن يتم تشغيل وضع zuru على الفور. قم zurumode_callback الاختيار الذي تم إجراؤه في zurumode_callback - لن يتم تمكين الوضع إلا إذا تم تعيين البت 25 padmgr_isConnectedController(1) قيمة غير صفرية.

بعد توصيل جهاز التحكم بالمنفذ 2 (الوسيطة isConnectedController تحتوي على فهرسة) ، يتم تنشيط وضع zuru. يظهر الحرف D ومعلومات حول التجميع على الشاشة الأولية ، ويمكننا ... التحكم في عرض التصحيح باستخدام أزرار وحدة التحكم الثانية!

تقوم بعض الأزرار بتنفيذ إجراءات لا تؤدي فقط إلى تغيير العرض ، ولكن أيضًا ، على سبيل المثال ، تزيد من سرعة اللعبة.

zerucheck_key_check


يبقى اللغز الأخير 0x4(zuruKeyCheck) . اتضح أن هذه القيمة محدثة بوظيفة معقدة ضخمة أظهرتها أعلاه:

zerumode_check_keycheck

باستخدام مصحح محاكي Dolphin ، تمكنت من تحديد أن القيمة المحددة بواسطة هذه الوظيفة هي مجموعة من البتات المقابلة للضغط على الزر في وحدة التحكم الثانية.

يتم تخزين تتبع نقرات الأزرار بقيمة 16 بت عند 0x2(zuruKeyCheck) . عندما تكون وحدة التحكم غير متصلة ، تكون القيمة 0x7638 .

يتم تنزيل 2 بايت تحتوي على أعلام الضغط على زر وحدة التحكم ثم يتم تحديثها في بداية zerucheck_key_check . يتم تمرير القيمة الجديدة مع تسجيل r4 للدالة padmgr_HandleRetraceMsg عندما تستدعي وظيفة رد الاتصال.

نهاية الاختيار الرئيسية

بالقرب من نهاية zerucheck_key_check يوجد مكان آخر حيث 0x4(zuruKeyCheck) تحديث 0x4(zuruKeyCheck) . , r3 , r3 , .

8040ed88 r4 0x4(zuruKeyCheck) . XOR- 1. — ( — ) 0 1. ( 0,
XOR 1 1. 1, 0. . XOR.)

key check end

في وقت سابق ، عندما درست القيم في الذاكرة ، لم ألاحظ هذا السلوك ، لكني سأحاول كسر هذه التعليمات في المصحح لفهم ما يحدث. تم تحميل القيمة الأصلية في 8040ed7c.

بدون لمس أزرار وحدة التحكم ، لن أصل إلى نقطة التوقف هذه على الشاشة الأولية. للوصول إلى هذا الجزء من الكود ، r5يجب أن تصبح القيمة متساوية 0xbقبل تعليمات الفرع التي تذهب قبل نقطة الفصل ( 8040ed74). من بين العديد من المسارات المختلفة التي تؤدي إلى هذه الكتلة ، يقوم مسار واحد فقط بتعيين r5قيمة 0xbأمامها على العنوان 8040ed68.

Setting r5 to 0xb

لاحظ أنه للوصول إلى الكتلة المخصصة r5للقيمة 0xB، r0يجب أن تكون القيمة متساوية قبلها 0x1000. بعد الكتل حتى السلسلة إلى بداية الوظيفة ، يمكننا رؤية جميع القيود اللازمة لتحقيق هذه الكتلة:

  • 8040ed74: r5يجب أن تكون القيمة متساوية0xB
  • 8040ed60: r0يجب أن تكون القيمة متساوية0x1000
  • 8040ebe8: r5يجب أن تكون القيمة متساوية0xA
  • 8040ebe4: r5يجب أن تكون القيمة أقل0x5B
  • 8040eba4: r5يجب أن تكون القيمة أكبر0x7
  • 8040eb94: r6يجب أن تكون القيمة 1
  • 8040eb5c: r0يجب ألا تكون القيمة 0
  • 8040eb74: يجب تغيير قيم زر المنفذ 2

Tracing the code path

لقد وصلنا هنا إلى النقطة التي يتم عندها تحميل قيم الأزرار القديمة وحفظ القيم الجديدة. ثم تأتي عمليتان تم تطبيقهما على القيم الجديدة والقديمة: تحدد عملية XOR جميع البتات التي تغيرت بين القيمتين. بعد ذلك ، تخفي العملية AND الإدخال الجديد لتعيين كافة البتات التي لم يتم تعيينها حاليًا على الحالة 0. والنتيجة هي مجموعة من البتات الجديدة (ضغطات الزر) في القيمة الجديدة. إذا لم تكن فارغة ، فنحن على الطريق الصحيح. لإحداث فرق ، يجب تغيير الزر الرابع من أزرار التتبع ذات 16 بت. بعد إدراج نقطة توقف بعد عملية XOR / AND ، اكتشفت أن زر START يؤدي إلى تشغيل هذه الحالة. السؤال التالي هو كيفية جعلها متساوية في البداية

old_vals = old_vals XOR new_vals
old_vals = old_vals AND new_vals


r0

r00x1000

r50xA . r5 r6 0x0(zuruKeyCheck) , , 0x4(zuruKeyCheck) .

, r5 0xA :

  • 8040ed50
  • 8040ed00
  • 8040ed38

8040ed38

  • 8040ed34 : r0 0x4000 ( B)
  • 8040ebe0 : r5 0x5b
  • 8040eba4 : r5 0x7

r5 0x5b

8040ed00

  • 8040ecfc : r0 0xC000 ( A B)
  • 8040ebf8 : r5 >= 9
  • 8040ebf0 : r5 10
  • 8040ebe4 : r5 0x5b
  • 8040eba4 : r5 0x7

r5 9

8040ed50

  • 8040ed4c: r0يجب أن تكون القيمة متساوية 0x8000(الضغط على الزر A)
  • 8040ec04: r5يجب أن تكون القيمة أقل0x5d
  • 8040ebe4: r5يجب أن تكون القيمة أكبر0x5b
  • 8040eba4: r5يجب أن تكون القيمة أكبر0x7
  • ثم كل شيء يسير كما كان من قبل ...

r5يجب أن تبدأ بـ 0x5c

يبدو أن هناك نوعًا من الحالة بين ضغطات المفاتيح ، وبعد ذلك تحتاج إلى إدخال سلسلة معينة من المجموعات من الأزرار ، وتنتهي بالضغط على START. يبدو أنه يجب استخدام A و / أو B قبل START مباشرةً.

إذا قمنا بتتبع مسار الكود الذي يحدد r5القيمة إلى 9 ، فسيظهر نمط: r5- إنها قيمة متزايدة يمكن أن تزيد إما عند r0العثور على قيمة مناسبة ، أو صفر. أغرب الحالات عندما لا تكون هذه قيمة في النطاق من 0x0إلى0xB , , , A B. , , , , .

:

  • r5 9, RIGHT 8040ece8 .
  • r5 8, C 8040eccc .
  • r5 7, C 8040ecb0 .
  • r5 6, LEFT 8040ec98 .
  • r5 5 ( r6 1), DOWN 8040ec7c .
  • r5 4, C 8040ec64 .
  • r5 3, C 8040ec48 .
  • r5 2, UP 8040ec30 .
  • r5 1 ( r6 1), Z 8040ec1c .

:

Z, UP, C-DOWN, C-UP, DOWN, LEFT, C-LEFT, C-RIGHT, RIGHT, A+B, START

Z : Z, 0x2030 : ( 0x10 0x20 ). , UP/DOWN/LEFT/RIGHT — D-pad, .

-


:

  1. امسك مصدات L + R واضغط Z
  2. دى اب
  3. سي داون
  4. C-up
  5. D- لأسفل
  6. د-اليسار
  7. ج-اليسار
  8. C-RIGHT
  9. D-RIGHT
  10. أ + ب
  11. ابدأ

يعمل! قم بتوصيل وحدة التحكم بالمنفذ الثاني وأدخل الرمز ، وبعد ذلك تظهر معلومات التصحيح. بعد ذلك ، يمكنك البدء في الضغط على الأزرار الموجودة على وحدة التحكم الثانية (أو حتى الثالثة) لأداء إجراءات مختلفة.

ستعمل هذه المجموعة بدون تصحيح رقم إصدار اللعبة. يمكن استخدامه حتى في نسخة التجزئة العادية من اللعبة دون أي أدوات الغش أو تعديل وحدة التحكم. تؤدي مجموعات إعادة الدخول إلى تعطيل وضع zuru.

Using the code on a real GameCube

«ZURU %d/%d» zurumode_callback , , ID 0x99 (, -). — , r5 . 1, , , r6 1.

, , , . , — . , - , .

الشاشة السوداء التي يتم عرضها عن طريق الضغط على Z هي وحدة تحكم لعرض رسائل التصحيح ، خاصة للجوانب ذات المستوى المنخفض ، مثل تخصيص الذاكرة وأخطاء كومة الذاكرة المؤقتة والاستثناءات السيئة الأخرى. حسب السلوك ، fault_callback_scrollيمكن افتراض أنه يستخدم لعرض هذه الأخطاء قبل إعادة تشغيل النظام. لا يقوم بتشغيل أي من هذه الأخطاء ، ولكن يمكن أن يسبب لهم طباعة زوجين من أحرف القمامة مع NOPs متعددة. أعتقد أنه في المستقبل سيكون مفيدًا جدًا لعرض رسائل تصحيح الأخطاء الخاصة بك:

JUTConsole garbage characters

, , ID
0x99 : https://tcrf.net/Animal_Crossing#Debug_Mode . ( , , , 3.) , , - .

هذا كل شيء. , , NES, .

Map select screen


, - , .

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


All Articles