Splitting the Atom back exit forward page 59-66

CHAPTER 9
METHODS FOR PREVENTION OF COPYING

Programs saved on tape by the Atom can be protected from copying by several general methods:

  1. Prevent the program from being LISTed
  2. When the program runs it alters some part of the machine's cassette operating system (COS)
  3. Load the main program using a 'preloader' program involving some machine code.

Several techniques for each of these methods are given below.

Of course, there is no way to totally protect a program other than by using a mathematical 'trap door' function, and these are unsuitable for small machines. Thus any program can be copied if a pirate has the right hardware and software, plus the skill, to do the job. As with most things this is a two-edged sword, since the techniques for preventing copying are the same as for pirating.

In general, a machine-oriented chip such as DISATOM will allow any of the protection techniques given to be overcome by a skilled user. If you do not have one in your machine, see the hex dump program in this book, which allows you to directly inspect and modify memory. Although this is more awkward than using a ROM, it is better than no tools at all.

The examples and techniques below are in order of increasing complexity. In all cases the following symbols will be used, and virtually ALL NUMBERS WILL BE HEX!!!

<...> = push this key, such as <space>, <CR> or <CTRL-C>.
[XX] = an actual byte in memory, as a hex number, e.g. [0D] or [03 CD 9F]

A) Using the REM statement

1. Start the program with:

10 REM <CTRL-L> <CTRL-C> <CTRL-U> <CR>

This clears the screen, turns off the printer, and turns off the VDU screen. As you type <CTRL-U>, the screen is disabled, but carry on typing the line, then type <CTRL-F> <ESC> and the screen is re-enabled. Now any attempt to list will send the control characters behind the REM to the print stream, and they will take effect. However, a RUN is still OK, since BASIC disregards anything after the REM. It is easier to insert the control codes directly into memory using the DISATOM, but this should be done after the program is completely perfected. For example, type in

10 <space> <space> <space> REM <space> <CR>

Then type

a 2900 <CR> <REPT> <ESC> .

This will give an ASCII DUMP of memory at 2900 as follows:

a 2900 0D 00 0A .R .E .M 20 20
a 2908 20 .C .A .N .' .T 20 0D

Move the cursor up to the a 2900 and <copy> the line over to the first 20. Change this and the next 20 to 0C 03, then hit <CR> and <ESC>. In the same way edit the final 20 (before the 0D) to 15 (see the appendix on the DISATOM toolkit for further details on its use). After editing, an ASCII dump gives:

a 2900 0D 00 0A .R .E .M 0C 03
a 2908 20 .C .A .N .' .T 15 0D

Now any attempt to LIST will clear the screen, the word CAN'T will appear in the upper let hand corner, and the printer and the screen will be turned off.

Unfortunately, since it must be physically the first line in the program, a pirate can overcome it simply by typing

0 <CR> L. <CR>

and if this has no effect he recovers the screen with:

<CTRL-F> <CR>		followed by
1 <CR> L. <CR>		and so on

This has the effect of eventually removing the BASIC line with the offending REM statement in it. Alternatively, if the pirate has DISATOM, he may do an ASCII dump and replace the 0C, 03 and 15 with 20's.

2. A REM statement can be used after a genuine BASIC statement. The REM is followed by four backspaces [08], and then some apparently legitimate BASIC statement such as X=3*A, then a [15] (screen off). The line is best set up by typing out:

10 DIM XX(12); REM <3 spaces> X=3*A <space> <CR>

The first three spaces [20] are then replaced by [08] (backspace), and the final [20] by [15] (screen off). When a list is attempted, the following appears on screen:

10 DIM XX(12); REM X=3*A	(screen fails)

The dimensioning of the array is genuine, but the second statement is a fake. The purpose of all this is to convince the user that the entire line is real, and leave him baffled as to why the screen failed. It can of course be overcome by an ASCII dump, which would reveal the REM, and it can then be removed. However, if someone attempts to delete the entire line (as in the last example) the entire program fails. You can see that there are several possible twists in this technique.

A slight sophistication is to have another REM as the last line of the program that reads

1000 REM [06]

Now when a LIST is called this results in

>LIST
   10 DIM XX(12); REM X=3*A
>

and the program appears to have only one line. The technique can again be defeated by an ASCII or HEX dump the reveals either the first or last REM.

3. Machine code in a REM statement

Quite a lot of machine code can be put in a disguised REM statement. As with the previous example, the first part of the line is valid BASIC, but buried in the REM is some machine code to be accessed by a later part of the program. Thus

40 x=6; ?1B=41;rem[7f 7f 7f 15 <m/c code here> 06 0D]
!! M/C CODE MUST NOT CONTAIN 0D !!

The first two instructions are valid and appear on LISTing. The REM causes three backspacing deletes and turns off the screen so your machine code is not seen, then turns it on again at the end. The line can be placed anywhere in the program, but the deeper the better, since this decreases the likelihood that someone will stumble on it with an ASCII dump. The machine code can be anything at all, but for example, it might alter the SAVVEC of the COS system to disable the tape saving function. There are two disadvantages to this method.

  1. you must exactly determine the entry point for the hidden machine code (then get P exactly equal to that address and have it assembled there), and
  2. you must eventually LINK to that address

Someone seeing a LINK into the BASIC text area will of course be suspicious, and in any event all LINKs can be found with a DISATOM using FIND "LINK" and FIND "LI.". It is possible to access this code using another, less suspicious machine code routine. Using this method without camouflage is a good way to save short machine code routines within BASIC itself, instead of having to assemble it each time, or using *SAVE to ensure machine code outside BASIC test is also saved. To prevent someone hitting <break> and then copying, site the BASIC program to start at 2800, and then having a hidden REM that contains NOP: RTS ([EA 60]) such that the NOP is at 2900 and the RTS is at 2901. On one occasion in the program proper, LINK to 29000 and the RS as 2901. If a pirate breaks from the program and copies it, the 2900,2901 machine code is lost, and the program will crash. An even more effective way is to have 28FF = JMP 28XX, and somewhere in the 2800's is another REM containing an RTS. Hitting <break> distorts the JMP location and the program crashes. Indirect jumps can also be used, via an address stored here. Once the program is running, it is easy to prevent the <ESC> key operating by intercepting the code from the keyboard and changing it. This is done by:

LDA @0; STA #B000	ENABLE the keyboard
JSR #FE94		GET a key in accumulator
CMP @#D			IF a <CR> jump to DISABLE
BEQ P+8
CMP @32
BCS @32			IF >= <> jump to DISABLE
LDA @32			CHANGE code to a <space>

PHA
LDA @10; STA #B000	DISABLE keyboard again
PLA
RTS

Finally, spanner the vector at 20A, 20B to point at this routine. The routine also prevents the entry of any other control codes, some of which re-enable the <ESC> key. Remember to set B000=10 as the first part of your BASIC program. This can be beaten by causing an error, which will return the user to the direct mode. To be safe you should therefore alter the BRK vector at 202, 203.

4) The long Line

The BASIC interpreter is perfectly happy to work on a line which is (almost) infinitely long, with the statements being separated by semicolons. The practical consequences of that are that

  1. the LIST command will turn back on itself (recycle from the start) if the line greater than 258 bytes (two of which are the line number), and
  2. if this is the first line in the program then BASIC is unable to add any new lines or delete any old ones, since it cannot find the end of the first line.

If the first line consists of something like P.; P.; P.; etc. etc. for the whole of page 29, then the rest of the program cannot be LISTed and the program cannot be edited, nor do the command OLD or END work, since the real size of the program is no unknown to the operating system. The real program can be terminated with LINK #C2B2, which accomplishes a NEW, or a GOTO X, where X is a real line number or label in the program, if you wish to repeat the program. Below is a procedure for setting up such a method, and it is given so that those without DISATOM can also do it, given some extra work. Make sure that you program is perfect BEFORE you protect it, and note that you have 258 bytes less space for your real program

  1. DIRECT COMMAND:
    F.I=#29000 to #2A048.4; !I=#3B202E50; N.
  2. DIRECT COMMAND
    ?18 = #2A
    NEW
    Now write and completely debug your program as normal,
    but the FIRST LINE MUST BE 1REM <3 spaces> <CR>
  3. When your program is perfect give DIRECT COMMANDS:
    ?18 = #29
    !#2900 = #5000000D
    !#2904 = #3B20203E
    !#2A00 = #3B202E50
  4. *SAVE the program in the usual way, remembering that the total program does start at 2900.

B) Disabling the SAVE

This can be done by spannering the SAVVEC at 20E, 20F to point at a different location. However, this is easy to spot. A much more subtle method is to point the SAVVEC to a machine-code routine that display the "RECORD TAPE", then waits an appropriate amount of time, say 2 minutes. Of course, nothing meaningful goes to the tape, but the pirate won't know this. Some examples, which will easily fit in a hidden REM are given below.

a.	JSR #FC40	print "RECORD TAPE", and wait for key
b.	LDY @05
	JSR #FB7D	each Y is worth 2 seconds, so this 
	DEY		section delays 10 seconds
	BNE P-4
	RTS		TOTAL = 11 BYTES

Another possibility is

JSR #FC40	as before
JSR #FAF8	put a small amount of garbage on tape
		then use part (b) from above.

C) Using preloaders

This technique involves using one program to call another from tape. At the same time the first program should be accessible only via machine code routes, should alter such things as the SAVVEC, and then destroy itself.

Both the *SAVE and *LOAD commands can be carried out from in program, and the usual prompts 'PLAY TAPE' etc can be avoided. This is done by changing the SAVVEC and/or LODVEC to point at your short routine (given below). Assume here that your saving routine will be at 8350, and loading routine at 8300:

	Vector Changes	Your Program
	--------------	------------
*LOAD	20C = 00	PHP; JMP #F97A
	20D = #83

*SAVE	20E = #50	PHP; JMP #FAF8
	20F = #83

A BASIC program at 8000 (on the screen) can be used to perform the actual *LOAD of the main program. Programs on screen are convenient because P.$12,<BRK> etc. erases them. They are best saved to tape by using yet another BASIC utility program, say at 8500, which

  1. uses the DISATOM "COPY" command to place the program on the screen, and then
  2. *SAVE the screen to tape.

The BASIC program on the screen should not be a runnable program, but should contain the missing parts, deliberate errors and misinformation. These will be corrected by a machine code program located at 8200.

Initially the main program should have some title which turns off the screen (to prevent *CAT), and should make reference to some part of the machine-code preloader at 8200, so that it will not run unless the machine-code has been run first. In summary, what we find is this:

Address		Program type
-------		------------
2900 and up	Main program
8000		Preloader, BASIC part
8200		Preloader machine code		ONE PROGRAM
8300		*LOAD spannering program
8350		*SAVE spannering program
8500		BASIC utility program to save on tape the main and preloader programs.

Given below are example of each program.

Program type: Main program	Location: 2900 and up	Main program
Program title: "[15 03]MAIN"
10 !#80=#C98046AD; !#84=#AD0FD04A; !#88=#0DC98000; !#8C=#15AD08D0
20 !#90=#D000C902; !#94=#B24C6001; ?#98=#C2
30 LI.#80
40 CLEAR 2; P.$12
50 REST OF PROGRAM FROM HERE ON

Lines 10 and 20 write a machine code program, and 30 links to it. The purpose is to ensure that the machine-code preloader has already been run. The code reads as:

80=	LDA 8046 ; CMP @4D; BNE 96
	LDA 8000 ; CMP @0D; BNE 96
	LDA 0215 ; CMP @0D; BNE 96
	RTS
96=	JMP C2B2

Finally, line 30 erases the entire preloader program.

Program type: Preloader, BASIC part	Location: 8000
Program title: "LOAD" 8000 8255 8200

NOTE:

  1. Deliberate errors are underlined,
  2. you MUST fill in the values for the TOP vector of your main program at 13,14
    in line 30 of this program (given here as XX XX).
[0D FF 00] !#80=03902000; !#84=#4C81FF8D; !#88=#FBEE; !#214=#FC7C0080
20 *LOAD"<3 spaces> AIN"
30 ?1B=41; ?13=XX; ?13=XX; LI. #FE86

This program should originally be written with the first line numbered as, say, line 5. You will later change this with DISATOM so that the area of memory storing this line number will read [0D 00 05]. This is of course creating an error, but the machine code part of the preloader will correct this to [0D 00 00], which BASIC interprets as the start of the program, line 0. The effect of the line when it runs is to set up machine code at #80, and then spanner the tape byte-getting routine to point at it. This causes the bytes loading from tape to appear in the lower right of the screen, thus visually confirming further LOADs, and then passes the byte to the correct location. Line 20 LOADs the main program into 2900. The title starts out as "<3 spaces>AIN". The machine code preloader will change the three spaces so the title reads "[15 03] MAIN". The title is therefore actually "TURN OFF SCREEN, TURN OFF PRINTER,MAIN", and so it cannot be *CATed, nor can the title or the rest of the program be LISTed once it is altered to its final form. Line 30 changes the BASIC text pointer to 2900, sets the value of TOP for the main program (you MUST provide this), then starts the main program at 2900. NOTE - if the main program contains DIM statements, you must first set the DIM pointer (at #23, 24) to the value of TOP, somewhere in the main program before the DIM statement.

The previous BASIC program has several deliberate errors to hinder copying and relocation. Here is a summary.

ERROR BYTE	AT	BECOMES	COMMENT
----------	--	-------	-------
FF		8001	00	BECOMES LINE NUMBER 0
30		800F	43	ALTERS MACHINE CODE
30		8010	39	FROM 00 TO C9
20		8044	15	CONVERTS PROGRAM LOAD TITLE
20		8045	03	TO
20		8046	4D	"[15 03]MAIN"
46		806C	43	ALTERS LINK FROM FE86 TO CE86
PROGRAM TYPE: Preloader, machine code part	LOCATION: 8200
PROGRAM TITLE: same as BASIC part, all saved as one program
LOCATION	SOURCE		OBJECT		REM
--------	------		------		---
8200		LDA @08		A9 08		WRITE MACHINE CODE
		STA #8300	AD 00 83	TO ENABLE
		LDA @#4C	A9 4C		*LOAD BY BASIC
		STA #8301	AD 01 83	PRELOADER
		LDA @#7A	A9 7A
		STA #8302	AD 02 83
		LDA @#F9	A9 F9
		STA #8303	AD 03 83
8214		LDA @00		A9 00		FIX DELIBERATE
		STA #8001	AD 01 80	ERRORS IN BASIC
		LDA @#43	A9 43		PRELOADER
		STA #800F	AD 0F 80
		LDA @#39	A9 39
		STA #8302	AD 02 83
		LDA @#15	A9 15
		STA #8303	AD 44 80
		LDA @#03	A9 03
		STA #8045	AD 45 80
		LDA @#4D	A9 4D
		STA #8046	AD 46 80
		LDA @#43	A9 43
		STA #806A	AD 6A 80
8237		LDA @00		A9 00		SPANNER LODVEC
		STA #020C	AD 0C 02	TO POINT AT
		LDA @#83	A9 83		OUR PROGRAM AT 83
		STA #020D	AD 0D 02
8241		LDA @40		A9 40		SPANNER SAVVEC
		STA #020E	AD 0E 02	TO PRINT MESSAGE
		LDA @#FC	A9 FC		THEN FAIL
		STA #020F	AD 0F 02
824B		LDA @80		A9 80		SPANNER TEXT
		STA #12		85 12		POINTER AND JUMP
		JMP #CE86	4C 86 CE	TO BASIC LAST BYTE AT 8251

Now to construct the entire preloader program:

i) Use the DIRECT COMMANDS

F.I=#8200 TO #8600; ?I-32;N.
?18= #82
NEW

ii) Type in the BASIC part of the preloader, as mentioned above, including the errors. Start with line 5. When finished, type NEW, then alter the program title in line 20 using either HEX DUMP or a DISATOM ASCII dump.

iii) Use the DIRECT COMMANDS

?18=#85
NEW

iv) Construct the SOURCE code give for the machine code part of the part of the preloader here at #8500, with P=#8400.

Needless to say, a program combining ALL the techniques listed her will be a truly formidable program to pirate.

back exit forward