Heroes of Might and Magic IV: علة الحانة أو الترقيع الكلاسيكي

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



صورة


كما تعلم ، في هذه السلسلة من الألعاب في كل حانة ، يمكن للاعب استئجار بطل جديد واحد فقط في الأسبوع. لكن…



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



يتم استخدام ملف heroes4.exe المفكك من أحدث ملحق رسمي "Winds of War" للعمل. تم العثور على إجراء تشغيل الحانة من قبل الفريق في وقت سابق ويقع على العنوان 4705E0. من خوارزمية عملها بأكملها ، أنا مهتم بالمكان الذي يتم فيه تحديد ما إذا كان من الممكن استئجار بطل في الحانة في الوقت الحالي ، أو ما إذا كان من الضروري الانتظار. يتجلى ذلك في اللعبة من خلال إخراج الرسالة المقابلة:





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



00470638                 call    HeroesPricesInTavern_Lost
0047063D                 mov   al, [ebp+48h]  // 0 –   ; 1 –     ( 7 ).
00470640                 add     esp, 8
00470643                 test    al, al
00470645                jz      loc_470866 //   ,      470823


أشتري في حانة Hero ، ثم أضبط "نقطة التوقف" للكتابة إلى الخلية الموجهة إلى [ebp + 48h] ، وبعد ذلك أنتظر 7 أيام في اللعبة. عندما يتم "إفراغ" الحانة ، ينبثق مصحح الأخطاء عند 470DFF. دعونا نرى الكود المحيط:



00470DF0 TavernCountDays proc near               
00470DF0                 mov     dl, [ecx+48h] // ECX+48h –   :
DL=0 –   ;
DL=1 –     ( 7 )
00470DF3                 xor     eax, eax 
00470DF5                 cmp     dl, al
00470DF7                 jz      short loc_470E06
00470DF9                 cmp     dword ptr [ecx+4Ch], 7 //  [ECX+4Ch] -         .   7 – . 
00470DFD                 jl      short loc_470E06
00470DFF                mov     [ecx+48h], al  //   (AL=0)
00470E02                 mov     [ecx+4Ch], eax  //   
00470E05                 retn
00470E06
00470E06 loc_470E06:                             
00470E06                                         
00470E06                 inc     dword ptr [ecx+4Ch] //          
00470E09                 retn
00470E09 TavernCountDays endp


يستخدم هذا الإجراء الصغير للتحقق من عدد الأيام التي يتم فيها إغلاق الحانة للتأجير. لاحظ أنه يتم استدعاؤها لكل حانة على الخريطة كل يوم لعبة. ما الذي يسبب الخطأ؟ لسبب ما ، يستمر البرنامج في حساب عدد الأيام التي لم يكن فيها توظيف بطل في الحانة وبعد الأسبوع الذي كانت فيه الحانة مغلقة (انظر العداد في 470E06). نتيجة لذلك ، حصلنا على الصورة التالية. دع التجنيد الأول للبطل يتم فقط في اليوم الثامن من اللعبة. عند مدخل الإجراء ، ستكون قيمة علامة توفر الحانة في [ecx + 48h] "1" (الحانة مغلقة) ، وقيمة عداد الأيام في [ecx + 4Ch] ستكون "8". ومع ذلك ، بعد المقارنة عند 470DF9 ، سيتلقى عنصر التحكم رمزًا عند 470DFF ، والذي يعيد فتح الحانة للتأجير! سيؤدي هذا إلى إعادة تعيين عداد اليوم.وبعد تعيين البطل الثاني ، ستعمل الخوارزمية كما أراد المؤلفون. ولكن بعد أسبوعين من اللعب ، ستعيد الدورة بأكملها نفسها.



أسهل طريقة لإصلاح الخطأ هي تخطي عد الأيام. دع العداد يعمل فقط عندما تكون الحانة مغلقة (وهذا أكثر منطقية) ، وبقية الوقت نضبطه على الصفر. يتم تحقيق ذلك بكل بساطة - عن طريق تغيير الانتقال على العنوان 00470DF7 إلى نهاية الوظيفة:



00470DF5                 cmp     dl, al
00470DF7                 jz      short loc_470E09


الآن كل ما تبقى هو تصحيح الكود الحالي. للقيام بذلك ، انظر إلى الأصل





وتعديلها





خيارات.



كما ترى ، يمكن تحقيق النتيجة المرجوة باستبدال 0D بـ 10 على العنوان 470DF8. كلاسيكي من هذا النوع: تصحيح الخطأ عن طريق استبدال بايت واحد فقط!



All Articles