Kidhak Prehistorik 2: unlock levels

Fans of this wonderful game are dedicated ...


image
... 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


image
Implement a small hack, as a result of which an old-timer like me could just enter the number of the desired level instead of the code. Go straight to the results.









Decision


image









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:

image

image

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

image

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.

image

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.

image

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 ...

image

... 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:

image

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.
imageimageimageimageimage

Also popular now: