пм
                                                л
                     ммм                        м
                    Влллллм                    мп
                    ВВлллллн                млп
                   ВВлллллллм           ммллп
 м  мм            ВВлллллллпплмммммллллппп
п  п м          ВВВлВВллллмм  лпппп
     ол        ВВлллллВллплппмн
      л        Вллллллллмлммллл
   пВл         Вллллллллллллллллм                          њ   м
   мп         Влллллллллллллллллллм                            о
              Влллллллллллллнллпплллм
             Влллллллллллллллмллммллп                     о    л
            Влллллллллллллллллллм                         он   о
             Вллллллллллллллллллп                         лл   о
             Влллллллллллллллллм                          ллм  н
         м   ВВллллллллллллллллл                         оллп  нм
        мВВммпВллллллллллллллВп                          олнн лн п мм
         пВВллллллллллллллллллм                        ммлпон лн  лллВ
           пВлллллплллллллллллл                     млллллнон лн  олллВ
             плллллмАлллллллллн                    ллллллл л  л    ллллВ
               плллллмлллллллп                    лллллллн л  л     ллл м
                  пллллллмпп                     лллллллп  н ол      лллмл
                    плллллллм                   оллллллм      л       ллллмпВм
      п               плллллллм                 ллллллВВлм   мл        лллллллл
       пм               ппплллллллммм           оллллллВВн    л       млллллллл
         Ап                    пппплллллммм      лллллллВ     п      мВлллллллн
                                      ппплллллммм  ппллВВн          мБВллллллл
                                             пппплллммм ппм        БВВлллллллн
                                                     ппппм  мм    мАБВВлллллл
                                                              п    ппАБлллллн
                                                                 плм ВААлллл
                                                                     оВАлллн
                                                                     лВлппп
                                                                     пп
 плп     плп          м                   л            л      л        мппппмп
  л       л  м мм  пммм   мм   м  м  мм  онмм    мм   он мм  он  ммм   плмм
  лм     мл   л  л   м п лп л он он л  п он он мп  м  онп  л онмп мпп    пплм
   ппм мпп   он он  он   мммп пммп онммп л  л  пммлпм л ммп  л  пммм  мпммммп


                                     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 њ ] -        К
 гФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФН
    гФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФН