魔法门之英雄无敌IV:酒馆小虫或经典补丁

这个简短的故事描述了Equilibris项目执行的项目之一-Equiightris项目的非官方Mod,适用于《英雄与魔法4》游戏。从逆向工程和修补的角度来看,它不是特别感兴趣-只是结局有些有趣。



图片


如您所知,在每个小酒馆的这一系列游戏中,玩家每周只能租用一个新英雄。但…



错误说明: 如果外部酒馆中没有招募人员,那么从第8天开始,您可以在两天内购买两个英雄。



最新的官方插件“ Winds of War”中的反汇编文件heroes4.exe用于工作。小酒馆的操作程序是由团队较早发现的,位于地址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


我买了英雄的酒馆,然后将“断点”设置为写入[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处收到代码,这将重新打开小酒馆以供租用!这将重置日计数器。在雇用第二位Hero之后,该算法将按照作者的预期进行计算。但是在游戏中的两个星期之后,整个循环将重复进行。



解决该错误的最简单方法是跳过计算日期。让计数器仅在小酒馆关闭(更合乎逻辑)时起作用,其余时间将其设置为零。这可以非常简单地实现-通过将地址00470DF7的转换更改为函数的结尾:



00470DF5                 cmp     dl, al
00470DF7                 jz      short loc_470E09


现在剩下的就是修补现有代码。为此,请看原始





并修改





选项。



如您所见,可以通过在地址470DF8上将0D替换10来获得所需的结果该类型的经典作品:只需替换一个字节即可修补错误!



All Articles