Speedran Legend of Zelda من خلال التلاعب بذاكرة اللعبة



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

باختصار ، يحدث هذا على النحو التالي:

  1. أدخل الرمز على شاشة إدخال الاسم.
  2. ندخل الزنزانة الثانية ، نأخذ الصافرة.
  3. نمر إلى المقبرة ، نسمي عشرة أشباح.
  4. ننتظر الشروط اللازمة ، ونوقف اللعبة مؤقتًا عندما تكون المخلوقات في أماكن معينة.
  5. خذ قسطًا من الراحة ، واضغط على A و B في نفس الوقت ، وهذا كل شيء!

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



كيف تسبب خطأ


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

  • يمكننا العمل مع ثلاثة ملفات فقط ، أي أن البرنامج يمكن أن يحتوي فقط على 3 * 8 أحرف = 24 بايت ؛
  • نحتاج إلى إدخال الأحرف الخمسة الأولى من أحد ملفات ZELDA إذا أردنا البدء بالمهمة الثانية.



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



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



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

هناك جزء صغير في الذاكرة يبدأ من الإزاحة 350 يخزن معرفات أحد عشر نقشًا. يتم إنشاء نقش متحرك عند تحميل الشاشة ، بدءًا من موضع بأقل إزاحة ممكنة للعفريت. هذا يعني أن العفاريت تبحث عن مركز بحد أدنى للإزاحة ، بدءًا من الإزاحة 350 وما بعدها. عندما يتم إنشاء نقش متحرك ، تبحث اللعبة عن قيمة فارغة في جدول الرموز المتحركة لاستبدالها بمعرف الرموز المتحركة ، وبالتالي إنشاؤها. على عكس إنشاء النقوش المتحركة عند تحميل الشاشة ، عند محاولة إنشاء نقش متحرك ، تبحث اللعبة عن موضع بأقصى إزاحة للعفريت. هذا يعني أنها تتحقق أولاً مما إذا كان من الممكن إنشاء نقش متحرك في الموضع 10 (0A). إذا لم يكن كذلك ، فإنها تتحقق من الموضع 9 (09) ، أي تعويض 359 ، وهلم جرا. إذا كانت جميع مواقع العفريت مشغولة ، فإن اللعبة "تستسلم" ولا تنشئ نقشًا متحركًا.



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

على شاشة المقبرة ، يحتوي هذا الجزء من الصفيف على معلومات حول الحالة الحالية لإجراءات الأشباح. لنتحدث الآن عن حالات عمل الأشباح. تتحرك الأشباح التي تم إنشاؤها في المقبرة بشكل عشوائي. هذا لأن أفعالهم يتم التحكم فيها من خلال السلوك الذي تحدده حالة عملهم. يمكن أن يكون لحالات الإجراء هذه أي قيمة من 0 (00) إلى 5 (05) ، اعتمادًا على إجراءات الشبح. وهي مكتوبة في نهاية مصفوفة تحتوي على معلومات حول العفاريت.

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



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

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

تنفيذ الشوائب


إذا فعلنا كل شيء بشكل صحيح ، فستحاول اللعبة تنفيذ البيانات في الموضع 5E من الجدول. يبدأ في القراءة كبيانات رمز تبدأ عند الإزاحة 602. يتم تخزين المعلومات المرتبطة بحالة إجراء الارتباط في الذاكرة عند الإزاحة 602 و 603 ، حتى نتمكن من التحكم فيها. عندما يكون Link واقفاً ، فإن القيم عند الإزاحة 602 و 603 ستكون 00. ولكن عندما نضغط على الزر B لاستخدام الصافرة ، ستكون القيمة عند 602 10 ، وعندما نضغط A لاستخدام السيف ، فإن القيمة عند 603 ستكون 01.



لذلك ، عندما نضغط على هذين الزرين في نفس الوقت ، ستكون البيانات المجاورة 10 01. تفسر اللعبة هذه البيانات على أنها أمر فرع BPL للانتقال إلى الإزاحة 605 وتنفيذ البيانات الموجودة فيها على أنها رمز. ستكون قيم 605 و 606 00 إذا لم تكن صحتنا منخفضة للغاية ، و 40 إذا كانت صحتنا منخفضة. لتمرير اللعبة بسرعة ، يجب أن تكون هذه القيم مساوية لـ 00 ، لذلك تحتاج إلى محاولة الحفاظ على الصحة حتى اكتمال الخطأ. القيمة 00 تتوافق مع تعليمات BRK (استراحة). نظرًا لأنه لا يفعل شيئًا هنا ، نحتاج إلى القيم لتكون 00 واللعبة لمواصلة تنفيذ الشفرة.



نظرًا لأننا استخدمنا السيف ، فستستمر اللعبة في تنفيذ التعليمات في البايت الفردي التالي. التعليمات التالية ، التي ليست BRK ، هي عند الإزاحة 08 ، ولكن نظرًا لأننا استخدمنا السيف ، فإن اللعبة تقفز فوقه وتنفذ الرمز عند 09 و 0 A. القيمة في البايت 09 هي دائمًا 10 ، مما يعني أننا نتعامل مرة أخرى مع تعليمات فرع BPL. تتعلق وحدات البايت عند الإزاحة 623 (62E) بالموسيقى. تحاول زيادة عملية تشغيل الموسيقى ، ولكنها تقفز أحيانًا إلى قيم أقل.

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



ومع ذلك ، بعد هذه البيانات الفوضوية ، هناك مجال للبيانات الآمنة. لذلك ، سنحاول القفز هناك. نحتاج إلى المزيد من البيانات في 60A لتخطي المنطقة غير الآمنة بدقة والوصول إلى البيانات الدائمة والآمنة. إذا ذهبنا إلى هناك ، فكل شيء في محله. ولكن عند الإزاحة 630 ، يوجد عداد لوفيات لينك. إذا مات Link مرتين ، ستكون هذه القيمة 02 ، والتي تشكل تعليمات وتوقف اللعبة. لذلك من المهم ألا تموت مرتين. لذلك ، ننتقل إلى تعويض 638 ، وهو بداية الجدول الذي يخزن أسماء الملفات. إذا وصلنا إلى هنا ، ستنفذ اللعبة الرمز الذي أدخلناه على شاشة الملف. وهنا تبدأ ...

كود


يتم تخزين أسماء الملفات في الذاكرة بالترتيب. هذا يعني أن البايت الأول الذي نقوم بتنفيذه هو ملف يسمى ZELDA. لحسن الحظ ، فإن الشفرة التي تنفذها هذه البايتات آمنة ، حتى نتمكن من الانتقال إلى الباقي. نظرًا لأن اسم ZELDA ليس مهمًا ، فلنلق نظرة على ما يفعله باقي الرمز. أولاً ، نقوم بتنفيذ ثلاثة أوامر PLP (سحب من مكدس ، سحب من مكدس). عندما نستدعي دالة ، فإنها تكتب قيمتين إلى المكدس. تتوافق هذه القيم مع المكان الذي كنت فيه في الكود عندما قمت بتنفيذ الوظيفة. حتى تتمكن اللعبة من معرفة مكان العودة إليها بعد أداء الوظيفة.

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

تتوافق قيم إزاحة الذاكرة 10 مع عدد العالم الذي نحن فيه. إذا كنا في عالم فوق الأرض ، فإن القيمة هي 00. بالنسبة إلى الزنزانة الأولى ، تكون القيمة 01 ، للثانية - 02 ، وهكذا. نظرًا لأن Zelda في الزنزانة التاسعة ، فنحن بحاجة إلى هذه القيمة لتكون 09. ومع ذلك ، فإننا نقوم بعمل خطأ في العالم فوق الأرض والقيمة هي 00. لذا نحتاج إلى إيجاد طريقة لمعادلته بـ 09. القيمة عند الإزاحة 11 تتوافق مع بعض البيانات عن حالة اللعبة. عندما يتم تحميل اللعبة ، تكون القيمة 00 ، عندما لا يتم تحميل اللعبة - 01. نحتاج إلى تحميل الزنزانة التاسعة ، لذا يجب أن تكون هذه القيمة 00.

تتوافق القيمة عند الإزاحة 12 مع جزء من الدولة. عندما يتم تحميل الشاشة ، تكون القيمة عادة 02 ، عندما لا يتم تحميلها - عادة 05. نظرًا لأننا نريد تحميل الزنزانة ، يجب أن تكون هذه القيمة 02.

آخر قيمة نريد تغييرها تتوافق مع المهمة التي نحن فيها. تتوافق القيمة عند الإزاحة 62D مع المهمة الأولى أو الثانية ، ولها القيمة 00 أو 01. لقد بدأنا من المهمة الثانية ، ولكننا نريد الانتهاء في المهمة الأولى ، لأن هذه هي الطريقة التي نخلط بين اللعبة. لذلك ، نحتاج إلى تغيير هذه القيمة إلى 00. وهذا سيضعنا في مزيج غريب من المهام الأولى والثانية. نحن بحاجة إلى هذه الحالة المختلطة لتنفيذ التعليمات البرمجية لغرض معين. سنلقي نظرة عليه عندما نشرح ما يفعله الكود.



حسنًا ، لقد حددنا أهدافًا ، فلننتقل إلى الشفرة. أولاً ، لدينا وظيفة LSR (التحول المنطقي إلى اليمين) للإزاحة 11. تقوم هذه الوظيفة بتقسيم القيمة إلى النصف وكتابة الباقي للحمل. 11 هو مكان في الذاكرة يقوم بتخزين القيمة المقابلة لحالة اللعبة ، وقبل هذه التعليمات تكون قيمته 01. عندما نقسم على اثنين ، نحصل على 00 مع الباقي 01 ، لأن القسمة صحيحة. عند الإزاحة 11 ، تتم كتابة القيمة 00 ، وفي النقل ، 01.

ثم لدينا وظيفة ROX للإزاحة 0D (استدارة لليسار ، لليسار) مع الفهرس X. نظرًا لأننا نستبدل حالة العمل للشبح الثالث الذي أنشأناه ، فإن X تساوي ثلاثة. 0D + X هو 0D + 03 ، وهو رقم سداسي عشري 10. لذلك ، تدور هذه الوظيفة لليسار عند الإزاحة 10. تضاعف هذه الوظيفة القيمة عند الإزاحة 10 × 2 وتضيف إلى الواصلة. تبدأ القيمة عند 0. صفر صفر 2 يساوي 0 و 0 + 1 يساوي 1 ، لذلك تتم كتابة القيمة للإزاحة 10.

الآن يتم تكرار عملية ROX مرة أخرى لتعويض 0D بالمؤشر X. لم تتغير قيمة X ، لا تزال ثلاثة ، لذلك ، هذا انعطاف يسار آخر عند الإزاحة 10. 1 * 2 = 2 ، وبما أننا استخدمنا بالفعل التحويل ، فإن قيمته هي 0. 2 + 0 = 2 ، لذلك تتم كتابة القيمة 2 للإزاحة 2.

بعد ذلك ، لدينا عملية ROX الثالثة للإزاحة 0D. 2 * 2 = 4 ، و 4 + 0 = 4 ، لذا تتم كتابة القيمة 4 عند الإزاحة 10.

التعليمات التالية هي LSR عند الإزاحة 12. نبدأ بالقيمة 5 ، لذا فإن القسمة على اثنين تعطينا الباقي 1. 2 مكتوب عند الإزاحة 12 ، و 1 - في النقل.

ثم انعطف ROX الأخير إلى اليسار عند الإزاحة 10. 4 * 2 = 8. قيمة التحويل هي 1 ، نضيفها إلى المنتج ، نحصل على 9.

التعليمات الأخيرة قبل العودة هي إزاحة منطقية يمين عند الإزاحة 62D. القيمة هنا هي 1 ، لأننا في المهمة الثانية. وبما أننا قسمنا على 2 ، فستكون القيمة تساوي 0. لذا فقد دخلنا في وضع البحث المختلط.

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



آمل أن يساعدك هذا على فهم ما يجري داخل لعبة Legend of Zelda عند تنفيذ التعليمات البرمجية التعسفية وتنفيذ خطأ لعبة سريع.

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


All Articles