💾 Archived View for spam.works › mirrors › textfiles › hacking › crackam1.txt captured on 2023-06-14 at 16:47:11.
View Raw
More Information
-=-=-=-=-=-=-
- *********************************************************************
Hacking Programs on the Amiga
By FunToHack of K1W1 Christchurch New Zealand
(all spelling mistakes are free)
Version 1
- *********************************************************************
AN INTRODUCTION TO HACKING
In this article I want to talk a about hacking on the Amiga (a lot of this
should also apply to the ST). The reason I am writing this article at all
is the number of time I have heard the question "how do you hack something"
and it is the one question that can't be answered by pointing the asker at
a book. So I thought I would put a few of the methods I use down in an
article to help inspire budding young hackers. I am certainly interested in
any methods that others are using. If you read this article and say I
didn't learn anything then the article was not intended for you. If you
read it then say I could have written a better article then please do so.
If you have done some hacking you may want to just skim the first stuff and
look at the bit entitled "THE ACTUAL HACKING OF THE GAME" I want to talk
about a few techniques of tracing programs and encryption of programs etc.
In the past I have written two files on the monitor program Monam which is
HighSofts Devpac's monitor program. One is just the instructions for
running Monam and the other one is a list of methods for using Monam to
help you trace etc. When I uploaded the second file there was so much
confusion as to which was which and if they where the same thing etc. Now
that I am doing a third one I have decided to hell with it all and have
included them both at the bottom of this file for completeness.
FORMS OF PROTECTION AND PHOTOCOPYING MANUALS
There are two basic forms of protection, there is Disk protection where the
disk has some funny track on it that is very hard to copy. But the game can
check whether this track has been copied correctly. This track will come up
as an error in your copy program although this is not necessarily true in
all cases. Some disks have some funny bytes out on a long track that the
game checks for. In fact the disk can be copied without error (missing the
extra bits) but still won't run. The other form of protection is manual
protection. This kind of protection is the one where the program comes up
and asks you for a word on a particular page of the manual so you have to
have a copy of the manual to run the game. They use to just do exactly that
but lately they are doing more to make it more difficult such as printing
the book red on black so that when you photocopy the book you get a lovely
black blob or they are doing what Future Wars did and getting you to
identify a colour picture and giving you different copies of the colour
picture to choose from so that even if you have a colour photocopy of the
manual the chance of you getting a good enough copy of the manual to tell
the subtle differences that the Amiga screen will allow is very slim. A
little note if you are trying to photocopy a page that has something like
red on black you can achieve good results by placing a filter over the page
you are photocopying. A filter I here you cry where do I get one of those
from. Well believe it or not you can get really good results with a white
plastic bag try it I didn't believe it until I saw someone do it. Of course
different colour bags can be used for different colour pages. The manual
form of protection is getting more and more popular with game writers one
of the main reasons is because you can put out a disk that can be installed
to hard drive. But the trouble with this is you have to get the manual out
ever time you want to run the game. This is of course also the case for the
guy who bought the original game and there are a lot of people who have
bought a game and are still very interested in a hacked copy of the same
game to get around the manual. Just ask anyone who bought a copy of
Midwinter there was a game that could take you anything up to 15 minutes to
get started, this is no reward for being nice enough to buy a real one.
COPYING THE DISK BEFORE HACKING
The first thing you do is copy the disk with a program such as Xcopy.
Always put verify on and I highly recommend you only use the Doscopy mode
because Doscopy+ will correct errors on the disk that the program maybe
looking for. To illustrate the point take a brand new disk that hasn't been
formatted and use it as the source disk in Xcopy with the Doscopy+ option
selected and you will find it copies the whole disk correcting each sector
it couldn't find as it goes. So copy the disk with Xcopy in Doscopy mode.
There are some games with weird disk formats that you will have to nibble
copy as well as hack I will talk about these in the section at the end
called "Disks with funny formats".
FINDING OUT THINGS ABOUT THE GAME YOU WANT TO HACK
The first thing you will want to know is whether the game runs from the CLI
or whether it boots from the boot sector. The way to find this out is to
boot the game up and hit CTRL D (repeatedly tap CTRL D not just hold it
down) and if the game stops executing then and drops to the CLI then you
know it starts from the startup-sequence and not a Boot sector. The game
won't stop if it has booted from a boot sector. I found an exception to
this when I hacked the game Castle Master which had code in the boot sector
which clobbered a lot of addresses and confused the machine into not
responding to the the control d sequence. This had me confused for a bit
but I found all I had to do was install the copy of the disk (so it had an
ordinary boot sector) and it made no differences to the running of the
game. I also remember hacking one on an St that booted from a boot sector
and loaded up everything directly from tracks but it had a directory on it
with about 12 files with big file lengths none of which were on the disk it
was just a directory of another disk. Both of these examples are rear but
serve to remind us that the programmer is trying to make it hard for us.
Sometime you will find the game stops loading but the screen is completely
black. There is no great secret here it is just that the preferences have
all the colours defined as black. The game when it runs would then go on an
set the colours to whatever is required. It doesn't effect the game at all
but it makes it hard for us to see what is going on there are two ways
around this one is to kill the System-Configuration file in the DEVS
directory or copy one off another disk. The other way is to boot of your
normal system disk and put the game to be hacked in the other drive and
have a look at it. Have a good look at the disk you will want to have a
look at the startup-sequence and see what program actually starts the game.
One of the things to find out is how far the copied game will go before it
fails it's protection. Some games stop straight away which are normally
easier to hack because you dont have to wade through as much code to find
the protection. Some games go into a demo mode which make the game a lot
harder to hack because to look at the code the program is busy doing real
things and it makes it harder to find where it is failing its protection.
Some noble the game in some way such as PipeManier and Where in Time is
Carmen Sandiago which let you play one level before it was obvious whether
you had succeeded in hacking the game or not. Especially Where in Time
because you had to beat the first level before you found out if you had
hacked it or not and if you are as thick as I am it takes you two or three
goes to complete the first level. This of course slows you down plus puts
you off your hacking. The other important thing to find out about the game
is will the game run from Monam. A lot of games detect if they are being
run from another task and go off and count white elephants before they even
do the protection. If this is the case then you have to find where it does
the checking and hack that bit first (isn't this fun). Another import thing
to notice is anything that happens when it fails its protection. On castle
master every time it failed it's protection it flashed the border red and
black. This made it a really easy job to find where the protection was you
just searched the code for the register that controlled the boarder colour
and worked backwards. It could also display a string saying it fail or even
if you are lucky you could get a Message from "The Federation Against
Software Piracy" (I think it is called that). If the game is using manual
protection then you should note any words asking you for a word from the
manual. If we can find the part of the program that displays this message
then we can put a break point there and run the game up until the break
point. This will save a lot of single steeping and it will probably be
doing the test for the correct word soon after this. Searching for these
strings is an easy matter (more about that latter). Another thing to listen
for is a loud graunching sound this is quite often the program checking for
the disk protection.
PREPARING TO TRACING THE GAME WHILE IT IS RUNNING
I use a Monitor program called Monam which is part of the Devpac package
from HighSoft. I have already written a file on Monam explaining the
commands and have added it and another covering handy hints for using Monam
to the bottom of this file. One of the things you may not know if you have
a copy of Monam but not a manual is that it has a companion library that
monam looks for in the LIBS directory (Libfile.Monam) of the system disk
(the disk you booted off). If Monam finds the library when it is started up
then when you are tracing the game it will convert all those system call
numbers to the proper call names so when you are tracing it you are not
constantly looking up the book all the time to find out what it is about to
do. Ok so you boot up off of your favorite hacking disk and start Monam
then insert the game disk and enter the program name and start tracing it.
This is fine if you don't have to boot off the game disk. Some games will
let you do this especially ones that have the protection in the program
that was listed in the startup-sequence and dont load any other files
before checking the protection. Also some games will go to where ever the
disk is and load any files it needs. But I don't think I have ever seen one
that checks for funny tracks on any drive other than drive DF0:. Ok if the
game really wants the system disk to be the game disk you can boot off of
the game disk (stopping it with a control D) and then run monam off of the
second drive with the command df1:c/monam. But it will still look in the
libs directory of the system disk for the Library file which in this case
will be the games disk and of course it will not find it there. Of course
you could always copy it there if there is room on the disk but you never
know when you are going to copy over something on the disk that is
important to the game. If you are at all worried there is a safe way to
have your cake and eat it to. To do this you use the assign command from
the CLI. Just insert your system disk with monam in DF1: and type
DF1:C/ASSIGN LIBS: DF1:LIBS so the amiga will treat the games disk as the
system disk except for the libs directory which it will find on DF1:. Ok if
you can get away with booting off your favorite hacking disk and loading
the program of the second drive or just booting of your hacking disk and
starting up Monam then put the game disk in and enter the program name to
load up and start tracing it then definitely do it. Some games will let you
run the whole game off of the second drive (or hard drive) and only go to
the first drive to check for disk protection. This can be a great help when
you are trying to find out when it checks for the protection.
- *********************************************************************
THE ACTUAL HACKING OF THE GAME
Now we have all that preliminary stuff out of the way it is time to start
getting on with the actual hacking of the game. This is not usually a small
job. It involve lots of late nights gallons of Coffee and the phone number
of a 24 hour pizza delivery. I will look at games that run a program first
and I will look at the boot sector ones at the end of this article. Ok load
up Monam and load in the program. The program loads into memory as if it
was going to run and stops with the program counter set to the start of the
program. I will try to break the file up into logical bits if I can.
The Symbol Table
When you are writing a program you use labels. Now if the guy (or girl)
writing the program has assembled the source code with the symbol table ON
it will be there when you enter Monam and the labels will appear down the
left hand side of the column. If you press L the labels and addresses will
be displayed. If the table is there then have a good look at the labels and
look for anything intelligent such as a routine called PROTECTION (don't
laugh it has happened on more than one occasion). Also labels pointing a
Protection Messages etc.
Tracing the Program
As mentioned above there is a file tagged to the bottom of this one on the
instructions for Monam quickly here are some of the trace commands.
CONTROL Z is the command to single step the program an instruction
at a time
CONTROL A is the command to place a break point at the next
instruction and run the program. This is wonderful
for running subroutines and also a great instruction
to run at the bottom of a DBEQ loop that is going
around and around. It will do all the loops and stop
when the program counter hits the breakpoint
AMIGA Z expand the window you are in to full screen
TAB move to the next window
G search for
B Byte 8 bits
W Wide 16 bits
L Long 32 bits
T Text
I Instruction (source code)
R Run the program
Amiga B set a breakpoint (enter address,parameter)
parameters =
nothing for stop first time and clear the break point
number (1-255) for go through this break point
the number of times then stop
* always stop here and never clear the break point
Remember you can't Break Point the rom and following library calls is silly
they take ages and are not really meant to be single stepped if you have
accidentally started into the rom or a library call then press H (for
history) and see where the instruction that you JSR from is and place a
break point after it then run the program and it will stop when it hits the
break point.
Ok you can trace the program with these instructions and especially if you
use the CONTROL A function a lot you can find out which subroutine the
protection lives in. So you trace the program going CONTROL A to execute
the BSR's and JSR's at full speed until you get the sound of the drive
checking for disk protection or asking you for a word from the manual. Ok
now do it all again but when you get to that subroutine don't go control A
go control Z instead so you can have a look at the subroutine. Normally you
will find it is a full of code and other subroutines. So you start going
down the subroutine going control A on its subroutines and see if you can
narrow down where the protection is. Gee that sounds nice and easy and
extremely quick to do. But the trouble is a lot of games have the
protection a long way into the game. You will often find it does an
introduction sequence before it even thinks about protection.
Jumping ahead in the code
Something you have to remember is that a little bit of program code turns
into an economize bit of source code (anywhere between 10-20 times the size
of the program code). So this is a hell of a lot of code to look through.
So this is where the stuff we noticed as the game starts up becomes handy.
Even if it is something simple like the program loads a Title Screen from
disk before the protection. You search through the program for the name of
the title screen and work backwards to find out what bit of code is using
the file name to load the file (see searching for strings). You can place a
Break point somewhere after the title screen is loaded. This saves you a
hell of a lot of single stepping to get to somewhere that might be of
interest to us. Anything you can find will save you a lot of time.
Searching for strings
Ok a lot of games these days are using Manual protection. This is quite
good for games that you want to install to hard drive. See "Forms of
Protection and Photocopying Manuals" (above) for advice about copying
colour protected manuals. Ok the games usually come up and ask you for a
word form the manual. The lines normally pretty easy to find you just
search memory for them. If you find the string check you haven't just found
a string left over from an earlier load of the game. The way to do this is
to note the address and then press Help (for hunk list) and check the
address is contained in one of the hunks otherwise it is not part of the
program we are running. Remember to get the case of the letters of the
string right or it wont find the string. Also remember you don't have to
search for the whole string just enough to make it unique. Also the longer
the string you search for the longer it takes to find it. Dont search for
strings like "Page Number Of the Manual" because "Page Number" and "Of
the Manual" might be two different strings that might have spaces between
them or might not. And of course dont search for any page numbers even if
you can see them on the screen. Because the chance that the program patches
the number into the string before printing the whole string is very
unlikely. Ok we have found the strings but that doesn't mean a thing, what
we need is the bit of code that uses the string not the string it's self.
So what we have to do is work backwards from there. First have a quick look
around to see if anything is pointing at the address of the string. More
likely than not you will have to search for it. I normally search for the
address with the Instruction version of the search command because of the
different addressing modes on the 68000 doesn't mean that the string will
be pointed to by a hex number it could be in the form of A3+1234 or
something like that. The hex searches won't find it but the Instruction
search will if A3 has the value it is supposed to. Another thing I have had
work a couple of times is to search for the distance between the start of
the Hunk that the string is in and the start of the string it's self (use
the O command to work it out). An important thing you must remember about
the string you are searching for is where it actually starts. To do this
you have to have a look at the string itself, some strings have the length
of the string in a byte in front of the string and the value you should be
searching will more likely be it's address and not the start of the letters
(also there could be control codes in front of the string as well). If you
are using the Instruction search there is nothing stopping you from
searching for part of the number i.e. say the string is at 71234 hex you
could search for 7123 and it would report all numbers from 71230-7123f.
Unfortunately there is no guarantee you will find the bit of code with any
of these methods because of the fact that the address of the string could
have to be calculated and addressed from a register. If you do find it it
will probably be in the form of PEA $71234. Ok you searched the file and
you didn't find the actual string it's self at all. There could be a number
of reasons other than the address having to calculated. One reason could be
the string that you see is actually graphics and not text, another reason
is that they are hiding the string in one way or another. One way it could
be hidden is for it to be in a bit of the program that is encrypted. I will
talk more about finding this sort of thing in the sections on Decryption
and Resetting the Machine. Another way of hiding it is to put it in another
file. The best way I have found to check whether this is the case or not is
to use the ARP'S search command. What? you are not running ARP Arp stands
for the Amiga Resource Project (or something like that) it has a dos
command word "SEARCH". You can use it from the dos line like this
SEARCH DF1: Manual ALL
The word "SEARCH" is the command, df1: is the drive, the word "Manual" is
the word we are searching for and ALL means do all files in all sub
dirrectories. If you have this file you are reading now then chances are
you got it from an Amiga BBS then if you want ARP you will surely find it
on the BBS. I highly recommend ARP in its entirety. If SEARCH finds the
word it tells you what file in what directory and the offset address in the
file (what more could you want). Ok if you find it in an other file then
you look through the main program and find where it loads the file and
start working from there.
Happy hunting.
CLEVER THINGS THEY DO TO STOP US
The protection systems are getting much better (harder). I remember when I
first got an St finding some of the games just checked for the protection
and if it failed they just halted the program by executing an instruction
like below
Here: BRA Here 60FE
all the instruction does is jump to it's self but the code for is always
going to be 60FE so if the program just froze I would load the program up
and search for the hex 60FE. If you found it you knew the protection
couldn't be far away because not to many games specialize in doing nothing.
Anyway these days we have encryption and all sorts of things things to make
it harder.
Address 24 hex
Address 24 is a very important address as far as monitor programs (like
Monam) are concerned. It is the address of the routine the monitor uses for
tracing programs. If the trace flag is set it gets the address to jump to
from this address. So a quite common thing to do is to overwrite this
address to upset any Monitor program. If you come across anything altering
this address you will have to take steps to get around it. There are two
ways around this, the first is to just step around the instruction using
the CONTROL S command which will move the program counter to the next
instruction without executing current instruction. The other way which can
be more convenient if the instruction is in a loop is to patch the program
in memory to replace the code with NOP'S you just change its hex numbers to
4E71, you of course may need more than one NOP. If you think the program is
doing this but you don't know where it is then you can search for anything
altering address 24 by using the instruction search command from monam
,$24
this will find any instruction that ends with ,$24. Note the comma is
important it stops you getting all the 24's in the world being dumped at
you.
Doing things to upset the Monitor
It is not uncommon in programs to have it do all sorts of things to upset
the monitor program. Whether it is deliberate or just part of the program
setting things up the result is the same, it stops you single stepping.
They are not to hard to find (just time consuming) you just single step
along and suddenly a number gets written to an Address and the monitor
stops listening to your commands. When this happens to you there is very
little you can do about it but reboot the computer to get out of it. But
next time you come up to the instruction (while single stepping) you have
to decide whether it is just in the process of setting the game up or there
to make life hard for you. If it is just setting the game up you might be
able to put a breakpoint farther on in the program and run the program
through the setup bit to the break point. Or you can use CONTROL S to step
around it or patch it out in memory with NOP's as in the paragraph "Address
24" (more on patching later).
Using the Illegal vector
Address 10 hex holds the address of the routine Illegal instruction
routine. Whenever the program comes across an Illegal instruction it jumps
off to the address held in the 10 and goes into supervisor mode which the
monitor program won't like (you can trace supervisor mode on the ST). So
what you see in a lot of programs is the address 10 being loaded with the
address the program wants to jump to and then the program executing and
ILLEGAL instruction. This is quit a nice simple easy way to through new
comers to hacking but stupid thing is nine time out of ten when you do see
it they are jumping to the instruction immediately after the ILLEGAL
instruction and more often than not they do it about three time in a row.
To get around this you alter the program counter to the address to be
placed in 10 hex. The thing you have to watch is the routine checking
whether it is in supervisor or not. The easiest way for the program to do
it is to examine the SR (status register) so have a good look at any
commands playing with SR. The other thing to remember is because the
program is supposed to be running in supervisor mode. So anything that the
program does in supervisor mode you will have to handle. One thing that
springs to mind is the RTE instruction (return from interrupt) which is a
command that can only be executed in supervisor mode so you cant single
step it because we are not in supervisor mode. To get the program to go to
the right place we have to do what a RTE would do for it. I quote from the
good book "Programming the 68000"
"The RTE (return from Exception) is used to load the status register and
the program counter (PC) by the use of a single instruction. This type of
operation is required when an operating system in supervisor mode passes
control to a user program in user mode. The new contents of the status
register and PC are popped off the stack. The status register is taken from
the first 16-Bit word on the stack, and the PC from the next 32-bit long
word. The stack pointer is incremented by six bytes."
What you do here depends a lot on the program if you find the program is
altering what is on the stack then doing a RTE remember the first 16 bits
are destined for the SR (which you can't alter anyway) and the next 32 and
the address the program is to return to. The big thing to keep an eye on at
all times is the stack pointer make sure it is pointing to where the
program expects it to be. Remember you can alter the stack (A7 normally)
just like any other register and looking at what is above and below where
the stack pointer is pointing to can be quite interesting. Quite often the
routine doesn't do anything important as far as hacking goes so you can go
through all the crap and work out where it is going to and run the program
up and just put a break point there and run the program. If there is
anything such as stamping on address 24 then Nop it out before running it.
The First instruction
Something worth noting when you start tracing a program is that Monam
actually runs the program but sets the trace bit so it stops running. The
thing to remember about this is the first instruction is actually preformed
before the trace kicks in and stops the program ready for tracing. I have
seen at lest one program (ghost & gouls for one) that the first instruction
was something that froze the keyboard or upset the computer in some way
that made tracing it impossible. The only way around this is to patch the
first instruction. But you can't patch the program in memory as you are
running it because it will freeze the machine before you get a chance to do
the patch. So you have to either patch it directly on the disk or use the
binary load method to patch it in memory (see the section on "Patching
Programs" for details on how to do this).
Not Enough Memory
I have done most of my hacking on Half Meg machines (Amiga and ST) and I
know it can be a problem trying to run a program from Monam that just runs
and no more in half a meg. Quit often you can still hack it depending on
what it wants the memory for. I have had heaps of programs that stop the
program running after they test the amount of available memory and compare
it to the amount that will be needed to run the program. But infact the
program does the protection bit before it actually needs all the memory. If
you can find where it does the memory check it is a simple matter to bypass
the check and continue on to the protection as long as you really don't
need the extra memory yet.
The program running another program
This is quit a cute method that will keep you up to all hours trying to
work out what is going on. What the program does is it loads into memory as
one program. But unbeknown to us is that the program actually consists of
two parts, both which are separate programs. The first part runs the second
part as a separate task and it is the second program that goes on an plays
the game. Monam will only work on the one task so you carry on single
stepping something that looks quite intelligent but isn't actually doing
the things that run the game. The first time you come across this you can
not work out what is going on you get so far through stepping the game and
something happens on the screen and then you start stepping it again from
the start of the program and it happens again at a different places in the
program. The easy way to find out is to run a program like XOPER and list
the tasks and you will soon see if there are anything running that you
don't know about. The way you get over to the new program is to find out
where the program creates the new task and see where it puts it. The best
way is to put a break point on the instruction that calls the function that
creates the procedure and run the program until it stops there. You now
find the it doesn't just pass an address to the function telling it where
it is. It actually uses a BCPL pointer to point to it which it passes in
the D3 register. What is a BCPL pointer ? a BCPL pointer is a pain in the
ass. It's reason for existing instead of just pointing straight at the
address is it is designed to be easy to convert to longword word aligned.
You can convert the BCPL pointer to hex by taking the number in D3 and
multiplying it by 4 then adding 4 to it. You can use Monam to do this for
you or use a calculator. I find it much better to use Monam because you can
change to the address while you do it and you can use the memory address D3
instead of having to key in the number it the memory address (see monam
methods in the article below). Once you have found where it is going you
can just go there and have a look around and trace the program visually to
find the protection. To run it properly you would have to alter the program
counter to the new address and start single stepping from there. The
ability to be able to do this depends alot on the first task. If the first
task runs the second task then kill it's self then you wont have to much
trouble. But if it passes values to second task or has to be running at the
same time then things get sticky. Another way to do it is to run the
program until the new task has been started and then go back to the
workbench and run XOPER and use the hunks command on the new task. It is
pointed to by a BCPL pointer as well so you have to multiply it by 4 and
add 4 to it as well.
ENCRYPTION
The biggest problem we face these days is encryption. What is encryption?
It is where the program self modifies itself on the fly. How? Well the
simplest way to think of it is to look at some code like the lot on the
left. The numbers in memory are 4E71 and 4E75. If we go through and add one
to each number we get the result on the right hand side were it turns into
something else.
HEX INSTRUCTIONS HEX INSTRUCTIONS
4E71 NOP 4E72 4E76 STOP #4E76
4E75 RTS 4E72 4E76 STOP #4E76
4E71 NOP 4E72 4E76 STOP #4E76
4E75 RTS 4E72 4E76 STOP #4E76
4E71 NOP
4E75 RTS
4E71 NOP
4E75 RTS
Of course to get the code back to it's original form all the program has to
do is go through and take one off of each word before it runs it. Please
remember something like adding one to each is about the simplest way you
could possible do it. They normally involve XOR'S and complicated loops.
Why do they do it? Well the first and obvious reason is that you can't read
what it says until it is decrypted and until then it just looks like a lot
of crap just another bit of graphics or somethings. An other reason that
isn't as obvious is you can't put a break point in the code to stop it
because the code gets changed by the decryption process so the break point
gets changed so it isn't a break point any more. And the biggest problem
for us is changing any of the code to what we want (but more about that
latter). Make sure you don't confuse decryption with a program that is just
unpacking it's self or translating some packed graphics. There is a big
problem for the guy writing the routine. To explain this you have to know
what happens to a program when you run it. When you run a program the
system loads it into any available bit of ram and uses a table that is
included in the file to relocate the program to run at that address. Now
once the program is loaded if the guy who wrote the program starts
decrypting it then he has to do one of two things he has to either handle
the relocation of that bit himself or write position independent code so it
will run anywhere. If the decrypting routine is decrypting code that is
elsewhere in memory then it is easy to decrypt. Just put a break point
after the routine for decrypting it and run it up to the break point.
START DECRYPTION CODE
DECRYPTION CODE
DECRYPTION CODE
DECRYPTION CODE
DECRYPTION LOOP TO START
MORE PROGRAM CODE <-Just drop a break point
MORE PROGRAM CODE Here and run it
MORE PROGRAM CODE
CODE TO BE DECRYPTED
CODE TO BE DECRYPTED
CODE TO BE DECRYPTED
CODE TO BE DECRYPTED
CODE TO BE DECRYPTED
If the code to be decrypted is straight after the code that is doing the
decryption (as below) then we have to be a bit more careful.
START DECRYPTION CODE
DECRYPTION CODE
DECRYPTION CODE
DECRYPTION CODE
DECRYPTION LOOP TO START
CODE TO BE DECRYPTED
CODE TO BE DECRYPTED
CODE TO BE DECRYPTED
CODE TO BE DECRYPTED
CODE TO BE DECRYPTED
We cant just put a break point after the decryption routine because that
would put a break point at the start of the code to be decrypted. Even
though monam displays the instruction that has the break point in it as the
correct instruction it has actually altered the code to put the break point
in it. So the decryption code trys to decrypt the break point instruction
instead of the code that should be there. You could single step all the
decryption routine but that would normally take ages. The way to get around
this is to make sure you go around the loop a few times by single stepping
it until the first couple of the instructions are decrypted before you pop
a Break point in the code and run the program until it hits the break
point. Another way to decrypt it is if you know where it will be going
after it has done the decryption (even if it has executed the decrypted
code) then just pop a break point there and run it. When it hits the break
point you can go back and have a look at the code that has been decrypted.
Ok this is still pretty simple decryption. What really stuffs you up is
when the combine it with the 68000 prefetch.
Prefetch
What is prefetch? The 68000 gets an instruction from the memory and then
while it is working out what the instruction does it prefetches the next
instruction which it will probably be running it next anyway. The prefetch
saves bus time, if it does want the next instruction then it gets it from
the prefetch buffer in the 68000 chip. If it does not want it (because of a
branch etc) then it is discarded and the instruction from the address to
branch to is fetched instead. Ok so what! it still get the same job done as
if it fetched the instruction, did it, then fetched the next instruction
etc. The thing you have to watch for is self modifying code. Code that
modifies the next instruction runs differently than it single steps. When
you single step a program it fetches every instruction as you need it, it
doesn't have a prefetch buffer. So if you have self modifying code that
alters the next instruction to be run you can get a different result single
stepping the code than you do running it. To really illustrate the point
look at the section of code below.
code1
code2
code3
code4
code5
code6
What actually happens when you run a program (looking at diagram below) is
the first Instruction is executed (A line) at the same time the next
instruction is prefeched (B line) then the second instruction is executed
from the prefetch buffer and the next instruction (3 line) is prefetched.
(A) execute code1 and prefetch code2 instruction
(B) execute code2 and prefetch code3 instruction
(C) execute code3 and prefetch code4 instruction
(D) execute code4 and prefetch code5 instruction
(E) execute code5 and prefetch code6 instruction
Ok that is fine until the program alters the next instruction in memory but
still runs the old one that it has in its prefetch buffer as below
start nop
nop
nop
move.w #$60fe,here
here nop
nop <-place the break point on this line
nop
The hex numbers 60fe is the hex numbers to jump to the same address. So at
first appearance the code above will do nothing for the first three lines
then store 60fe in the line with here at the start of it. Then the program
counter will fall through to the new instruction on the line Here
HERE BRA.S HERE
Which of course will just go around in a circle and never go any farther
and this is exactly what will happen if you single step the program. But if
you run the program with a break point on the instruction after the here
line. Where it would appear the program counter wont ever get to you
discover the program will stop on the break point not on the new
instruction BRA.S Here. Even though the instruction BRA.S here is there for
all to see. The reason is because it ran the instruction from the prefetch
buffer instead of prefetching the new altered instruction. I suggest you
set and run this is quite a dag of a thing to see. This is the reason that
some games wont run on the 68010 68020 68030. It is not because the game
wont run it is because they fail there own protection. It is quit a funny
thought to think there are hacked games out there that will run on 68010
68020 68030's because they have had the protection removed though the
originals wont
Combining Encryption and Prefetch
Now it starts to get complicated if you didn't understand the encryption or
the prefetch then go back and get to understand them or skip this bit. The
problem comes when you find a game with the code to be decrypted directly
after the decryption routine. You would normally just single step around
the loop a few times to get around it and pop in a break point as discussed
above. But if the routine is using the prefetch feature at the end of the
decryption routine then you cant single step the decryption routine at all.
We cant just pop a break point after the decryption routine and run it
either because we would be corrupting the code we are trying to decrypt.
What you normally find is they have the decryption routine directly before
the code to be decrypted and the loop that does the decryption isn't
completely there because the program self modifies the code to complete the
decryption loop (which it wont do if you single step because of the
prefetch feature). So What do you do. All you have to do is copy the code
that does the decryption to somewhere else in memory (use the I function in
Monam to copy it) and run the copy of the code instead of the real code to
decrypt the decrypted code. You have to make sure that the copy of the code
you have made still points at the original decrypted code. This is normally
not hard because it usually loads the values into registers and the
decryption routines are pretty small so they are normally position
independent. So the decryption routine will normally run anywhere in memory
after the registers values have been loaded. All you have to do then is run
the copy and place a breakpoint after the copy of the decryption routine
where the program counter would normally fall through after completing the
decryption.
PATCHING CODE
I will talk about simple patches then look at patching stuff that has been
encrypted.
Simple Patches
Ok you have found the bit in the program you want to change and you may
even be able to run the program up to the bit that needs changing, change
it by hand then go off and run and play the game. But how do make it
permanent. We cant just patch the program in memory and then save it back
to disk. Why cant you?. Ok when you load the program into Monam it pretends
to run it and stop it after the first instruction. This means the program
has used the relocation table on the end of the file to relocate it to run
at this address. We can't just patch the code and save the memory back down
because there is no guarantee it will load in the same place. Plus all the
hunks are spread around memory anyway. What you have to do is either use a
disk editor (such as filemaster) and alter it directly on the disk. To do
this you want to search the file for the bytes around where you want to
patch. Now you have to make sure you the bytes you are searching for are
not some bytes that will be changed when the file is loaded into memory
(such as absolute memory addresses etc). Changing the file directly on the
disk makes sure that you don't save the file down on the disk in a place
that might effect the game. You are normally pretty safe if the game uses a
sector or track it is normally allocated so it is unavailable. But of
course nothing is every guaranteed. The other method which is the method I
use most is to load the program up into Monam and alter it there. Dont load
the program normally, load it as a binary image by using the B function. To
do this run Monam and when it asks you for a Program name just press return
then Press B and enter the name of the program and it will be loaded. The
program is loaded but you can't run it or trace (because you haven't loaded
a runable program). You can disassemble it though which is good for finding
the place to put the patch and checking you have it right. Remember you
have loaded the complete program this includes the bit at the start and the
relocation table and symbol table if it has one. Remember it hasn't been
relocated so it will look a bit different to when you loaded the program as
a runable program. Ok use the E function of Monam to patch in the Hex
numbers of the commands you want to put in. There are only a few
Instructions you ever use such as Nop Rts Bra etc. If you don't know the
Hex numbers for the Instruction you can either set them in Genam and look
at the results from Monam or you can use the Instruction search from Monam
to find one in the Rom or the program and have a look at the Hex values
from there. After you have patched the code all you have to do is save the
program back down with the S option. The important thing to do is get the
exact start and the exact end of the file right which is made very easy by
using Monams M0 and M1 registers these get set to the value of the START
and END of the file when it is loaded into Monam so all you have to do when
Monam asks for the start and end is enter M0,M1 and it has to be write.
Things to note about simple patching
You have to patch somewhere that wont be altered by the relocation table.
Dont confuse Instructions that will be alter by the relocation table with
ones that wont. Just because the instruction disassembles with an address
in it dosn't mean that the address was put there by the relocation table. A
lot of instructions are position independent which means they will run at
any address. The way they do this is instead of saying branch to address
$12345 the instruction actually says branch 20 instructions ahead (or what
ever numbers). But Monam disassembles the code with addresses instead for
our convenience. The way to learn if it is an Instruction that will be
altered by the relocation table is to have a look at the instructions hex
dump and see if there is that address in it. All this must be done on a
program you have loaded in the normal way not just binary loaded. When you
come across a bit that has been altered by the relocation table and you
want to alter it there are a few ways around it. If you have something like
JMP $C57B96 4EF9 00C5 7B96
and you want to remove it from the program then you can't just put in three
NOP'S because when the relocation table alters the address where the
$C57B96 is it will alter the NOP'S instead and god knows what they will
turn into. Ok the way around this is to just alter the first two Bytes
(4EF9) to get the program to BRA 6 bytes ahead. You do this by putting a
6006 where the 4EF9 is you don't bother about the other 4 bytes they will
disassemble as rubbish but the program counter wont actually go through
them so it doesn't matter.
More Difficult Patches
We need more Difficult patches to get around various things such as
encryption. When the bit we want to patch is in a section of code that is
encrypted there is no general way to get around it you have to judge each
one separately, I can only give you a few examples of ways I have used in
the past. The first most obvious way is to work out what value the bytes
need to be so that when the program is decrypted it will end up being the
bytes that you want. For a simple decryption this is not as hard as it
sounds remember the guy that wrote the encryption would have used a
variation of the decryption routine you are looking at to encrypt it to
start with (remember I said if it is a simple decryption). You may be able
to work it out with a calculator or here is a method you could try. If you
decrypt the code from monam (discussed above) and patch the code to what
you want the code to say after it is decrypted. Then get out the charts of
what bits XOR's and OR's etc effect and see if you alter his decryption
routine back to an encryption routine. Now you put the program counter back
at the start of routine and run the routine again on the code (make sure
that the registers are Initialised to correct values etc). If you have
managed to do it correctly then the rest of the code will now be decrypted
back to it's original form. So all you have to do is find out what values
the bytes you are interested in are changed to then pop these values into
some undecrypted code and see if it will work. More than likely you will
come up against a decryption routine that does something like use the value
of the byte before it to help decrypt the next value. This of course stuffs
you for changing just a couple of values in the code because any changes
you make will effect the bytes after it and you would have to alter all the
code to be decrypted. One way around this I used a couple of times on the
ST in programs that encrypted a bit of code but the encryption wasn't to
complicated was to load the program up as a binary image and then run the
encryption code on its self. The way to do this is have a dummy file on
your disk consisting of just a START and an END or just any small program
and what you do is you load this program as a runable program (use Cntrl L)
and then load the file you are really interested in as a Binary file. You
can then move the program counter to the start of the decryption routine
and set any registers that need loading and run the decryption routine on
the binary image. When the decryption is complete you then patch the code.
Now all you have to do is Noble the decryption code so it doesn't try to
decrypt the code again when the program is run then save the program down
again. Yet another way get the program to decrypt and then patch it after
it has decrypted. This is of course a great Idea but as yet I haven't seen
a program that has the decryption code and a great big patch of NOP's with
the words "INSERT HACKING CODE HERE". But there are ways to get your code
executed with out reassembling the program. If the program is one that
loads code at an absolute address then there is all sorts of things you can
do you. If you can get some code into memory first then you can jump to it
and do anything such as decryption and patching and then jump back again.
This is very messy and you never know when you code is going to be covered
up by something else being loaded up. A much more elegant way to do it is
to have the block of code you want to jump to inside the program. There are
quite often heaps of strings you can hide code in. There is quite often a
title page with the Authors Name and the Gaming houses Name etc. You have
to look at the string and see how it is controlled. It normally just has a
Null (0 Hex) at the end of it and if you move this closer to start of the
string it will still print what is between the start and the Null but leave
you all the bytes from the Null to where the real Null is to put code in.
It may have a CR (0D hex) or it may the number of bytes long the string is
stored in front of the string so you just make it smaller. It is quite
surprising just how much code you can get into a string especially if it is
an 60 char long copywrite message. Ok this string or spare bytes of some
description has to be in the same hunk as the code you want to play with
and within reach of a relative branch etc to call it and all the code must
be position independent because it wont be updated by the relocation table.
So the program counter is running along happily setting up the game and it
comes to the decryption routine which you have altered. You could if you
have enough room have the hole decryption routine hidden somewhere and have
it decrypt the code and patch it before relative branching back to just
after the decryption routine to get on with the real code. More than likely
you wont have enough room and you probably just have altered the bottom
couple of lines of the decryption routine (the bit that sends the program
back around again to decrypt more code) to branch off to your code where
the first thing you will do is any instructions that you have had to patch
over to get the program counter to branch to your code. You of course just
keep sending the program counter back to the decryption routine until the
code is all decrypted then do the patch. Sometimes you find messages to
hackers in the code that are a good place to put extra code. Please see the
example below to clear up what I am talking about.
- ***********************************************************************
ORIGINAL CODE
- ***********************************************************************
LOOP DECRYPTION CODE 1
DECRYPTION CODE 2
DECRYPTION CODE 3
DECRYPTION CODE 4
DECRYPTION CODE 5
IF NOT FINISHED GOTO LOOP
CODE TO BE DECRYPTED
CODE TO BE DECRYPTED
CODE TO BE DECRYPTED
CODE TO BE DECRYPTED
The Next bit is a string somewhere in memory
STRING
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- **********************************************************************
PATCHED CODE
- **********************************************************************
LOOP DECRYPTION CODE 1
DECRYPTION CODE 2
DECRYPTION CODE 3
DECRYPTION CODE 4
PATCHED CODE JUMP TO STRING
CODE TO BE DECRYPTED
CODE TO BE DECRYPTED
CODE TO BE DECRYPTED
CODE TO BE DECRYPTED
The Next bit is the patched string
STRING
DECRYPTION CODE 5
IF NOT FINISHED GOTO LOOP
CODE TO PATCH DECRYPTED STUFF
JMP TO START OF THE DECRYPTED CODE
Checksums
Sometimes I am amassed how few games actually check to see weather the code
has been altered in any way. I doubt if it is because they are scared of
drawing attention to the code that needs changing. It is actually very hard
to checksum code and reliably get the same answer because the program loads
where ever it feels like and then relocates so the total can very wildly.
But I have seen programs that load up chunks of code to absolute addresses
so it will always be the same and no relocation is necessary and still they
dont bother to run a quick checksum later in the game to check if all is
well. Anyway How do you get around checksums? Well the obvious way is to
find where is does the checksum and noble it. But this can be a real pain
because it is normally quite a way into the game. There are a couple of
ways around them. If it is just counting up the bytes you can sometimes
alter some bytes around it so the total comes out to be the same, don't
forget it could be adding bytes, words or longs. More than likely if they
have any sense they will be using some routine where position of the bytes
is important as well and just modifying something else wont be good enough.
There is a good way around this. Normally it will only be totalling a small
bit of the program which is position independent. So what you do is change
the program back to its original state before the checksum is done. For
example
CODE
CODE
CODE
BSR Do_Protection
CODE
CODE
CODE
in the above example what we want to do is NOP out the BSR Do_Protection
instruction but this will cause the checksum to fail so what to do is
change the code to
CODE
CODE
JMP TO_MY_CODE_HIDDEN_IN_A_STRING
CODE <- COME BACK HERE
CODE
CODE
Now the code that you have HIDDEN in a string does nothing but restore the
program to it's original form and then jump to the line with the left arrow
after it. The effect of this is the same as the BSR Do_Protection being
NOP'ed out but the checksum is still the same. This is of course a simple
example you could do heaps of things in the code in the string.
Programs that boot from a boot block
These seem at first to be very hard programs to hack but they don't have to
be. Programs that start from a boot block dont use the filing system to run
the game they load the game directly from disk. The program handles which
track and sectors to load etc. The way to see what is going on in the boot
sector is to use a Disk Monitor of some sort. It doesn't matter how funny a
disk is you will always be able to load the boot sector. I make mention of
this because most programs that boot from a boot sector will run fine if
you just boot off them but if you boot of a system disk and then stick the
game into the second drive the machine will report the disk as stuffed and
recommend disk doctor. This is because when you stick a disk into the Amiga
it goes away and says hello to it and on these funny games disks it finds A
lot missing so it reports it stuffed. So just keep clicking on cancel and
then load up the first track. I use DiskMonPro the main reason I use
DiskMonPro is because it tells you where in memory it has the track.
DiskMonPro has a monitor program built in but I normally run Monam in the
background and jump to that after loading the track (or just the boot
sector). You disassemble the boot sector and have a general look around.
Save the boot sector down to a disk (remember it is two sectors). We dont
have to worry about relocation tables with the boot sector because it has
to be position independent code to be in the boot block so we can load it
anywhere. I normally reboot to clean up the memory and then load monam.
What we want to do is to run the boot sector to do this we use the method I
discussed in "MORE DIFFICULT PATCHES" which is load a small dummy file as a
runable file then load the boot sector file as a binary file and move the
program counter to the start of the code in the boot sector (which is a 12
decimal instructions from the start of the boot sector). Now put the disk
you want to hack in DF0:. You will probably have to press cancel a couple
of times to stop it complaining about the disk. Now you just start single
stepping the boot block as if it was a program. There are two problems with
single stepping a boot block the first is that when a boot block is being
booted while playing a game the machine is in supervisor mode. This itself
isn't a problem if the boot block is well behaved you can run it in user
mode and get the same results. The problem is it doesn't have to be well
behaved and if the programmer feels like taking over the machine completely
you normally are the first thing to stop working. The other problem is
programmers who make games boot from a boot block and especially the ones
who take over the machine completely and kickout the operating system drive
the hardware directly are normally bloody good programmers and tend to make
it tough for you. So you just keep single stepping the game as if you were
working on a program you had loaded up. But instead of it loading other
files it will be loading tracks etc into memory. Once the game has got far
enough into the program to load up the appropriate track and do the
protection you note what track it is. You then load up the track with
DiskMonPro and alter the bytes and save it down again. If you dont know
what track you are looking at you can use a disk monitor program that will
let you search the disk for the bytes to find out where it is.
Disks with funny formats
These disks are easy to identify they are the ones that wont copy with
Xcopy Doscopy command. So you have to copy them with the nibble function of
Xcopy. These disks cause all sorts of problems for us. You cant just load a
program to have a look at it because everything is loaded from tracks but
you cant just load up tracks with DiskMonPro and have a look at it from
Monam because the disk has a funny format that has to be loaded using the
games loader. The biggest problem is once you have found what you want to
change and you may even know its exact position on the disk but you cant
change it because you have to write the funny track down to the disk. You
could in theory reverse engineer the loading routine and write one to save
the track down again. This could be pretty easy if you discover that all
the program is using is a different sync byte but this is not normally the
case. The other way to do it is to let the program load the track and then
patch it in memory. To do this you have to use the techniques discussed in
the patching bits. The big problem comes when the boot sector doesn't load
the bit you want. Instead it loads a file which it runs and then that loads
another file which it runs and then loads the bit that you want to patch. I
had this when I hacked Midwinter you have to patch each lot of tracks that
are loaded to patch the next lot and the last one patches the protection.
The best way to do this is to put all the patching code in one block and
pop it in the boot block and have it relocate to a safe area in memory.
Then you only have to handle patching the files not trying to hide the
patches in strings. So the boot sector gets loaded relocates your block of
patches then loads the first track and jumps to the first of our patches
which then turns around and patches the first track at the memory location
after the routine that loads the next lot of tracks. It patches it to jump
to our second patch. It then jumps to the start of the first track and
executes all it code including loading the next lot of tracks and hits our
patch that sends it to the second patch. The second patch patches the next
lot of tracks after there load routine. You keep doing this until you get
to the lot of tracks that have the protection in them and patch the
protection. Midwinter was a dag it did this three time and also checksumed
the code so I had to restore the file to original condition for the
checksum to calculate correctly. It was a fun game to hack especially to
get my Name into but I never did work out how to play it properly.
MISCELLANEOUS OTHER STUFF
Resetting after loading
This is a good way to see code after it has been decrypted and to have a
look at code that has come off a special format disk. It can also be the
only way to hack a game that you dont have enough memory to run with Monam.
What you do is reset the computer and load up Monam and have a look at what
is left in memory (I am afraid the ST clears all the available memory when
any program is loaded so it is gone). If you find Monam or the operating
system is loading over the code you want to look at then when you boot up
you can move the bottom 40k up to 40000 hex with a boot block called Multi
Boot (the version I have doesn't work with 1.3) you can always put the code
in a boot block yourself (Multi Boot does lots of other things as well.
Bra Here
Quite often you are looking through some code and you come across "Branch
if_whatever_instruction" and you want to know the result but the program
kicks Monam out or loads all the files in the world and you run out of
memory. One way to find out is to put the hex numbers
60FE
These are the hex numbers to make the program counter loop to it's self.
This can be very handy when use in conjunction with Resetting the machine.
If you run the program and it hangs you know which way it went when it hit
Bye Bye
I have really only just scratched the surface of hacking. I have confined
myself to mainly tracing from monam and haven't talking much about other
programs such as Resource (a disassembler program with balls). If have
access to a BBS there is a good chance they will have the demo version of
Resource on it. Download it and have a look at it. There is various things
you can do with XOPER. I spoke about using the hunks in the section (The
program running another program). You can also use the stacks command to
help find out where a program has been by backtracing the tasks stack and
looking at the addresses that have been pushed onto the stack by BSR and
JSR calls. You take the stack pointer lower (SPlower) and add the amount
reserved for the stack (SIZE) (note it is in decimal) then take away the
amount used (USED). This should give you the position of the stack pointer
of a frozen task. You now start having a look at the memory around this
address in hex and looking for intelligent things. There are various
hardware add-ons you can get to make hacking alot easier. I think these
take all the sense of achievement out of hacking a game. I hope this
article has helped anybody starting out wanting to hack programs.
Happy Hacking!