Heroes of Might and Magic III

Posted by

Reverse Engineering

SND File Format

The SND file format is very simple. The first 4 bytes tell us how many files are in the archive:

0..3 Number of Files

Then, there is a list of files, with each structure containing the file name, offset and size is as follows:

40 Bytes – File Name
4 Bytes – Offset
4 Bytes – Size

This is repeated for as many times as the first four bytes of the SND file indicates, e.g. Heroes3.snd equals 1014 files.

H3M File Format (Compressed)

The file is stored as a basic zlib stream, so using zlib (version 1.2.3 here), you should be able to uncompress the map file without any special treatment. The accompany zpipe.c example inf() function works just fine.

Use the H3M Compressor / Decompressor tool to compess and uncompress H3M files.

H3M File Format (Uncompressed)

0..3 – Header

RoE – 0x0000000E;
AB – 0x00000015;
SoD – 0x0000001C;
WoG 0x00000033;

4 – Junk Byte
5..8 – Size of Map (e.g. 36 = 36×36, 72 = 72×72, etc)

Windowed Mode Research

Given the issue with Heroes of Might and Magic III coming up with the in-game message “This game runs in 65536 color mode. You must switch the desktop to this mode before playing the game.”, I have done some debugging to see what can be done.

Here are my findings so far:

Address 0x0060150C – DirectDrawCreate

CPU Disasm
Address Hex dump Command Comments
0060150C |. E8 F11F0000 CALL
00601511 |. 85C0 TEST EAX,EAX
00601513 |. 74 11 JE SHORT 00601526

The SetDisplayMode function sets up the screen resolution (as will be seen in the next section), although, it’s a little tough to find, so given the knowledge that it is called roughly after the DirectDrawCreate function, we can just look out for a pointer call and the appropriate resolution values, which in this case are 800x600x16.

Address 0x0060155D – Setting resolution and calling SetDisplayMode

CPU Disasm
Address Hex dump Command Comments
0060155D 6A 20 PUSH 10
0060155F |. 68 58020000 PUSH 258
00601564 |. 68 20030000 PUSH 320
00601569 |. 8B08 MOV ECX,DWORD PTR DS:[EAX]

This is the call to SetDisplayMode with the aforementioned screen resolution. I naively changed the value at 0x0060155D to 0x20 (32) to see if this would work.

Address 0x004F80F4 – Start of Switch Case for dealing with window change?

CPU Disasm
Address Hex dump Command Comments
004F80F4 |> \8B15 B8876900 MOV EDX,DWORD PTR DS:[6987B8] ; Case 9C49 of switch Heroes3.4F8071
004F80FA B9 01000000 MOV ECX,1
004F80FF |. 2BCA SUB ECX,EDX
004F8101 |. E8 9A981000 CALL 006019A0
004F8106 |. 84C0 TEST AL,AL

I presume that the Call instruction at 0x004F8101 hits some code that checks for appropriate desktop colour depth and whatnot.

Address 0x004F8101 – In-game Error Message:

CPU Disasm
Address Hex dump Command Comments
004F8108 /75 23 JNE SHORT 004F812D
004F810A |. |6A 00 PUSH 0 ; Arg10 = 0
004F810C |. |6A FF PUSH -1 ; Arg9 = -1
004F810E |. |6A 00 PUSH 0 ; Arg8 = 0
004F8110 |. |6A FF PUSH -1 ; Arg7 = -1
004F8112 |. |6A 00 PUSH 0 ; Arg6 = 0
004F8114 |. |6A FF PUSH -1 ; Arg5 = -1
004F8116 |. |6A 00 PUSH 0 ; Arg4 = 0
004F8118 |. |6A FF PUSH -1 ; Arg3 = -1
004F811A |. |6A FF PUSH -1 ; Arg2 = -1
004F811C |. |6A FF PUSH -1 ; Arg1 = -1
004F811E |. |BA 01000000 MOV EDX,1
004F8123 |. |B9 B8F96700 MOV ECX,OFFSET Heroes3.0067F9B8 ; ASCII “This game runs in 65536 color mode. You must switch the desktop to this mode before playing the game.”
004F8128 |. |E8 43E4FFFF CALL 004F6570
004F812D |> \33C0 XOR EAX,EAX

We can change the JNE command to a JMP command at 0x004F8108 which bypasses the ingame message. This is merely an aesthetic property. It has no bearing on whether or not the game will actually switch modes.

Hope anybody finds that interesting and/or useful. If you manage to crack it before me or just have some questions, please let me know. 🙂

Terry Butler