********************************************************************** 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!