Training Tutorial for the PC by The Untouchables (UNT)
20 of 35 files
the untouchables
- Browsers may flag this download as unwanted or malicious. If unsure, scan it with VirusTotal.
-
Last modified Jun 29, 2003 5:40:25 PM
MD5 checksum 1a7cc05b9d35e74ea409e45c74b813c6
Mime type Zip archive data
Download tt-unt.zip
Size 35 kB
1993 May 5
- Text / Guides and how-tos
- Dr Detergent, writer credits
10 items in the archive
- UNT.NFO
- TT-UNT.DOC
- PP2T-TSR.COM
- PP2T-LDR.COM
- PP2T-T&L.DOC
- FRT-TSR.COM
- FRT-TSR.DOC
- LOMT-TSR.COM
- LOMT-TSR.DOC
- FILE_ID.DIZ
▀▄
█
▄▄▄ ▄
▓█████▄ ▄▀
▓▓█████▌ ▄█▀
▓▓███████▄ ▄▄██▀
▄ ▄▄ ▓▓███████▀▀█▄▄▄▄▄████▀▀▀
▀ ▀ ▄ ▓▓▓█▓▓████▄▄ █▀▀▀▀
▐█ ▓▓█████▓██▀█▀▀▄▌
█ ▓████████▄█▄▄███
▀▓█ ▓████████████████▄ · ▄
▄▀ ▓███████████████████▄ ▐
▓█████████████▌██▀▀███▄
▓███████████████▄██▄▄██▀ ▐ █
▓███████████████████▄ ▐▌ ▐
▓██████████████████▀ ██ ▐
▓█████████████████▄ ██▄ ▌
▄ ▓▓█████████████████ ▐██▀ ▌▄
▄▓▓▄▄▀▓██████████████▓▀ ▐█▌▌ █▌ ▀ ▄▄
▀▓▓██████████████████▄ ▄▄█▀▐▌ █▌ ███▓
▀▓█████▀████████████ ▄█████▌▐▌ █▌ ▐███▓
▀█████▄░█████████▌ ███████ █ █ ████▓
▀█████▄███████▀ ███████▌ █ █ ███ ▄
▀██████▄▀▀ ███████▀ ▌ ▐█ ███▄█
▀███████▄ ▐██████▄ █ ████▄▀▓▄
▀ ▀███████▄ ██████▓▓█▄ ▄█ ████████
▀▄ ▀▀▀███████▄▄▄ ▐██████▓▓▌ █ ▄████████
░▀ ▀▀▀▀█████▄▄▄ ███████▓ ▀ ▄▓███████▌
▀▀▀█████▄▄▄ ▀▀██▓▓▌ ▄▒▓███████
▀▀▀▀███▄▄▄ ▀▀▄ ▒▓▓███████▌
▀▀▀▀▄ ▄▄ ▄░▒▓▓██████
▀ ▀▀░▒█████▌
▀█▄ ▓░░████
▐▓░███▌
█▓█▀▀▀
▀▀
▀█▀ ▀█▀ ▄ █ █ █ ▄▀▀▀▀▄▀
█ █ ▄ ▄▄ ▀▄▄▄ ▄▄ ▄ ▄ ▄▄ ▐▌▄▄ ▄▄ ▐▌ ▄▄ ▐▌ ▄▄▄ ▀█▄▄
█▄ ▄█ █ █ ▄ ▀ █▀ █ ▐▌ ▐▌ █ ▀ ▐▌ ▐▌ ▄▀ ▄ ▐▌▀ █ ▐▌▄▀ ▄▀▀ ▀▀█▄
▀▀▄ ▄▀▀ ▐▌ ▐▌ ▐▌ ▄▄▄▀ ▀▄▄▀ ▐▌▄▄▀ █ █ ▀▄▄█▀▄ █ ▄▄▀ █ ▀▄▄▄ ▄▀▄▄▄▄▀
PRESENT :
╔══════════════════════════════════════════════════════════════╗
║ ║
║ Training Tutorial for the PC. By Dr. Detergent / UNT'93 ║
║ ║
╚══════════════════════════════════════════════════════════════╝
Table of contents
═════════════════
Section:
════════
1 - Introduction.
2 - Before starting.
3 - Debugging through.
4 - Different file compression techniques.
5 - Once inside the game's code.
6 - Most common training byte structure composition.
7 - Searching for the most common training byte structure composition.
8 - Problems finding the most common training byte structure composition.
9 - Setting the break points.
10 - Once you have found the trainer data.
11 - Making a "hard-cheat"
12a - Generic trainer interfacing routine.
12b - Interfacing to the game's keyboard routine.
12c - Finding the game's keyboard handling routine.
12d - Prince of Persia II keyboard handling routine listing.
13 - Handling different DS values.
14 - Writing the trainer loader or TSR code.
15 - Generic TSR self-removal routine.
16a - Generic trainer code interfacing routine.
16b - Prince of Persia II interactive trainer interfacing routine.
16c - Finding the runtime CS:IP of the keyboard handling routine.
16d - Comparing the program's current IP.
16e - Interfacing with different keyboard handling routines.
17 - Fox Ranger Interactive 9 option trainer routine listing.
18 - Legend of Myra Interactive 10 option trainer routine listing.
19 - Interactive TSR/loader trainer examples.
20 - Summary.
╔═════════════╗
║ Section 1 ║
╚═════════════╝
Introduction:
═════════════
Every game player has at some point during gameplay, wished that he/she had
more lives/energy/weapons/time etc - just to be able to finish that level or
see the game's ending for that matter.
Have you ever played a game for months, each time getting better and better,
finally you make it to the last level only to find that the monster at the
end is impossible to kill even with all your past experience?
Ever play a game for 5 hours and finally get to the last level - just before
the ending intro, and suddenly get killed by some small rodent - and have to
restart all over?!
Well I am sure you have experienced the above. This is why hackers/crackers
developed a kind of "Training Aid" if you want to call it that. The
terminology training means to bring an individual to a higher degree of
success through practice. In computer terms, the phrase training was
developed by hackers on the C-64/Amiga.
Whenever someone played a game and couldn't finish it, when using a trainer,
the person could train on the last level and become proficient in the skills
required in mastering that level, then he could turn off the trainer and try
his newly acquired skills in the real thing.
The term CHEAT as some people refer to, is not a good description of what a
real trainer actually is. Most trainers are interactive, meaning that they
let you toggle certain things on/off or select different items during game
play - a cheat however, mostly gives you straight away unlimited lives/items
etc and rarely let's you "train" while playing the game.
Training games has been going on for ages. It started back as far as the
C-64, maybe even further. It has seen it's days on all the computers that
one can use to play games.
Training was revolutionized mostly on the Amiga computer. The games for the
Amiga are outstanding, and so are the trainers. I have seen trainers for
some games that I thought were the game itself.
On the PC, training started the day that games were designed for it. Since
it's early days, training on the PC has revolutionized from small
"cheats/character editors" to todays interactive, multi-functional, user
defined, mega-trainers.
This Training Tutorial was written for those who always wondered how one
makes trainers on the PC, and it portrays this art to you. Never the less,
it all depends on you - how good you are with understanding the assembly
language and programming.
I'm confident that your average ASM programmer or hacker will find the
information herein helpful and useful.
Through my many years of training on the PC, and after developing more than
285+ trainers/cracks, I have learned lots of different tricks and methods
that I will reveal to you in this training tutorial.
╔═════════════╗
║ Section 2 ║
╚═════════════╝
Before starting:
════════════════
First, you must have a general knowledge of debugging software and ASM
programming. Before you begin to even think about training a certain game,
ask yourself the following questions :
1) Has a trainer already been released for that game - sometimes you spend
hours training a game only to find out just before you are about to
spread it world-wide, that there already is a trainer out for it - and
it is even better then yours!
2) Is the game trainable - if yes, what items/things can it be trained for?
You will be surprised how many requests I had to make trainers for
games that are not trainable - like text adventure games! - so make sure
that at least something in your game is trainable.
3) Is it worth it - are you going to spend 5 hours training a shareware
pacman-type game?!
4) Can you handle the code - do you think you can get by the game's nasty
encryption/anti-debugging routines or script-compiler type code?
5) Will you be able to make the trainer - do you think that you can write
the code that will integrate your trainer with the game and be able to
modify the necessary data? Sure you can find the necessary data to
alter in the program, but can you write up a TSR or a loader that can
integrate itself to the game's code and modify the necessary data
locations?
Once you have asked yourself the above questions, and feel confident about
your answers, then proceed to section 3.
╔═════════════╗
║ Section 3 ║
╚═════════════╝
Debugging Through:
══════════════════
This section deals with debugging the game program. It will outline the
various debuggers you can use, various compression methods and how to get
through them.
Before we even begin - what debugger are you going to use? Ok, I will
make this question simpler - if you have a 386+ CPU, what debugger are you
going to use?
That's right - SOFT-ICE 2.52+!. This is the best debugger. Below are
some other debuggers listed in priority order, you might consider using:
Turbo Debugger 386+
Code View 386+
Any other 386+ virtual mode debugger
Turbo Debugger 286-
Code View 286-
Periscope
Debug.exe
Ever since I have been cracking/training games, I have never seen a more
powerful or complete debugger than Soft-Ice. Now don't think that you have
to have Soft-Ice to train, I have used debug on my XT / CGA to train
some complex VGA games, - not even being able to see the screen, and having
the trainer tested on my friends VGA, back in the old days.
You can train a game with ANY debugger and still make a good trainer at
that. But using soft-ice will speed up the process extremely and yield the
best results. That's why in some examples here I will use Soft-Ice as the
main debugger.
Ok, so you are not lame, and do have a 386+ chip, vga, extended memory,
and soft-ice loaded. Now you have your game neatly installed and ready to
be debugged and trained.
Now you have to find the start-up file. This is the EXE or COM loader that
starts the game. This is where you will find the necessary data to train
your game - 95% of the time. Remember that the EXE/COM loader can load up
an OVR or a BIN file, so if the start-up file is really small like 5 k, then
you know for sure it's going to load in some overlay code.
Ok, so use soft-ice's LDR.EXE to load up the start-up file (or debug the
file with another debugger). Now unassemble the first instructions and
study the code. Try to determine if the code is compressed by something
like LZEXE, PKLITE, DIET, EXEPACK, Secure-Wrap or some other COM/EXE file
compressor.
You can skip this step if you know how to write a loader or a TSR.
Otherwise, this step gives you an idea if you can or can't train the
program - if you can't write a TSR or loader, then how can you interface and
change the necessary data in the game if it's encrypted? (Even if you knew
at what location the lives decrementing instruction etc is, searching the
EXE/COM file with a hex editor to do a hard-train will yield no results)
╔═════════════╗
║ Section 4 ║
╚═════════════╝
Different file compression techniques:
══════════════════════════════════════
Here are some examples of the different compression techniques used on
COM/EXE files:
╔════════════════════════╗
║ PKLITE 1.20 (COM File) ║
╚════════════════════════╝
0100 B8BDE2 MOV AX,E2BD
0103 BA2284 MOV DX,8422
0106 3BC4 CMP AX,SP
0108 7367 JNB 0171
010A 8BC4 MOV AX,SP
010C 2D4403 SUB AX,0344
010F 25F0FF AND AX,FFF0
0112 8BF8 MOV DI,AX
0114 B9A200 MOV CX,00A2
0117 BE7C01 MOV SI,017C
011A FC CLD
011B F3 REPZ
011C A5 MOVSW
011D 8BD8 MOV BX,AX
011F B104 MOV CL,04
0121 D3EB SHR BX,CL
0123 8CD9 MOV CX,DS
0125 03D9 ADD BX,CX
0127 53 PUSH BX
0128 33DB XOR BX,BX
012A 53 PUSH BX
012B CB RETF ;*** RETF Instruction ***
012C 0C01 OR AL,01
012E 50 PUSH AX
012F 4B DEC BX
0130 4C DEC SP
0134 20436F AND [BP+DI+6F],AL
0137 7072 JO 01AB
0139 2E CS:
* Note the RETF instruction at 012B. This instruction when encountered in
the beginning of the code like this, nearly always gives an indication
that the file is compressed.
(The code after 012B is just compressed garbage. When you see garbage
after a RETF instruction, found in the beginning of the code, than you are
nearly sure that the file is compressed by something)
╔═══════════════════════╗
║ LZEXE 0.91 (EXE File) ║
╚═══════════════════════╝
000E 06 PUSH ES
000F 0E PUSH CS
0010 1F POP DS
0011 8B0E0C00 MOV CX,[000C]
0015 8BF1 MOV SI,CX
0017 4E DEC SI
0018 89F7 MOV DI,SI
001A 8CDB MOV BX,DS
001C 031E0A00 ADD BX,[000A]
0020 8EC3 MOV ES,BX
0022 FD STD
0023 F3 REPZ
0024 A4 MOVSB
0025 53 PUSH BX
0026 B82B00 MOV AX,002B
0029 50 PUSH AX
002A CB RETF ;*** RETF instruction ***
002B 2E CS:
002C 8B2E0800 MOV BP,[0008]
* Note the RETF instruction at 002A.
╔═══════════════════════╗
║ DIET 1.10a (COM File) ║
╚═══════════════════════╝
0100 BE5409 MOV SI,0954
0103 BFDC13 MOV DI,13DC
0106 B91404 MOV CX,0414
0109 3BFC CMP DI,SP
010B 7204 JB 0111
010D B44C MOV AH,4C
010F CD21 INT 21
0111 FD STD
0112 F3 REPZ
0113 A5 MOVSW
0114 FC CLD
0115 8BF7 MOV SI,DI
0117 BF0001 MOV DI,0100
011A AD LODSW
011B AD LODSW
011C 8BE8 MOV BP,AX
011E B210 MOV DL,10
0120 E96D12 JMP 1390
0123 64 DB 64 \
0124 6C DB 6C / Garbage from here onwards.
╔════════════════════════╗
║ EXEPACK ??? (EXE File) ║
╚════════════════════════╝
0010 8BE8 MOV BP,AX
0012 8CC0 MOV AX,ES
0014 051000 ADD AX,0010
0017 0E PUSH CS
0018 1F POP DS
0019 A30400 MOV [0004],AX
001C 03060C00 ADD AX,[000C]
0020 8EC0 MOV ES,AX
0022 8B0E0600 MOV CX,[0006]
0026 8BF9 MOV DI,CX
0028 4F DEC DI
0029 8BF7 MOV SI,DI
002B FD STD
002C F3 REPZ
002D A4 MOVSB
002E 50 PUSH AX
002F B83400 MOV AX,0034
0032 50 PUSH AX
0033 CB RETF ;*** RETF instruction ***
0034 8CC3 MOV BX,ES
0036 8CD8 MOV AX,DS
0038 48 DEC AX
0039 8ED8 MOV DS,AX
* Note the RETF instruction at 0033.
╔══════════════════════════════════════════╗
║ Some other compression method (EXE File) ║
╚══════════════════════════════════════════╝
000C 8CD3 MOV BX,SS
000E 8EC3 MOV ES,BX
0010 8CCA MOV DX,CS
0012 8EDA MOV DS,DX
0014 8B0E0800 MOV CX,[0008]
0018 8BF1 MOV SI,CX
001A 83EE02 SUB SI,+02
001D 8BFE MOV DI,SI
001F D1E9 SHR CX,1
0021 FD STD
0022 F3 REPZ
0023 A5 MOVSW
0024 53 PUSH BX
0025 B82E00 MOV AX,002E
0028 50 PUSH AX
0029 8B2E0A00 MOV BP,[000A]
002D CB RETF ;*** RETF instruction ***
002E B80010 MOV AX,1000
0031 3BC5 CMP AX,BP
0033 7602 JBE 0037
0035 8BC5 MOV AX,BP
0037 2BE8 SUB BP,AX
0039 2BD0 SUB DX,AX
003B 2BD8 SUB BX,AX
003D 8EDA MOV DS,DX
003F 8EC3 MOV ES,BX
0041 B103 MOV CL,03
0043 D3E0 SHL AX,CL
0045 8BC8 MOV CX,AX
0047 D1E0 SHL AX,1
0049 48 DEC AX
004A 48 DEC AX
004B 8BF0 MOV SI,AX
004D 8BF8 MOV DI,AX
004F F3 REPZ
0050 A5 MOVSW
0051 0BED OR BP,BP
0053 75D9 JNZ 002E
0055 FC CLD
0056 8EC2 MOV ES,DX
0058 8EDB MOV DS,BX
* Note the RETF instruction at 002D.
So basically you get the picture. Now to trace through the code to the part
where the whole program uncompresses itself is really easy.
First, always remember to TRACE or PROCEED through any RETF instruction.
In most cases there is only one RETF instruction to trace or proceed
through. Then once you traced or proceeded through it, you will be either
at CS:0000 or somewhere else. The next step is simple too - Just
unassemble the code until you find the following instruction:
CS:
JMP FAR [BX]
Once found, simply go to the address containing CS:, then trace or proceed
through. Now you should have the clean uncompressed code. If you did not
find the above instruction, then try looking for another RETF instruction.
Once found go to it and trace or proceed through and you should have the
clean uncompressed code.
Remember some files may be compressed with 2 compression programs
(for "added protection" as software authors think!). If so, simply perform
the above steps twice.
Finding the part of the program that the file starts up at is helpful in 2
ways :
1) You are sure that the program didn't start executing any instructions
yet - like moving lives/energy etc variables into memory.
2) You can note the CS, DS, or any other memory variables so that when you
do write up a TSR or a loader, you will be able to interface it easier.
Note:
═════
(You need to know the program's current CS,DS upon startup, if you are
going to write the generic tsr or loader trainer interfacing routine as
outlined in section 12a).
If you don't care about getting to the program's very beginning, and just
want to get through the uncompression as fast as possible, then if using
soft-ice, set a break point on INT 21 - it will break in when the program
does a DOS VER check, a memory allocation call or any other function using
INT 21. All games and most programs have INT 21's present in their program
code.
Some of you might even want to start the game, get the game fully running,
and then break into the debugger. I use this method. Doing this has some
goo d points and some bad points. The good points might be that the CS,DS
values are already redefined and you more or less see where the program
keeps it's data values. Some bad points might be that you have skipped
past the value-initialization routine (of the lives etc). If you are
unexperienced, then I recommend that you do not use this method.
Some software programmers put anti-debugging routines in their software code
to deter hackers/crackers from cracking their software. This works to the
trainer's disadvantage - sometimes. I'm not going to describe the various
anti-debugging methods and their antidotes in this training tutorial - learn
all about it in the upcoming "Cracking on the PC - THE mega tutorial!"
╔═════════════╗
║ Section 5 ║
╚═════════════╝
Once inside the game's code:
════════════════════════════
Ok, so you are in the program now. What now? A lot of people have asked
me what's harder to do - crack a game or make a trainer for it. Well it
depends really. Some games can be cracked in 5 minutes, while making a good
trainer can take 8+ hours. But in general I think making trainers is a bit
more difficult than cracking. Mostly because making a trainer will always
consume more time - at LEAST 1 hour to find/make/write/package the
trainer.
Also, when cracking a game, you isolate the protection in a certain area of
the program, then focus all your attention on it and crack it. When
training a program, you are looking through everything, everywhere,
gathering all sorts of unnecessary data before finding the right bytes, let
alone understanding the game code operation.
But once again, there are short cuts to everything. This is why training
might be easier that cracking after all. Every program uses more or less
the same technique to decrement/increment your lives/energy/ammo/inventory
items, etc.
Through my years of training, I have narrowed it down to the most common
byte structure composition, as outlined in section 6.
╔═════════════╗
║ Section 6 ║
╚═════════════╝
Most common training byte structure composition:
════════════════════════════════════════════════
= DECREMENTING =
Decrementing or subtracting means to decrease a certain thing. The game
uses various decrementing instructions to decrement (or subtract if you
like) your lives/energy/time/ammo/weapons/inventory items etc.
The following is a list of the most common decrementing instructions that
games use:
DEC WORD PTR [1234] - ████
In HEX : FF 0E 34 12
DEC BYTE PTR [1234] - ████
In HEX : FE 0E 34 12
SUB WORD PTR [1234],XX - ▒▒
In HEX : 83 2E 34 12 XX
SUB BYTE PTR [1234],XX - ░
In HEX : 80 2E 34 12 XX
SUB [1234],AX - ▒▒
In HEX : 29 06 34 12
SUB [1234],DX - ░
In HEX : 29 16 34 12
= INCREMENTING =
Incrementing or adding means to add a value to a certain thing. The game
uses various incrementing instructions to increment (or add if you like)
your current level/energy/time/ammo/weapons/inventory items etc. The
following is a list of the most common incrementing instructions that games
use:
INC WORD PTR [1234] - ████
In HEX : FF 06 34 12
INC BYTE PTR [1234] - ████
In HEX : FE 06 34 12
ADD WORD PTR [1234],XX - ▓▓▓
In HEX : 83 06 34 12 XX
ADD BYTE PTR [1234],XX - ▒▒
In HEX : 80 06 34 12 XX
Legend :
════════
████ - Very common - nearly 100% probability.
▓▓▓ - Common - about 70% probability.
▒▒ - Likely - about 40% probability.
░ - Sometimes - about 10% probability.
╔═════════════╗
║ Section 7 ║
╚═════════════╝
Searching for the most common training byte structure composition:
══════════════════════════════════════════════════════════════════
By now you should be in the program viewing the uncompressed code. Simply
start searching for the above bytes - depending for what you are looking
for. For starting out, you should not be concerned with searching for the
incrementing or adding instructions - these instructions are used for
incrementing levels in the game, or inventory, etc. Training for those
options is much harder at first, so stick to the decrementing instructions.
So now start searching for the most common decrementing instruction - mainly
the DEC WORD PTR [XXXX]. I will use this example because it's the most
common decrementing instruction that you will find. Obviously you can, and
you should, search for the other less common decrementing instructions too.
The following search example can be used to search for all the decrementing
and incrementing instructions.
Example:
════════
S CS:0 L FFFF FF 0E (Works with most debuggers)
Note:
═════
We only search for the first 2 bytes of the DEC/INC instruction because the
3rd and 4th bytes contain the value of the address where the DEC/INC is
going to take place.
To make things simpler, let's assume that you are searching for the above
example (DEC WORD PTR [XXXX]). I will use this example from now on.
Remember, you can apply this example the same way to search or process all
the other DEC/INC instructions, as outlined in section 6.
╔═════════════╗
║ Section 8 ║
╚═════════════╝
Problems finding the most common training byte structure composition:
═════════════════════════════════════════════════════════════════════
If you didn't find anything, or just a few DEC's that are not related to
anything, then it's because of the following :
1) You are looking in the wrong CS. Some games have many different CS
values. If the program's current CS is 1200, and you search for the DEC
bytes and find about 4, and then run the program, break in again, and
notice CS is 2245, and search for those bytes again, you might find 30
or more, so make sure you search all the possible CS values in the game.
It's hard to break in, just hoping to find the next CS value in the
game - if any. A good technique is to search like this:
Find the lowest CS value in the game, - eg: 0900.
Then search CS:0 l FFFF FF 0E
Then search 2000:0 l FFFF FF 0E
Then search 3000:0 l FFFF FF 0E
Then search 4000:0 l ffff FF 0E
Etc - get it? If the CS is always high during the game, and you never
seem to be able to break in when it's lower, then start the search at
about 0800, and then proceed higher.
2) The second possibility (if you didn't find anything after searching for
all the listed decrementing instructions) is that the game is using a
different decrementing instruction.
3) The third possibility is that the game's code is a script-compiler type
code. You can forget about training this type of game - even if you are
an experienced trainer maker. But if you can train it, then you belong
to the TOP-GUN trainer makers!
The Script-compiler type code is found in such games from Sierra,
Delphine Software, Lucas Arts and CVS. It is a programming method
which uses pre-defined scripts to run certain program operations.
Everything from producing the sound on the sound blaster to drawing the
graphics on the screen is done all in the same program loop - using
different scripts. Therefore training, or even cracking this type of
game is really a pain, but never the less, can be done.
╔═════════════╗
║ Section 9 ║
╚═════════════╝
Setting the break-points:
═════════════════════════
From the search, you should have found quite a few of those decrementing
instructions in the game's loader. If you are using soft-ice, note the
current CS and write it down. Then unassemble that address, study the code
and make sure it's a valid decrement, then set a break point on execution
(BPX in soft-ice) for about the first 8 of the found DEC WORD PTR [XXXX]
instructions.
The reason for unassembling the found instructions first and then putting a
break point on execution - as with soft-ice, or a CC, as with other
debuggers, is because the bytes FF 0E can represent any other code or data
value in the program. When you unassemble that address where the bytes FF
0E where found and study the code, if you see that the prior or following
instructions are garbage or don't make sense, then don't bother setting a
break point on that address since it's not going to be executed anyway.
If you are not using soft-ice, do the above but instead of setting a break
point on execution, replace the first byte of the DEC instruction with CC -
so it will look like this :
Example:
════════
Original found instruction : FF 0E 34 12
1st byte replaced by CC : CC 0E 34 12
This will put an INT 3 at the beginning of that instruction. Your debugger
should break on INT 3 when it executes that instruction. Do this for about
the first 8 of the found DEC WORD PTR [XXXX] instructions.
Now why did we do the above? Well we want to see which one of the
decrementing instructions decrements the lives/energy/timer etc values. So
the next step is to run the program.
Get by the introduction screen, etc and start playing the game. (If your
debugger breaks in even before you get to the game, then simply remove that
break point on execution from that address - if using soft-ice, or
replace the CC value with FF. This is done since that instruction won't
have anything to do with decrementing your lives/energy/timer etc in the
game - since the game has not even started yet.
Once your game starts, and the debugger breaks in right away - simply run
the program again. If the same thing happens more than about 3 times, and
it always happens at the same address, then remove the break point on
execution from that address - if using soft-ice, or replace the CC value
with FF. The reason for this is because the game might be using that
instruction to do something else other than decrementing your
lives/energy/timer etc.
The next step is to try and get killed, or use your gun and waste a few
bullets, or do something like that - to see if any inventory options,
gadgets, energy bars, life counters, etc, are being decremented. If they
are, you will suddenly find yourself in the debugger. Suppose you just got
shot and even before you saw your energy bar decrease, the debugger broke
in. The first thing that you do is write down that address - CS:XXXX. Then
see what value is being decremented at that address.
Example:
════════
The debugger broke in at 45C8:
1170:45C7 RET
1170:45C8 DEC WORD PTR [0320]
Now simply view what is at that address (There is no CS:, ES:, or SS:
above the 45C8 instruction, so you know the default is DS:):
D DS:320 (Using soft-ice, or use your debugger's dump command)
If you energy bar has for example 6 energy bars, and the value at DS:0320 is
06, then you know you could very well have found the address where the game
stores your current energy value.
Now the next step is to check if that address is indeed the current energy
value storage address. Simply enter FF at DS:320 and then run the game
again - notice anything different - more energy bars? If so, you found it.
If not, then maybe you still found it, but there is another routine that
updates the screen with the current energy value.
So the next step is to NOP out that DEC instruction at that address. But
instead of doing that, simply replace the first 2 bytes of the DEC
instruction (FF 0E) with EB 02 - thus jumping to the next instruction. This
is useful if you ever want to restore that DEC instruction back - all you
have to do is replace EB 02 with FF 0E.
If you NOP it out completely, not only do you have to put NOP 4 times, but
you are erasing the address value of the DEC instruction so unless you wrote
down the address, you will have to restart the program to restore back that
instruction.
Ok, so you replaced the FF 0E with EB 02. Now run the game and notice if
some things are different - does the timer still go down, or are the enemies
still moving etc. Now get your energy to go down. If you notice it go
down, keep on getting hit until the whole energy bar declines. If it does,
and you are still alive, then the game has 2 separate routines for storing
and displaying the energy bar. (Maybe another DEC instruction, which you
have not yet processed, is responsible for this).
If you died, then try something else now. Try to waste some
bullets/inventory items etc. If they all decrement and nothing is different
in the game, than that DEC instruction does something else in the game.
Repeat the search command, as outlined in section 7, and process the next 8
DEC instructions. Do this until you have gone through them all. You should
find at least some decrementing instructions which decrease something
like the energy/lives/timer/enemy energy/inventory etc. If not, then search
for the next most common decrementing string, mainly the FE 0E -
DEC BYTE PTR [XXXX]
If you don't find anything there, proceed again with the next most common
decrementing string - until you find something. If you still don't seem
to be able to find anything worthwhile, then refer to section 8.
NOTE :
══════
The code for some new games is written in a way that whenever you set a
break point on a certain address, the debugger won't break there. Instead
it will produce an error, or simply will skip over that break point and
continue running the program as if nothing happened.
This is especially noticeable when using soft-ice's BPX command. So if you
really think that you have found the right DEC/INC instruction, but
soft-ice does not break in, then use the same method of putting a break
point as for the other debuggers - by putting a EB 02 there at that address.
Now see if any changes occur in the game play.
What I sometimes noticed when debugging this type of game is that after I
set a break point on a certain dec instruction, run and play the game, get
hit, and notice that my energy/lives etc don't go down - and soft-ice
does not break in. What happens there is that the game's code jumps over
the dec instruction which has a break point on it, thus never executing it.
If you encounter this, then it is yet another indication that the game is
using this type of weird coding.
╔══════════════╗
║ Section 10 ║
╚══════════════╝
Once you have found the trainer data:
═════════════════════════════════════
So once you have found the locations where the game keeps all the goodies
- like your live/energy/timer value, etc, make sure you write down the
location of the DEC/INC instruction, and what memory area it decrements
or increments.
Once you become more experienced with training, you might take some time to
study the code next to the DEC/INC instructions and see if there are any
other goodies - like making your man be totally invincible to everything
etc.
There are also some built-in tricks that game authors put in - like a secret
cheat mode option etc, so the work might already be done for you. Sometimes
all that it takes is the value 01 at some memory location - and you have
everything set to unlimited etc.
A good way of finding this sort of thing is to trace into the decrementing
routine and study the code at the start of that routine - if they have a
CMP WORD/BYTE and then a JZ to the end of that routine, this could very well
be that WORD/BYTE you have been looking for. And if that's set, the whole
routine is bypassed and therefor there will be no decrementation of whatever
it was going to decrement.
Another thing you might check for, if looking for a secret built-in trainer
option in the game, is to check to see what command line parameters the game
checks for. Sometimes game authors put in secret command line parameter
options that activate the already built-in trainers. A good example is Wing
Commander from Origin. They have a secret command line parameter that
activates the game's built-in trainer.
Checking to see for what command line parameters the game checks is very
easy to do with soft-ice. Simply use LDR.EXE and load up the game's loader
with some garbage parameter string.
Example:
════════
LDR GAME.EXE testing
Now once in soft-ice, set a break point on memory range (BPM) at DS:0082 -
which points to your command line parameter "testing". Then run the program
and see what your "testing" string is compared to.
╔══════════════╗
║ Section 11 ║
╚══════════════╝
Making a "hard-cheat":
══════════════════════
If you don't know anything about writing a loader or a tsr, then you might
consider making a "hard-cheat" - this means that you simply will HEX edit
the game's loader file and search for the bytes that make up the DEC
instruction(s) and nop them out. To do this, you can use the following
method:
Write down the HEX string that the decrementing instruction is composed of.
Example:
════════
You found this code :
15FF C3 RET ;Returns somewhere
1600 FF0E0734 DEC WORD PTR [3407] ;This is your dec
1604 833E073400 CMP WORD PTR [3407],+00 ;This CMP's it
1609 7415 JZ 160C ;This JMPS if Zero
160B C3 RET ;Returns somewhere
160C C606020301 MOV BYTE PTR [0302],01 ;This sets a byte
1611 C3 RET ;Returns somewhere
Now simply note the byte composition at 1600 - FF 0E 07 34. You might
also want to take note of the following bytes (83 3E 07 34 00 74 15 C3) just
to be sure you have the correct address when you search for them.
Remember thou, lots of games have more than 1 DEC/INC instruction, so it
might be a good idea to search for only the first 4 bytes that compose that
decrement/increment instruction, that way you will find them all.
So now you wrote down those bytes. Quit the game and use a hex editor or
debug.exe etc, and search the game's exe or com file for those bytes. Once
found, nop them out and save the file. If you are using debug.exe to make
the changes, and want to edit an EXE file, make sure that you rename the EXE
file to an extension like DAT, prior to debugging it. This is because you
can't write to EXE/HEX files with debug.exe.
Note:
═════
Look at the instruction above, at address 160C - MOVE BYTE PTR [0302],01.
Whenever the word at DS:[3407] is 0, the byte at DS:[0302] is set to 1.
What do you think this does? Here is the advantage of studying the game's
code around the DEC/INC instructions.
The game will check to see if the byte at DS:0302 is 1 and then it will
display "GAME OVER" or something like that - but if you nop out that
MOVE BYTE PTR [0302],01 instruction, your lives/energy/ammo/time etc will
still go down, but the game won't end or you will still have unlimited ammo
etc - because, in this example, the game checks somewhere in the program,
the byte at DS:0302, not the value of DS:3407 to make it's decision whether
to end or continue the game, etc.
Entering 1 byte (00) at CS:1610 as for the above example, will not only save
you 4 nops at CS:1600, but might even make you a better trainer using a
"No-Touch" or invincible mode option - because the game might always "think"
that you are alive etc.
As you will see, there are many ways of training a game.
Note:
═════
If you don't know how to write TSR's or loaders, then study the interactive
TSR and loader trainer examples included in this training tutorial package.
╔═══════════════╗
║ Section 12a ║
╚═══════════════╝
Generic trainer interfacing routine:
════════════════════════════════════
By now you should have your addresses written neatly down on a piece of
paper. What now? Next step is interfacing your trainer with the game's
code.
There are many ways to interface your code into the game's code. I will
show you just the best one. I have seen so many people playing around with
the timer, having their own keyboard handling routines, hooking onto lots of
unnecessary interrupts - all this just to make a lousy 2 option "trainer".
Not only does this type of programming slow down the game, but it is much
harder and longer to write up this garbage code.
╔═══════════════╗
║ Section 12b ║
╚═══════════════╝
Interfacing to the game's keyboard routine:
═══════════════════════════════════════════
The following routine is the routine I use in all my trainers, and sometimes
cracks. Using this method, you can interface your code into practically any
software for the PC. It is by far the cleanest and best way to interface
your trainer into the game.
Practically all the new games today have their own keyboard handling
routine. The method in interfacing a trainer for those games who don't have
their own keyboard handling routine, is discussed in section 16e.
By now you should be still in the game. If you are not, simply restart the
game, and start playing it. Then break in with your debugger and set a
break-point on INT 9. To find the game's keyboard handling routine using
soft-ice, all you have to do is use the command BPINT 9, re-run the program
and press any key. You should now be in the game's keyboard handling
routine.
Note:
═════
Make sure you write down some bytes composing the beginning of the keyboard
handling routine. You will need them to search for that same routine again
- as referred to in the example, in section 14.
╔═══════════════╗
║ Section 12c ║
╚═══════════════╝
Finding the game's keyboard handling routine:
═════════════════════════════════════════════
The game usually saves the original INT 9 vector address and then redefines
the INT 9 vector address to point to it's keyboard handling routine. So
when you start debugging the game, trace it all the way until you notice
the INT 9 vector being redirected to another location. This is the location
that I'm referring to.
If you have problems finding the routine in the game's program code which
redirects INT 9, then you can do the following:
Start and play the game, then break in with your debugger and view the INT 9
vector address currently in the vector table (at 0000:0022).
Example:
════════
After you dumped 0000:0022 you see the following:
0000:0022 1F 10 20 AC XX XX XX XX XX XX XX XX XX XX XX XX
A B C D
Your main concern is with the first 4 bytes. I have named them A,B,C,D.
Now to find out where the game's keyboard handling routine points to, simply
view it this way:
BA:DC - now replace each letter with the value it stands for:
101F:AC20 - simple ey! - so if you set a break point on this address, and
then press any key, you will be right in the game's keyboard routine.
Once you set a break point on INT 9 or at the beginning of the keyboard
handling routine, run the game, and press any key. Your debugger should
break in. Now study the code. Below, in section 12d, is an example of the
beginning of a typical keyboard handling routine (taken from Prince of
Persia II).
╔═══════════════╗
║ Section 12d ║
╚═══════════════╝
Prince of Persia II keyboard handling routine listing:
══════════════════════════════════════════════════════
165D 1E PUSH DS ;Save current DS
165E 50 PUSH AX ;Save current AX
165F 53 PUSH BX ;Save current BX
1660 B8C03F MOV AX,3FC0 ;Move data-area value into AX
1663 8ED8 MOV DS,AX ;Move AX to DS
1665 E460 IN AL,60 ;*** Read keyboard port ***
1667 8AD8 MOV BL,AL ;Move read value in AL to BL
1669 D0C0 ROL AL,1 ;etc
166B 2401 AND AL,01 ;etc
Most keyboard handling routines have the same structure as the above. Note
the instruction at 1660 - MOV AX,3FC0 - this is the games data segment
address. This value is then moved to DS. Lots of games use this technique.
The above technique helps us a lot because your trainer doesn't always have
to find out what the game's current DS value is. This instruction is
nearly always present in the keyboard handling routines of most games.
The reason for this is as follows. Whenever you press a key in the game,
the game's current DS can be anything - because INT 9 will interrupt the
current operation of the program and execute the keyboard handling routine,
- with the DS value being whatever it was just before the INT 9 was called.
That is why the program has to reset the current DS address with the
predetermined DS address where it always keeps the key press values.
Most often, the DS address value used in the keyboard handling routine, is
the SAME as the DS address value for which the game uses to store it's
lives/energy/ammo etc values. - Sometimes this is not so. (Read "Handling
different DS values", outlined in section 13 for explanations how to cope
when the game's keyboard handling routine's DS value is different from
the DS value where the game keeps the energy/lives/ammo etc, values).
Once you have found the game's keyboard handling routine, your main concern
is the address where the keyboard port is read in - with the instruction
IN AL,60. Put a break point on that address and run the game. Press any
key now and you should be in the debugger. Write down the current IP where
the IN AL,60 instruction is. (You will need that IP value later on when
writing the trainer interfacing routine).
╔══════════════╗
║ Section 13 ║
╚══════════════╝
Handling different DS values:
════════════════════════════
Remember that the DS that the keyboard handling routine uses to store it's
data is not always the same DS that the game keeps the
lives/energy/ammo/timer etc values at. If the DS value in the keyboard
handling routine is different from the DS value where the game keeps your
lives/energy etc values, then you will have to do the following :
Write down the DS value that the keyboard handling routine uses and the DS
value that the game uses to store your lives/energy/ammo/timer etc values.
Quit the program and calculate how much to add or subtract from the keyboard
routine's DS value, to obtain the DS value that the game uses to store it's
lives/energy etc, values at. I use debug.exe to do the calculations.
Example:
════════
DS in the keyboard handling routine is 2CF0. The DS value where the game
keeps your lives/energy etc values is 1345 (which is lower than 2CF0, so
you will subtract it from 2CF0).
Using debug.exe:
A 100
XXXX:0100 MOV AX,2CF0
XXXX:0104 SUB AX,1345
Now simply proceed through those 2 instructions and note the AX value after
the SUB instruction. Write it down. In this example the value of AX after
subtraction is 19AB. So in your loader/tsr code you could do the following:
PUSH AX ;Save current AX value
PUSH DS ;Save current DS value
MOV AX,19AB ;Move 19AB to AX (the calculated value as shown above)
SUB DS,AX ;Subtract the game's current keyboard DS value with the
calculated AX value. Now DS will equal the DS value where
the game keeps the lives/energy etc values at.
Remember also that you don't necessary have to use DS always - the game can
be using CS to store your current lives/energy etc values - if so, simply
modify the above routine to work with CS. The above trick works for every
possible address, so you will always find your data.
╔══════════════╗
║ Section 14 ║
╚══════════════╝
Writing the trainer loader or TSR code:
═══════════════════════════════════════
By now you should have all the training-related information on paper. It
should include :
1) The addresses where the lives/energy etc are stored (XXXX:YYYY) - (not
the actual DEC/INC instruction address locations, but the addresses that
the DEC/INC instructions modify).
2) The value to add/decrement to/from the above addresses. (If you want
to increase your energy, for example, to full, note what value
represents energy full at that address, so when you later on define the
trainer keys, and select the energy-boost key, you will know what value
to add to the energy storage address to boost up the energy to max).
3) The address of the program's keyboard handling routine and the IP of the
IN AL,60 instruction. (If there is no IN AL,60 instruction in the
keyboard handling routine, then write down the address of the IP of your
chosen instruction to replace with CD 21 - for more information refer to
"Interfacing with different keyboard handling routines", outlined in
section 16e).
You should have 2 addresses of the program's keyboard handling routine.
The first one should be the address that you check/interface your
trainer code into the game's keyboard handling routine.
To get this address, start up your debugger, debug the game's loader and
set a break point on INT 21 - if using soft-ice, or trace the program to
the first INT 21. Then once you are there, don't trace into the INT 21,
just merely search for the keyboard handling routine using the program's
current CS. (You should have previously noted some of the bytes which
compose the beginning of the keyboard handling routine. Refer to the
"Note", back in section 12b).
Example:
════════
You are looking for the following bytes : E4 60 8A D8 D0 C0
S CS:0 L FFFF E4 60 8A D8 D0 C0
If you find nothing, try DS, ES, or SS. If you still find nothing, then
search higher in memory like 2000, 3000, 4000 etc. (Refer to section 9 for
more information on searching for data).
If you still don't find those bytes, then the keyboard handling routine in
the program might still be compressed or encrypted. Run the program for a
bit and then retry the above steps.
Note :
══════
If you didn't find the routine while searching with CS, DS, ES, or SS,
but found it when you searched the higher memory, like 3000 for example,
then you will have to do either one of the following:
3a) Set a break point on the next INT 21, or run the game for a bit, then
reset the break point back to INT 21. Then try again to search for the
keyboard routine's bytes - only using CS, DS, ES, or SS. If you still
don't find anything, then resort to step 3b.
3b) Since the keyboard handling routine address cannot be found using the
current CS, DS, ES or SS, you won't be able to interface your trainer
code using the above registers. You will have to use the method
described in section 13, and use the memory range address at which you
DID manage to find the keyboard handling routine with (eg: 0800:XXXX or
3000:XXXX etc).
The second address should be the game's current CS:IP when the game is
running. (For more information, refer to "Finding the runtime CS:IP of the
keyboard handling routine", outlined in section 16c).
Note:
═════
The 2 addresses described above, can be the same - the game's CS can be the
same at startup and once it's running, but if it's not, then follow the
above steps to obtain those 2 addresses. You will need them later on to
write the generic trainer code interfacing routine, as outlined in section
16a.
4) If the DS value in the program's keyboard handling routine is different
from the address where the game keeps the lives/energy etc values, as
outlined in section 13, you should have both the program's keyboard
handling routine's DS value and the address (XXXX:YYYY) where the
program keeps the lives/energy etc values at.
(You should also have calculated out what the final DS value should be
for the above. (For more information refer to "Handling different DS
values", outlined in section 13)).
5) The keyboard key press scan value that you will compare later on in your
trainer code, for your defined trainer keys.
Once you have necessary information as stated above, then you are ready for
the next step.
The loader or TSR that you are going to use has to be able to hook onto an
existing interrupt and redefine it's vector to your trainer routine. I
usually hook onto INT 21, but in theory you can hook onto any interrupt you
wish. But hooking onto INT 21 is preferable because of 2 things :
1) All the games will use INT 21 at some point in the game - therefor
activating your defined INT 21 routine, which in turn integrates itself
directly to the game's code.
2) There won't be much "confusion" once the game is running. - Games very
seldomly execute INT 21's during game play - so your INT 21 "interface"
will not slow-down/conflict with any game playing operations.
Also loader-trainers are better than writing TSR-trainers mainly because
they are "cleaner" - sure they both hook onto certain interrupts, but a
loader always restores it's hooked interrupt(s) upon exiting the program,
and in most cases, uses less memory.
If you don't know how to write loaders, or prefer to write TSR's, then I
suggest that you also include a self-removal option in your TSR - either
user requested or upon program termination. You can use the routine
outlined in section 15.
╔══════════════╗
║ Section 15 ║
╚══════════════╝
Generic TSR self-removal routine:
═════════════════════════════════
0100 1E PUSH DS
0101 50 PUSH AX
0102 52 PUSH DX
0103 06 PUSH ES
0104 0E PUSH CS
0105 1F POP DS
0106 A12C00 MOV AX,[002C]
0106 : Get the DOS environment segment address.
0109 8EC0 MOV ES,AX
010B B449 MOV AH,49
010D CD21 INT 21
010D : Free the allocated memory.
010F C5167801 LDS DX,[0200]
010F : Load pointer using DS - from DS:[0200] (DS=CS). This is done to
restore the original INT 21 vector. The original vector was saved at
CS:0200.
0113 B82125 MOV AX,2521
0116 CD21 INT 21
0116 : Hook and restore back the original INT 21 vector.
The below routine removes the TSR from the memory block:
0118 8CC8 MOV AX,CS
011A 48 DEC AX
011B 8ED8 MOV DS,AX
011D C70601000000 MOV WORD PTR [0001],0000
0123 07 POP ES
0124 5A POP DX
0125 58 POP AX
0126 1F POP DS
0127 CF IRET
0200 0000 0000 ;Original INT 21 vector saved here
╔═══════════════╗
║ Section 16a ║
╚═══════════════╝
Generic trainer code interfacing routine:
═════════════════════════════════════════
The way this routine works is by hooking itself to the game's code, mainly
at the address where the IN AL,60 - keyboard port read instruction is. It
replaces the original bytes of that instruction (E4 60) with CD 21. Every
time you press any key during the game, your trainer routine is executed
instantaneously.
I will take you step by step through the next example, taken from the
Interactive 8 option trainer for Prince of Persia II.
╔═══════════════╗
║ Section 16b ║
╚═══════════════╝
Prince of Persia II interactive trainer interfacing routine:
════════════════════════════════════════════════════════════
0100 9C PUSHF ;Push Flag
0101 55 PUSH BP ;Push BP
0102 1E PUSH DS ;Push DS
0103 89E5 MOV BP,SP ;Move current SP to BP
0105 8E5E08 MOV DS,[BP+08] ;Move current CS to DS.
The principle of operation of the 0105 instruction is as follows.
Whenever an interrupt is called, the original FLAGS, CS, and IP are pushed
into the stack. Now if you move the current SP to BP, then move the value
at SS:[BP+08] to DS, you will get the program's current CS.
0108 26 ES:
0109 813E6516E460 CMP WORD PTR [1665],60E4
0109 : Compare the values at address ES:1665 to 60 E4.
Why ES:? Remember that your trainer routine is hooked onto INT 21. Now
whenever the game starts up - the very first INT 21 executed, will either
be the dos version checking INT 21, or a memory allocating INT 21 etc.
Now every time ANY INT 21 is executed in the game, if the current CS:IP is
let's say at 2300:1200, and the keyboard handling routine's IN AL,60 address
is at 14FA:0377, then you won't be able to interface your code to the
keyboard handling routine's code, since the program's current CS is way
higher than 14FA.
The reason I used the ES value is because the value was just perfect - I
found the E4 60 bytes at address 1665 when searching with ES:, but couldn't
find them when searching with CS, DS, or SS. (You see, it's a good idea
to search with DS, ES, or SS first - if unable to find anything using CS,
before adverting to the procedures outlined in section 13).
But in most cases you will be able to interface directly to the game's
keyboard handling routine with the program's current CS value. (For more
information, refer to step 3 in "Writing the trainer loader or tsr",
outlined in section 14).
0109 : The instruction at 0109 is checking if at ES:1665 the bytes E4 60
exist - if they do, it means that's where the instruction IN AL,60
is. (Refer to "Prince of Persia II keyboard handling routine
listing", outlined in section 12d).
010F 7507 JNZ 0118 ; If it is not, then jump to the exit
portion of your routine.
0111 26 ES:
0112 C7066516CD21 MOV WORD PTR [1665],21CD
0112 : Else, replace the instruction at ES:1665 with CD 21 (your already
hooked INT 21 handling routine).
0118 817E066715 CMP WORD PTR [BP+06],1567
011D 7405 JZ 0124
0118 : Compare if SS:BP+06 (which is the game's current IP BEFORE it
entered your INT 21 hooked routine) to 1567. This routine is
comparing if the INT 21 instruction is YOURS or if it's some other
INT 21 instruction used by the game. This is accomplished by
comparing the game's current IP (instruction pointer) to 1567. If it
is indeed YOUR inserted INT 21 routine calling, then the trainer
JMPS to it's trainer routine (which starts here at 0124).
In this example, you will notice that the IP is different from the address
1665 - it's 1567. Why? Simple, because when the game runs, the CS was
different from ES - which you previously used to insert the CD 21 with.
(For more information regarding the IP, refer to section 16c).
The routine below, restores DS,BP,FLAGS and jumps to the original INT 21
vector:
011F 1F POP DS
0120 5D POP BP
0121 9D POPF
0122 EB77 JMP 019B
The above routine is executed due to one of the following:
1) Either the E4 60 value was not found at the specified address or;
2) The program's current IP is not pointing to your inserted INT 21 IP
address. (This might be another INT 21 instruction that the game is
currently using somewhere else - so the trainer code will restore DS, BP
and the FLAGS, and jump to the original INT 21 saved vector, thus
letting the game do whatever it wanted to.
Else, the following code is executed :
0124 1F POP DS
0124 : Restore the program's current DS. In this case the keyboard handling
routine's DS value is the same for where the game keeps it's key
presses and where it stores the value of your current
energy/time/level etc, values. That's why I restored DS right here,
so my trainer can use it later on. (And also note that for this
trainer example, you don't need to use the procedures listed in
"Handling different DS values", as outlined in section 13)
0125 E460 IN AL,60
0125 : This instruction reads the keyboard port. This instruction has to be
present in the trainer code, since you replaced it with CD 21 in the
game's code, remember?
The following code compares the key press to the function keys defined for
the trainer, and jumps correspondingly:
0127 3C3B CMP AL,3B
0129 741F JZ 014A
012B 3C3C CMP AL,3C
012D 7422 JZ 0151
012F 3C3D CMP AL,3D
0131 745D JZ 0190
0133 3C3E CMP AL,3E
0135 7421 JZ 0158
0137 3C3F CMP AL,3F
0139 7433 JZ 016E
013B 3C40 CMP AL,40
013D 7436 JZ 0175
013F 3C43 CMP AL,43
0141 743D JZ 0180
0143 3C44 CMP AL,44
0145 7441 JZ 0188
If some other key was pressed, which is not used by the defined trainer
keys, the following routine is executed. It merely restores the BP, FLAGS
and IRETS back to the program. The AX value however was not saved in the
beginning of the routine, and is always different upon returning back to
the program. There, it is used by the game to determine what keys were
pressed. (The original DS value was restored earlier remember?).
0147 5D POP BP
0148 9D POPF
0149 CF IRET
The following instructions change the data values in the program's DS to
train the game. The trainer data was derived using the same techniques as
outlined in this training tutorial.
014A C606865C01 MOV BYTE PTR [5C86],01
014F EBF6 JMP 0147
0151 C606865C00 MOV BYTE PTR [5C86],00
0156 EBF7 JMP 014F
0158 C6060D5C21 MOV BYTE PTR [5C0D],21
015D C6064D5C21 MOV BYTE PTR [5C4D],21
0162 C606CD5C21 MOV BYTE PTR [5CCD],21
0167 C6060D5D21 MOV BYTE PTR [5D0D],21
016C EBE8 JMP 0156
016E C6062A5EFF MOV BYTE PTR [5E2A],FF
0173 EBF7 JMP 016C
0175 C6062C5E01 MOV BYTE PTR [5E2C],01
017A FE06465E INC BYTE PTR [5E46]
017E EBF3 JMP 0173
0180 C706825C9300 MOV WORD PTR [5C82],0093
0186 EBF6 JMP 017E
0188 C706825CC101 MOV WORD PTR [5C82],01C1
018E EBF6 JMP 0186
0190 C706925C1919 MOV WORD PTR [5C92],1919
0196 EBF6 JMP 018E
0198 90 NOP
0199 90 NOP
019A 90 NOP
019B EA00000000 JMP XXXX:XXXX ;Jump back to the original INT 21
vector.
For a better understanding of the above code, study the Prince of Persia II
interactive 8 option TSR or loader trainer examples (PP2T-TSR.COM and
PP2T-LDR.COM and their DOC - PP2T-T&L.DOC). Both are included in this
training tutorial package. They correspond exactly to the above example.
╔═══════════════╗
║ Section 16c ║
╚═══════════════╝
Finding the runtime CS:IP of the keyboard handling routine:
═══════════════════════════════════════════════════════════
To always know what the current IP will be once the program is running,
simply set a break point in the program's keyboard handling routine, press a
key, and once your debugger breaks in, note the address of the keyboard
handling routine.
Write down the address of the IN AL,60 instruction. If the game doesn't use
INT 9 or IN AL,60 in it's keyboard handling routine, then refer to
"Interfacing with different keyboard handling routines", as outlined in
section 16e).
╔═══════════════╗
║ Section 16d ║
╚═══════════════╝
Comparing the program's current IP:
═══════════════════════════════════
When comparing the program's current IP - like in the above example in
section 16b, at 0118, you have to remember that the program's current IP
points to the address AFTER the interrupt was called.
Example:
════════
If the code looks like this :
0100 E460 IN AL,60
0102 88C3 MOV BL,AL
And you replace E4 60 with CD 21:
0100 CD21 INT 21
0102 88C3 MOV BL,AL
Then once the program executes your interrupt 21, and you check for the
program's current IP as described above, make sure you compare the IP to
0102! - the instruction right after the INT 21 - because after all, once the
program exits from your INT 21 routine via the IRET instruction, it doesn't
return back to 0100, it returns to the next following instruction.
╔═══════════════╗
║ Section 16e ║
╚═══════════════╝
Interfacing with different keyboard handling routines:
══════════════════════════════════════════════════════
All games have a keyboard handling routine. But some rare OLD games might
not use INT 9 to handle their key presses, or they might not use the IN
AL,60 instruction - just INT 16 for checking key presses.
So what's the problem there? Again, simply find a 2 byte instruction
somewhere right after the INT 16 instruction that you can replace with CD
21, and you are in business.
Example:
════════
0100 30E4 XOR AH,AH
0102 CD16 INT 16 ;here is the game's INT 16
0104 88C3 MOV BL,AL
0106 80EB11 SUB BL,11
There is a nice instruction at 0104 that you can change to CD 21. Then all
you have to do in your INT 21 hooked routine is to execute that instruction
somewhere in the beginning or the end of your code - doesn't really matter
where, but make sure BL equals the AL key press value, once your routine
IRETS back to 0106.
╔══════════════╗
║ Section 17 ║
╚══════════════╝
Below is another example, taken from the Fox Ranger interactive 9 option
trainer. Notice that at 010A, there is no E4 60 (IN AL,60). I'm hooking
INT 21 at some address which is in the game's program loop - you see, it can
be done in lots of different ways, as described above in "Interfacing with
different keyboard handling routines", in section 16e. I will only explain
the important stuff in the following example:
Fox Ranger interactive 9 option trainer routine listing:
════════════════════════════════════════════════════════
0100 9C PUSHF
0101 55 PUSH BP
0102 1E PUSH DS
0103 89E5 MOV BP,SP
0105 8E5E08 MOV DS,[BP+08]
0108 26 ES:
0109 813EBA1DB000 CMP WORD PTR [1DBA],00B0
010F 7507 JNZ 0118
0109 : Compare ES:[1DBA] to 00 B0, if not, restore DS,BP,FLAGS and jump to
the original INT 21 vector.
0111 26 ES:
0112 C706BA1DCD21 MOV WORD PTR [1DBA],21CD
0112 : Hook your defined INT 21 routine at ES:[1DBA]
0118 817E06BC1C CMP WORD PTR [BP+06],1CBC
011D 7405 JZ 0124
0118 : Compare current SS:[BP+06] (BP=SP) which is the program's current IP
to 1CBC - if it's at your INT 21 IP, then jmp to the trainer routine,
else restore DS,BP,FLAGS and jump to the original INT 21 vector
(as in 011F-0122).
011F 1F POP DS
0120 5D POP BP
0121 9D POPF
0122 EB7D JMP 01A1
0124 8CDD MOV BP,DS
0126 06 PUSH ES
0127 1F POP DS
0128 A0722D MOV AL,[2D72]
0128 : Move into AL the key press which the game stored at ES:[2D72] - (As
you see, the game does not always have to have the IN AL,60
instruction, for you to be able to interface your trainer with the
keyboard. As long as you find out where the game stores it's key
presses, you will always be in business.
The following compares the key press to see if it's one of the defined
trainer key presses:
012B 3C4A CMP AL,4A
012D 7459 JZ 0188
012F 3C4E CMP AL,4E
0131 744B JZ 017E
0133 3C26 CMP AL,26
0135 7461 JZ 0198
0137 3C30 CMP AL,30
0139 7427 JZ 0162
013B 3C20 CMP AL,20
013D 742A JZ 0169
013F 3C32 CMP AL,32
0141 7412 JZ 0155
0143 3C21 CMP AL,21
0145 744B JZ 0192
0147 3C24 CMP AL,24
0149 7425 JZ 0170
014B 3C1E CMP AL,1E
014D 7428 JZ 0177
014F B000 MOV AL,00
0151 1F POP DS
0152 5D POP BP
0153 9D POPF
0154 CF IRET
The following is the training routine. The training data was derived using
the same techniques as outlined in this training tutorial.
0155 A2802F MOV [2F80],AL
0158 893E812F MOV [2F81],DI
015C 893E832F MOV [2F83],DI
0160 EBED JMP 014F
0162 C606BF2F01 MOV BYTE PTR [2FBF],01
0167 EBF7 JMP 0160
0169 C6067A2F01 MOV BYTE PTR [2F7A],01
016E EBF7 JMP 0167
0170 C606244305 MOV BYTE PTR [4324],05
0175 EBF7 JMP 016E
0177 C6067E2F01 MOV BYTE PTR [2F7E],01
017C EBF7 JMP 0175
017E 8EDD MOV DS,BP
0180 C70660DD0900 MOV WORD PTR [DD60],0009
0186 EBF4 JMP 017C
0188 8EDD MOV DS,BP
018A C70660DDB304 MOV WORD PTR [DD60],04B3
0190 EBF4 JMP 0186
0192 FE06792F INC BYTE PTR [2F79]
0196 EBF8 JMP 0190
0198 FE06762F INC BYTE PTR [2F76]
019C EBF8 JMP 0196
019E 90 NOP
019F 90 NOP
01A0 90 NOP
01A1 EA00000000 JMP XXXX:XXXX ; Jump back to the original INT 21
vector.
For a better understanding, study the Fox Ranger interactive 9 option
tsr trainer example (FRT-TSR.COM and read it's DOC - FRT-TSR.DOC) included
in this trainer package. It corresponds exactly to the above example.
╔══════════════╗
║ Section 18 ║
╚══════════════╝
Below is another example, taken from the Legend of Myra Interactive 10
option trainer:
Legend of Myra Interactive 10 option trainer routine listing:
═════════════════════════════════════════════════════════════
0100 9C PUSHF
0101 55 PUSH BP
0102 1E PUSH DS
0103 89E5 MOV BP,SP
0105 8E5E08 MOV DS,[BP+08]
0108 813E250E8AD8 CMP WORD PTR [0E25],D88A
010E 7506 JNZ 0116
0108 : Compare the word at CS:[0E25] (DS=CS because of the instruction at
105) to D8 8A. Skip the following instruction if not zero.
0110 C706250ECD21 MOV WORD PTR [0E25],21CD
0110 : Interface your INT 21 hooked routine at CS:[0E25]
0116 817E06270E CMP WORD PTR [BP+06],0E27
011B 7406 JZ 0123
0116 : Compare the word at SS:[BP+06] (which is the program's current IP) to
0E27. Note that the address of the program's current IP and the
address where you inserted your CD 21 word is identical - you see,
sometimes the program's current CS can be the same at startup, and
during game play. (Refer to step 3 in "Writing the trainer loader or
tsr code", outlined in section 14).
(The reason for the 2 byte increase from 0E25 to 0E27 now, is because
the program's current IP points to the next following instruction
after your INT 21. (For more information on this, refer to
"Comparing the program's current IP", outlined in section 16d).
The next instructions listed below restore DS,BP,FLAGS and jump back to the
original INT 21 vector - if the compare at either 0108 or 0116 failed.
011D 1F POP DS
011E 5D POP BP
011F 9D POPF
0120 E97F00 JMP 01A2
The instructions below move into AL the key presses taken from the program's
keyboard key press storage data area and compare them to the trainer defined
keys:
0123 1F POP DS
0124 5D POP BP
0125 50 PUSH AX
0126 A0E409 MOV AL,[09E4]
0129 3C3B CMP AL,3B
012B 743B JZ 0168
012D 3C3C CMP AL,3C
012F 743D JZ 016E
0131 3C3D CMP AL,3D
0133 7427 JZ 015C
0135 3C3E CMP AL,3E
0137 743B JZ 0174
0139 3C3F CMP AL,3F
013B 7425 JZ 0162
013D 3C40 CMP AL,40
013F 7415 JZ 0156
0141 3C41 CMP AL,41
0143 7435 JZ 017A
0145 3C42 CMP AL,42
0147 7437 JZ 0180
0149 3C43 CMP AL,43
014B 7440 JZ 018D
014D 3C44 CMP AL,44
014F 7435 JZ 0186
0151 58 POP AX
0152 9D POPF
0153 EB44 JMP 0199
0155 90 NOP
The following is the training routine. The training data was derived using
the same techniques as outlined in this training tutorial.
0156 C646F643 MOV BYTE PTR [BP-0A],43
015A EB38 JMP 0194
015C C646F6CE MOV BYTE PTR [BP-0A],CE
0160 EB32 JMP 0194
0162 C646F65E MOV BYTE PTR [BP-0A],5E
0166 EB2C JMP 0194
0168 C646F691 MOV BYTE PTR [BP-0A],91
016C EB26 JMP 0194
016E C646F693 MOV BYTE PTR [BP-0A],93
0172 EB20 JMP 0194
0174 C646F6CD MOV BYTE PTR [BP-0A],CD
0178 EB1A JMP 0194
017A C646F6C3 MOV BYTE PTR [BP-0A],C3
017E EB14 JMP 0194
0180 FE06EE1F INC BYTE PTR [1FEE]
0184 EBCB JMP 0151
0186 C606FD3D01 MOV BYTE PTR [3DFD],01
018B EBC4 JMP 0151
018D C606D01F64 MOV BYTE PTR [1FD0],64
0192 EBBD JMP 0151
0194 58 POP AX
0195 31C0 XOR AX,AX
0197 EBB9 JMP 0152
0199 C606E40900 MOV BYTE PTR [09E4],00
019E 88C3 MOV BL,AL
01A0 CF IRET
01A1 90 NOP
01A2 EA00000000 JMP XXXX:XXXX ;Jump back to the original INT 21
vector.
For a better understanding, study the Legend of Myra interactive 10 option
tsr trainer example (LOMT-TSR.COM and read it's DOC - LOMT-TSR.DOC) included
in this training package. It corresponds exactly with the above example.
╔══════════════╗
║ Section 19 ║
╚══════════════╝
Interactive TSR/loader trainer examples:
════════════════════════════════════════
This training tutorial comes with 4 interactive trainer examples (in COM
format) There are 3 interactive TSR trainer examples and 1 interactive
trainer loader example, included with this training tutorial. The ASM code
structure of all 4 interactive trainer examples, is identical to the ASM
code structure of the examples outlined in this documentation. Even the
trainer code found in each of the 4 trainer examples, starts at CS:0100
- exactly as listed here in this training tutorial.
This was done so that you will be able to study the examples listed here and
then refer to the actual interactive TSR/loader trainer examples.
You should note however, that all the 3 TSR trainers use the same install
checking routine - to see if they have already been previously installed
in memory. Remember to only install one at a time.
╔══════════════╗
║ Section 20 ║
╚══════════════╝
Summary:
════════
By studying the above examples and the actual trainer program examples
(PP2T-TSR.COM, FRT-TSR.COM, LOMT-TSR.COM, PP2T-LDR.COM) included in this
trainer tutorial package, you will learn how to write trainers for the PC,
or at least broaden your knowledge on this topic.
I hope this trainer tutorial helps all you boys out there who always
wondered how it's done. Maybe now I can retire for good since you boys will
be making all the trainers from now on!
Anyways...
From the boys at UNT, : Take care & have PHUN!
Dr. Detergent / UNT'93
############################################################################
By the way...
I'm a pilot currently without a job! - if you are an owner of a
charter company or a flight school, or have contacts in the aviation
industry, and know of a job opening, then by all means contact me -
through the UNTOUCHABLES!
Got a valid flight instructor's rating, multi-engine, glider lic,
certified on 10 types of aircraft, and other goodies.
Ready and willing to relocate ANYWHERE!
And if you think that my cracking/training/programming is good,
then wait till you see me fly!
############################################################################
╒═══[ THE UNTOUCHABLES CREW ]═══╕
╓────────────────────────────────────────────────────────────────────╖
╓───────── ── · · ── ──────────────────────────── ── · · ── ────────╖
║ ║
║ ½─────────────────────────≡ UNTOUCHABLES ≡───────────────────────────» ║
║ ║
║ Bandieto Mr. Fizz The Psychiatrist The Whistler ║
║ ║
║ Booper Chester Code Breaker Dark Knight Dr. Detergent Faceless ║
║ ║
║ Fenris Wolf Silver V Spyke the Impaler The Bandit ║
║ ║
║ Wayward Ford Prefect ║
║ ║
║ ½───────────────────────≡ The Courier Team ≡─────────────────────────» ║
║ ║
║ Nightblade Vertigo ║
║ ║
║ August Spies Cable Dr. Donnatello Macgyver Minotaur ║
║ ║
║ Mirage Quazar Satch Shadowhawk Sinclair Specs ║
║ ║
║ Tasslehoff Burrfoot The Invid The Predator The Roamer Torgall ║
║ ║
╙────────────────── ── · · ── ─────────────────╜
╙────────────────────────────────────────────────────────────────────╜
╒═══[ UNTOUCHABLES BOARDS ]═══╕
╒════════════════════════════════════════════════════════════════════╕
╒════════════════════════════════════════════════════════════════════════════╕
│ < BOARD NAME > │ < NUMBER > │ < SYSOP > │ < NODES/POSITION > │
╞════════════════════════════════════════════════════════════════════════════╡
│ - [ ALL HQs ] - │
│────────────────────────────────────────────────────────────────────────────│
│ Apocalypse ........ │ ITS-PRI-VATE │ The Whistler │ 5 │ World ..... HQ │
│ The Dark Palace ... │ ITS-PRI-VATE │ Escape Key .. │ 10 │ Courier ... HQ │
│ The Burning Church │ ITS-PRI-VATE │ -aD! ........ │ 3 │ Canadian .. HQ │
│────────────────────────────────────────────────────────────────────────────│
│ - [ MEMBER BOARDS ] - │
│────────────────────────────────────────────────────────────────────────────│
│ House of the R/Sun │ 703-406-8920 │ Dark Knight . │ 2 │ UNTNET HUB │
│ Members Only ...... │ ITS-PRI-VATE │ Chester ..... │ 4 | Member - Board │
│ MidWest Exchange .. │ ITS-PRI-VATE │ Silver V .... │ 5 | Member - Board │
│ Pristine Towers ... │ ITS-PRI-VATE │ Vertigo ..... │ 2 │ Member - Board │
│────────────────────────────────────────────────────────────────────────────│
│ - [ SITES ] - │
│────────────────────────────────────────────────────────────────────────────│
│ Power Base ........ │ +49-XXX-XXXXXX │ Powerlite ... │ 1 | Distro .. Site │
│ The GodsLand ...... │ 410-360-3598 │ Crash ....... │ 1 | Distro .. Site │
│ The Land's End .... │ 703-XXX-XXXX │ Rogue Trader │ 1 | Distro .. Site │
│ Twilight Zone ..... │ 504-XXX-XXXX │ Jack Flash .. │ 3 | Distro .. Site │
│ Xcess Unlimited ... │ +49-XX-XXXXXXX │ Creme ....... │ 2 │ Distro .. Site │
╘════════════════════════════════════════════════════════════════════════════╛
╘════════════════════════════════════════════════════════════════════╛
╒═══[ PLEASE NOTE ]═══╕
╓────────────────────────────────────────────────────────────────────╖
╓────────────────────────────────────────────────────────────────────────────╖
║ ║
║ We are now accepting applications, please pick up an application at any ║
║ UNTOUCHABLES HQ, or contact us on our VMB. ║
║ ║
║ 1-800-328-3440 450 (After 6PM -EST) ║
║ ╓ ╖ ║
║ ║ If you like and use a software, please take it upon yourself to buy ║ ║
║ ║ it. Supporting quality programmers is in all of our interest. ║ ║
║ ╙ ╜ ║
╙────────────────────────────────────────────────────────────────────────────╜
╙────────────────────────────────────────────────────────────────────╜
╓────────────────────────────────────────────────────────────────────╖
╓──────────────────────────────────────────────────────────────────────────╖
║ - [ · U · N · T · O · U · C · H · A · B · L · E · S · ] - ║
╙──────────────────────────────────────────────────────────────────────────╜
╙────────────────────────────────────────────────────────────────────╜