Tuesday, October 11, 2011

ASSEMBLY LANGUAGE - CRASH COURSE --

+-------+-------+--------------------------------+
|  ASM  |  HEX  |            Meaning             |
+-------+-------+--------------------------------+
|  je   |74/0F84|         jump if equal          |
+-------+-------+--------------------------------+
|  jne  |75/0F85|       jump if not equal        |
+-------+-------+--------------------------------+
|  jmp  | EB/E9 |      jump unconditionally      |
+-------+-------+--------------------------------+
|  jg   | 0F8F  |      jump if greater than      |
+-------+-------+--------------------------------+
|  jl   | 0F8C  |       jump if less than        |
+-------+-------+--------------------------------+
|  jge  | 0F8D  |jump if greater than or equal to|
+-------+-------+--------------------------------+
|  jle  | 0F8E  | jump if less than or equal to  |
+-------+-------+--------------------------------+

CRASH COURSE IN ASSEMBLY LANGUAGE

 Crash Course in Assembly Language
         ---------------------------------
              If you are already well familiar with the assembly
         language, you may wish to skip this section.  Cracking
         demands the knowledge of assembly language.  If you wish to
         become a "serious" cracker, you might like to read up more
         about this fascinating language.  This section will only give
         you enough info for intermediate level cracking.
              At this point, you should familiarize yourself with
         DEBUG and its commands as we will be using them shortly.

         Registers
         ---------
              One of the neato things that you will be fooling around
         most often with are called the registers.  Registers are like
         variables (such as in BASIC) that are located within the CPU
         itself.  These registers may hold a positive integer from 0
         to 255 or from 0 to 65535.  They can also hold negative
         integers from -128 to 127 or from -32768 to 32767.  The
         registers are given names as follows:

              AX => accumulator - this register is most commonly used
                    for mathematical or I/O operations
              BX => base - this register is used commonly as a base or
                    a pointer register (we'll talk more about this
                    later)
              CX => count - used commonly for counting instructions
                    such as loops
              DX => displacement - much like the base register

         The registers stated above are considered general purpose
         registers, since they can basically be used to store whatever
         the user wants.  Let's try putting some number in these
         registers.  Type in "R {enter}".  You should see a bunch of
         info, of which are four of the above mentioned registers.
         Now, type in "RAX {enter}".  Then type in a number like
         8FABh.  Type in "R" again and noticed how the accumulator
         (AX) has change its number.
              These general purpose registers can also be "split" in
         half into its higher and lower order components.  Instead of
         having one register AX, you can have two registers, AH and
         AL.  Note however that while you have a range of 0 to FFFFh
         for AX, you will now have a range of 0 to FF for AH and AL.
         You cannot change these directly in debug, but be aware that
         programs will use it.  If AX contains 0A4Ch, then AH will
         contain 0Ah and AL will contain 4Ch.
              The following are called the segment registers:

              CS => code segment - the block of memory where the code
                    (instructions are located)
              DS => data segment - the block of memory where data can
                    be accessed.  In block move operations in which
                    huge blocks of memory are moved, this is commonly
                    the segment in which the CPU reads from.
              ES => extra segment - also another data segment.  In
                    block move operations in which huge blocks of
                    memory are moved, this is commonly the segment in
                    which the CPU writes to.
              SS => stack segment - this is the block of memory in
                    which the CPU uses to store return addresses from
                    subroutines.  (more on this later)

         In introductory level of cracking, we don't mess around with
         these registers.  Later, we will see how we can use these to
         trick a program into thinking other things, but that's later.
         You can also change these registers in debug.  Type in "RCS
         {enter}".  Then enter "0 {enter}" and notice how the CS
         register changed.
              There are other registers that we use to see what the
         program is doing.  These registers can also be change in
         debug.  Included are the following:

              SI => source index - this register is used in
                    conjunction with block move instructions.  This is
                    a pointer within a segment (usually DS) that is
                    read from by the CPU.
              DI => destination index - this register is also used in
                    conjunction with block move instructions.  This is
                    a pointer within a segment (usually ES) that is
                    written to by the CPU.
              BP => base pointer - a pointer used commonly with the
                    stack segment
              SP => stack pointer - another pointer used commonly with
                    the stack segment (this one, you don't touch)

              By now, you may probably be confused about this
         segment/pointer bit.  Here is an analogy that my straighten
         things out.
              Pretend you are in kindergarden learning to read.  There
         are four black boards surrounding the room.  These black
         boards are like SEGMENTS.  Let's pretend the front blackboard
         is the code segment (CS).  The teacher has written some
         instructions on pronunciation rules.  This is what the
         students refer to when they try to pronounce words.  In a
         program, this is what the CPU refers to when it follows
         directions.
              Okay, now the teacher has gone to the blackboard on the
         left of the classroom.  We will call this board the data
         segment (DS).  The teacher has also written a set of words on
         the board.  Then she uses a wooden stick or a POINTER to
         point to a word.  Let's pretend this stick is the source
         index (SI).  She points to the word "their".  Now, the
         students look at the front blackboard (CS) to see how to
         pronounce the word and they say "their".
              Now, the instructor wants the students to learn how to
         write.  She points the stick to the word "apple".  The
         students pronounce the word.  Then she goes to the blackboard
         on the right.  We shall call this one the extra segment (ES).
         She then uses her finger as a different POINTER and points to
         a location on the board where Mary Jane will write "apple".
              That's basically what segments and pointers are.
         Segments are the blackboards and pointers are the teacher's
         stick (we're not talking sexually here) or finger.
              One last important register is the flags register.
         These registers control how certain instruction work, such as
         the conditional jumps (in BASIC, they are like IF-THEN's).
         They are stored as bits (0's or 1's) in the flags register.
         We will most often use:

              zero => ZR/NZ (zero/not zero) - tells you whether an
                      instruction (such as subtraction) yielded a zero
                      as an answer
              sign => NG/PL (negative/positive) - tells you whether an
                      instruction yielded a positive or negative
                      number
              carry => CY/NC (carry/no carry) - tells you whether an
                      instruction needed to carry a bit (like in
                      addition, you carry a number over to the next
                      digit).  Various system (BIOS) functions use
                      this flag to denote an error.
              direction => DN/UP (decrement/increment) - tells a block
                      instruction to either move forward or backwards
                      in reads and writes

         Try changing some of these bits.  Type in "RF {enter}".  Then
         type in "DN {enter}" to change the direction flag to its
         decrement position.

         The Instructions
         ----------------

         MOV - move
         ----------
              Now we get to the actual instructions or commands that
         the CPU will use.  The first instruction you will see most
         often is the move instruction.  Its form is
         MOV {destination},{source}.  Let's try programming now.  Exit
         (q) and reenter debug again.  Now, type in "A {enter}".  You
         will see a bunch of number to the left.  You can think of
         these as line numbers.  Now type in "MOV AX,7A7A {enter}".
         Then type "MOV DX,AX" and so on until your program looks
         similar to the one below:  (type "U 100" to see)

         xxxx:0100 B8A77A         MOV    AX,7AA7
         xxxx:0103 89C2           MOV    DX,AX
         xxxx:0105 B90000         MOV    CX,0000
         xxxx:0108 88D1           MOV    CL,DL
         xxxx:010A 890E0005       MOV    [0500],CX
         xxxx:010E 8B160005       MOV    DX,[0500]
         xxxx:0112 BB0200         MOV    BX,0002
         xxxx:0115 26A30005       MOV    ES:[0500],AX

         Press enter again until you see the "-" prompt again.  You
         are ready to run your first program.  Type "R {enter}" and
         note the values of the general purpose registers.  Then type
         in "T {enter}".  Debug will automatically display the
         registers after the execution of the instruction.  What is in
         the AX register?  It should be 7AA7h.  Now, "T" again.  What
         is in the DX register?  It should also be 7AA7h.  Trace again
         using "T" and note that CX should be 0 if it was not already.
         Trace again and note what is in the CX register.  It should
         be 00A7h.  Now trace another step.  What is this instruction
         doing?  It is now moving the contents of CX into memory
         location 500h in the data segment (DS).  Dump the memory by
         typing in "D 500".  The first two two-digit numbers should be
         the same as in the CX register.  But wait a minute you say.
         They are not the same.  They are backwards.  Instead of
         00A7h, it is A700h.  This is important.  The CPU stores 16
         bit numbers in memory backwards to allow for faster access.
         For 8 bit numbers, it is the same.  Now, continue tracing.
         This instruction is moving the memory contents of address
         500h into the DX register.  DX should be 00A7h, the same as
         CX regardless of how it looked in memory.  The next trace
         should be nothing new.  The next trace again moves the
         contents of a register into memory.  But notice it is using
         the BX register as a displacement.  That means it adds the
         contents of BX and 500h to get the address, which turns out
         to be 502h.  But also not the "ES:" in front of the address.
         This additional statement tells the CPU to use the extra
         segment (ES) rather than the data segment (DS which is the
         default).  Now dump address 502h by entering "D ES:502" and
         you should see A77Ah, which is backwards from 7AA7h.

         CMP/J? - compare/conditional jump
         ---------------------------------
              Another instruction you will see quite often is the CMP
         or compare instruction.  This instruction compares the two
         "variables" and changes the flags register accordingly.  The
         source and destination operands are the same as those for the
         move instruction.
              Let's consider an example in which the AX register holds
         21 and the BX register holds 22.  Then "CMP AX,BX" is
         performed.  The compare instruction is like a subtraction
         instruction, but it doesn't change the contents of the AX
         register.  So, when 22 is subtracted from 21, the answer will
         be -1, but we will never see the answer, only the flags which
         have resulted from the operation.  Number 21 is less than 22,
         so the carry flag and the sign flag should be set.  Just
         remember that when the carry flag is set, the first number is
         less than the second number.  The same is true for the sign
         flag.  Why have two flags if they tell us the same thing?
         This is more complicated and you should not concern yourself
         with it.  It requires knowledge of hexadecimal arithmetic,
         the denotation of signed and unsigned integers.
         So, now that we have done the compare instruction, there
         will most likely be a conditional jump instruction after.  If
         we wanted to jump if AX is less than BX (which it is), then
         there would be an instruction like "JB 200".  This
         instruction says Jump if Below to instruction 200h.  What
         about if we wanted to jump if AX is greater than BX.  Then we
         might have "JA 200".  This is read Jump if Above to
         instruction 200.  What about AX equal to BX.  We would then
         have "JZ 200" or "JE 200".  (Please note that the previous
         instructions are synonymous.)  This is read Jump if Equal to
         instruction 200h.  Here are the jumps you will most likely
         encounter:

              Mnemonic  Flag(s) Checked  Description
         -------------------------------------------------------------
              JB/JNAE   CF=1             Jump if below/not above or
                                         equal (unsigned)
              JAE/JNB   CF=0             Jump if above or equal/not
                                         above (unsigned)
              JBE/JNA   CF=1 or ZF=1     Jump if below or equal/not
                                         above (unsigned)
              JE/JZ     ZF=1             Jump if equal/zero
              JNE/JNZ   ZF=0             Jump if not equal/not zero
              JL/JNGE   SF not equal     Jump if less/not greater or
                        to OF            equal (signed)
              JGE/JNL   SF=OF            Jump if greater or equal/not
                                         less (signed)
              JLE/JNG   ZF=1 or SF       Jump is less or equal/not
                        not equal OF     greater (signed)
              JG/JNLE   ZF=0 or SF=OF    Jump if greater/not less or
                                         equal (signed)
              JS        SF=1             Jump if sign
              JNS       SF=0             Jump if no sign
              JC        CF=1             Jump if carry
              JNC       CF=0             Jump if no carry
              JO        OF=1             Jump if overflow
              JNO       OF=0             Jump if not overflow
              JP/JPE    PF=1             Jump if parity/parity even
              JNP/JPO   PF=0             Jump if no parity/parity odd

         There are all the possible combinations of conditional jumps
         that you will encounter.  I realize that we have not
         discussed some of the flags such as overflow or parity, but
         be aware that they exist and programs sometimes use them.

         JMP - jump
         ----------
              This instruction does what it suggests.  It jumps too
         different sections of code.  Several forms of the jump
         instruction include:

         2E0B:0208 EBF6           JMP    0200
         2E0B:020A 3EFF24         JMP    DWORD PTR DS:[SI]

         The first instruction jumps to an address within the segment.
         The latter instruction jumps to an address pointed to by ds:
         si.  The DWORD says that this will be a far jump, a jump to a
         different segment (a different blackboard).  So, if the
         double word that is pointed to by ds:si contains 1000:0040h,
         then, the instruction will jump to 1000:0040h whereas the
         previous jump instruction will jump within the current
         segment (or blackboard).

         CALL - procedural transfer
         --------------------------
              This instruction is the baby that you will be carefully
         watching out for most often.  This instruction calls another
         procedure and upon it's completion, will return to calling
         address.  For example, consider the following block of code:

         2E0B:1002 E8BB46         CALL   56C0
         2E0B:1005 7209           JB     1010
         2E0B:1007 0C00           OR     AL,00

         The first line calls another procedure at "line number"
         56C0h.  Upon its completion, the instruction pointer will
         point to the second line.  Note that there is a "JC"
         instruction.  Remember that programs often use the carry flag
         to signal errors.  If the call instruction called a copy
         protection instruction and you entered a wrong code or
         something, it may return with the carry flag set.  The next
         instruction would then jump if there was an error to an
         exiting procedure.
              Note, this is a near call.  A program can also have far
         calls just like jumps.

         INT - generate an interrupt
         ---------------------------
              This instruction is much like the call instruction.  It
         also transfers control to another procedure.  However, the
         number after the INT instruction does not point to an
         address.  Instead, it is a number pointing to an address that
         is located in something called an interrupt vector.  You will
         commonly see "INT 10", "INT 21", "INT 13".  Just know (for
         now) that they are like calls to procedures.

         LODSB/LODSW/STOSB/STOSW - load/store a byte/word
         ------------------------------------------------
              These instructions either load in or store a byte or a
         word to or from memory.  The DS:SI register pair points to
         the source data.  These are the registers the CPU will use
         when reading from memory using the LODS instruction.  The
         AX/AL register will hold the number to either read from or
         write to the memory.  So, if DS:SI points to a byte which is
         maybe 60, then a "LODSB" instruction will load in the number
         60 into the AL register.  A LODSB or STOSB will use the AL
         register while the LODSW or STOSW will use the AX register.
        
         The STOS writes whatever is in the AX/AL register to the
         memory pointed to by ES:DI.  So, if ES:DI points to 100:102h
         and if AL held 50, then the byte at 100:102h will hold 50.
              After the instruction is finished, the CPU will either
         increment or decrement SI or DI according to the status of
         the direction flag.  So, if SI was 100h and a "LODSW"
         instruction was performed with a cleared direction flag
         (forward), the SI will now point to 102h.

         MOVSB/MOVSW - copies a byte/word from source to destination
         -----------------------------------------------------------
              This instruction gets a byte or a word from the data
         pointed to by DS:SI and copies it to the data pointed to by
         the ES:DI address.  When the instruction is finished, SI and
         DI will be incremented or decremented accordingly with the
         status of the direction flag.  So, if DS:SI pointed to a byte
         with the number 30, a "MOVSB" instruction would copy into the
         byte pointed to by ES:DI the number 30.

         REP - repeat
         ------------
              The REP instruction in front of a MOVS/LODS/STOS would
         cause the MOVS/LODS/STOS instruction to be repeated for a
         number of times specified in the CX register.  So, if CX
         contained 5, then "REP STOSB" would store whatever was in the
         AL register into the byte pointed to by ES:DI five times,
         increasing DI each time.

         LOOP - looping
         --------------
              The LOOP instruction repeats a block of instructions for
         a certain number of times.  This number will be held in the
         CX register.  Each time we reach this instruction, the CPU
         will decrement the CX register and jump to a specified
         instruction until CX becomes zero.  This instruction looks
         like "LOOP 1A00" where the number indicates the instruction
         address to loop to.

         Arithmetic Operators
         --------------------
              Arithmetic instructions allow you to perform various
         arithmetic function of data.  "ADD" and "SUB" work the same
         way as "MOV" instructions do in that it subtracts whatever is
         in the source register from the destination register and
         stores it in the destination register.
              The "MUL" and "DIV" instructions are a bit more
         complicated and they are not used as intensively as the "ADD"
         or "SUB" since they are slow, so we will not talk about them.
              There are also a multitude of other instructions that
         you should familiarize yourself with if you are thinking of
         becoming a serious cracker.  The instructions given above are
         only the BARE minimum that you need.  There is no way around
         learning assembly for better cracking.

                                  THE CRACKING

         The Cracking
         ------------
              Now the fun stuff begins.  First, we must discuss the
         different forms of copy protection schemes.  They are
         basically divided into the disk based and manual based copy
         protection schemes.
              With disk based schemes, the software often reads from
         specific sectors on a disk to determine the disk's validity.
         How can this be done?  When you perform a disk format, the
         disk is formatted with specific sector sizes.  Once the
         sector size changes, DOS cannot recognize it, thinking that
         it is a bad sector.  Since this looks like a bad sector, a
         simple DISKCOPY will not work in copying such disks.
         Interrupt 13h (the assembly mnemonic is INT 13) was commonly
         used to handle such copy protections.  It is now very rare to
         encounter the once famed INT 13h copy protection method
         nowadays since it was quite easy to defeat.  Any professional
         commercial software will often use their own custom based
         disk I/O routines.  This involves intimate access to I/O
         ports using IN and OUT instructions.  This is beyond the
         scope of the first release of this manual.  However, if you
         are lucky, the I/O functions might be called from a "CALL"
         instruction in which case you may defeat the protection
         without much difficulty.  Another disk based scheme used to
         denote legality of software is used during the installation
         process of the software.  With certain programs, when you
         install it, it copies the files into the hard drive.  But it
         also sets a specific sector in the hard drive so that the
         program can recognize it.  This is also similar to diskette
         copy protections, but can be defeated in much the same way.
              Thank goodness that disk based copy protections are
         almost completely out of the software industry.  However, a
         sometimes more difficult copy protection scheme has arisen
         that may sometimes prove to be even more difficult to crack.
         These schemes are commonly known as the doc checks in which
         the user must have a copy of the manual to bypass the
         protection.  With programs compiled as true assembly (you can
         call then "normal" programs), these protections are not too
         bad to trace through and crack.  With programs that run
         scripts (such as Sierra games), this can he a real chore
         however.  Why?  It is because it is like running a program
         within a program.  You just have to be very very patient in
         this case, carefully tracing through the instructions.
              As if these copy protection schemes weren't enough,
         software companies have also added trace inhibition schemes
         to their code.  What does this mean?  This means that you
         will have a hell of a time trying to trace through code.
         However, if you know how these things work, it should not be
         too much of a problem.
              Run-time compression/decompression and
         encryption/decryption of files also make changes to the
         program difficult.  In this case, the loader sure comes in
         handy.  Also, when the data within the file changes due to
         overlays, loaders are also good to use.

                          DISK BASED COPY PROTECTIONS

         Disk Based Copy Protection
         --------------------------
              Since disk based copy protection schemes are rarely
         used, we will not go into great depth in its discussion.

         INT 13h
         -------
              I have previously mentioned that INT 13h copy protection
         schemes are hardly ever used anymore.  Nevertheless, it would
         be good practice for the beginner to learn how to defeat the
         code.  You will most likely see INT 13h used with function 2,
         read sector.  This means that:

              AH => will contain the number 2 (function 2)
              AL => the number of sectors to read in.  This is
                    commonly only 1 since you just want to check a few
                    sectors for disk validity.
              CH => will contain the cylinder number
              CL => will contain the sector number
              DH => will contain the head number
              DL => will contain the drive number
                    00h - 7Fh for floppies
                    80h - FFh for fixed disks
              ES:BX => will point to the address into which the data
                    read from the disk will be written to

              Upon the return for this interrupt, if the carry flag is
         set, that means that the program could not read the sector,
         and therefore the disk is valid.  If the carry flag is clear,
         that meant that INT 13h could read the sector properly and so
         the disk would be bad in the eyes of the program, thinking it
         was a copied disk.
              Okay, now that we know to look for INT 13h in the
         program code, we can begin tracing.  First, we must know the
         difference between debug's "T" and "P".  "T" is the trace
         instruction, which tells it to follow instructions step by
         step.  That also means that in LOOP or REP instruction, the
         trace will patiently go through the loop until finished.
         Also, during CALL instructions, trace will go into the call
         and execute the instructions pointed to by the call
         instruction.  The "P" command is similar to the "T" but with
         the difference in that it traces over instructions.  That
         means that if it encounter a LOOP or REP, it will quickly
         finish up the loop and point to the next instruction.  With a
         CALL, the "P" (proceed) will not go into the subroutine.
         Instead, it will just execute the procedure, then point to
         the next instruction.
              Okay, before you start tracing for hours through a
         program, you must first notice when and where the copy
         protection appears.  Run the program in DOS first and make
         careful note of when things happen.  You might see an intro
         screen, then the music pops up, then the menu comes out.

         Notice this so you will know where you are in the program.
              Once you have done that, you can begin debugging the
         program.  Whenever you start out with a program, you use "P"
         to trace through the program.  Be patient as this might take
         a while.  While you are tracing, watch out for CALLs and
         INTerrupts.  When you are just about to execute the step, try
         to remember the segment and offset of the instruction.  The
         segment is the number to the left of the colon while the
         offset is the number to the right.  As you continue tracing
         through the program, you will find that the screen might
         blank and display the intro screen or something like that.
         This is a good sign and it tells you that you are headed in
         the right direction.  Start slowing down when you feel that
         you are near to the copy protection.

         Situation 1 - Exit from copy protected CALL
         -------------------------------------------
              Oops, you have traced over a call that accessed drive A.
         Unfortunately, you also exited the program.  That's good.
         You have just narrowed down the location of the copy
         protection code.  Now I hope you remembered the address of
         that CALL.  If not, you gotta start all over to find it.
         Anyway, restart the program now.  Now Go to that instruction
         by "G {segment:address}".
              Did something go wrong?  Did the computer freeze or
         something?  It is most likely that this is an overlay or
         encrypted code or something that caused the code at that
         location to change.  In this case, you will have to remember
         the addresses of various instructions along the way.
         Instructions that you want to take note of are far calls (if
         you remember, calls with a segment:offset address as their
         operand).  You don't have to do this for every call.  As you
         crack more and more, you will get the hang of which
         instructions to keep track of.
              Okay, let's assume you have gotten back into the
         location of the code again.  It is a CALL instruction that
         will access the disk drive.  At this point, try skipping the
         CALL instruction.  To do this, type in "RIP {enter}".  Then
         type in the address of the next instruction.  Then execute
         the do or die instruction, "G".  If the program runs fine
         without asking for the copy protection, congratulations!  You
         have cracked the program.
              If the program freezes or does something weird, restart
         the program and trace back to the suspected copy protected
         location.  Now use the "T" command once and start using "P"
         again.  Remember to write down the address of that CALL
         instruction you just traced into so you can come back to it
         quickly.  As you keep tracing, using the above procedures,
         pretend you eventually come up to an INT 13h instruction.
         See what it does by tracing over it.  Make sure you have a
         disk in drive A too.  If there was no error, force an error
         by turning on the carry flag and proceeding.  With INT 13h
         copy protections, this should be sufficient to crack the
         program.

         Situation 2 - Return from copy protected CALL
         ---------------------------------------------
              Okay, the CALL that you just traced over accessed the
         disk drive, but it didn't kick you out.  Keep on proceeding
         and this point.  If there is an instruction that causes you
         to jump because of a carry flag, try fooling around with this
         carry flag and see how the program reacts.  INT 13h copy
         protections are usually simple enough for you to just change
         the carry flag to allow the program to bypass the copy
         protection.

         Access to the Hard Drive
         ------------------------
              The cracking for installation software is also the same
         as cracking for the INT 13h.  You just keep tracing until you
         see some disk activity.  At that point, you try messing
         around with some of the conditional jumps to see what
         happens.  If you have the original program, you should run it
         also to see the differences between the valid and invalid
         copies.

                           DOC CHECK COPY PROTECTIONS

         Doc Check Copy Protections
         --------------------------
              Okay, we have just quickly scanned over disk based copy
         protections because they are rarely used nowadays.  Doc
         checks will be discussed in greater detail for the rest of
         this manual.
              Unlike the disk based protections, which are based on
         hardware identification, doc checks are based on software
         identification.  Therefore, the only information that will
         indicate that a copy protection is happening is the screen,
         unlike the whirr of the disk drive.  The moral, watch the
         screen.  Because this copy protection is software based, it
         will be more of a challenge to trace, but of course, that is
         the "fun" part of cracking.

         The Basics
         ----------
              Make sure you have the COMPLETE version of the program
         you are about to crack.  When you do, run the program in DOS.
         While the program is loading, take note of exactly what goes
         on with the screens, sounds, etc.  Here is what you might
         want to note:

              1)  What comes up first?  Is it a standard text output
                  that asks you for the type of graphics adaptor you
                  have, the number of joysticks, the sound card?
              2)  When does the intro screen come up?  Is it after the
                  music starts?  After the copyright notice?  After
                  the text prompt for the graphics mode you will be
                  operating in?
              3)  What happens now?  An animated sequence that brings
                  you through the beginning plot of a game?  If so,
                  can you press a key and escape from it?
              4)  Now what?  Is there a main menu?  When you start the
                  game by selecting the "START GAME" option from the
                  menu, does the copy protection come up immediately?
              5)  If it doesn't come up immediately, when does it come
                  up?
              6)  Does the copy protection only appear when you are
                  playing the game, or does it come up also when you
                  select "CHANGE OPTIONS" from the main menu?

         Obviously, these questions are merely prompts for you to
         follow.  Use your own mind in discovering what to take note
         of.  There are no set rules for cracking.  It is a puzzle
         that you must use your mind on.
              Okay, once you have run the program, go into your
         debugger (in our case, DEBUG) and load up the program.  One
         tip to use when you first start out programming is to use the
         "P" command to trace through code.  As you become a more
         advanced cracker, you might start seeing patterns in coding.
         These patterns are characteristic of high level programming
         languages (Pascal, C, etc.) and are usually the
         initialization code for the rest of the program.  Use "P" for
         each instruction, one at a time.  Be patient as this might
         take a while.
              Okay, you have been tracing for some time now and
         finally, you notice something happen.  The screen might have
         blanked or maybe a message prompting you to enter the
         graphics mode may have popped up.  Was this what you have
         noted before?  It should be and you can assure yourself that
         you are headed in the right direction.  As you keep tracing
         programs, you notice that CALLs usually do something
         significant.  A CALL might clear the screen or sound some
         music.  When it does something rad like this, write down its
         address as the segment:offset pair.  The segment is the
         number to the left of the colon while the offset is the
         number to the right of the colon.  Don't be a dork and set a
         breakpoint there.  Write it down on paper or something.  We
         will see later on why breakpoints fail miserably in the cool
         wares.
              Why take note of these instructions?  As you trace
         deeper and deeper into programs, the coding often loads up
         overlays or maybe decompresses code to the memory location
         that you have just traced over.  Therefore, if you set a
         breakpoint there, or execute a "G" instruction to that
         address, you will fuck up the program and cause your computer
         to freeze.  We will see why when we examine how breakpoints
         and single stepping works.
              Also, while you are tracing using "P", mentally remember
         the addresses of the CALLs.  That way, if you trace over a
         call that brought you immediately to the copy protection, you
         won't have to retrace the code again.  You don't have to
         write down all of the addresses, of course, just remember one
         at a time and write them down if they do anything
         significant.

         Code Guards Through Keyword Entry
         ---------------------------------
              Okay, you know that the copy protection is one in which
         the program waits for you to type in a keyword that you have
         to look up in the manual or something.  Here are then
         following steps you should take.

         Situation 1 - Return from a copy protected CALL
         -----------------------------------------------
              When a copy protection coding reveals itself on the
         screen, you can have a situation in which you are returned to
         the debugger, waiting for the next instruction to be
         executed.  Now, suppose that the CALL asked you to enter a
         code.  You entered an incorrect code and were returned to the
         debugger, but you have not exited the program.  Make sure
         that you have previously recorded the address of this CALL.
         Now, you can do two things, (1) you can try skipping over the
         CALL, (2) you can trace on further.  As you become more
         experienced, you will be able to better decide.  As one with
         experience, however, I can say that 90% of the time, you will
         have to trace further on, but hey, you might get lucky.
              For now, let's say you are lazy and decide that you want
         to skip over the call to see what happens.  To do this, you
         must restart the program.  Then trace your way back to the
         CALL where the copy protection was located.  Use "G
         {segment:offset}" to do this.  If, for some reason, the
         computer freezes when you do this, you will have to use "G"
         followed by the addresses of the CALLs that you have noted
         down to be significant.  If that doesn't work, resort to
         retracing the code over again.  As you become more
         experienced, you will find that you rarely have to retrace
         the entire code since you can "feel" what is going on.  Okay,
         now that you are at the location of the CALL, this is the
         time to skip over the instruction.  To do this, enter "RIP"
         and then the address of the next instruction's address.  Now
         enter the "G" command and see what happens.  If the program
         runs just fine, you've cracked the program.  If the program
         kicks you out or crashes, you have to do some more tracing.
              Okay, so you've decided to continue tracing from the
         point of the copy protection.  There are usually a bunch of
         CMP and J? CMPS? instructions after the call.  This point on
         is the difficulty of cracking for a beginner since you don't
         know what the fuck is going on.  All those compares and jumps
         don't mean shit to you are you are about to pass out in
         frustration.  Don't distress, here are a few tips I can give
         you.  If these don't work, you gotta find out your own
         solutions to the problem.
              Okay, in all probability, the CALL that you just traced
         over was acting as a read string procedure (like BASIC's
         INPUT).  That means somewhere in the computer's memory, there
         lies the code that you typed in and the code that you were
         supposed to have typed in.  What this would mean is that the
         code after the CALL will do some sort of string comparison.
         Look out for these.  It might be hidden inside another CALL
         if you're lucky.  In such a case, does the program kick you
         out?  If it does, you have to trace into the call using "T"
         to see what is going on.  Okay, the string comparison will
         most likely take the form of some kind of loop.  Maybe "REP
         CMPSB" or "LOOP".  In the case of the REP CMPSB, there might
         be a JZ/JNZ or JCXZ/JECXZ that follows it.  When strings
         match, the CX register will be zero.  If CX is not zero, the
         strings are not the same and the conditional jump will
         probably jump to an exit routine.  All you have to do is to
         change the status of the zero flag.  Then, try out the "G"
         instruction.  If it still didn't work, start over and do some
         more tracing.  If the string compare is not of the REP form,
         there will be some kind of loop that will check between two
         memory locations.  In such a case, you will just have to
         become accustomed to realizing that the code is a string
         compare.  There is no standard code for this.  If you know
         you have entered a wrong code, trace through the loop and see
         where in the loop you are thrown out of the loop.  At this
         point, you can go back to it, change some flags to make sure
         you stay in the loop.  When you exit through a different
         location, you have probably bypassed the code and now, you
         can enter "G" to see what happens.

         Situation 2 - Exit from a copy protected CALL
         ---------------------------------------------
              When a copy protection coding reveals itself on the
         screen, you can have a situation in which you are not
         returned to the debugger, instead, causing you to exit the
         program.  In this case, you have to restart the program and
         trace into the CALL using "T".  After that, you can start
         using "P" again to uncover the location of the code.  You
         will most likely encounter a condition that will resemble
         situation 1.  Follow its instructions.

         Shortcuts For Keyword Entry Protections
         ---------------------------------------
              With keyword entry systems, you might be lucky to have
         the codes stuck somewhere into file in its
         uncompressed/unencrypted form.  This means that you can "see"
         the keywords in its ASCII format.  This case is cool because
         you won't have to do any tracing to crack the program.  All
         you have to do is to dump the contents of the files to find
         something that looks like a keyword.  (Always backup the file
         that you are about to alter.)  When you have found such a
         file and the location of the codes, all you have to do now is
         to change the codes to values that you know.  For example,
         one code might call for you to enter "PIRATE".  It's a bitch
         if you don't know the code.  But if you change the code to
         your name or something else you will never forget ("CYBORG"),
         then you'd be set.
              However, in most instances, you can't simple just type
         over the old code with your new code.  In high level
         languages, these codes are stored as strings.  In 'C',
         strings are stored in their ASCII equivalent.  They are then
         terminated with a NULL character (this is a 0).  In Pascal,
         the lengths of the strings are first stored in the first
         position.  Then, the ASCII is stored.

         NULL Terminated Strings
         -----------------------
              So, if you see zeros after the codes, this is a NULL
         terminated string.  Now, start at the beginning of the string
         and enter your code.  Then, enter the '0'.  Make sure your
         string is less than the original string since 'C' refers to
         these strings also with pointers.

         Pre-Length Indentifier
         ----------------------
              If you see numbers before strings, enter your own code.
         Then change the length of the code appropriately.  Make sure
         you do not exceed the length of the original string.

         Code Guards Through Pointed Icons
         ---------------------------------
              We have a case where we do not type in keywords.
         Rather, we must use a pointer device such as the cursor keys
         on the keyboard, the mouse, or joystick.  These protections
         are a bit more complicated since there are no strings to
         compare against.  Rather, the input will be a number stored
         in memory or a register.  This is what makes this copy
         protection more difficult to crack.  We have to hunt through
         code to find out which compare instruction is the key.
              What you have to do is to find the general location of
         the copy protection code as before.  Then, instead of typing
         in the keyword, you select the icon.  Like before, you must
         step slowly through the code and go until the program JUST
         STOPS asking you for the code.  For example:

         2E0B:0000 E8740E         CALL   0E77
         2E0B:0003 38D0           CMP    AL,DL
         2E0B:0005 7569           JNZ    0070
         2E0B:0007 CB             RETF

         You might decide to trace over the call at address xxxx:0000.
         But then, you see that the screen displayed the icons and you
         got to select the code.  Then, the procedure does some disk
         activity and you return to address xxxx:0003.  If you see
         something happen after you have just finished entering the
         code or if it is slow in returning you to debug, then,
         some code must have been performed before you returned.  In
         this case, you must trace into the CALL to see what has
         happened.  If not, there is still a small probability that
         there were some instructions that formatted the code you
         entered and saved it to a memory location.  (We'll talk about
         multiple doc checks later.)
              Realize that most of the programs that you will be
         cracking have been programed by C or some other high level
         language.  These languages often use the stack (SS:SP) to
         pass parameters (variables) or to create local variables for
         a procedure's use.  Most likely, you will see compares to
         data contained within the stack such as "CMP AX,WORD PTR
         [BP+10]" or "MOV DX,WORD PTR [BP+10]".  This is what you hope
         to find, although not always the case.  If you do see some
         access via the stack using the BP register as a pointer, you
         may have something there.  Then, all you would have to do is
         to mess around the flags register (most likely, JZ/JE will be
         used) at the compare instruction.

         Multiple Doc Checks
         -------------------
              There are some wares that invoke multiple doc checks,
         doc checks that pop up either systematically or randomly.  In
         addition, there could also be two types of this protection.
         The doc check could be a similar type (eg. typing the code
         found on page...) or they could be different (eg. typing in
         the code on page... then select the correct icon), although
         the latter is more rarely used due to its extensive memory
         usage.

         Situation 1 - Similar doc checks
         --------------------------------
              Cracking multiple doc checks that are similar is just
         like cracking with just one doc check.  The procedure to
         trace is still the same.  Keep Proceeding until you come up
         to the CALL that contains the copy protection.  Just use the
         sequences mentioned above.  When you are absolutely positive
         that the call contains the copy protection (skip the CALL and
         see what happens; if the protection has been bypassed but
         appears at other times, you got something), here is what you
         do.

              1)  Note what type of CALL it was.  Near if the operand
                  (number after the CALL) was a four digit number or
                  far if the operand contained the segment:offset
                  pair.
              2)  Trace INTO the call.
              3)  At the first instruction, note the address inside
                  the CALL.
              4)  Then, type in "A" then the address of that very
                  first instruction.
              5)  If there was a near call performed, now type in
                  "RETN", otherwise, type in "RETF".
              6)  Now run the program ("G") and see what happens.

         If this call was definitely the copy protection, you should
         have bypassed the copy protection completely.  Otherwise, you
         might have a case like situation 2.

         Situation 2 - Different doc check types
         ---------------------------------------
              Again, cracking multiple doc checks are like cracking
         single doc checks.  You follow the same procedures until you
         come up to a copy protected location.  Then, you would trace
         into the code as explained in situation 1 just to make sure
         that the code is not called up again.  Different doc checks
         are a bitch to do because you have to manually keep tracing
         until you find each one to effectively rid yourself of the
         copy protection.  There is not sure way of getting rid of all
         the doc checks any other way.  But luckily, there are very
         few wares out there like this.  Remember, the more the
         company shoves into the program's memory, the more money it's
         gonna cost them.

              Of course, I cannot cover every single type of doc check
         since there are too many of them.  You'd just have to use
         your own imagination to solve some of them.

                               SPECIAL SITUATIONS

         Special Situations
         ------------------
              What all crackers are faced with at one time or another
         are situations that call for intuitive thinking to overcome
         the barrier.  Remember, there is no one sure way of cracking.

         INT 3 - Problems During Tracing
         -------------------------------
              Sometimes, when you start cracking, you just find your
         instruction pointer messing up.  You keep tracing and
         tracing, then your computer freezes.  But then, when you type
         "G" at the beginning of the program, it works just fine.
         What is happening here?  There are several things that the
         program could do to impede tracing.  Unless you have a
         hardware debugger, you have to settle in for more primitive,
         intuitive methods.  First, we have to find out how a software
         debugger works.
              I now introduce you to INT 3 and INT 1.  They are the
         breakpoint and single stepping interrupts respectively.  We
         will be looking at INT 3 the most.
              What happens when you set breakpoints?  Well, here is
         what the debugger does.  At the address you have specified,
         the debugger will read in the byte at that address and store
         it somewhere else in its own memory.  This byte is part of
         the whole instruction located at that address.  For example,
         if there was an "INT 13" at that location, the machine
         language equivalent will be CD13h.  Debug will read in the
         first byte, CDh, and save it in memory.  The CDh will then be
         replaced by INT 3 (CCh).  So, the code will now look like
         CC13h in machine language.  When you unassemble this at the
         address, you will see "INT 3" (the instruction only takes up
         one byte) and some gibberish after that.  So, when the CPU
         comes up to this address, it will encounter INT 3 and will
         return control to the debugger.  The debugger then replaces
         the INT 3 with the CDh byte used before.
              With single stepping, the same thing occurs.  Debug will
         also insert the INT 3 instruction at the instruction after
         the one you are about to execute.  Then, internally, a "G"
         instruction is performed until it reaches the INT 3, at which
         point, the byte will be replaced and everything will be cool.

         Use of INT 3 to Call Up Other Interrupts
         ----------------------------------------
              This INT 3 deal seems to be cool, working in many
         situations.  But what if the software vendor reprograms INT 3
         to point to an INT 21?  Many programs use INT 21 to access
         DOS functions like reading a file, etc.  There would be a
         conflict now as the program uses INT 3 to call up DOS while
         debug wants to use INT 3 for its breakpoints.  There is also
         another problem.  INT 21 uses two bytes (CD21h) while INT 3
         uses only one byte (CCh).  Therefore, you cannot replace INT
         3 with the INT 21.

              Also, INT 3 could be reprogrammed so that every time it
         is used, the program will just exit to its higher process.
         So every time you single step, you will be kicked out of the
         program.

         Parity Errors with INT 3
         ------------------------
              The tough copy protections use the change of memory to
         obstruct tracing.  Examine the code below:

         2E0B:0500 FC             CLD
         2E0B:0501 B80000         MOV    AX,0000
         2E0B:0504 BB0000         MOV    BX,0000
         2E0B:0507 BE0005         MOV    SI,0500
         2E0B:050A BF0010         MOV    DI,1000
         2E0B:050D B90005         MOV    CX,0500
         2E0B:0510 AC             LODSB
         2E0B:0511 345A           XOR    AL,5A                         ;'Z'
         2E0B:0513 01C3           ADD    BX,AX
         2E0B:0515 AA             STOSB
         2E0B:0516 E2F8           LOOP   0510
         2E0B:0518 3B1E0043       CMP    BX,[4300]
         2E0B:051C 7403           JZ     0521
         2E0B:051E E9EF2A         JMP    3010
         2E0B:0521 D1E0           SHL    AX,1

         Notice what the program is doing.  It is performing a simple
         decryption of a block of code from address 500h and putting
         it in address 1000h.  In addition, there is a checksum being
         performed at address .  The program is adding all those bytes
         up, then comparing the number with some other number (a
         checksum value) in memory at address 4300h.  So what you may
         say.  When the program is run without any set breakpoints,
         the program will run fine.  But when you start tracing
         through the code, or putting a breakpoint somewhere after the
         loop, the program will cause you to exit.  If you decide to
         change the program so that it will let you pass regardless of
         the checksum value, somewhere along the line, the program
         will fuck up.
              This goes back to the idea of INT 3.  Right before debug
         executes an instruction, it places an INT 3 at the next
         instruction.  In this program, when debug places this
         interrupt and executes an instruction, the program is reading
         in this INT 3 at the address and copies it to a different
         address.  INT 3 is obviously a different number than the
         other instructions, so the checksum value will be different.
         So, now that INT 3 is copied to another location in memory,
         debug also cannot replace that with it's original byte value.
         Therefore, if you try to force the checksum to match and
         continue running the program, the program will crash because
         the INT 3 is causing the instructions after itself to be
         interpreted incorrectly by the CPU.
              To bypass this, you have to make sure not to get your
         INT 3 placed in the wrong place at the wrong time.  Looking
         at the program, you can keep tracing normally until the SI
         register points to any byte past the CMP instruction at
         address 519h.  Then, you can do a "G 518" to finish off the
         loop quicker.  Debug will place a temporary INT 3 at address
         518h, but it doesn't matter now since SI will be past 518h.
         This is obviously a simple example, but it gets the point
         across that you have to watch where you trace.

                                OVERLAYS/LOADERS

         Overlays/Loaders
         ----------------
              Sometimes, programs will have an initialisation code and
         upon its completion, call up another program or overlay.
         These programs present unique situations in which it is
         sometimes difficult, after finding the copy protection code,
         to write the changes to disk.  Let's see what these programs
         do before we go on to the next topic of making changes
         permanent.
              Loaders are usually small programs that might first ask
         you for the graphics mode or what sound card you have.  When
         finished, it will load up another program.  Sometimes, this
         is done with DOS' interrupt 21h, function 4B00h (load and
         execute).  This is the same interrupt DOS uses to load up
         programs when you type them in at the DOS prompt.  You can
         tell what file is going to be executed by tracing up to the
         INT 21 instruction and dumping the address pointed to by
         DS:DX (type in "D DS:DX").  Also, internal procedures could
         be used to call up the program.  Use what you've learned to
         trace through them.
              Code decryptions or dynamic heap allocation where data
         is to be loaded presents problems as well.  Code that changes
         as the program progresses makes code changes difficult in the
         file itself.  And when you want to alter sometime in the data
         area, something called a heap is often used to store the
         data.  The thing with the heap is that it can be allocated at
         anytime and depending on what is currently in memory, you
         can't tell where the memory is going to be located.  In these
         cases, you might choose to go with run-time memory overlays
         (discussed later).

         Writing the Changes Out to the File
         -----------------------------------
              Okay, so you've found the copy protection.  You also
         know how to bypass it.  Now, the next problem you will most
         likely encounter is writing it out to a file.  But first,
         let's assume a simple case.

         Using a Hex Dump Program
         ------------------------
              Included is this package is one of the files from Norton
         Utilities which does a decent job of finding and changing the
         contents of files.  Before we exit that debugger, we must
         know what to look for.

              1)  At the location of the instruction, copy down the
                  machine language equivalent of the instruction.  At
                  instructions after that, also take down their
                  machine level equivalents.  This is what you will
                  use to search for the code in the file.
                  a)  If there is a near call or a near jump or a near
                      memory access, you can just write down all the
                      hex numbers.
                  b)  If there is a far call (CALL DS:[5C10+BX]) or a
                      far jump (JMP DWORD PTR ES:[5080+BX]) or a far
                      memory access (MOV AX,WORD PTR ES:[10+SI]), then
                      do not write these instructions down.  In .EXE
                      files, anything that is located in different
                      segments will have different displacement
                      values.  This is a value in the file.  At the
                      beginning of the file is a table that tells DOS
                      where these instructions are located.  When the
                      program is loaded into memory, the pointers are
                      changed appropriately to match the memory
                      location.  So, write down other near
                      instructions like CLD, JZ 100, INC AX, etc.
              2)  After you know what to search for, you must now know
                  what you will have to be changing.  Very often,
                  NOP's are used to "delete" code.  For example, if
                  there is a CALL 3140 and we want to skip this call,
                  we can NOP it out.  The near call takes up three
                  bytes.  The NOP takes up one byte.  So, type in "A"
                  at the address of the call and enter "NOP" three
                  times.  Then unassemble the code to make sure that
                  the code still looks okay.  Take down the machine
                  level equivalents of the NOP's (90h).  Same thing
                  with conditional jumps.  Suppose you have a JZ 90
                  and you want it to jump to address 90 everytime,
                  then type in "A" at the jump instruction and enter
                  "JMP 90".  Then, just write down the machine code as
                  before.  One thing, however.  You cannot do what I
                  have just said above with far calls.  Remember, the
                  numbers will be different in the file as compared to
                  memory.  So what do you do?  No problemo.  At the
                  call instruction, trace into the call and place a
                  "RETF" instruction at the address of the callee.
                  This will be the location that you will search for
                  (write down the bytes here) and where you will be
                  writing to (RETF is CBh in machine language).
              3)  Finally, after all this is through, you can enter
                  your file editor and search for the numbers you
                  wrote down.  Then, you can change the numbers.  Now
                  run the program and it should be cracked.  But
                  remember, always backup the file you are about to
                  change.

         Using a Memory Overlay
         ----------------------
              When do you use these things?  You would use memory
         overlays when step 3 (stated above) has failed in some way.
         Maybe you couldn't find the code, or when you change it, the
         program freezes up.  Don't fret, the memory overlay is here.
         What is a memory overlay?  It is an external program (TSR)
         that when it reaches a certain point during program
         execution, it will change the location in memory you have
         specified.  It overlays the code during run time.

         Here is what you will need to do to make the overlay
         work.  First, you must find some way for the program to call
         up the overlay code.  This can most easily be done by
         reprogramming interrupts.  So, the first thing you have to do
         is look for an interrupt usage near the copy protection code
         (usually an INT 21h or INT 10h).  When you find this
         interrupt (it must be fairly close to the code), write down
         the address of the NEXT instruction.  You must get down the
         segment and the offset.  Also, get down the current status of
         the registers.  For interrupts like INT 21h and INT 10h,
         write down the functions numbers (eg. AX,AL,BX,DX,etc.).
         Then, keep tracing until the copy protection code.  Get the
         address of the instruction that you want to change (the
         segment and the offset).  Also get down the machine language
         equivalent of the changed code.  This should be all you need
         for the overlay program.  Here is the overlay program:

INT_SEG         equ     1DA5h           ;SEG:OFF of instruction after the
INT_OFF         equ     05D1h           ; calling interrupt
CHANGE_SEG      equ     2DA5h           ;SEG:OFF of instruction to change
CHANGE_OFF      equ     0432h

OVERLAY segment para    'code'

        assume  cs:OVERLAY,ds:OVERLAY

        org     100h                    ;This will be a .COM program

START:  jmp     INITCODE                ;Initialization code

;**************************************************************************

OLDINT          dw      0,0             ;Storage for old interrupt address

ADDR_OFF        equ     <word ptr [bp+2]>
ADDR_SEG        equ     <word ptr [bp+4]>

CR              equ     0Dh             ;Carriage return
LF              equ     0Ah             ;Line feed
BEEP            equ     07h             ;Beep
EOS             equ     '$'             ;End of DOS string

DISPLACEMENT    equ     CHANGE_SEG - INTSEG

;**************************************************************************

NEWINT  proc    far

        push    bp                      ;Establish stack frame
        mov     bp,sp
        push    ax                      ;Save necessary registers
        push    bx
        push    cx
        push    dx
        push    si
        push    di
        push    ds
        push    es

        mov     bx,ADDR_OFF             ;Get offset
        cmp     bx,INT_OFF
        jnz     EXIT

        cmp     ax,0201h                ;Check for AX=0201h     <=(1)
        jnz     EXIT
        cmp     bx,0001h                ;Check for BX=0001h     <=(2)
        jnz     EXIT

        mov     bx,ADDR_SEG             ;Get segment
        add     bx,DISPLACEMENT
        mov     ds,bx                   ;This will be the segment of change

        ;change the number at the next line to point to the offset of
        ; the address to be changed
        mov     bx,1C12h                ;This is the offset of the change
        mov     al,0EBh                 ;This is the byte to be changed
        mov     [bx],al

        ;change the number at the next line to point to the offset of
        ; the address to be changed
        mov     bx,1C20h                ;This is the new offset of the change
        mov     ax,0B8h                 ;This is the byte to be changed
        mov     [bx],ax
        mov     al,0                    ;This is the next byte to be changed
        mov     [bx+2],al

        pop     es                      ;Restore necessary registers
        pop     ds
        pop     di
        pop     si
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        pop     bp
        iret                            ;Interrupt return

EXIT:   pop     es                      ;Restore necessary registers
        pop     ds
        pop     di
        pop     si
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        pop     bp
        jmp     dword ptr cs:OLDINT     ;Jump to old interrupt
                                 
NEWINT  endp

;**************************************************************************

FINISH  equ     $

MESSAGE db      "This is an overlay loader.",CR,LF
        db      "Written by The Cyborg.",CR,LF,BEEP,EOS

INITCODE:
        mov     ax,cs
        mov     ds,ax                   ;DS point to CS

        mov     ah,9                    ;Print string
        mov     dx,offset MESSAGE       ;The address of the message
        int     21h

        mov     ax,3510h                ;Get old interrupt address
        int     21h
        mov     OLDINT[0],bx            ;Save in memory for later use
        mov     OLDINT[2],es

        mov     ax,2510h                ;Set new interrupt address
        mov     dx,offset NEWINT        ;Point to new procedure
        int     21h

        lea     dx,FINISH               ;CS:DX of last byte of code to remain
        int     27h                     ; in memory.  Terminate and stay
                                        ; resident.

OVERLAY ends

        end     START

         All you have to do is set the first four values in the first
    four lines of the file.  They are the segment:offset pairs of the
    interrupt address and the address of the bytes to be changed.
    Also, change the functions to check for at (1) and (2) to
    appropriately check for proper code entry.  Then, specify which
    bytes you will be changing at the specified lines.  Then compile
    this crack ("ASM OVL {enter}").
         The next program demonstrates a simple loader.  It also
    demonstrates what you can do if you have a program that utilizes
    scripts or dynamically allocated data areas in heap spaces.  This
    program scans for a known segment in memory for a "keyword".  When
    it finds this, it can then begin writing new code to overlay the
    old data.  Note, KEYWORD specifies the keyword to look for.  Then,
    CRK (0's) is the list of bytes to replace the data areas pointed
    to by addresses listed in LIST.  The addresses in LIST are
    displacement addresses.  This means that at the address the
    keyword was found in, the appropriate number listed in LIST is
    added to that address.  There are thirteen addresses whose data
    are to be changed in this case.
         Also interesting to note is that this program is using two
    interrupt vectors, INT F1h and INT 21h.  INT 21h is used in the
    same way as the above overlay program uses it.  It replaces two
    bytes at offset 1FE5h with CDF1h.  This is the machine language
    equivalent of INT F1h.  Now, let's examine what INT F1h actually
    does.  First, it changes the return address in the stack so that
    instead of returning to the address right after the INT F1h
    instruction, it will return to another instruction, located at
    offset 1FE5.  This is the location of the INT F1h instruction.
    This interrupt, upon its completion, will replace the INT F1h
    instruction with the original instruction and run the program
    normally.
         The loader itself is simple.  It reallocates the memory
    located to itself to accommodate a "daughter" program, the program
    that it is going to load.  If it can't find the program or if an
    error has occurred trying to execute the program, the loader will
    load itself up as a TSR.  Then, you can run the program via DOS.
    This loader also checks if INT F1h has been occupied and returns
    an error if it is.

LOADER  segment para    'code'

        assume  cs:LOADER,ss:LOADER

        org     100h

BEGIN:  jmp     INIT

CR      equ     0Dh
LF      equ     0Ah
BEEP    equ     07h
EOLN    equ     '$'

OPTION  db      1                       ;Options
CRC     dw      0                       ;Cyclic Redundency Checking data

START   equ     $

OLDINT1 dw      0,0
OLDINT2 dw      0,0
KEYWORD db      "weat"
CRK     db      0,0,0,0
LIST    dw      0h,014h,019h,02Dh,041h,046h,05Ah,05Fh,073h,087h,08Ch,0A0h,0B4h

        ;********** New Interrupt 1 **********;

NEWINT1 proc    far

        push    bp                      ;Establish stack frame
        mov     bp,sp
        push    ax                      ;Save registers
        push    bx
        push    cx
        push    dx
        push    di
        push    si
        push    ds

        mov     ax,cs
        mov     ds,ax

        mov     ax,word ptr [bp+2]      ;Get offset
        cmp     ax,1FE7h
        jnz     EXIT1

NEXT1:  mov     ax,1FE5h                ;Where to return next
        mov     word ptr [bp+2],ax

        mov     ax,word ptr [bp+4]      ;Get segment
        mov     ds,ax                   ;Put in data segment
        mov     bx,1FE5h                ;Offset to change
        mov     ax,0D803h               ;The new code to put in
        mov     [bx],ax                 ;Store changes

        mov     ax,cs                   ;Get current data segment
        mov     ds,ax

        mov     di,0                    ;Where to start search
        mov     dx,0FF00h               ;Search the entire segment
        mov     bx,0
COMP:   mov     di,bx                   ;Where to begin
        mov     si,offset KEYWORD       ;Get keyword
        mov     cx,4                    ;Lenght of keyword
        repe    cmpsb                   ;Compare until done
        jz      MATCH
        inc     bx
        dec     dx                      ;Done?
        jz      EXIT1                   ;If no match, exit
        jmp     COMP

MATCH:  mov     dx,bx
        mov     ax,0E07h
        int     10h
        mov     bx,offset LIST          ;Get list of codes to change
        mov     cx,13                   ;Number of locations to change
NEXT2:  push    cx
        mov     cx,4                    ;Lenght of string
        mov     di,[bx]                 ;Get destination
        add     di,dx
        mov     si,offset CRK           ;Get string to copy from
        rep     movsb                   ;Copy String
        inc     bx                      ;Next location
        inc     bx
        pop     cx
        loop    NEXT2

EXIT1:  pop     ds                      ;Restore registers
        pop     si
        pop     di
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        pop     bp
        iret                            ;Interrupt return

NEWINT1 endp

        ;********** New Interrupt 2 **********;

NEWINT2 proc    far

        push    bp                      ;Establish stack frame
        mov     bp,sp
        push    ax                      ;Save registers
        push    bx
        push    ds

        mov     bx,word ptr [bp+2]      ;Get offset
        cmp     bx,0Ch                  ;See if called from the proper offset
        jnz     EXIT2                   ;If not, exit

        cmp     ah,30h                  ;See if want this function call
        jnz     EXIT2                   ;If not, exit

        mov     bx,word ptr [bp+4]      ;Get segment
        add     bx,0F8Dh                ;New segment
        mov     ds,bx
        mov     bx,1FE5h                ;New offset
        mov     ax,0F1CDh               ;The new instruction
        mov     [bx],ax                 ;Save changes in memory

EXIT2:  pop     ds                      ;Restore registers
        pop     bx
        pop     ax
        mov     sp,bp
        pop     bp
        jmp     dword ptr cs:OLDINT2    ;Call old interrupt

NEWINT2 endp

FINISH  equ     $

        ;********** Initialization Code **********;

PARAM   dw      0
        db      80h,0
PARAM1  dw      5 dup(0)
PROG    db      8 dup('1234567890')

MESS    db      'Savage Empire áeta Crack v1.0  July 15,1991',CR,LF
        db      'Loader needed only after creating a character.',CR,LF
        db      "Press {ENTER} at the copy protection.",CR,LF,BEEP,EOLN
ERR1    db      'ERROR: Not enough memory.  '
        db      'Activating TSR sequence.',CR,LF,BEEP,EOLN
ERR2    db      'ERROR: Could not load program.  '
        db      'Activating TSR sequence.',CR,LF,BEEP,EOLN
ERR3    db      'ERROR: Interrupt vector (0xF1) already occupied.',CR,LF
        db      ' Release memory before restarting.',CR,LF,LF,BEEP,EOLN

INIT:   mov     ah,9                    ;Print string
        mov     dx,offset MESS
        int     21h

        mov     ax,35F1h                ;Get interrupt vector
        int     21h
        mov     OLDINT1[0],bx           ;Save in memory
        mov     OLDINT1[2],es

        cmp     word ptr es:[bx],8B55h  ;Check for vector occupation
        jnz     CONT1

        mov     ah,9                    ;Write string
        mov     dx,offset ERR3
        int     21h
        mov     ax,4C03h                ;Exit with error 3
        int     21h

CONT1:  mov     ax,25F1h                ;Set interrupt vector
        mov     dx,offset NEWINT1
        int     21h

        mov     ax,3521h                ;Get interrupt vector
        int     21h
        mov     OLDINT2[0],bx           ;Save in memory
        mov     OLDINT2[2],es

        mov     ax,2521h                ;Change interrupt vector
        mov     dx,offset NEWINT2
        int     21h

        cmp     OPTION,0                ;See if wants to run program
        jz      EXIT3

        mov     ax,cs
        mov     ds,ax
        mov     es,ax
        mov     bx,offset ENDCODE       ;Get end of memory
        shr     bx,1                    ;Convert to paragraphs
        shr     bx,1
        shr     bx,1
        shr     bx,1
        inc     bx
        mov     ah,4Ah                  ;Reallocate memory
        int     21h
        jnc     OKAY1                   ;If no error, continue
        mov     ah,9h                   ;Write string
        mov     dx,offset ERR1
        int     21h
        jmp     EXIT3

OKAY1:  mov     ax,cs
        mov     PARAM,ax
        mov     PARAM1,ax
        mov     bx,offset PARAM
        mov     dx,offset PROG
        mov     ax,4B00h                ;Load and execute child
        int     21h
        jnc     OKAY2                   ;If no error, continue

        mov     ah,9h                   ;Write string
        mov     dx,offset ERR2
        int     21h
        jmp     EXIT3

OKAY2:  mov     ax,25F1h                ;Restore interrupt vector
        lds     dx,dword ptr OLDINT1
        int     21h

        mov     ax,2521h                ;Restore interrupt vector
        lds     dx,dword ptr OLDINT2
        int     21h

        mov     ax,4C00h                ;Exit with error code 0
        int     21h

EXIT3:  lea     dx,FINISH               ;Offset of booster
        int     27h                     ;Exit with ejection of booster

LOADER  ends

        end     BEGIN

                                CONCLUSION

    Conclusion
    ----------
         Okay, so we've seen the processes of cracking.  If you are
    just a beginner and don't know much about programming, you
    probably got lost somewhere right after the introduction.  I would
    suggest that you spend some time learning assembly before doing
    anything else.  Actually, you don't have to start out with
    assembly.  I started programming using BASIC.  When I got really
    good at it, I jumped into Assembly, regardless of how difficult
    people said it was.  Assembly is not at all difficult if you have
    had some previous knowledge of another language.  It is only
    difficult if you make it hard.  And after you've learned assembly,
    you get a "feel" for the other languages and can learn them in a
    matter of days.  Pascal, Modula-2, C, C++, ..., they're are based
    on assembly language programming.
         Cracking is like the debugging process of programming.  To
    become experienced with debugging is to become adept at cracking.
    You just need lots o' practice as practice makes perfect.
         One final note.  I got this manual out kinda quickly so there
    are bound to be errors, inconsistencies in what I've said, unclear
    passages, etc.  Well, too bad.  If you really want a good manual,
    tell me or something and I'll consider it.  I got really bored
    towards the last parts of the manual so it went pretty fast,
    skipping over some stuff.  If a lot (and I mean A LOT) of people
    want a better manual, tell me and give me suggestions.  I'll find
    the time to do it somehow.
         Anyways, have fun!

0 comments:

Post a Comment

mobile here

Popular Posts