10 P%=&50 20 [OPT3 30 .irq PHA 40 ORA #1 50 STA &3CA 60 PLA 70 JMP (&230) 80 .init SEI 90 LDA &204 110 STA &230 120 LDA &205 130 STA &231 140 LDA #irq MOD256 150 STA &204 160 LDA #irq DIV256 170 STA &205 180 CLI 190 RTS 200 ] 210 CALLinit
We now would appear to have an uncopyable program which can only be *RUN and, once run, cannot be broken into. Of course, it would be naive to think even this system is infallible. It is possible to crack a locked file by substituting line 50 with AND #254 .
10 REM @********************************[ 20 REM ]* *[ 30 REM ]* This program is copyright *[ 40 REM ]* *[ 50 REM ]* It is illegal to copy it. *[ 60 REM ]* *[ 70 REM ]********************************[ 80 REM REST OF PROGRAM 90 PRINT"THIS PROGRAM WILL STILL RUN" 100 GOTO90 110 REM]
We want to change @ (line 10) to a clear screen (code 12); {chr$21 ; and } to CHR$6 (lines 20 to 70 and 110). To do this you must first type the commands:
PAGE=&2000 NEW
Then you must type in and run the following program. Disc users will need to change the setting of A% at line 10 to &1900
10 A%=&E00 20 IFA%?1=&FF END 30 A%=A%+3 40 A%+A%+1:IF?A%=13 THEN20 ELSE IF?A%<>&F4 THEN40 50 REPEATA%=A%+1:IF?A%=ASC"@" ?A%=12 60 IF?A%=ASC"}" ?A%=6 70 IF?A%=ASC"{" ?A%=21 80 UNTIL?A%=13:GOTO20
Notice that in line 50 the REPEAT command does not need a : after it. This is never needed after a REPEAT statement.
Now set PAGE back to its usual value and try listing the program. Note that the program still runs normally.
This program first finds the start of each line of the program then looks for the token (&F4) for a REM statement. It then searches the rest of the line for the characters we want to replace. This way the program won't accidentally alter line numbers or lines of BASIC.
Alternatively, you can use a machine code monitor (such as the one in chapter 4) to look directly at and modify the relevant characters in the BASIC coding.
A very effective (and far more subtle) way of using this technique is to double-bluff the pirate. For instance, say that in the BASIC loader for a macine code game the last two commands are:
*LOAD game 3000 CALL &30B2
The pirate will look at this and will be able to examine the machine code. If we can arrange for him not to know the load and execution addresses then his task is much harder. Even better, if we can convince him that the load and execution addresses are, say, &2800 and &293A respectively.
The way to do this is to put a dummy set of commands at the end of the program and then conceal the real ones. The original program ending would look like this:
320 REM * load machine code *{ 322 *LOAD game 3000 324 CALL &30B2 326 REM } 330 *LOAD game 2800 340 CALL &293A
Try typing this in and using the alteration program as before, then listing the program.
Note that the line numbers that the pirate will see are in steps of ten, leaving no clue to the missing lines.
One word of warning before you use this technique. There is a major, very annoying bug in the operating system! When the VDU drivers have been disabled with VDU21 any carriage return sent to the VDU drivers are sent to the printer: even if the printer hasn't been enabled - even if your printer has been turned off - even if you don't have a printer! This irritating quirk means that every time you list your program the printer spits paper at you! Also, if your printer is not turned on, these carriage returns (and line-feeds if you have used *FX6,10 accumulate in the printer buffer. If the number of these reaches 63 the whole computer seizes up until either ESCAPE or BREAK is pressed. So don't fill your programs full of CHR$21s.
If you are writing a program with the VDU21 command in it you can get around this by using the command *FX3,64 before using VDU21. This disables the printer driver completely except for characters sent using the VDU1,x command.
XY + 0 | Drive number | |
XY + 1 | ||
to | Load / Save address. | |
XY + 4 | ||
XY + 5 | Number of parameters (3) | |
XY + 6 | Command (&53 for load, &4B for save). | |
XY + 7 | Track number. | |
XY + 8 | Sector number. | |
XY + 9 | High nibble: sector length in 128-byte groups. Low nybble: number of sectors to be loaded/saved. | |
XY + 10 | Error number (0 if no error). |
SAVE "TESS|HT"
The problem with this is that the catalogue and compact routines use the length of the filename to set out the catalogue on the screen. So, if you are not careful, filenames will tend to be shifted left if they are printed on the same line, but further right than, a doctored filename. This is where the subtle approach is not necessarily the best. Very good effects can be obtained by titling the disc with a clear screen, a suitable message, and a CHR$21! You can then add a CHR$6 to the end of the last file on the catalogue. If your disc boots then you don't even have to let the user catalogue the disc at all!
If you don't have the old DFS you will need to load the first block on the disc (track zero, sector zero) into the memory, alter it accordingly, and save it back again - a somewhat more cumbersome method.
However, all this is child's play next to what can be achieved. It is not very useful to stop the pirate loading the program and looking at it if he can just 'backup' to a new disc. Here's how to stop him:
The second block of the disc contains the load and execution addresses, the lengths, and the locations on the disc, of all the files. It also contains eight bytes at the very start of the block. The first four of these are the last four bytes of the title (the first eight bytes of the title are the first eight bytes of block zero). Then comes one byte which stores the number of times the disc has been written to since formatting (this number appears in brackets after the title in the catalogue). Then comes a byte which gives the number of files in the catalogue, times eight. And finally, two bytes that give the total number of blocks on the disc. These are stored high byte first (yes, this is unusual). Also, the high nibble of the high byte is used to store the OPT number.
You may wonder of what use all this is. The answer is that we can set the total number of blocks on the disc to zero! This may seem foolish but it doesn't affect the way the DFS loads from disc. It only has an effect when you start saving on the disc or when you back-up the disc. When backing-up, the computer copies on to the new disc the number of blocks specified in block one of the source disc. This means that, by setting this to zero, the back-up command will copy precisely no blocks. If you want to be even more cruel to the poor, defenceless pirate, you could arrange for just enough blocks to be copied to copy the loader from disc but not the main program. The loader could then check a block at the end of the disc to see if it contains a specific string - which, of course, you will have put there on the original disc; and, if it is not there, then it would print a suitable message, such as 'This is an illegal copy' and crash!
Note that if the length has been set to zero you can't save any more programs on disc. It also fools certain utilities' commands for looking at the disc directly - pirates occasionally use this for breaking into discs.
A useful side effect is that *COPYing all the files on disc will not copy the string at the end and so the copy won't work. This leads me to another suggestion for disc protection: have a well-protected loader which loads the main program off the disc directly using OSWORD &7F. This way you need not even put the main program on the catalogue. You might even like to store the program on disc in some personal encryption code.
Another interesting point is that, if you add 128 to all the bytes that make up a filename in block zero, that filename will promptly vanish from the catalogue completely! It will, however, still load and run perfectly normally - IF you know the filename!
Yet another thing that you can do if you have a utility such as DISC DOCTOR which allows you to format sections of a disc, is take an unformatted disc and format it leaving some tracks unformatted. If the pirate tries to make a back-up of this he will get a load error! To cover these tracks set up a dummy file in the catalogue that occupies the space.
There are plenty of other ways of confounding the pirate. You could try coding (that is, encrypting) your program and placing a decoding routine at the start. This won't stop a determined pirate as he can deduce the code from the decoding program, but it will slow him down. In fact, you will find it very difficult to stop a determined pirate. You can only protect against the person who casually copies programs. By combining a large number of protection methods you can make the pirate's job difficult enough so that he will think twice before attempting anything. What you must decide is whether all this is worth it.
A companion book in the MASTER GUIDE series, MASTERING THE DISC DRIVE (BBC Publications, 1985) goes into the disc system in great detail.