
كما تعلم ، في هذه السلسلة من الألعاب في كل حانة ، يمكن للاعب استئجار بطل جديد واحد فقط في الأسبوع. لكن…
وصف الخطأ: إذا لم يكن هناك تجنيد في الحانة الخارجية ، فابتداءً من اليوم الثامن ، يمكنك شراء بطلين في غضون يومين.
يتم استخدام ملف 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. كلاسيكي من هذا النوع: تصحيح الخطأ عن طريق استبدال بايت واحد فقط!