في الصيف الماضي ، بدأت الهندسة العكسية لعبور الحيوانات في 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
.
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".
بافتراض أنه يمكن أن يكون نصًا يابانيًا مع ترميز الأحرف متعددة البايت ، مررت السلسلة من خلال أداة التعرف على التشفير واكتشفت أن السلسلة تم ترميزها باستخدام Shift-JIS. في الترجمة ، يعني السطر ببساطة "تغيرت قيمة zurumode_flag من٪ d إلى٪ d." هذا لا يعطينا الكثير من المعلومات الجديدة ، لكننا نعلم الآن أنه يتم استخدام Shift-JIS: في الملفات الثنائية وجداول الصفوف هناك المزيد من الأسطر في هذا الترميز.
zurumode_callback
- المكالمات
zerumode_check_keycheck
- يتحقق عدة بت في
osAppNMIBuffer
- يتم
zurumode_flag
قيمة zurumode_flag
- المكالمات
zurumode_update
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
! ماذا يجري بحق الجحيم؟
قمت بتعيين نقطة توقف على هذا الشيك (
80404E18
) وعملت على الفور. كانت قيمة
zurumode_flag
صفرًا ، لذلك في التنفيذ العادي ، كان البرنامج قد فاته الاستدعاء لهذه الوظيفة. قمت بإدراج تعليمات فرع NOP بدلاً من ذلك (استبدلتها بإرشادات لا تفعل شيئًا) للتحقق مما يحدث عندما يتم استدعاء الوظيفة.
في مصحح Dolphin ، يمكن القيام بذلك عن طريق إيقاف اللعبة مؤقتًا ، والنقر بزر الماوس الأيمن على التعليمات واختيار "Insert nop":
لم يحدث شيء. ثم راجعت ما يجري داخل الوظيفة واكتشفت بنية متفرعة أخرى تحايلت على كل شيء مثير للاهتمام يحدث في
803981a8
. قمت أيضًا بإدراج NOP بدلاً من ذلك ، وظهر الحرف "D" في الزاوية العلوية اليمنى من الشاشة.
في هذه الوظيفة عند
8039816C
(
zzz_DebugDrawPrint
) ، لا يزال هناك مجموعة من التعليمات البرمجية المثيرة للاهتمام ، ولكن لم يتم استدعاؤها. إذا نظرت إلى هذه الوظيفة في شكل رسم بياني ، يمكنك أن ترى أن هناك سلسلة من عوامل التفرع التي تتخطى كتل التعليمات البرمجية في جميع أنحاء الوظيفة:
بعد أن أدخلت NOP بدلاً من العديد من الإنشاءات المتفرعة الأخرى ، بدأت أرى أشياء متنوعة مثيرة للاهتمام على الشاشة:
كان السؤال التالي هو كيفية تنشيط وظيفة التصحيح هذه دون تغيير التعليمات البرمجية.
بالإضافة إلى ذلك ، في بعض
zurumode_flag
الفروع ،
zurumode_flag
مرة أخرى في وظيفة سحب التصحيح هذه. أضفت رقعة أخرى بحيث في
zurumode_update
zurumode_flag
دائمًا تعيين علامة
zurumode_update
للقيمة 2 ، لأنه عندما لا تتم مقارنتها مع 0 ، يتم مقارنتها تحديدًا بالقيمة 2.
بعد إعادة تشغيل اللعبة ، رأيت في الزاوية اليمنى العليا من الشاشة مثل هذه الرسالة "msg. لا ".
الرقم 687 هو معرف السجل لآخر رسالة معروضة. لقد راجعتها باستخدام برنامج عارض الجدول الذي كتبته في بداية التحليل ، ولكن يمكنك أيضًا التحقق منه باستخدام
محرر جدول السلسلة بواجهة مستخدم رسومية كاملة ، والتي كتبتها لقرصنة ROM. إليك ما تبدو عليه المشاركة في المحرر:
عند هذه النقطة ، أصبح من الواضح أن دراسة وضع 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 ، يحدث شيء مثير للاهتمام:
يظهر الحرف "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
بعد ذلك ، إذا لم يتم تعيين البت 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:- يتم تعيين بت 26 إلى
0x3C(osAppNMIBuffer)
- يتم تعيين بت 25 إلى
0x3C(osAppNMIBuffer)
ووحدة التحكم متصلة بالمنفذ 2 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.
لتعيين
DVDGetCurrentDiskID
يجب أن يكون البايت الثامن الذي تم إرجاعه من
DVDGetCurrentDiskID
0x99
. يقع هذا المعرف في بداية صورة قرص اللعبة ، ويتم تحميله في الذاكرة عند
80000000
. في إصدار التجزئة المنتظم للعبة ، يبدو المعرف كما يلي:
47 41 46 45 30 31 00 00 GAFE01..
باستبدال البايت الأخير من المعرف
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. ما الذي يجعلها قيد التشغيل؟
اتضح أنه يجب عليه استخدام نفس التحقق مثل البت 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)
. اتضح أن هذه القيمة محدثة بوظيفة معقدة ضخمة أظهرتها أعلاه:
باستخدام مصحح محاكي 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.)
في وقت سابق ، عندما درست القيم في الذاكرة ، لم ألاحظ هذا السلوك ، لكني سأحاول كسر هذه التعليمات في المصحح لفهم ما يحدث. تم تحميل القيمة الأصلية في 8040ed7c
.بدون لمس أزرار وحدة التحكم ، لن أصل إلى نقطة التوقف هذه على الشاشة الأولية. للوصول إلى هذا الجزء من الكود ، r5
يجب أن تصبح القيمة متساوية 0xb
قبل تعليمات الفرع التي تذهب قبل نقطة الفصل ( 8040ed74
). من بين العديد من المسارات المختلفة التي تؤدي إلى هذه الكتلة ، يقوم مسار واحد فقط بتعيين r5
قيمة 0xb
أمامها على العنوان 8040ed68
.لاحظ أنه للوصول إلى الكتلة المخصصة 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
لقد وصلنا هنا إلى النقطة التي يتم عندها تحميل قيم الأزرار القديمة وحفظ القيم الجديدة. ثم تأتي عمليتان تم تطبيقهما على القيم الجديدة والقديمة: تحدد عملية XOR جميع البتات التي تغيرت بين القيمتين. بعد ذلك ، تخفي العملية AND الإدخال الجديد لتعيين كافة البتات التي لم يتم تعيينها حاليًا على الحالة 0. والنتيجة هي مجموعة من البتات الجديدة (ضغطات الزر) في القيمة الجديدة. إذا لم تكن فارغة ، فنحن على الطريق الصحيح. لإحداث فرق ، يجب تغيير الزر الرابع من أزرار التتبع ذات 16 بت. بعد إدراج نقطة توقف بعد عملية XOR / AND ، اكتشفت أن زر START يؤدي إلى تشغيل هذه الحالة. السؤال التالي هو كيفية جعلها متساوية في البدايةold_vals = old_vals XOR new_vals
old_vals = old_vals AND new_vals
r0
r0
0x1000
r5
0xA
.
r5
r6
0x0(zuruKeyCheck)
, ,
0x4(zuruKeyCheck)
.
,
r5
0xA
:
8040ed38
8040ed34
: r0
0x4000
( B)8040ebe0
: r5
0x5b
8040eba4
: r5
0x7
- …
r5
0x5b
8040ed00
8040ecfc
: r0
0xC000
( A B)8040ebf8
: r5
>= 98040ebf0
: r5
108040ebe4
: 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, .
-
:
- امسك مصدات L + R واضغط Z
- دى اب
- سي داون
- C-up
- D- لأسفل
- د-اليسار
- ج-اليسار
- C-RIGHT
- D-RIGHT
- أ + ب
- ابدأ
يعمل! قم بتوصيل وحدة التحكم بالمنفذ الثاني وأدخل الرمز ، وبعد ذلك تظهر معلومات التصحيح. بعد ذلك ، يمكنك البدء في الضغط على الأزرار الموجودة على وحدة التحكم الثانية (أو حتى الثالثة) لأداء إجراءات مختلفة.ستعمل هذه المجموعة بدون تصحيح رقم إصدار اللعبة. يمكن استخدامه حتى في نسخة التجزئة العادية من اللعبة دون أي أدوات الغش أو تعديل وحدة التحكم. تؤدي مجموعات إعادة الدخول إلى تعطيل وضع zuru.«ZURU %d/%d»
zurumode_callback
, , ID
0x99
(, -). — ,
r5
. 1, , ,
r6
1.
, , , . , — . , - , .
الشاشة السوداء التي يتم عرضها عن طريق الضغط على Z هي وحدة تحكم لعرض رسائل التصحيح ، خاصة للجوانب ذات المستوى المنخفض ، مثل تخصيص الذاكرة وأخطاء كومة الذاكرة المؤقتة والاستثناءات السيئة الأخرى. حسب السلوك ، fault_callback_scroll
يمكن افتراض أنه يستخدم لعرض هذه الأخطاء قبل إعادة تشغيل النظام. لا يقوم بتشغيل أي من هذه الأخطاء ، ولكن يمكن أن يسبب لهم طباعة زوجين من أحرف القمامة مع NOPs متعددة. أعتقد أنه في المستقبل سيكون مفيدًا جدًا لعرض رسائل تصحيح الأخطاء الخاصة بك:, , ID
0x99
:
https://tcrf.net/Animal_Crossing#Debug_Mode . ( , , , 3.) , , - .
هذا كل شيء. , , NES, .
, - , .