Beating Tape Protection

By Mr. Spock

Originally published in EUG #65

Introduction

The webmaster of Acorn Electron World called upon me about a year ago. My mission, should I choose to accept it, was to wade through a pile of games only ever released on tape for the Acorn Electron.

However, it wasn't going to just be a case of loading up a tape to disc program, hooking up a tape and disk drive and letting the micro do the work. These were only the games that had your Average Joe stumped. The ones where disassembling them brought up seemingly nonsense hexadecimal codes. Where the ordinary loading messages were replaced with strings of numbers, changing filenames or hidden execution addresses.

Playing around to evade the pirates back in the Eighties meant problems for emulation too. There's still no uef (tape images) of a lot of the stuff I successfully 'hacked' and ported to disc. Hopefully, you all noticed games like The Hacker, Impossible Mission and One Last Game popping up in the Professional library of this web site. But there's still a few games to be done yet, so if you're familiar with assembly language but need a bit of inspiration to kickstart you into action, here's an article about six of the games I have transferred. If you can answer any questions I have, then please do contact me.

BIRDSTRIKE

Right, first off the classic tape loader that all the Firebird games have. This is approximately one and a half pages of machine code to retrieve a series of bytes from tape. The bytes may be:

  1. a page of encrypted game code
  2. meaningless bytes for a delay loop, or
  3. an address to which the machine code loader is directed to get the next group of bytes.

Here is part of that loader:

  EA7JSR &ECB:STA &64 \Get address, &ECB is routine to get
JSR &ECB:STA &65 \one byte from tape
...
EB7JMP (&64)

If you poke an instruction in at &EB7 to divert the routine through some code:

P%=&EB7:[JMP &900:]
P%=&900:[PHA:LDA &5E:JSR &B545:LDA &64:JSR &B545:PLA:JMP (&64):]

then this will keep a watch on where the routine goes to load in the next page (&E57 for Birdstrike, until loading is complete when it is &600).

The following poke:

P%=&900:[PHA:LDA &5E:JSR &B545:PLA:JMP (&64):]

shows you which page the code is being loaded into - page &06, page &1E ... &2F, &07.

Note that &B545 is the address of a routine in BASIC 2 to print the accumulator in hex and, in the case of Birdstrike, &5E/F contains the address where the code is being loaded.

Armed with this information we can intercept the program just before it JuMPs to &600 to decrypt and execute, and save it to disk!

This technique worked perfectly on BIRDSTRIKE, THE HACKER and Video Classics. Unfortunately, it doesn't work with Star Drifter and so far I've drawn a blank at decrypting this last title. Does anyone reading this have any ideas?

STAIRWAY TO HELL

The tape loaders in this contain purported 'nonsense code' but I worked out that the decryption routine contains 'undocumented' (useless but harmless) codes interspersed with real machine code. This decrypts a page of machine code proper to load in the game by BGETting the bytes from tape, plus some fancy code makes the tape counter look like it's counting down instead of up. (It appears as 00, FF, FE, FD, etc on screen.)

There are originally four parts to this game so putting it on disc is made much more difficult as I do not know what instruction is executed when the end of any part is reached. I presume it will try to *RUN the next part from tape, because the game is so big it needed to have all disc systems disabled before it runs proper.

I ended up writing a (rudimentary) menu system to allow the user to select which of the four parts he wished to play every time the game loaded. In time I might be able to do some more surgery on the game code to re-select the disc system for loading the next part. But that does seem rather difficult - ordinarily it's impossible to reinitialise a system like ADFS after its workspace has been corrupted with game data!

JET SET WILLY

Both the JSW games will not run unless the small tape loader program is resident in zero page. Therefore, a bit of twiddling with the machine code and this game can quite easily be put into memory. The disc version simply *LOADs the loader a second time after the download is complete.

WIZZY'S MANSION

WLOAD is an example of a loader program that depends on the state of the cassette workspace (&380-&3DF) after loading. There's a JMP (&3CB) at the end of the tape loader. &3B2-&3D0 contain information about the most recent tape block read, and in this case, when loading from tape, &3CB and &3CC contain &1100 after the last block.

Of course, if you transfer the file to disc then load it, these two locations are empty and so JMP (&3CB) won't work! After downloading all the parts, the solution is just to jump to address we know - JMP &1100 - instead.

XOR

This protection is some of the most difficult I have encountered on a game. The program needs to be arrested to save the code onto disk. The loader program decrypts itself then deletes itself as it goes along! e.g.

  603LDA #&28:PHA\Return address of &28FF so exec
LDA #&FF:PHA\address of game &2900
LDA #26:PHA:LDA #22:PHA\used for decryption
...
61DSTA &600,Y\Delete code from &600-&61E
INY:CPY #&1D:BNE &61D 
PLA:STA &70:STA &71:PLA:STA &72 
... (decryption routine)
678STA &600,X\Delete code at &601-&677
DEX:BNE &678 
RTS 

The puzzling RTS at the end (Where does it return to?) makes sense when you realise that a new return address minus one had been pushed onto the stack beforehand.

ULTRON

Part of the loader program on tape was encrypted:

  900 LDY #0
902 LDA &915,Y:EOR #&55:STA &915,Y
LDA &A15,Y:EOR #&55:STA &A15,Y
INY:BNE &902
915 \ This bit is decoded by the time it is reached. The file LASTBIT is loaded in and decrypted using a simple loop to EOR all bytes with &FF and execution is at &3C00.

I hope that's given a bit of insight into the methods commerical programmers used to protect their programs. I'm busy working on lots more conversions from tape to disc and will see you all in the next EUG!

Mr Spock, EUG #65