Of course, everyone knows about the third heroes. Weeks of time lost behind the hotseat, chiselled characteristics of units, tactics of development, development. Weekly gatherings with friends for the heroes c coffee and bagels. Great, in general, it was. But the other day I wanted to repeat and play on the network. All are already gone, hotseat is not a ride. They downloaded the Armageddon blade distribution kit, set up hamachi, but something went wrong. Ping is big for some reason, nothing happened. Well, busy all, there is no time to understand, and reluctance. The game did not go.
And the characters are installed, the desire to play is. I decided to go through the campaign (to my shame, I never had the patience to go through it in the past). Launched, chose the campaign of the revival of Eratia, clicked on the episode "Victims of War." And I do not know, intuition, probably, appears during the time you are programming. In general, the heroes showed me this picture:

And, as often happens with me, the game is over, and a more interesting and exciting activity has begun.
I start in the debugger, I select the same problem point. In this section of the code, an exception occurs when accessing memory on line mov bl, [eax + ecx + 1F879h].
. text : 004567A3 mov ecx , dword_68C818
. text : 004567A9 test ecx , ecx
. text : 004567AB jl short loc_4567F2
. text : 004567AD mov dl , [ eax + edi + 1F879h ]
. text : 004567B4 mov bl , [ eax + ecx + 1F879h ]
')
I look at the values of the registers: EDI is equal to zero, EAX indicates the correct memory location, ECX is just huge and points to nowhere. Most likely, the problem is in it. Now you need to find where the value is entered into it. I climbed a little higher on the code, I find the line mov ecx, dword_68C818. Yeah, then the ECX register is populated with a global variable. I open the cross-reference window to see where the value is written to this variable.

Interestingly, the value in it is written in the same function. In general, a strange thing. The variable is global, and is used only in one function. Does it mean that it should be created on the stack? Well, well, I probably do not understand something. I look who writes it. And it looks like this:
. text : 00456736 mov eax , [ eax + 1F468h ] ; this is an argument
. text : 0045673F push eax
. text : 00456743 mov ecx , [ ecx + 0A4h ] ; here is an object with a "bad" value
. text : 00456749 mov edx , [ ecx ] ; and this is his table of pointers to virtual functions
. text : 0045674B call dword ptr [ edx + 20h ] ; here call subroutine
. text : 00483A60 push ebp
. text : 00483A61 mov ebp , esp
. text : 00483A63 mov eax , [ ecx + 8 ]
. text : 00483A66 mov ecx , [ ebp + arg_0 ] ; this argument is -1
. text : 00483A69 mov eax , [ eax + ecx * 8 ] ; something like result = arr [-1] happens here. Very suspicious place
. text : 00483A6D pop ebp
. text : 00483A6E retn 4
. text : 0045674E mov dword_68C818 , eax ; here we write to our global variable the value that the subroutine returned. This is the same “bad” figure, which brings down the game.
It is very strange that the array is addressed at a negative index. It can be assumed that the error in the argument. Text search seeking access to a variable with offset 1F468h

As you can see, refer to it exactly twice. The first time a constant is written into it at initialization (apparently this constant is exactly what I get). The second case will have to be studied in more detail. I’m going to the address specified in the search results (I’m not going to give a large function), put a breakpoint, choose a script. Nothing happens. I go higher to the top of the function. The function is called quite often. By the presence of multiple branches, it can be assumed that this is processing some messages. I try to click on all the buttons that are in the script window. The breakpoint is triggered during the selection of the initial prize. Something like this:

Now we can formulate a mistake in a human way. There is a virtual function getStartupBonus, which returns the initial bonus. In scripts of one type, a variable is returned, in scripts of another type, an array element specified by some external index. It is understood that the index does not extend beyond the array. But for some reason, before loading the script, the wrong value is written to the index. There is an output outside the array, the application crashes.
There are several solutions. You can, for example, change the constant with which the variable is initialized to zero. But, truth, it can lead to quite unexpected consequences. It seems to me that it would be best to add a few instructions to the function that checks the argument before the function that works with the array. And the function will look like this:
. text : 0048385A push ebp
. text : 0048385B mov ebp , esp ; ebp points to stack
. text : 0048385D mov eax , [ ecx + 8 ] ; eax points to an array
. text : 00483860 mov ecx , [ ebp + arg_0 ] ; The argument contains the estimated array index
. text : 00483863 test ecx , ecx ; check if the index is negative
. text : 00483865 jns short loc_483869 ; if it is not, then go to reading the array element
. text : 00483867 xor ecx , ecx ; if the array index is negative, then we equate it to zero
. text : 00483869 mov eax , [ eax + ecx * 8 ] ; return array element
. text : 0048386C pop ebp
. text : 0048386D retn 4
I write down the changes in the executable file, restart the game, select the campaign, it works.