Cheating in games. Lesson #2

by

Indian_Trail

  1. ASSEMBLER TUTORIAL
  2. SOFTICE INTRODUCTION
  3. AQUANOID LIVES CHEAT

ASSEMBLER LANGUAGE TUTORIAL

Some people say that assembler language is hard to learn. People who says that, probably have never tried to learn it. Every programmer should know assembler cause it allows you to control the computer at the lowest level. You should know that a computer is nothing but a microprocessor system. A microprocessor is a programmable device that can be used to control other electronic devices. You'll find them inside almost every electronic device such as microwave ovens, VCRs, cameras, etc. The CPU is the same as the microprocessor. CPU = Central Processing Unit.

The CPU controls everything that is connected to your PC: keyboard, graphic card, sound card, RAM memory, the monitor (screen), etc. The way it controls them is by sending them digital electronic signals which can either be one or zero (1 or 0). The commands that are used to program the CPU are ones and zeroes, called machine code language. To write machine code is very hard for human beings since they are binary (1s or 0s) . It's a lot easier if the commands have names instead of binary codes and that's where assembler comes in. Assembler uses mnemonics (like MOV for move) instead of binary codes and when the compiler (used for making the source code executable) compiles the code, it translates the mnemonics into machine code.

Every code, no matter in what language it was written, is compiled to assembler language and then to machine language. Assembler is basically the same as machine language. The only difference is that instead of typing "10001" as a command, you type "mov" or "jmp" or whatever. Because the programs are compiled to assembler language, it is pretty easy to look at a program code using a debugger. So a program is a bunch of commands for the CPU.

BASIC is the easiest language to learn since the commands are plain English. Therefore the code is written in plain English. Here is an example of that:

10 PRINT "Enter your name: "
20 INPUT A$
30 PRINT "Hello ", A$

This program asks the user to type his/her name. Then it prints on the screen "Hello " and the name the user just typed in. As you see the code is very easy to understand. The only thing a "non computer user" would wonder about is "A$", which is a variable used for strings. A variable is a reserved memory space which can contain numbers or letters (chars). The "$" sign is used to tell the computer that the variable contain letters (in BASIC language). When one or more letters are used in a variable, the variable is called a string. This is BASIC language.

Let's see what this means for the CPU:
  1. It outputs "Enter your name ".

  2. Then it checks the keyboard to see if any key has been pressed. If so, the letter is stored in a predefined place in memory (A$). It will keep checking the keyboard until return has been pressed, that indicates the end of the string. When return has been pressed it puts a "0" at the end of the string (A$) in memory.

  3. Then it outputs "Hello " and reads the letters (A$) stored in memory. It will read the memory until it reaches a zero, which indicates the end of the string. Then it will output the letters to the screen after "Hello ".

As you can see, there are a lot of things to do. To make things easier, the BIOS and DOS have their own small written programs to do basic things like printing to the screen and reading from the keyboard. These programs are called "interrupts". The interrupts are very handy when programming in assembler. At the end of this document I have included a small interrupt list. But a more complete list is available on the Web on the Randall server. The URL is at the end of this lesson. Go there and study. On that server is a complete assembler book.

BIT, BYTE AND WORD

There are binary numbers, decimal numbers and hexadecimal numbers. The decimal number system uses the base of 10. The decimal number 123 looks like this:

1 * 102 + 2 * 101 + 3 * 100 = 123

The above is pretty easy to understand. First we have 1 * 102 which is the same as 1 * 10 * 10. Then we have 2 * 101 which is the same as 2 * 10 and at last we have 3 * 100 which is the same as 3 * 1. This give us 100 + 20 + 3 = 123.

The binary system uses the base of 2. It uses ones and zeroes (1s and 0s). Here's how goes the coding of a 4 bit binary number.

0000 = 0 * 23 + 0 * 22 + 0 * 21 + 0 * 20 = 0
0001 = 0 * 23 + 0 * 22 + 0 * 21 + 1 * 20 = 1 * 1 = 1
0010 = 0 * 23 + 0 * 22 + 1 * 21 + 0 * 20 = 1 * 2 = 2
0100 = 0 * 23 + 1 * 22 + 0 * 21 + 0 * 20 = 1 * 4 = 4
1000 = 1 * 23 + 0 * 22 + 0 * 21 + 0 * 20 = 1 * 8 = 8

0011 = 0 * 23 + 0 * 22 + 1 * 21 + 1 * 20 = 1 * 1 + 1 * 2 = 3
1010 = 1 * 23 + 0 * 22 + 1 * 21 + 0 * 20 = 1 * 2 + 1 * 8 = 10

If you are unfamiliar with the binary system read this a couple of times and it all will become clear to you. Every 1 or 0 in a binary number is called a bit. The above numbers are 4 bit long. 4 bits are called a nibble and 8 bits are called a byte. 16 bits are called a word. It's very hard to calculate binary numbers for us, but for a computer it's very easy since digital signal are either 2.5-5V (1) or 0-2.5V (0). We shall therefore use the hexadecimal system as intermediate level between decimal (humans) and binary (computer) systems.

HEXADECIMAL SYSTEM

Hexadecimal numbers use a base of 16 and therefore have a combination of 16 digits:

0 1 2 3 4 5 6 7 8 9 A B C D E F

1 = 1 * 160 = 1 * 1 = 1
11 = 1 * 161 + 1 * 160 = 16 + 1 = 17
1A = 1 * 161 + 10 * 160 = 16 + 10 = 26

OK, I think you'll understand this by now, if you don't then pick up your old math books and read them.

CONVERTING DECIMAL TO HEXADECIMAL NUMBERS

To make the conversion you have to divide the decimal number by 16. The rest will give you the least significant digit. Then you have to divide the module again by 16, the rest will give you the next digit. Repeat the process until the module is less than 16. This will be the most significant digit. For example, how is 1200 in hex:

1200/16 => module = 75, rest = 0
75/16 => module 4, rest = 11 (B in hex)

Therefore 1200 decimal is 4B0 in hex. Let's check that: 4 * 162 + 11 * 161 + 0 * 160 = 4 * 256 + 11 * 16 + 0 * 1 = 1024 + 176 = 1200. Since DOS use 16 bit numbers, which is the same a 2 bytes, you should add a zero before the first number, i.e., 04B0. As I said in Lesson #1, the Intel processor stores the numbers backwards, so when searching for 04B0 you should reverse it to B004.

Alright, let's move on with assembler and have a look at the Intel processor.

THE INTEL PROCESSOR

The Intel processor 8086 is the CPU used for PC systems. The 8086 was used in the first PC. Then came 8088, etc. Today Pentium and 80486 are used a lot. But the instructions are the same for all of these processors because they are from the same "family". Newer processors have more instructions and more features. For each new processor new commands are added and so on. The important thing here is that they are 100% compatible with the 8086 instructions. So that is the processor we shall learn how to program. When you have the basic knowledge of assembler you can go on and learn specific features of the newer CPUs. OK, let's have a look.

A processor has registers that are used for different things. One register is used for calculations and another one is used for copying strings, etc., etc. This is a map over the Intel 8086:
MSB                     LSB
 15                      0
 _________________________
|           A X           | AX is a 16 bit register, AL and AH
|     AH     |     AL     | are 8 bit registers. The same
|_________________________| applies for BX, BL, BH, CX, CL,
|           B X           | CH, DX, DL and DH.
|     BH     |     BL     |
|_________________________| These registers are called
|           C X           | common registers.
|     CH     |     CL     |
|_________________________|
|           D X           |
|     DH     |     DL     |
|_________________________|
|           SI            | SI and DI are string registers used
|_________________________| for copying and comparing strings,
|           DI            | i.e., password protections.
|_________________________|
|           SP            | SP and BP are stack registers.
|_________________________| I'll get to the stack later.
|           BP            |
|_________________________|
|           CS            | CS, DS, ES and SS are SEGMENT
|_________________________| registers.
|           DS            |
|_________________________|
|           ES            |
|_________________________|
|           SS            |
|_________________________|

 _________________________
|           IP            | Instruction Pointer
|_________________________|
|    O D I T S Z A P C    | Flags
|_________________________|
Alright, that's how the 8086 CPU looks like. As you can see there's a lot of registers you are unfamiliar with, but don't worry, I'll cover them here.

Are you getting confused, dizzy or even ill? Just pick up your favorite Fender and plug it into your favorite amplifier and play some guitar for a while and it all will come clear to you. But beware that only good rock and roll or blues will do, anything else will get you even more confused. If this doesn't work then read this file over and over until you get it. There's a lot of interesting sites for newbies on the Web that cover assembler language. Sniff there and learn as much as you can.

THE INSTRUCTIONS SET

OK, that's it. Now we shall move over and study different mnemonics. I'll not cover all the instruction mnemonics here, if you want a complete list I'd suggest that you visit Intel's Homepage and look for instruction lists.

OK, you don't have to understand all of the above instructions. You will see how they are used in the programs that we'll study (for cheating and perhaps cracking). These aren't all of the instructions set that Intel CPUs have. Search the Web if you bump into an instruction that is not mentioned here. Search also the Web and read all the assembler tutorials you can find because there's a lot of ways to learn assembler and I only give you the basics so that we can debug and cheat in games.

THE INTERRUPTS

Lets study some interrupts. As I previously said, an interrupt is a small program which (mainly) the operating system or the BIOS offers to you. We shall describe the DOS interrupt 21 services here. The interrupt 21 has several services (small programs) available. All of the services a specific interrupt offers are stored in an interrupt vector. From that vector we can choose what service we want. Let's say we wanna type something to the screen. There's a service of int 21 which can help us. The way to choose a service from int 21 is to put the number of the service in AH. In our case:

         Function         AH      In data
     ----------------     --     ----------
     Output to screen     02     char in DL
This is what an interrupt listing at the Randall server would tell us when we are looking under the INT 21 list. The above means that if we wanna print something to the screen we must put 02 in register AH. The letters that we wanna print have to be put in register DL. So to print the char "A" on the screen we shall write the following in our program:

MOV     AH,02     ; Put the service number in AH
MOV     DL,41     ; ASCII number for "A" in hex
INT     21        ; Execute interrupt
Here is a small program that uses int 21 services to print "Hello world" on screen:

DOSSEG                         ; We are using DOS segment
.MODEL SMALL                   ; Defines how much memory our program needs
.STACK 100h                    ; Reserves 100h bytes for the stack
.DATA                          ; Under this we shall put our variables
MESSAGE DB 'Hello world',13,10 ; Our message
.CODE                          ; This is where our program starts
MOV AX,@DATA                   ; Put the address of the data in AX
MOV DS,AX                      ; And then move it to DS
MOV AH,9                       ; Select DOS int 21 output service
MOV DX,OFFSET MESSAGE          ; Put the offset of MESSAGE in DX
INT 21                         ; Print the message on the screen
MOV AH,4C                      ; Select service to quit and exit to DOS
INT 21                         ; And execute it
END                            ; End of the program
OK, type this in a text editor like DOS "edit" and save it as hello.asm. Then compile it with TASM or any other ASM compiler. The compiler creates a hello.obj file. You have to link the .obj file to get the executable file. If you save the file as hello.asm. This is what you have to do:

tasm hello.asm
tlink hello.obj

And then you'll have the executable file hello.exe. You can see the difference between BASIC language and assembler language right here. In BASIC we wrote only 3 lines of code, but in assembler we can control everything and get it exactly as we want it.

Here is a small list of services of interrupt 21:

      Function           Num                    In/out data
--------------------     ---     -----------------------------------------
Input from keyboard      01      AL contains the typed char after
with echo to screen              the int has been executed.

Print char on screen     02      DL contains the char to be printed.

Print string             09      The segment:offset of the string
on screen                        is taken from DS:DX.

Create file              3C      CX attributes of the file, DS:DX
                                 pointer to the name of the file.
                                 Returns AX handle or error code.

Open file                3D      AL access and sharing modes, DS:DX file
                                 name. Returns AX handle or error code.

Read from file           3F      BX handle, DS:DX pointer to data
                                 buffer. Returns AX number of
                                 bytes read or error code.

Write to file            40      BX handle, CX number of bytes to write,
                                 DS:DX pointer to data buffer. Returns
                                 AX number of bytes written or error code.
Most usual non-file handles:

0 = Standard input, usually the keyboard.
1 = Standard output, usually the screen.
2 = Standard error, usually the screen.
3 = serial COM1.
4 = parallel LPT1.

Let's write another program with the information above:

dosseg
.model small
.stack 200h
.data
password db 'fender','$'        ; The strings and data we shall use
login    db 100 dup (0)
rig      db 'correct','$'
.code
mov     ax,@data
mov     ds,ax
mov     ah,3fh                  ; Read function from int 21
mov     bx,0                    ; Handle 0 (keyboard)
mov     cx,3                    ; Just check the 3 first letters
mov     dx,offset login         ; Offset in DX
int 21h
and     ax,ax                   ; See if something was typed in
jz      fin                     ; No? So end
mov     cx,ax                   ; Move the number of bytes read into CX

mov     ax,seg login            ; Put segment address in AX
mov     es,ax                   ; So we can put it in ES
mov     ax,seg password         ; Same here but with another string
mov     ds,ax                   ; And store it in DS
mov     di,offset login         ; Do the same with the offsets
mov     si,offset password      ; of both strings
repe cmpsb   password,login     ; Compare them
je      equals                  ; If equal then go to equals

fin:                            ; End program function
mov     ah,4ch
int 21h

equals:                         ; Subroutine for strings equal
mov     dx,offset rig
mov     ah,9
int 21h
ret
end
This is a simple password checking program. @DATA is a predefined variable that holds the address of the DATA field we reserved at the beginning of the program. You may be wondering why we first put @DATA into AX and then into DS, can't we just put it into DS with MOV DS,@DATA? No, we can't. You can't put values in DS or ES directly. You have to read them into another register and then into the DS or ES registers.

Now I suggest you either buy a book on this subject or search the Web for some more information about the assembler language. Remember that experimenting is very important.

Alright brothers and sisters, I'll leave the assembler tutorial here and move on to Softice.

SOFTICE DOS VERSION 2.62

Note: do not use Softice 2.8.

Alright, have you installed it? Then add it in your config.sys. When DOS has been loaded press Ctrl-D and you're in. Great, isn't it? But what the hell is it?

Softice is a debugger, it can be used to see what a program is doing. For example, if you load one of the programs that we wrote in the assembler tutorial, you will see the code as it executes. That's why we use a debugger to make cheats and cracks. The only difficult thing is to find the code we are looking for. If we wanna change the number of lives in a game we have to find where the lives are stored. Once we find that place we can modify the value. This is what we'll do at the end of this lesson.

OK, here is what you should see in Softice. The registers are at the top. Then the data window and the code window. At the bottom you enter the commands. Read the whole Softice manual before proceeding. Read it? Great!

What we'll do now is to change the first program we wrote. The one that printed "Hello world" on the screen. If you have read the manual you should know all about breakpoints and how you change code in memory, etc. Here is what we'll do:

  1. Load the program into Softice:

    LDR hello.exe

  2. Have a look at the code, you should recognize it.

  3. Put a breakpoint on int 21 (write to file or device):

    BPINT 21 AH=40

  4. Let the program execute, it will stop when instruction int 21 AH=40 comes up.

  5. Let's see what is in DS:DX:

    D DS:DX and look at the data window. There is our "Hello world" string.

  6. Now let's change that:

    E

    Now you are in the data window and you are able to change the string to whatever you want. Try and see. When you're done changing the string just hit enter and you'll see that the program prints your changed string instead of "Hello world" that it was supposed to do. Great huh!

Try to debug other programs and change their output, you'll learn a lot doing that. Cracking is also something that is both, funny and educational. I promised a cheat for a real game, didn't I?

AQUANOID

Aquanoid is a breakout game which is available free on the Web (happy puppy, download.com, etc.). We will change the number of lives that the programmer gave us to something that we think is more suitable :)

LDR aqua.exe

Now let's think! Every time we miss the ball the lives decrease. We just need to find where the number of lives is stored. How? Beats me.

THE END

No, just kidding, the summer is affecting me in some strange way. Where were we? Yeah, right now we are looking for a place in memory that changes every time we miss the ball. And it should only change by decreasing or increasing by 1. Here is what to do.

Snap_save the whole DS block. Snap takes a snapshot of that register so that you can compare it later and see what has changed. Play the game until the ball is going off screen (when you just missed it). Switch to Softice and do a snap_save of the DS register:

SNAP S DS:0 DS:FFFF

Now switch back (Ctrl-D) and let the lives be decremented. When you've lost a life switch back again to Softice and do a snap_compare:

SNAP C

A row of numbers will now display all the changes. Since you had 6 lives at the start, you will now have 5 after you died. The number of lives can change in two ways, it can either start from 0 or 1 and increase until it reaches 5 or 6, or it could start from 6 and decrease down to 1 or from 5 to 0 which is most likely. Look for these changes. If you find a place that changes from 6 to 5 write the address down. Remember that after the address is the old value and after that is the new value, so this is what you are looking for:

XXXX:XXXX 05 04

or

XXXX:XXXX 06 05

Actually there's a lot of changes in memory every second, that's why you must snap_save the DS register just before you die. Hey look, there's a change from 06 to 05. Write that address down and keep looking. Keep scrolling through the list. Yeah, I know it takes 1-3 minutes but that's alright, I think. This is the funny part where you try to locate the code setting up different traps you can think of. In this case we used the command snap_save. In another case we might use a breakpoint.

As you can see there was only one change from 06 to 05. Remember when I told you that the segment address a program is given depends on the amount of available memory and hence on the programs previously loaded (memory configuration). Therefore my segment addresses will not be the same as yours. So the address is:

CS:0004

Let's view that address while we keep loosing lives:

D CS:0004

As you can see it decreases every time we lose a life. Let's change the value on that address:

E CS:0004

Change it to whatever you fancy, e.g. 11h = 17 lives, and keep on playing the game and notice how many lives you have, nothing happens the first 11 times you loose, but then it ticks down. Let's find the decreaser:

BPM CS:0004 W

The W means write only. The program will stop when something is written at CS:0004. Loose another life and BANG!, you're in Softice again facing the code that decreases the number of lives. The instruction looks like this:

CS:39A9 FF8C44AC        DEC WORD PTR [SI+AC44],+00

Replace that with a NOP:

A CS:39A9

CS:39A9 NOP

Play some time and you'll see that the number of lives is always the same, it is not decreasing anymore. Great huh!

OK, let's make this cheat a permanent one. See the letters and numbers before the instruction (mnemonics). The instructions we changed was:

FF8C44AC        DEC WORD PTR [SI+AC44],+00

We replaced it with NOP. Let's search using our hex editor the string FF8C44AC. There are two hits, let's just change the first one. Replace the FF8C44AC with 90909090 (90 is NOP in machine code). Save the file and wow it works, we made a cheat. Feels good, doesn't it? Well, that's all about it for now. See you in Lesson #3.

All opinions on my work are welcomed. Please feel free to ask questions at my e-mail indian_trail@hotmail.com.

INTERESTING LINKS

You can find the best Softice DOS version at ftp://ftp.sai.msu.su/pub/dos/hackers/s-ice262.zip.

Study the page http://cracking.home.ml.org, it has a lot of useful information. Here is also the Windows version of Softice plus all the manual (you'll need it later, so you might get it as well).

Aquanoid is available from http://download.com.

The Randall server is at http://webster.ucr.edu.


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