Heroes of Might and Magic IV: error de taberna o parche clásico

Esta breve historia describe uno de los proyectos llevados a cabo por el proyecto Equilibris , un mod no oficial para el juego Heroes of Might and Magic IV. Desde el punto de vista tanto de la ingeniería inversa como del parcheo, no es de particular interés, solo el final resultó ser algo divertido.



imagen


Como sabes, en esta serie de juegos en cada taberna, el jugador solo puede contratar un nuevo héroe por semana. Pero…



Descripción del error: si no hubo reclutamiento en la taberna externa, entonces, a partir del octavo día, puedes comprar dos héroes en dos días.



El archivo heroes4.exe desmontado del último complemento oficial "Winds of War" se utiliza para trabajar. El procedimiento de operación de la taberna fue encontrado por el equipo anteriormente y está ubicado en la dirección 4705E0. De todo el algoritmo de su trabajo, me interesa el lugar en el que se determina si es posible contratar un Héroe en la taberna en este momento, o si es necesario esperar. En el juego, esto se manifiesta por la salida del mensaje correspondiente:





Desde un punto de vista programático, esta es una nueva ventana que se crea en el juego usando la función NewWindowCreate (720C80) (las funciones reconocidas en el desensamblador reciben sus propios nombres). Hay varias llamadas a esta función en el procedimiento de la taberna, y el primer retador es una llamada a la dirección 470823. Con la ayuda del depurador, me aseguro de que, de hecho, esta llamada crea el cuadro de diálogo deseado. El código que controla esta llamada a NewWindowCreate está arriba en 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


Compro en la taberna del héroe, luego establezco el "punto de interrupción" para escribir en la celda dirigida a [ebp + 48h], después de lo cual espero 7 días en el juego. Cuando la taberna se "vacía", el depurador aparece en la dirección 470DFF. Veamos el código circundante:



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


Este breve procedimiento verifica el número de días que la taberna está cerrada para alquiler. Tenga en cuenta que se llama para todas las tabernas del mapa todos los días de juego. ¿Qué está causando el error? Por alguna razón, el programa continúa contando el número de días durante los cuales el héroe no fue contratado en la taberna y después de la semana en que la taberna estuvo cerrada (ver el mostrador en 470E06). Como resultado, obtenemos la siguiente imagen. Deja que el primer reclutamiento del héroe tenga lugar solo en el octavo día de juego. A la entrada del procedimiento, el valor de la bandera de disponibilidad de la taberna en [ecx + 48h] será igual a "1" (la taberna está cerrada), y el valor del contador de días en [ecx + 4Ch] será igual a "8". Sin embargo, después de la comparación en 470DF9, el control recibirá un código en 470DFF, ¡que reabrirá la taberna para alquilar! Esto restablecerá el contador de días.y después de contratar al segundo héroe, el algoritmo ya funcionará, como pretendían los autores. Pero después de dos semanas en el juego, todo el ciclo se repetirá.



La forma más sencilla de corregir el error es dejar de contar los días. Deje que el mostrador funcione solo cuando la taberna esté cerrada (lo cual es más lógico), y el resto del tiempo, póngalo en cero. Esto se logra de manera muy simple cambiando la transición en la dirección 00470DF7 al final de la función:



00470DF5                 cmp     dl, al
00470DF7                 jz      short loc_470E09


Ahora todo lo que queda es parchear el código existente. Para hacer esto, mire el original





y modificado





opciones.



Como puede ver, el resultado deseado se puede lograr reemplazando 0D con 10 en la dirección 470DF8. Un clásico del género: ¡corrige un error reemplazando solo un byte!



All Articles