Boulderdash (Hacking Tips #3)

By Mr. Spock

Originally published in EUG #71

Boulderdash - example of self-decrypting loader, called CODE on tape, plus decryption of game before execution.

0A00 LDA #15    \*FX15,0
0A02 LDX #0     \Clear keyboard
0A04 JSR OSbyte 
0A07 LDX #0
0A09 SEI        \Disable interrupts 
0A0A LDA &0B00
0A0E ADC #33
0A10 EOR &0A00,X 
0A13 EOR #78 
0A15 SEC 
0A16 SBC &0A14
0A19 EOR &0A00,X
0A1C EOR #43
0A1F ADC #33
0A21 EOR #102 
0A23 SEC
0A24 SBC #13
0A26 EOR &0A00,X
0A29 INX
0A2A BNE &0A0D
0A2C STA &0B00
0A2F LDA #1     \Disable Escape
0A31 STA &0258  \*FX200,1 equivalent
0A34 LDA #&4C   \Code for JMP
0A36 STA &0287  \
0A39 LDA #&5C   \store &A5C so when Break
0A3B STA &0288  \pressed JMP &A5C
0A3E LDA #&0A   \
0A40 STA &0289  
0A43 INC &0A14
0A46 DEC &0A0F
0A49 INC &0A0B
0A4C INC &0A2D
0A4F BNE &0A0A
0A51 LDA &0BFF  \Checksum
0A54 CMP &0BF0  \If doesn't match go to
0A57 BNE &0A5C  \loop-forever routine 
0A59 JMP &0B00  \else continue 

This is the address to which the Electron jumps on pressing Break or if checksums don't match at &A51.

0A5C LDA #0     
0A5E STA &70 
0A60 LDA #&0B
0A62 STA &71
0A64 LDY #0
0A66 LDA #0       \In Basic this will be
0A68 STA (&70),Y  \FOR A%=&B00 TO &7FFF
0A6A INY          \?A%=0:NEXT
0A6B BNE &0A66
0A6D INC &71 
0A6F LDA &71 
0A71 CMP #&80
0A73 BNE &0A66
0A75 BEQ &0A5C    \loop forever

The code from &B00 was decoded using the following Basic program. It copies some of the code to (displacing +&2000 bytes for easy reference) and adds instructions to affect the relocated code as well as the original code where appropriate. This is necessary as the decryption routine relies on self-changing code to work - so putting an RTS at &A59 for example will fail.

   20 *L.CODE A00
   30 FORX%=&0ATO&2E:X%?&2A00=X%?&A00:NEXT
   40 P%=&2A2F:[INC&A14:INC&2A14
   50 DEC&A0F:DEC&2A0F
   60 INC&A0B:INC&2A0B
   70 INC&A2D:INC&2A2D:BNE&2A0A
   80 RTS:]
   90 X%=0:CALL&2A0A
0B00 LDA &0258 \Check that *FX200,1
0B03 CMP #1    \has been set
0B05 BEQ &0B0A \
0B07 JMP &0A5C \if not go to memory clearing routine
0B0A LDX #0
0B0C LDA #0      \zeroise &2A1-&2AF
0B0E STA &02A1,X
0B11 INX  
0B12 CPX #15  
0B14 BNE &0B0C
0B16 LDY &FFB6   \Y=length of default vector table
0B19 LDA &FFB7   \copy vector table address in OS rom
0B1C STA &70     \to &70/1
0B21 STA &71 
0B23 LDA (&70),Y \copy default vectors
0B25 STA &0200,Y \so any naughty ones the user has set up
0B28 DEY         \won't work
0B29 BNE &0B23
0B2B LDX #&38    \command line 
0B2D LDY #&0B    \at &B38
0B2F JSR OScli   \*load file at &1300
0B32 JSR &0B47 \decrypt game code
0B35 JMP &31C0 \and execute 
Block containing command line "LOAD ___1___ 1300"
0B30 ** ** ** ** ** 4C C0 31      L.1
0B38 4C 2E 5F 5F 5F 31 5F 5F L.___1__
0B40 5F 20 31 33 30 30 0D ** _ 1300 

The following routine decrypts the main game code at &B47. In Basic it would be:

 FOR Y%=0 TO &FF:Y%?A%=Y%?A% EOR j EOR k
   k=(k-2) AND &FF
 j=(j-1) AND &FF
UNTIL A%=&5800

0B47 LDA #0
0B49 STA &70     
0B4B TAY          \Y%=0
0B4C LDA #&13     \A%=&1300:j=51:k=152
0B4E STA &71    
0B50 LDA (&70),Y  \REPEAT
0B52 EOR #&33     \?A%=?A% EOR j
0B54 EOR #&98     \EOR k
0B56 STA (&70),Y 
0B58 DEC &0B55    \k=(k-2)AND&FF
0B5B DEC &0B55
0B5E BNE &0B63
0B60 DEC &0B53    \j=(j-1)AND&FF
0B63 INY          \(Y%=Y%+1)AND&FF
0B64 BNE &0B50    \UNTIL Y%=0
0B66 INC &71      
0B68 LDA &71      \A%=A%+&100
0B6A CMP #&58     \UNTIL A%=&5800
0B6C BNE &0B50

Mr Spock 26 Mar 2004