سجل استبدال البايت الواحد
منتجع كارتون كارتون سمر
كان صيف عام 2000. لقد بلغت السادسة ، انتهيت للتو من الصف الأول ، وبدأت العطلات. هذا يعني أنه يمكنني اللعب لفترة طويلة في الشارع ، ومشاهدة الرسوم المتحركة وتشغيل كمبيوتر والدي باستخدام Windows 98 للبحث عن الألعاب في أرض جديدة تمامًا ومجهولة تسمى الإنترنت. أحد المواقع المفضلة لدي كان موقع Cartoon Network. لقد وجدت الكثير من ألعاب الفلاش الرائعة المبنية على رسوم متحركة تلفزيونية. في ذلك الصيف أصدروا سلسلة من الألعاب تسمى منتجع Cartoon Cartoon Summer Resort.
طريقة اللعب في الحلقة الأولى من منتجع Cartoon Cartoon Summer Resortكانت هذه اللعبة عبارة عن مغامرة RPG ثنائية الأبعاد مع منظر علوي من الجانب ، يتألف من أربع حلقات. سيطر اللاعب على شخصية كرتونية في إجازة في المنتجع مع شخصيات كرتونية أخرى. في كل حلقة ، ظهرت مشكلة في المنتجع تحتاج إلى حل. يتعين على اللاعب حلها عن طريق التفاعل مع الشخصيات والعثور على الأشياء أو تبادلها.
يعود إلى 18 سنة
خلال إحدى هجمات الحنين الأخيرة ، تذكرت هذه اللعبة وأدركت أنني سألعبها مرة أخرى. كانت تبلغ من العمر عقدين تقريبًا ، لذلك كان من الصعب العثور على رابط عمل.
بالإضافة إلى ذلك ، لن يقوم أي متصفح حديث بتشغيل مشغل Shockwave القديم والضعيف ... باستثناء Internet Explorer. ربما كنت أول شخص يجد سببًا شرعيًا لاستخدام Internet Explorer في 2018.
بعد اللعب قليلاً ، لاحظت لحظات لا يمكن تجاهلها. على سبيل المثال ، موسيقى الخلفية الرتيبة التي يتم تشغيلها في حلقة لا نهائية ، وضعف الاعتراف بالتصادم.
نفس الخطأ
بعد مرور بعض الوقت ، وجدت خطأ في اللعبة:
عند التنقل عبر مناطق لا يجب أن يحدث فيها شيء ، يظهر مربع حوار في بعض الأحيان.كما يتبين من الرسوم المتحركة ، في اللعبة يمكنك استئجار قارب للتنقل في الماء. عندما تحاول استئجار قارب آخر ، تظهر الرسالة "اليوم لم يعد هناك قوارب مستأجرة!" إذا أبحرت شمالًا وسرت على طول الحافة اليمنى للجزيرة ، فسترى نفس النص الذي يجب أن يظهر في رصيف القارب.
في هذه المرحلة ، سيعتبر أي شخص عاقل يحترم وقته وطاقته أن الخلل مصدر إزعاج طفيف ، مذكّرًا نفسه بأنها لعبة ويب متوسطة للأطفال ، تم إنشاؤها قبل عقدين ، وستستمر في اللعب. لكن ليس أنا.
امتلاكًا بالفعل لكل معرفتي البرمجية والنظر إلى اللعبة ، رأيت هذا الخطأ جذابًا بشكل غريب. بدا لي أنني اكتشفت قبرًا قديمًا ووجدت فيه لغزًا لم يمسه يمكن أن يختفي ، ولم يتم حله من قبل أي شخص. بالنسبة لي ، كان هذا الخطأ فرصة للتعلم واكتشاف شيء جديد. ومن المثير للاهتمام ، أن هذه الفرص هي التي أعطتها لي
عملية اللعبة نفسها في مرحلة الطفولة. هناك شيء شاعري تقريبًا في الكيفية التي يمكن لشيء ما أن يشكل ، دون قصد ، تحديات جديدة إذا نظرت إليها من زاوية مختلفة.
لعبة التفكيكية
لإصلاح الخطأ ، كنت بحاجة إلى فهم الإجراءات الداخلية للعبة. بعد فحص المشكلة ، اكتشفت أن اللعبة تم إنشاؤها على Shockwave في تطبيق
Director . عند العمل مع المدير ، يتم حفظ المشاريع كملف
.dir
(مدير). هذا الملف مشابه لملف PSD لـ Photoshop. مثلما يحتوي ملف PSD على معلومات غير مدمرة حول الطبقات والنص ، يحفظ مشروع
.dir
جميع الموارد ، وشفرة المصدر الأولية ، والمعلومات الأخرى التي تساعد في عملية التطوير. استخدم المدير لغة البرمجة النصية الخاصة
Lingo لتحريك المشاهد.
إذا تم حفظ اللعبة في ملف
.dir
، يمكنني فقط فتحها في المخرج ومعرفة كيفية عمل اللعبة بسهولة. ومع ذلك ، يتم نشر اللعبة كملف
.dcr
. ملف
.dcr
هو نسخة مجمعة من مشروع المدير. بمعنى ، يتم تجميع كل التعليمات البرمجية المصدر في كود البايت الذي يعمل على منصة Shockwave. تشبه هذه العملية كيفية تبسيط ملف PSD وتصبح صورة PNG. صورة PNG (في حالتنا ، ملف DCR) أصغر حجمًا ، لكنها لا تحتوي على معلومات حول الطبقات والتحريرات ، وهي مخصصة للتوزيع فقط.
هذا يعني أنني كنت أحمل كائنًا ثنائيًا بحجم 500 كيلوبايت دون توثيق هيكله. حتى لو اكتشفت كيفية العثور على رمز ثانوي منخفض المستوى ، يبدو أنه لم يقم أحد بإجراء هندسة عكسية لرمز Lingo bytecode وتوثيق مبدأ منصة Shockwave. كل هذه المعلومات مملوكة ، وهي مملوكة لشركة Adobe ، وليس لديها سبب لنشرها. بدت فرص فهم اللعبة قاتمة إلى حد ما.
تخفيف الضغط
الشعور بالهزيمة لأنني على الأرجح لم أستطع القضاء على هذا الخطأ ، قررت معرفة ما إذا كان يمكن استخراج الموارد بطريقة أو بأخرى من اللعبة. اكتشفت أنه من المرجح أن يجد قسمًا من البيانات المضغوطة أو شيء مشابه. بعد البحث ، وجدت برنامجين يسمى
offzip و packzip . يمكن لهذه الأدوات البحث عن بيانات zlib في الثنائيات العشوائية ، وإظهار الإزاحات واستخراجها في ملفات منفصلة.
لقد قمت بفك ضغط ملف DCR ولدهشتي ، لقد وجدت الأرشيفات حقًا! 249 قطعة ، لتكون أكثر دقة.
$ ./offzip.exe -a 1.dcr
- open input file: 1.dcr
- zip data to check: 32 bytes
- zip windowBits: 15
- seek offset: 0x00000000 (0)
+------------+-----+----------------------------+----------------------+
| hex_offset | ... | zip -> unzip size / offset | spaces before | info |
+------------+-----+----------------------------+----------------------+
0x00000026 . 164 -> 214 / 0x000000ca _ 38 8:7:26:0:1:7b6349f6
0x000000d3 .. 3932 -> 9169 / 0x0000102f _ 9 8:7:26:0:1:c1079d84
...
0x00080490 . 265 -> 472 / 0x00080599 _ 0 8:7:26:0:1:04d6b43f
0x00080599 . 209 -> 366 / 0x0008066a _ 0 8:7:26:0:1:7da3ba08
- 249 valid compressed streams found
- 0x0004040d -> 0x001565c8 bytes covering the 50% of the file
استخرجت كل هذه الملفات في مجلد وبدأت في دراسة النتائج. كان هناك 206 ملفات
.dat
و 38 ملفات
.fff
و 4
.atn
وملف
.ini
واحد.
الاكتشافات
لقد بدأت بملف INI ، ولكن لم يكن هناك أي فائدة. كان جدول تحويل خط بسيط من Directory 7.0 بين Windows و Mac. ثم انتقلت إلى ملفات DAT. كان معظمها 1 كيلوبايت ، لذلك بدأت بـ 144 كيلوبايت ضخمة. فتحته في محرر سداسي ودرست. في الغالب كانت بيانات غير مقروءة. ومع ذلك ، وبمرور الوقت ، وجدت بضع كلمات فيها تبدو كمعرفات لغة.
أعطاني تحليل ملفات DAT الكبيرة بعض الأدلة ، واحتفظوا ببعض الرسائل المثيرة للاهتمام. لقد وجدت أن Photoshop 3.0 كان يستخدم على الأرجح للرسومات. تعلمت أيضًا أن اللعبة تحتوي على أداة تحرير خرائط داخلية تسمى
Map-O-Matic v1
. أود أن أرى كيف تم إنشاؤه وكيف تم إنشاؤه.
كما وجدت اسم الشركة التي تطور اللعبة:
Funny Garbage . كان اسم المطور الرئيسي موجودًا أيضًا في الملف ، لكنني لن أسميه. كان من الرائع اكتشاف مؤلف اللعبة ، التي حاولت إصلاحها بعناد بعد ما يقرب من 20 عامًا ، وأخيرًا رأيت وجه الشخص الذي أصبح السبب المحتمل لهذا الألم. كل هذه المعلومات كانت مثيرة للاهتمام بالطبع ، لكنها لم تساعد كثيرًا.
اختراق
ثم بدأت في دراسة ملفات
.fff
في محرر سداسي عشري. لدهشتي الكبيرة ، كانت جميع البيانات في هذه الملفات قابلة للقراءة وتبدو مثل بيانات الخريطة:
قمت باستخراج بعض هذه البيانات يدويًا وتنظيفها في محرر نصوص. ما فعلته يشبه إلى حد كبير مجموعة JSON:
[
#member: "block.104",
#type: #FLOR,
#location: [16, 9],
#width: 64,
#WSHIFT: 0,
#height: 32,
#HSHIFT: 0,
#data: [
#item: [
#name: "",
#type: #WALL,
#visi: [
#visiObj: "",
#visiAct: "",
#inviObj: "",
#inviAct: ""
],
#COND: [[#hasObj: "", #hasAct: "", #giveObj: "sunscreen", #giveAct: "gotscreen"], #none, #none, #none]
],
#move: [#U: 0, #d: 0, #L: 0, #R: 0, #COND: 1, #TIMEA: 0, #TIMEB: 0],
#message: [
[#text: "You bought the sun screen.", #plrObj: "", #plrAct: ""],
[#text: "No more sunscreen today!", #plrObj: "", #plrAct: "gotscreen"]
]
]
]
كان ذلك مهمًا جدًا ، لأنني تمكنت من معرفة الكثير عن كيفية عمل اللعبة.
- تتوقع اللعبة أن تكون بيانات الخريطة والنص والحدث في كائنات Lingo Objects تشبه JSON
- كل إدخال
#member
هو #member
أو كتلة أو حرف #member
. - يمكن
#member
والأحجام #member
.
مع العلم أن مربعات حوار اللعبة تم حفظها في هذه الملفات ، كتبت سطرًا قصيرًا لتصدير مربع حوار واحد فقط إلى ملف:
grep -a -o '#text: "[^"]*' Uncompressed/*.fff | awk '{print $0,"\r"}' > Dialogue.txt
باستخدام هذا الملف ، يمكنني العثور بسرعة على النص الخاطئ ومعرفة الملف الذي كان فيه:
النص الخاطئ إما في
0004eda0.fff
أو في
0004f396.fff
. في حالتنا ، ظهر نص الخطأ في الملف الأول. نحن نعلم ذلك لأنه بعد ذلك مباشرة نتلقى رسالة عند التفاعل مع Og ، وهو شخصية على نفس الخريطة مثل البلاط مع الخطأ.
إصلاح الخلل
الآن يمكنني فتح
0004eda0.fff
والعثور على الخط حول القارب في محرر السداسي. بعد العثور عليه ، تمكنت من العثور على كائن العضو المرتبط به. ثم قم بتغيير خصائصه وحفظ الملف. ثم قمت
packzip
مرة أخرى
packzip
ملف مصدر لعبة DCR باستخدام
packzip
.
$ ./packzip -o 0x0004EDA0 Uncompressed/0004eda0.fff test.dcr
عندما أقوم بتغيير نوع الكتلة من
block.11
إلى
block.13
وتصحيح اللعبة ، يمكنني أن أرى بوضوح مخطط تجانب الخطأ:
من خلال تغيير معرف التجانب ، يمكنك رؤية حدود منطقة المشكلةإصلاح الخلل نفسه بسيط للغاية. كل ما كان علي فعله هو تغيير معرف
#message
الخطأ هذه إلى
#fessage
:
الآن ، إذا قمنا بتصحيح التغييرات والعودة إلى هذه المنطقة ، فلن تظهر الرسائل مرة أخرى!
تم إصلاح الخلل في اللعبة ، وتغيير حرفيا 1 بايتلماذا من الممكن إصلاح الخطأ؟
يمكنني فقط أن أفترض أن محرك اللعبة من المرجح أن يتحقق من البلاط الذي يقف عليه عندما يتحرك اللاعب. إذا تم استيفاء بعض الشروط ، فإنه يعرض الرسالة المقابلة لهذا
#message
من
#message
الصفيف. بعد تغيير
#message
إلى
#fessage
لم يعد يتم العثور
#fessage
رابط إلى
#message
الذي تبحث عنه الشفرة. يعتبر هذا كائنًا فارغًا (أو غير محدد؟) ولا يعرض أي شيء.
فكر في مثال على JS:
function foo(bar) { if (bar["message"] !== undefined) {
لنفترض أنه لا يمكننا تغيير الوظيفة
foo()
، لكننا نحتاج إلى تغيير النتيجة. لدينا حق الوصول إلى البيانات المرسلة إليها. يمكنك إعادة تسمية خاصية
message
للكائن الذي تم تمريره وستعتقد الوظيفة أنه لم يكن موجودًا.
كيف ظهر هذا الخطأ؟
أفترض بسبب الكسل. استخدم المطورون محرر خرائط لإنشاء هذه المنطقة. على الأرجح ، قاموا بنسخ بطاقات سابقة الصنع إلى مناطق جديدة ، ثم قاموا بتغييرها. هذا أسهل من إنشاء كل شيء من البداية. ولكن نظرًا لأن بيانات الحدث والبيانات النصية مختلطة ، فمن المرجح أن يتم تجاهلها في بعض الأماكن ونسي حذفها أو استبدالها. يبدو هذا الأكثر منطقية ، لأن الحوار الخاطئ غالبًا ما تم أخذه من بطاقة مجاورة ، حيث تم استخدامه بشكل صحيح.
لماذا تنفق الكثير من العمل على شيء مهم جدا؟
لا اعرف. ربما بسبب الحنين؟