Cheating in games. Lesson #3

by

Indian_Trail

CRACK, SNAP AND PINBALL FANTASIES

In the previous lesson I showed you the basics of the assembler language and how to find a byte in memory using Softice. This method is very fast and reliable. If you wanna add some lives in a game in a fast way, the snapping method is probably the best. One side effect with this method (so far) is that the changes in the game are made permanent unless you have Softice running while playing the game. Once the .EXE file has been patched the only way to get back the number of lives the programmer gave us is changing the file again.

Since quite a long time game programmers (appz even) include hidden features. In games such features are usually cheat codes that you type in during the game (or at the main menu of the game). In this lesson I'll show you how to obtain these cheat codes in two different ways. I'm using Pinball Fantasies here because it's ideal for cracking and cheating studies. It's fairly spread and should be available on the Web or in some warez channel on IRC. I like to stress the importance of using Softice 2.62 cracked Marquis de Soiree. When searching for Softice (if the links in Lesson #2 have died) use a FTP search engine. You'll find hundreds of sites containing Softice 2.80. That version is USELESS for our purposes, because it doesn't snap (the snap function doesn't work), you'll have to find Softice 2.62. Only use the DOS version of Softice as long as the Windows version (though it allows you to debug DOS boxes) is more complex.

OK, let's start:

Before we can crack a protection scheme we must understand how it works. As you probably already discovered, Pinball Fantasies (PF from now on) is protected with a manual protection scheme, i.e., "Please enter the word # 3 on page # 4 in your manual". These schemes are usually very easy to defeat (it took me less than 5 minutes). This is how it works:

  1. Get user input from keyboard buffer and store it in memory.
  2. Load the real password and store it in memory.
  3. Compare user input with real password.
This is a logical conclusion of what should happen. The weak point of the protection is the comparison of the user input and the true password. A normal approach would be to enter "cheat" as a password and then as we press enter and the "Sorry incorrect password, try again" message pops up, we would search for our input in memory to find out where the program stores it. Then trace through the program using breakpoints until we find the CMP user,password operation.

A protection scheme like this can compare the input string from the user with the correct string in two different ways. The first one is by simply comparing both strings using CMPSB, usually like REPZ CMPSB which would compare the string that DS:SI points to with the string pointed by ES:DI. The B in CMPSB stands for byte and could as well be a W, like CMPSW, which would then mean word.

The second way of comparing the two strings is byte by byte, like loading the first char in the user input string into AH and the first char of the correct password into AL. Then simply do a CMP AH,AL and then loop back until the end of the correct string is reached or as soon as the AH doesn't match AL. To load a char into a register like AL, the command LOADSB is very suitable. It will load the byte that DS:SI points to into AL. And to load AH with a byte a simple MOV AH,[BX] would do. [BX] means the content of the memory address BX. For example, if BX is 3010 and at the address 3010 the char A is stored, MOV AH,[BX] means load AH with 'A'.

The assembler language can seem hard to understand at first, but after you have debugged some programs or written some of your own (in assembler) you'll get the hang of it. ASSEMBLER IS PRETTY EASY BECAUSE IT IS USUALLY THE SAME COMMAND OVER AND OVER. Those all phoney fakes who keep screaming in my ear that assembler is hard got what they deserved (or became deaf at least). So LODSB, CMPSB and MOVSB can be used for string operations.

Now that we know some basic string operations in assembler we shall go on and crack PF. One thing: though the manual protection scheme is not used anymore as frequently, if you find a program that has a manual scheme CRACK IT even if you have the CRACKED FILE. That's the best way of learning, studying the past. If you have a cracked manual protected game you could try to uncrack it, that's basically the same thing.

Alright, let's move on.

CRACKING PINBALL FANTASIES

PINBALL.EXE is the .EXE file that will start the game. Its size is very small, only 1.7 Kb. Therefore it's not very likely that it contains the code for the main program. PINBALL.EXE is a loader which will access other files. Within one of these files the protection scheme is hidden, so therefore let's have a look in our directory where PF is installed.

D:\GAMES\PF>dir *.exe

PINBALL.EXE
SETSOUND.EXE

D:\GAMES\PF>dir

Will show a lot of files where one is very interesting:

INTRO.PRG

Hmmm, let's see if there's more .PRG files:

D:\GAMES\PF>dir *.prg

INTRO.PRG
TABLE1.PRG
TABLE2.PRG
TABLE3.PRG
TABLE4.PRG

It seems that the loader PINBALL.EXE accesses these .PRG files and that TABLEx.PRG is the flipper table file and INTRO.PRG is probably where the protection dwells.

Looking at the memory mapping you soon find out that INTRO is the current program running (if you have executed PINBALL.EXE). So the first section of INTRO in memory starts at 0E98:0000 and ends at 0E98:000B. Remember that the segment addresses will change from computer to computer but the offset will be always the same. This section of INTRO is obviously too short, only 11 bytes, so we keep looking. The next INTRO section is found (in my computer) at 1101:0000. This section is a lot larger, it ends at 1101:3B91. This is where we should look for our input. So type in something unusual like "hell" or "qwert" for the password and then search for your input in the 1101 segment. Again the address won't be 1101 in your computer, just look for the section of INTRO that has the starting offset 0 and the ending offset 3B91. Let's search:

S 1101:0 L FFFF "QWER" (your command to Softice)
1101:5ADF (Softice response)

So the inputs are stored at offset 5ADF. Let's dump that location:

D 1101:5ADF

Now you should see your input string in the data window. Since "QWERT" is not the correct password PF asks us again to type in the correct password. Type one letter and change back to Softice and see if that letter has been stored at 5ADF, it should have been. You may be wondering why we are using capital letters in our search string, that's because PF changes our inputs to capital letters as you can see while you are typing them in. Another question that might hit you is why we aren't searching for all the chars we typed. That's because if PF only stores the first four letters we won't find any match while searching for five letters. So now you know that :-)

We have now found the keyboard buffer, so let's put a breakpoint on that location:

BPR 1101:5ADF 1101:5ADF+4 R

Press enter and BOOOM, you're in Softice. We are now in the code that manipulates our input. You should see this CODE:
MOV   AH,[BX]     ; Move a letter into AH
INC   BX          ; BX points to the next letter
LODSB             ; Store encrypted letter in AL
CMP   BX,51E7     ; Check if BX is a space (20 in hex)
JAE   3DF4        ; If so then jump
ROR   AL,1        ; This is the first instruction to decrypt AL
XOR   AL,A2       ; And now we have a letter stored in AL
CMP   AL,00       ; Check to see if it was the last letter in the correct
                  ; password
JZ    3DEF        ; If so then jump here
CMP   AH,AL       ; Compare user letter with correct password letter
JZ    3DB8        ; If the same then jump and go on with next char
Wow! What does it mean? Well, the important thing here is the CMP AH,AL operation. Don't be nervous if you don't understand all of the above code, time and practice will educate you. I've read some cracking tutorials and I didn't understand much the first times I saw the code of the protection routines. So how do we crack this?

When a program makes a CMP it subtracts the operands and the Zero flag will indicate if the two operands were equal or not. JZ means jump if zero, which means it jumps if the Zero flag was set, if it wasn't it won't jump. So to crack this we simply change the JZ into a JNZ or a JMP. JNZ means jump if not zero and JMP means jump anyway.

MOV   AH,[BX]     ; Move a letter into AH
INC   BX          ; BX points to the next letter
LODSB             ; Store encrypted letter in AL
CMP   BX,51E7     ; Check if BX is a space (20 in hex)
JAE   3DF4        ; If so then jump
ROR   AL,1        ; This is the first instruction to decrypt AL
XOR   AL,A2       ; And now we have a letter stored in AL
CMP   AL,00       ; Check to see if it was the last letter in the correct
                  ; password
JZ    3DEF        ; If so then jump here
CMP   AH,AL       ; Compare user letter with correct password letter
JMP   3DB8        ; Jump anyway and go on with next char
Now it doesn't matter if AH and AL are the same, the program will always work. Another way of defeating this protection would be to compare the true password with the true password like this:

MOV   AH,[BX]     ; Move a letter into AH
INC   BX          ; BX points to the next letter
LODSB             ; Store encrypted letter in AL
CMP   BX,51E7     ; Check if BX is a space (20 in hex)
JAE   3DF4        ; If so then jump
ROR   AL,1        ; This is the first instruction to decrypt AL
XOR   AL,A2       ; And now we have a letter stored in AL
CMP   AL,00       ; Check to see if it was the last letter in the correct
                  ; password
JZ    3DEF        ; If so then jump here
CMP   AL,AL       ; Compare correct password letter with itself
JZ    3DB8        ; If the same then jump and go on with next char
This way the Zero flag will always be set. You could experiment with this a lot.

SNAPPING

Let us find the address that stores the player ball and then find the increaser or decreaser. Start the game and play some pinball. Switch back to Softice and snap save the DS register.

SNAP S DS:0 DS:FFFF

Loose the ball, switch back and snap compare. Look for changes from 1 to 2 since PF tells us that we start with ball 1 and after loosing it we have ball 2. There are not many changes in memory with these values.

2DB4:000D
2DB2:000B
2DB2:000E
2DFF:000F
2E02:000E

Dump these areas to see if they change after you loose a ball. If they change without loosing a ball then they are not the correct addresses. We are looking for a change in memory that ONLY happens when we loose a ball. You quickly realize that 2E02:000E is the correct storage address of the number of balls we have left. It's an increaser. We start with the value 1, then it increases until the value is 3 and is about to change to 4. I don't think I have to remind you that the segment addresses will be different for you. Alright let's put a value on that address.

E 2E02:000E (and change it to 9)

Ah, it didn't work. I knew it wouldn't, did you? As I said this address hold the player balls and it will be compared with a predefined value. If you want more balls you gotta find the predefined value. That's very easy, just breakpoint on memory access to 2E02:000E

BPM 2E02:000E RW

The next time Softice pops up will be when you loose a ball and you will see this code:

MOV AL,[33DF]     ; Get predefined value
CMP [33DE],AL     ; Compare it with user value
JA  0B4D          ; If the same jump to end session
Let's change the predefined value:

E DS:33DF (and change it to whatever you fancy)

And it works just fine. Use a hex editor as usual to patch it. Now this way of making cheats is very nice and funny. But a more elegant way would be to make a trainer. So everytime we press "+" we increase our ball limit in 1 ball. Trainers involves pretty complex assembler programming. There are some trainer tutorials on the Web, but they assume that you are at least on an intermediate level of assembler programming. Don't worry I will explain for you in a later lesson (if there's a demand) in detail how to write trainers. I'll explain the whole set, how to write TSR programs which is basically the same as writing a trainer. For those of you who can't wait for that lessons here are some clues.

The program has to be memory resident. It has to read the keyboard on every cycle of the processor to see if a key has been pressed and if so, which key was pressed. To make a program resident you'll have to hook an interrupt and redirect it to your program.

CHEAT CODES, WHERE???

As I said in the beginning, almost all of the games released since 1992 contains built in options which can be triggered. In PF there are some cheat codes that the programmers put in. I will now show you the basics of finding these codez.

There are two ways of finding them, both can be useful in different cases. The first one is simply dumping the file in a hex editor and read all the strings you find. The other way is to debug the game (what else) and put a breakpoint on keyboard reading, usually interrupt 09, and see what the program is looking for. Let's try the first method.

Load TABLE1.PRG in a hex editor. Search for "cheat", "is" and everything else you can think of if you come up empty. When I searched PF for the string "cheat" it was found in three places. Here is what I found.

JOHAN$       CHEAT$
TECH$        EARTHQUAKE$
TSP$         EXTRA*BALL$
DANIEL$      SNAILS$
GABRIEL$     FAIR*PLAY$
ROBBAN$      STEIN$
GREETS$
And just below them are the messages you'll get when you have typed them in.

_________________
I would rather be a sparrow than a snail
----------------------------------------
You will now get 7 balls dude
----------------------------------------
All cheats have now been reset
----------------------------------------
The tilt feature is now disabled
----------------------------------------
There are alot of nasty cheats in this game....
----------------------------------------
The dot machine system.....coded by JOHAN
----------------------------------------
Music......................coded by DANIEL
Obviously there are cheat codes here, you can get 7 balls and disable the tilt function. And you can reset the cheats. I call this an built-in trainer (almost). I'll leave it up to you to try these codes. For method 2 I'll leave it up to you as a homework to study debugging techniques to find the cheat codes by tracing through the keyboard routines.

That's all for now friends, more in the next lesson. Please e-mail me with your work (the cheats you have made, write an essay on it, on how you approached the program, etc., etc.). Your questions and remarks on my work are also welcomed.


indian_trail@hotmail.com (10-Oct-97)
Color line
Back Go to the parent page: Software hacking.