عكس الهندسة رائعة بالدوار

Fantastic Dizzy هي لعبة منهاج ألغاز تم إنشاؤها في 1991 بواسطة Codemasters. إنها جزء من سلسلة Dizzy . على الرغم من حقيقة أن سلسلة Dizzy لا تزال شائعة ، وأنها تخلق ألعاب الهواة ( Dizzy Age ) ، يبدو أنه لم يشارك أحد في التطوير العكسي للألعاب الأصلية.


كتبت بعض الأدوات البسيطة لاستخراج موارد اللعبة الأصلية وعرضها وتعبئتها. أدوات نشرت على جيثب .

تفريغ EXE


يتم حزم الملف الثنائي PCDIZZY.EXE في تنسيق Microsoft EXEPack . على الرغم من وجود العديد من أدوات Linux التي يمكنها فك ضغط هذه الملفات القابلة للتنفيذ ، يبدو أن أيا منها لا يدعم الإصدار المستخدم لـ Fantastic Dizzy. لذلك ، لتفريغ الملف القابل للتنفيذ ، استخدمت إصدار DOS من UNP . بعد فك ضغط الملف القابل للتنفيذ ، يمكن تنزيله على المؤسسة الدولية للتنمية. بشكل ملائم ، مازال الإصدار الذي تم فك حزمه من الملف الثنائي يعمل بشكل جيد ، لذلك يمكن تصحيحه باستخدام مصحح أخطاء DOSBox.

ملفات البيانات


يوجد ملفان للبيانات في اللعبة: DIZZY.NDX و DIZZY.RES. توفر لنا الإضافات ، وكذلك أحجام الملفات ، تلميحًا حول ما قد تحتوي عليه. يبلغ حجم ملف NDX حوالي 8 كيلو بايت ، وملف RES حوالي 800 كيلو بايت. نظرًا لأن اللعبة مكتوبة بلغة C ، فيمكننا البحث في المكالمات المفتوحة في المؤسسة الدولية للتنمية لمعرفة أين تفتح ملفات البيانات. في ألعاب DOS المكتوبة في المجمّع ، تحتاج إلى البحث عن التعليمات int 21 h (لفتح الملف ah = 3d). يحتوي Dizzy binary على وظيفة التفاف حول fopen تتيح لك تحديد الاسم الرئيسي وامتداد الملف. يؤدي بنا إلى كتلة التعليمات البرمجية التالية:


يقوم بتحميل الملفات DIZZY.RES و DIZZY.NDX ، كما يحفظ مؤشرات الملفات في المتغيرات العامة. عند عكس هندسة الثنائيات DOS ، تنشأ مشكلة مزعجة: السجلات فيها 16 بت ، ولكن المؤشرات في بعض الحالات يمكن أن تكون 32 بت. يبلغ حجم مؤشرات FILE * 32 بت ويتم إرجاعها من do_open_file إلى ax: dx. لاحظ أن السلاسل هي أيضًا مؤشرات 32 بت ، ويتم تمرير dizzy_basename إلى وظيفة الاستدعاء على المكدس (وهذا التحليل التلقائي IDA المشوش - كان يعتبر وسيطة وضع لـ fopen).

من خلال البحث عن تكرارات g_dizzy_res / ndx في xrefs ، يمكنك العثور على مكان قراءة الملفات. يعد مصحح أخطاء DOSBox مفيدًا في هذه المرحلة ، نظرًا لوجود احتمال كبير للعديد من عمليات قراءة الملفات العشوائية ، وسيكون استخدام IDA لتحديد إزاحة القراءة عملية رتيبة للغاية. يمكن العثور على إرشادات جيدة حول إنشاء مصحح أخطاء DOSBox واستخدامه هنا .

عند استخدام IDA و مصحح أخطاء DOSBox معًا ، يصبح من الواضح أن ملف NDX يُستخدم ك فهرس لملف RES. يستغرق كل إدخال في ملف NDX 16 بايت ؛ يقوم بتخزين معرف الجزء ، وحجمه وإزاحته في ملف RES. بالنظر إلى كيفية قراءة بيانات RES ، يمكنك أن ترى أن بايت العلم يتم فحصه أولاً في ملف NDX. إذا لم يتم تعيين بت 0x80 ، فسيتم قراءة البيانات مباشرة من ملف RES ، وإلا يتم تنفيذ مسار رمز أكثر تعقيدًا. تم تعيين العلم لمعظم الأجزاء ، لذلك مع درجة عالية من الاحتمال يمكننا أن نفترض أنه يدل على نوع من الضغط المستخدم لهذه الأجزاء.

ضغط


يبدأ مسار الضغط بالقراءة من أساس الجزء RES كلمتين 32 بت تشير إلى الأحجام الأولية والنهائية ، ومن ثم تسمى وظيفة الضغط. في عام 1991 ، كان الترميز بطول المدى البسيط (RLE) وضغط القاموس شائعًا ، مثل خوارزميات Liv-Zempel المختلفة. تبدو بداية دورة التفريغ كما يلي:


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


فقط يحفظ البايت الحالي ، يتلقى الرمز التالي ويستمر في العمل. إذا تم مسح العلم ، يتم تحديد مسار رمز أطول ، والذي ينتهي بتعليمات rep movsb. يشير هذا إلى استخدام نوع من القاموس في الضغط.

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

 : AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD  1: 6543210F 7  2: 543210F 76  3: 43210F 765 

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

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

ترميز طول السلسلة يبدو غريبا بعض الشيء. يقوم فاتح الحزم بقراءة البتات حتى يصل إلى صفر بت. ثم عدد البتات المستخدمة لترميز الطول هو اثنين بالإضافة إلى عدد البتات غير الصفرية. على سبيل المثال ، عند تشفير طول 58 (0x3a) ، يشبه تدفق البيانات التالي:

 11110 111010 

يتطلب الترميز 11 بت. يتم تشفير الأطوال الصغيرة بشكل أفضل لأن الحد الأدنى لطول البتة هو 2. يتطلب نسخ الأطوال يصل إلى 3 فقط 3 بت فقط للتشفير ، وحتى 7 يتطلب 5 بتات ، وهكذا. لا أعرف بالتأكيد ما إذا كان هذا النوع من الترميز هو أسلوب شائع.

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

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

المستويات


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

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

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


مستوى القمة

إنها الطبقة السابعة من tree1.stg:


المستوى السابع

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

كما المستويات في اللعبة ، كما يتم تخزين cutscenes ، صور شخصية وشاشة مراقبة المخزون. يبدو أن هذه التقنية قياسية لألعاب DOS ، ربما لأنها تقلل من مقدار الشفرة المطلوبة.


"مستوى" إدارة المخزون

العفاريت


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

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


شخصية اللاعب العفاريت

ماذا تبقى؟


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

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

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


All Articles