
Kidhak Prehistorik 2: unlock levels
Fans of this wonderful game are dedicated ...

... if there are any. However, I am sure that not everything is so bad and Crysis has not absorbed the brain of mankind completely and completely.
So, the aforementioned fans of old games, and in particular one wonderful game of 92 years old, can remember that the save system in the game is made in a somewhat prefixed spirit: codes are scattered across the levels (sometimes in rather unexpected and hard-to-reach places), which are carefully used during MS-DOS recorded on a piece of paper and stored like a treasure. The code entered in the main menu allowed you to start the corresponding level from the starting position.
Soshite, in our time, there was, in some way, a problem for those who would like to play Prehistorik 2. Namely, the need to emulate a game in Dosbox: not everyone has the opportunity to find in a landfill or, much more rarely, to get it out of the mezzanine carefully kept there 486th.
The fact is that when generating codes, the game uses BIOS environment variables. How it is emulated in Dosbox, I did not understand, I know for sure that with each new start of the emulator the codes in the game are different. Accordingly, a piece of paper with codes becomes useless, and the possibility of a pleasant and non-stressful passage of the game comes to naught: the game can be completely completed in just one sitting. Perhaps this is solved by detailed configuration of Dosbox. But ... it’s so trivial, so trivial that it scares even more than a little digging into the game’s executable.
Formulation of the problem

Implement a small hack, as a result of which an old-timer
Decision

Most of the time it took me to unpack the game file. An intro of a team that once cracked copy protection was added to the originally packed game code, and then all this was again packed with another algorithm. For help in unpacking, I turned to Mr. Grechnikov’s article: habrahabr.ru/post/187072 , in which I was interested in the section under the heading “Unpacking”, specifically the following paragraph:
That is, the rest of the loc_19960 procedure is not called if you pass the / ni parameter on the command line. We try, we see that with this parameter the game skips a reminder of the valiant Hybrid team and immediately proceeds to the game itself. We conclude that the whole seg002 is a screen saver unnecessary for the game, hung on a working exe'shnik. Rewrite in the header cs: ip to 0000: 0003, ss: sp to 1681: 0080, trim the last 5E90h bytes, accordingly adjusting the size and additional memory fields in the header.
(It was not interesting further, because a ready-made solution is not what I wanted.)
After I followed this advice, I found an egg in a duck previously extracted from a hare ... or as it usually happened in old Russian fairy tales ? It is easier to compare this with a matryoshka:


After unpacking the diet, the program grew to 90 Kb and nothing prevented you from running dirty paws into it. This is what I did, opening Hiew and immediately finding the line that interests me: I’ll

clarify for those who are the same as me who are gaining experience (although you should always learn) that finding a line in Hiew is right after starting F4 - Hex, F7 - ASCII - > "The line of interest to us."
The line address is 15401. Now I need to find out in which place the program is accessing this line. Naturally, such calls with a high degree of probability will be close to the part that I intended to break.
How can I find out? In fact, there are many ways. You can open the file in Ida Pro and examine cross-references. True, at first Ida was configured to be friends with the type of string used. But since Id couldn’t make friends with Dosbox at such a level that it was possible to debug 16-bit files calmly and without annoying factors (Dosbox constantly forgot that it was a debugger and tried to live its own life, despite the patch and plugin) , then I decided not to use such heavy artillery at all where I needed, most likely, just to correct a few bytes.
Therefore, we will do it easier. To find out where the offset to this line is used in the program, you first need to find out the offset itself. To do this, you need to know the database of the data segment. In Hiew, this is more than simple. Hit F8 and look at the file header.

So, first we’ll open the calculator, switch to the hexadecimal system and enter the value Paragraphs in header: 86, then multiply by 10. Copy this value to the buffer and return to Hiew, where the header window is still not closed. Without exiting, press F5 to go to the entry point. And here we’ll switch to decode mode (F4 - decode). This is a listing:
listing 1.
00000468: FA cli
00000469: FC cld
0000046A: BAFFFF mov dx,0FFFF ;" "
0000046D: BE8000 mov si,00080 ;" А"
00000470: AC lodsb
00000471: 98 cbw
00000472: 8BC8 mov cx,ax
00000474: E35E jcxz 0000004D4 ---↓ (1)
00000476: AC lodsb
00000477: 3C2F cmp al,02F ;"/"
00000479: 7404 je 00000047F ---↓ (2)
0000047B: E2F9 loop 000000476 ---↑ (3)
0000047D: EB55 jmps 0000004D4 ---↓ (4)
0000047F: AC lodsb
00000480: 24DF and al,0DF ;"▀"
00000482: 3C46 cmp al,046 ;"F"
00000484: 7506 jne 00000048C ---↓ (5)
00000486: 2E83260300FE and w,cs:[0003],0FFFE ;"■"
0000048C: 3C4D cmp al,04D ;"M"
We are not interested in all this. We are interested in assigning a value to the ds register. Without even having to search, we scroll down the screen quite a bit and find what we are looking for:
Listing 2.
000004D4: B8030A mov ax,00A03 ;"◙"
000004D7: 8ED8 mov ds,ax
We take out 00A03 and stuff it into the calculator, where we also multiply by 10 and add to the value previously stored in the buffer. We get the A290 . And now, subtract A290 from 15401: B171 . This is the line offset to be used inside the program. Now go to the hex mapping (F4 - Hex) and press F7, where we enter 71 B1 in the line named by the Basurm word “Neh” (bytes go in the reverse order, remember?). We go to the following listing:
Listing 3.
00009E23: E85801 call 000009F7E ---↓ (1)
00009E26: C606A7B103 mov b,[0B1A7],003 ;""
00009E2B: BB71B1 mov bx,0B171 ;"▒q"
00009E2E: C706A2B1F20A mov w,[0B1A2],00AF2 ;"◙Є"
00009E34: E8EDFE call 000009D24 ---↑ (2)
00009E37: C606A7B104 mov b,[0B1A7],004 ;""
00009E3C: BB6CB1 mov bx,0B16C ;"▒l"
00009E3F: C706A2B1C912 mov w,[0B1A2],012C9 ;"╔"
00009E45: E8DCFE call 000009D24 ---↑ (3)
00009E48: 803EA6B101 cmp b,[0B1A6],001 ;""
00009E4D: 7503 jne 000009E52 ---↓ (4)
00009E4F: E90001 jmp 000009F52 ---↓ (5)
00009E52: 803EA6B102 cmp b,[0B1A6],002 ;"☻"
00009E57: 7503 jne 000009E5C ---↓ (6)
00009E59: E90601 jmp 000009F62 ---↓ (7)
00009E5C: 8A1E7028 mov bl,[2870]
00009E60: F6C380 test bl,-080 ;"А"
00009E63: 7403 je 000009E68 ---↓ (8)
00009E65: E91501 jmp 000009F7D ---↓ (9)
00009E68: A02928 mov al,[2829]
00009E6B: 0A060C28 or al,[280C]
At the beginning of this listing, actions occur with the line of interest to us, and then the same actions occur with the adjacent line "[[[[". Perhaps you can’t get by with static observation. It is necessary to resort to the help of a debugger. In order not to violate the atmosphere of consonance, I will resort to the special release of Dosbox 0.74, which contains a debugger. In addition, this option is much more stable than the crutch Ida + Dosbox plugin.

So, I open Dosbox-74-debug (after setting up the conf-file, where the commands to mount the game directory and directives for launching it with the debug prefix are simply indicated). Without further ado, we start the game in trace mode and soon we will find out what is in this place:
Listing 4.
022E:014C 7B00 jpo 0000014E ($+0)
022E:014E C606A46C00 mov byte [6CA4],00
022E:0153 B80300 mov ax,0003
022E:0156 E86701 call 000002C0 ($+167)
022E:0159 E8138D call FFFF8E6F ($-72ed)
022E:015C 803E862D08 cmp byte [2D86],08
022E:0161 7234 jc 00000197 ($+34)
After calling the second subfunction, the main menu is launched, which “spins” inside this subfunction. We put a break at the entrance to the first subfunction and start the game again, sending it first to free flight.
It soon turns out that ...

... the drawing of the main menu ends on this command. And right after it follows such a listing:
Listing 5.
022E:8E99 8ED8 mov ds,ax
022E:8E9B 33C0 xor ax,ax
022E:8E9D A3EC27 mov [27EC],ax
022E:8EA0 A3EE27 mov [27EE],ax
022E:8EA3 32C0 xor al,al
022E:8EA5 3806F227 cmp [27F2],al
022E:8EA9 7548 jne 00008EF3 ($+48)
022E:8EAB 3806F327 cmp [27F3],al
022E:8EAF 7557 jne 00008F08 ($+57)
022E:8EB1 A02928 mov al,[2829]
022E:8EB4 0A060C28 or al,[280C]
022E:8EB8 7539 jne 00008EF3 ($+39)
022E:8EBA 813EEC270E01 cmp word [27EC],010E
022E:8EC0 72E3 jc 00008EA5 ($-1d)
The main menu, I recall, offers to click either 1 or 2. The listing has two transitions. At this point, the game loops between 022E: 8EA5 and 022E: 8EC0. Everything is obvious. Set breakpoints on both options: ВР 022Е: 8EF3 and ВР 022Е: 8F08 , "release" the game in free mode by pressing F5 and press 2 - a menu item prompting you to enter password.
After some tracing time, we arrive at listing 3. The string "[[[[", rendered together with "ENTER CODE" - can be either the string "_ _ _ _", which is displayed in this way due to a cunning font, or a reserved place under the code. Assume that the latter is true and set a breakpoint to access the memory at offsets of suspicious 4 bytes: BPM 0С11: В16С, ВРМ 0С11: В16D, ВРМ 0С11: В16E and ВРМ 0С11: В16F (we can see the current database of the data segment in the debugger). We start the game again, in the code entry menu, press the key, entering the symbol of the proposed code, and the program stops at listing:
Listing 6.
022E:9A57 FF06A4B1 inc word [B1A4]
022E:9A5B FEC3 inc bl
022E:9A5D 80FB04 cmp bl,04
022E:9A60 7303 jnc 00009A65 ($+3)
022E:9A62 E9B800 jmp 00009B1D ($+b8)
DEBUG: Memory breakpoint: 0C11: B16C - 5B -> 38
Some kind of variable is incremented, then an increment of the register occurs and a check, apparently, for exceeding 0004, is logically connected with the need to enter 4 characters. According to the results of the check, there is a transition either to ret or to some additional sequence of commands. Including this:

Variable 0C11: B1B5 stores the code “4789” just entered by me as a number. Then comes the interesting section:
Listing 7.
022E:9AAC 33D2 xor dx,dx
022E:9AAE 8BC2 mov ax,dx
022E:9AB0 E8A6F8 call 00009359 ($-75a)
022E:9AB3 3906B5B1 cmp [B1B5],ax
022E:9AB7 7420 je 00009AD9 ($+20)
022E:9AB9 42 inc dx
022E:9ABA 83FA14 cmp dx,0014
022E:9ABD 76EF jbe 00009AAE ($-11)
Zero dx and ax; a subfunction is called, after which the newly cleared register ah is compared with the entered code (in numerical form). If they are identical, then there is a transition somewhere into the distance, otherwise dx increases by one, and if it does not exceed 14, then the operations are repeated.
It is logical to assume that fourteen correct passwords are enumerated and compared with the entered ones (the first 9 levels are for Beginner complexity, the rest are for Expert, although there are only 2 exclusive levels for this complexity: Castle and Minotaur, I do not know how other levels differ, for example, at number 10, Icy is loaded). All facts confirm that we are on the right track.
Actually ... that's all. There is nowhere to go; just change the conditional transition to unconditional. In principle, it would be nice to also change the number of entered characters, since if you leave this unchanged, you will have to enter the seventh level number as 0007 - after all, it will be more convenient to enter it as 07. To do this, change Listing 6 to the following:
Listing 6_1.
022E:9A57 FF06A4B1 inc word [B1A4]
022E:9A5B FEC3 inc bl
022E:9A5D 80FB02 cmp bl,02
022E:9A60 7303 jnc 00009A65 ($+3)
022E:9A62 E9B800 jmp 00009B1D ($+b8)
To look for where and how a line of four dashes is drawn, to replace them with two, I was already too lazy. Despite the fact that Zmiro used the < symbol to draw an exclamation mark from a font resource , and a > symbol for a comma , searching for “I don’t know what” could be very laborious. Having spent some more time step-by-step in the debugger, it was possible to localize this place, but I'm not so perfectionist.
Conclusions. What is done
The new executable file of the game prel.exe. Remember to check for viruses. ;) The
need to collect passwords by levels has been eliminated. It is possible to select a level from the main menu by entering its serial number from two digits instead of a password of four. As unnecessary, the letters of the Latin alphabet (AF) were removed from the mask of input characters, only numbers were left possible; Added checking the range of input level numbers (01-14). In fact, why should players, by mistake or from excessive curiosity, observe a crash in " Insert disk with levelFF.sqz"instead of loading the level. The prompt in the password entry mode from" ENTER CODE "was changed to" SELECT LVL ". At the very beginning, the Hybrids intro was cut from the game. The first developer intro was changed (" Yeaaa ... My game is still working in ... " ), - supplemented with information about Hybrids and this modification. Changed lines of difficulty names.
Pictures are clickable, especially the latter.




