***************************************
*                                     *
*     KRAKOWICZ'S KRACKING KORNER     *
*                                     *
*      THE BASICS OF KRACKING 3:      *
*                                     *
*   MEMORY MOVES, BINARY FILES, AND   *
*       KRAMMING FOR THE FINALS       *
*                                     *
***************************************


  In the last episode, we pondered the starting address of a program and
ways to find it in spite of the protectors' subterfuge. This time we'll
discuss how to get the program into saveable format, even if it's too
long to save as a bfile. Although we'll be referring at first to
single-load programs, most of these techniques are applicable to
programs with disk access.

  Before we begin the process, let me philosophize for a few seconds on
the procedures and practices to be used. This is a discipline: perhaps
not so demanding as championship karate or the unification church, but
it requires knowledge, patience, and attention to detail. I urge you to
begin each adventure in kracking with a sharp pencil, plenty of paper,
and a good eraser. From this point forward in our quest, record-keeping
will occupy an important part of the total activity. If you have a
printer, print out any pertinent sections of code and write in your own
comments about what it means. Write down every address of interest, and
keep especially careful notes of the nature and sequence of all memory
moves, starting points, and tricks used by the protectors. Do this not
just because it's character building, but because unless you have
exceptional recall, all programs will eventually blend together into a
warm and fuzzy memory. Keep good notes on everything you learn, and
remember: "those who cannot recall the mistakes of the past are doomed
to repeat them."

  Suppose you have loaded in, reset with your old monitor rom, and
finally located the starting address to the greatest game ever written:
"hyperspace android clone killer" or "hack". The starting address is
4123, and the game occupies memory from 800 to B000. You already know
that if any memory above 9D00 has been used by the program, dos is dead,
and you can't save the program to disk with a DOS command. As you also
undoubtedly know, if the program were smaller you would have the option
of booting a disk and saving the game as a binary file. Let's take just
a second, though, and review what happens to memory when you boot a
disk.

  First of all, don't use a master disk, since the DOS on a master is
loaded first into 1600-3FFF and then relocated to the higher regions of
memory. Booting a 48K slave disk will disturb only 0-8FF and 9600-BFFF,
and if your program lives within or can be rearranged to fit these
boundaries, you can safely boot the disk and save the program as a
binary file.

  An old method of saving a binary file is well-known to those of us who
bought apples in the dark ages before the Disk II, but there are now
maybe half a million (!) Apple owners who are unfamiliar with the
cassette port and its use. In general, almost any cassette recorder that
has a tone control can be used, but for some reason the cheaper ones are
generally better. To use one, plug both cables into the correct
connector ("in" means into the computer, not into your recorder), and
turn the tone control almost to the top of the treble range. Save a
small basic program (refer to the manual for use of the basic commands)
at any old volume control setting. Try loading the program back in
several times, increasing the volume control setting until the program
loads reliably. You'll find that the tape works very well, even on long
files, especially when the same recorder is used to record and
playback.

  What's good about the tape system is that even when dos is completely
dead, the monitor commands for tape I/O are still active (assuming you
didn't wipe them out of your old monitor ROM). See the reference manual,
page 46 for a complete description. With tape, you can always save any
part of memory at any time! (worth keeping in mind for those crucial
situations when the system crashes just as you are finishing your term
paper on the word processor). The cassette routines use only locations
3C-3F and 42-43 in zero page, and the only part of memory you shouldn't
try to save is C000-C0FF-- some terrible things can happen if you try.
In most cases, it's best to save a long program in two files so it can
be reloaded in between 800 and 9600 after DOS is in memory. For our
example of "hack", the necessary monitor commands are:

  *0.4FFFW  (long wait)
  *5000.AFFFW  (longer wait)

after booting a disk, you can reload with:

  *1000.5FFFR (reload first half)
  *BSAVE HACKLOW,A$1000,L$5000

  *1000.6FFFR (load second half)
  *BSAVE HACKHI,A$1000,L$6000

note that in the tape read and write commands, unlike DOS, the actual
starting and ending locations are listed. Be sure you understand the
one-byte difference between the two before you use them.

  There are also occasions when you would like to save applesoft or
integer basic programs loaded in from a modified dos on a protected disk
(Arcade Machine and the Rapid-Fire series from SSI are examples). This
is simple with the tape recorder, since the monitor routines are totally
ignorant of the operating system in RAM. If you can list a basic
program, you can usually save it to tape. Try the following with one of
the above programs: load in a program module (anything in Arcade Machine
except the main menu), then hit reset while it's running. Type D6:00
(this removes the applesoft internal "protection"), then C081 to select
the mother board ROM (unless you have an Apple II with applesoft on a
ROM card, then it's C080 to select slot 0). Type control-c and you
should be able to list the program and then save it to tape with the
"save" command (sometimes an additional fairly trivial protection scheme
is used with applesoft programs: deleting the first line number so it
won't list. It will still save to tape and you can reconstruct the line
number at your leisure). Remember that the basic "load" and "save"
commands don't allow a file name to be added. If there are more than a
few files on the disk, this is a very tedious way to krack a program,
but back in the middle ages before demuffin plus it was sometimes the
only way. You also have to be wary of binary routines which are called
from or modify the basic programs.

  Yes, you're right. Getting out and hooking up the tape recorder is a
cramp in the calvins, so it's usually left for emergencies when nothing
else works. In general, it's best to learn how to manipulate memory to
scrunch your program down into a DOS file (it will always have to be
done, anyway). In the best of all possible worlds, your DOS would be in
rom memory, and would allow you to save any program that resided in ram
memory. In the real world, it's generally necessary to reduce a program
to a file that can be loaded in by DOS from a normal disk (we'll talk
later about those that can't be). This process is usually called "memory
moving", and the purpose is to "tuck in" all the pieces of the program
that lie outside the normal program memory of 800-9600 allowed by DOS.
The other half of the process is the "unfolding" of the tucked-in
portions of memory after the program is reloaded under DOS. To gain
perspective on the process, let's look at memory maps with DOS active
and with "hack" in memory.

_______________________________________
!           !           !             !
!F800-FFFF->!MONITOR ROM!AUTOSTART ROM!
!-------------------------------------!
!F000-F7FF->! INTEGER   ! APPLESOFT   !
!E800-EFFF->!     BASIC !     "       !
!E000-E7FF->!  "    "   !     "       !
!D800-DFFF->!(INSPECTOR)!     "       !
!D000-D7FF->! (WATSON)  !     "       !
!-------------------------------------!
!C800-CFFF->!PERIPHERAL SLOT ROM SPACE!
!C000-C7FF->!SOFT SWITCHES & SLOT ROMS!
!-------------------------------------!
!B800-BFFF->!           ^             !
!B000-B7FF->!           !             !
!A800-AFFF->!          DOS            !
!A000-A7FF->!           !             !
!9800-9FFF->!           V             !
!-------------------------------------!
!9000-97FF->!      ^                  !
!8800-8FFF->!      !                  !
!8000-87FF->!      !                  !
!7800-7FFF->!      !                  !
!7000-77FF->!      !                  !
!6800-6FFF->! PROGRAM MEMORY          !
!6000-67FF->!      !                  !
!------------------!------------------!
!5800-5FFF->!      !        ^         !
!5000-57FF->!      !  (HI-RES PAGE 2) !
!4800-4FFF->!      !        !         !
!4000-47FF->!      !        V         !
!------------------!------------------!
!3800-3FFF->!      !        ^         !
!3000-37FF->!      !  (HI-RES PAGE 1) !
!2800-2FFF->!      !        !         !
!2000-27FF->!      !        V         !
!------------------!------------------!
!1800-1FFF->!      !                  !
!1000-17FF->!      !                  !
!0800-0FFF->!      V  (TEXT PAGE 2)   !
!--------------------------------------
!0000-07FF->!ZERO PG,STACK,TEXT PAGE 1!
---------------------------------------

  And, with "hack" in memory:

_______________________________________
!           !           !             !
!F800-FFFF->!MONITOR ROM!AUTOSTART ROM!
!-------------------------------------!
!F000-F7FF->! INTEGER   ! APPLESOFT   !
!E800-EFFF->!     BASIC !     "       !
!E000-E7FF->!  "    "   !     "       !
!D800-DFFF->!(INSPECTOR)!     "       !
!D000-D7FF->! (WATSON)  !     "       !
!-------------------------------------!
!C800-CFFF->!PERIPHERAL SLOT ROM SPACE!
!C000-C7FF->!SOFT SWITCHES & SLOT ROMS!
!-------------------------------------!
!B800-BFFF->!         (EMPTY)         !
!B000-B7FF->!      ^                  !
!A800-AFFF->!      !                  !
!A000-A7FF->!      !                  !
!9800-9FFF->!      !                  !
!------------------!------------------!
!9000-97FF->!      !                  !
!8800-8FFF->!      !  (EMPTY)         !
!8000-87FF->!      !  (EMPTY)         !
!7800-7FFF->!      !                  !
!7000-77FF->!      !                  !
!6800-6FFF->! PROGRAM "HACK"          !
!6000-67FF->!      !                  !
!------------------!------------------!
!5800-5FFF->!      !        ^         !
!5000-57FF->!      !  (HI-RES PAGE 2) !
!4800-4FFF->!      !        !         !
!4000-47FF->!      !        V         !
!------------------!------------------!
!3800-3FFF->!      !        ^         !
!3000-37FF->!      !  (HI-RES PAGE 1) !
!2800-2FFF->!      !        !         !
!2000-27FF->!      !        V         !
!------------------!------------------!
!1800-1FFF->!      !  (EMPTY)         !
!1000-17FF->!      !  (EMPTY)         !
!0800-0FFF->!      V  (TEXT PAGE 2)   !
!-------------------------------------!
!0000-07FF->!ZERO PG,STACK,TEXT PAGE 1!
---------------------------------------

  Before we begin the discussion of the techniques of memory moving,
let's restate the objective: we're trying to arrange all the program
into a small enough space that we can bsave a file under DOS (the DOS
manual will tell you that the largest binary file you can save is 128
sectors, but if you change location $A964 (43364) to $BF(191) you can
save a file as large as the entire RAM memory). Remember that booting a
slave disk will mess up 0-8FF and 9600-BFFF, so the largest file it's
practival to save is about 145 sectors (you can, with care, overwrite
much of the screen memory and pages 2 & 3 to save a bfile of about 151
sectors, but that requires knowledge and considerable care).

  Looking at the memory map with hack, you can see that the memory from
9600 to B000 will have to be stored somewhere else to bring the file
size down, and the page from 800-8FF will have to be stashed temporarily
during the disk boot to restore DOS. To find out what areas of memory
are free, search through all memory with the inspector and look for
blank pages. The following trick will help: before you load the
original, clear all of memory to zero (or any other byte you like)
with:
  
  *800:0
  *801<800.95FFM
  
then you'll be able to see unused memory areas. This doesn't always
work, since many areas are copied to a second location and not used
afterwards, so if you're hard pressed for storage memory, it's a good
idea to scan through once with the inpector set to decode ascii to
detect suspicious sectors (lately, some of the protectors have taken to
storing garbage such as source code in unused pages of memory and on
empty disk sectors). Note down any pages that are totally clear, any
that are all one byte, regardless of what is is, or any that contain
junk. Let's assume for this example that locations 1000-1FFF and
8000-8FFF are blank. We have 1A00 (B000-9600) bytes of memory "leftover"
or outside of the dos boundaries, so they will all fit into the $2000
blank locations that we located.

  Store the excess bytes in the holes by typing:

  *8000<9600.A5FFM
  *1000<A600.AFFFM

or equivalent; the split can be any way that helps you keep track of the
process. Finally, stash the memory from page 8 with *1B00<800.8FFM.
Remember that this is only temporary. Before you do anything else, boot
your 48K slave disk, then restore page 8 with *800<1B00.1BFFM. Before
you do anything else, save the program with "BSAVE HACKALL,A$800,L$8E00"
(nine out of ten times you'll forget to change $A964; consider changing
it in the DOS in memory before you initialize the disk so it will be
permanent). You can now take a deep breath and relax: all of the program
memory is safely tucked away. All that's left is to write a short
program to reverse the memory storage.

  Two short routines, similar to those shown in our first basics lesson
are required. Again, let's review the steps necessary from here to run
the game:

  1. Load the (compressed) game into 800-95FF.
  2. Move the piece of memory at 8000-9FFF to 9600-A5FF.
  3. Move the piece of memory at 1000-19FF to A600-AFFF.
  4. Jump to the starting address at $4123.

  The following program will take care of steps 2-4. It may not be
immediately obvious that this program must be stored within the
compressed program in a page that is both empty and unaffected by the
memory moves you are about to make. In this case, page 1C is safe.

  1c00  ldy #$0     ;clr y-reg
  1c02  lda $8000,y ;get a byte at 8000+
  1c05  sta $9600,y ;store it at 9600+
  1c08  iny         ;incr. Counter
  1c09  bne $1C02   ;if not pagend, redo
  1c0b  inc $1C04   ;incr. Source hibyte
  1c0e  inc $1C07   ;incr. Dest hibyte
  1c11  lda $1C07   ;get the dest hibyte
  1c14  cmp #$90    ;if 90,we're done
  1c16  bne $1C02   ;if not, do more
  1c18  lda $1000,y ;repeat the process
  1c1b  sta $A600,y ;for the second
  1c1e  iny         ;block
  1c1f  bne $1CA8
  1c21  inc $1C1A
  1c24  inc $1C1D
  1c27  lda $1C1D
  1c2a  cmp #$1b
  1c2d  bne $1CA8
  1c2f  jmp 4123    ;and jump to the
  Starting location

  This may seem hard at first, but the form is so constant that you'll
be able to write these moves in your sleep after a few tries with the
mini- assembler (the place you'll most likely mess up is in the 'cmp
#90' by typing 'cmp $90'--watch it carefully!).

  Time out for a brief discussion of one of the subtle points of memory
moves. Although you're generally able to make your memory moves
non-overlapping, you can have a problem moving large amounts of memory.
The memory move routines shown above are "forward" memory moves: that
means that each page moves is one ahead of the one just moved. Sometimes
you will need to move, for instance, locations 6000-8FFF to 8000-AFFF.
If you use the forward moves as shown, you can see that the first page
(page 60 or 6000-60FF) will land at 8000-80FF, smack on top of the
original page that was supposed to be moved later to page A0
(A000-A0FF). To avoid this conflict, you can use what's called a
"backwards" memory move. This technique moves the last page first and
works "down" in memory instead of up. In this example, page 8F is first
moved to aF, then 8E to AE, etc. This way, when it finally comes times
time for page 60 to be moved to page 80, the original page 80 will
already have been moved. A typical routine for this is:

  1000  ldy #$0
  1002  lda $8F00,y
  1005  sta $6000,y
  1008  iny
  1009  bne $1002
  100b  dec $1004
  100e  dec $1007
  1011  lda $1007
  1014  cmp #$5f
  1017  bne $1002

  Ok--all that remains is to get to the start of the earlier memory move
routine when we "BRUN" the game. This is accomplished by putting the
code for "jmp $1C00" or 4C 00 1C at location $7FD-$7FF and making this
the first location of the program. We can then save a complete,
funtioning version of hack with "BSAVE HACK,A$7FD,L$8E03". This creates
your final, 145-sector file of hack which will BRUN whenever you
wish.

---------- a few helpful hints ----------

1. Always keep a few initialized 48K slave disks nearby--it's alarming
how fast a disk fills up with slightly different 145-sector versions of
the program undergoing kracking.

2. Make your program names as descriptive as you can, especially when
saving a program in pieces. It's very disturbing to return to a kracking
effort after a long weekend to find programs on the disk titles
"hackhi", "hackhigh", "high", "hh", etc. And not be sure what each one
is. Better to type in a few extra letters to let you know that it's
"hack without 9600up" or or "hack 4000-B000 only".

3. Whenever possible, compress the game to the minimum number of sectors
by doing a few more memory moves before and after saving. Your friends
will appreciate your thoughtfulness in maximizing the number of games
per disk and minimizing modem time.

4. =>VERY IMPORTANT<= when you think you have a complete, working
version, check it out thoroughly on all levels and in all modes. It's
extremely embarassing to have to issue a "product recall" when you learn
a month later that hack crashes on level 47 just as the hypergalactic
frog is about to devour New Pittsburgh on the Mars colony...

******** next time -- picture packing and ram card techniques ********

This file was brought to you by Christer Ericson. (christer@cs.umu.se)