PGOETZ@LOYVAX.BITNET (04/13/88)
ELECTRONIC ARTS PROTECTION LANGUAGE
I was boot-code tracing Amnesia, and I came to $3700. A protection
routine starting at $3704 evidently checked for one sector of nothing but $AFs,
but I didn't see where it was called. The tracing became very complicated and
indirect, but I noticed that I kept circling back to $38C3. Then I realized
that $38C3 was the equivalent of Applesoft's GETCHR for EOA's own interpretive
language. After much tracing and disassembling, I decoded this language, which
I call EOAPL. It is basically a small subset of 6502 machine language, and it
is of course much slower, so its only purpose is to confuse crackers.
To see this code, boot Amnesia. When it asks you PLAY A SAVED GAME?
insert a normal disk into the drive and press reset. All the code is left
unaltered.
In Amnesia, $3700 jumps to $376A:
376A- JSR $38E1
376D- JSR $38B4
3770- JMP $376A
$38B4 is the call to the interpreter. It stores the address 3 bytes beyond
the next instruction in the interpreter's program counter (in this case, $3773)
and falls through to $38C3, which starts running the program at $3773.
$38C3 is the crucial routine to look for:
38C3- B1 52 LDA ($52),Y Get opcode
38C5- C8 INY Advance program counter
38C6- D0 02 BNE $38CA
38C8- E6 53 INC $53
38CA- AA TAX
38CB- BD D4 38 LDA $38D4,X Get low byte of address which
executes this instruction
38CE- 8D E0 39 STA $39E0 Store it in the JMP
38D1- 4C DF 39 JMP $39DF Execute; routine will return
via a JMP $38C3
39DF- 4C xx 39 JMP $39xx
Each instruction consists of a 1-byte opcode followed by a 0, 1, or 2
byte parameter.
The opcodes are not encoded. Each 1 byte parameter is EORed with $4C.
Every 2 byte parameter is EORed with $D903 (the low byte is EORed with 3 and
the high byte with $D9).
EOAPL uses $56 as the accumulator and $53,52 as the program counter.
$50-5F are used for various things.
The commands are:
Op. Len Addr Mnemnonic Function
0 3 3900 GOTO addr
1 3 3927 JSRV addr Call a machine language subroutine with $56 as a
value parameter: On entry A <- $56, on exit $56 <- A.
2 3 3955 GONE addr Go to addr if $56 > 0
3 2 395F LD56 num
4 3 396D LD56 addr
5 3 398A GSUB addr
6 3 39AD ST56 addr
7 2 39B9 S56- num $56 <- $56 - num
8 1 39A2 RTRN Return from subroutine
9 3 394F JSR addr Call a machine language subroutine
A 3 39CE INC addr INC addr : $56 <- (addr)
B 1 3926 RTS Exit program & return to machine language caller
C 3 3979 S56+ addr $56 <- $56 + (addr)
So, for example, a routine to print 4C would look like this:
0300- 20 B4 38 JSR $38B4
0303- 60 RTS
0304- 00 BRK
0305- 00 BRK
-------- disassembled EOAPL --------
0306- 03 00 LD56 #$4C
0308- 01 D9 24 JSRV $FDDA
030B- 0B RTS
About $B0 bytes are in EOAPL - too many to disassemble by hand. So I
rewrote the monitor disassembler ($F882-FA3F, enter at $F8D0) to disassemble
EOAPL. It is written for the Apple Toolkit Assembler.
1. Enter the start address in 1,0.
2. Enter the number of lines to disassemble in 2.
3. 800G (or CALL 2048).
Ex: CALL-151
0:0 30 10
800G
would disassemble 16 lines of EOAPL starting at $3000.
ORG $800
CODE EQU 2
FORMAT EQU $2E
LENGTH EQU $2F
LDA 0
STA $3A
LDA 1
STA $3B
LDA 2
STA 6
L1 JSR EOADIS
LDA LENGTH
SEC
ADC $3A
STA $3A
BCC L2
INC $3B
L2 DEC 6
BNE L1
RTS
EOADIS JSR INSDS1
PRNTOP LDA ($3A),Y
JSR $FDDA
LDX #1
PRNTBL JSR $F94A
CPY LENGTH
INY
BCC PRNTOP
LDX #3
CPY #4
BCC PRNTBL
;PRINT MNEMONIC
LDA CODE
ASL A
ASL A
TAY
LDX #4
PMN LDA MTAB,Y
JSR $FDED
INY
DEX
BNE PMN
JSR $F948
LDY LENGTH
LDX #6
PRADR1 CPX #3
BEQ PRADR5
PRADR2 ASL FORMAT
BCC PRADR3
LDA $F9B3,X
JSR $FDED
LDA $F9B9,X
BEQ PRADR3
JSR $FDED
PRADR3 DEX
BNE PRADR1
RTS
PRADR4 DEY
BMI PRADR2
STX 3
LDX LENGTH
CPX #2
BCS ED903
EOR #$4C
JMP PR45
ED903 EOR ETAB,Y
PR45 JSR $FDDA
LDX 3
PRADR5 LDA FORMAT
CMP #$E8
LDA ($3A),Y
BCC PRADR4
JSR $F956
TAX
INX
BNE PRNTYX
INY
PRNTYX TYA
JSR $FDDA
TXA
JMP $FDDA
RTS RTS
ETAB DFB $3,$D9
LENTAB DFB 2,2,2,1,2,2,2,1,0,2,2,0,2,0
FMTTAB DFB $80,$80,$80,$20,$80,$80,$80,$20,0,$80,$80,0,$80,0
MTAB ASC /GOTOJSRVGONELD56LD56GSUBST56S56-RTRNJSR INC RTS S56+????/
INSDS1 LDX $3A
LDY $3B
JSR $FD96
JSR $F948
INSDS2 LDA ($3A,X)
CMP #$D LEGAL OPCODE?
BCC GETFMT YES
LDA #$D ????
GETFMT TAY
STA CODE
LDA LENTAB,Y
STA LENGTH
LDA FMTTAB,Y
STA FORMAT
LDY #0
RTS
Hex dump of disassembler:
0800- A5 00 85 3A A5 01 85 3B
0808- A5 02 85 06 20 1F 08 A5
0810- 2F 38 65 3A 85 3A 90 02
0818- E6 3B C6 06 D0 EE 60 20
0820- F0 08 B1 3A 20 DA FD A2
0828- 01 20 4A F9 C4 2F C8 90
0830- F1 A2 03 C0 04 90 F2 A5
0838- 02 0A 0A A8 A2 04 B9 B8
0840- 08 20 ED FD C8 CA D0 F6
0848- 20 48 F9 A4 2F A2 06 E0
0850- 03 F0 2E 06 2E 90 0E BD
0858- B3 F9 20 ED FD BD B9 F9
0860- F0 03 20 ED FD CA D0 E7
0868- 60 88 30 E7 86 03 A6 2F
0870- E0 02 B0 05 49 4C 4C 7C
0878- 08 59 9A 08 20 DA FD A6
0880- 03 A5 2E C9 E8 B1 3A 90
0888- E0 20 56 F9 AA E8 D0 01
0890- C8 98 20 DA FD 8A 4C DA
0898- FD 60 03 D9 02 02 02 01
08A0- 02 02 02 01 00 02 02 00
08A8- 02 00 80 80 80 20 80 80
08B0- 80 20 00 80 80 00 80 00
08B8- C7 CF D4 CF CA D3 D2 D6
08C0- C7 CF CE C5 CC C4 B5 B6
08C8- CC C4 B5 B6 C7 D3 D5 C2
08D0- D3 D4 B5 B6 D3 B5 B6 AD
08D8- D2 D4 D2 CE CA D3 D2 A0
08E0- C9 CE C3 A0 D2 D4 D3 A0
08E8- D3 B5 B6 AB BF BF BF BF
08F0- A6 3A A4 3B 20 96 FD 20
08F8- 48 F9 A1 3A C9 0D 90 02
0900- A9 0D A8 85 02 B9 9C 08
0908- 85 2F B9 AA 08 85 2E A0
0910- 00 60
So to disassemble the code in Amnesia at $3773, we type:
*0:73 37 13
*800G
and we get:
3773- 04 62 EE LD56 $3761
3776- 07 74 S56- #$38
3778- 02 8E E1 GONE $388D Crash if $3761 has been changed
377B- 04 61 EE LD56 $3762
377E- 07 2C S56- #$60
3780- 02 8E E1 GONE $388D Same for $3762
3783- 04 6B EE LD56 $3768
3786- 07 74 S56- #$38
3788- 02 8E E1 GONE $388D Same for $3768
378B- 05 AB EE GSUB $37A8 Call $3704 & check for original
378E- 02 97 EE GONE $3794 Fail, try again
3791- 00 A6 EE GOTO $37A5 OK, exit
3794- 05 AB EE GSUB $37A8
3797- 02 9E EE GONE $379D Fail
379A- 00 A6 EE GOTO $37A5 OK, exit
379D- 07 4E S56- #$02
379F- 02 8E E1 GONE $388D Crash if $56 wasn't 2 after $37A8
37A2- 00 70 EE GOTO $3773 Do it again
37A5- 09 A4 E1 JSR $38A7 Exit to caller
Inspection of the disassembly shows us we can bypass the protectiobn by
switching the GONE $3794 at $378E with the GOTO $37A5 at $3791. That way it
exits OK regardless what happened, and any checksums are satisfied. Scanning
the disk, we find 02 97 EE 00 A6 EE on T9 S2 at bytes $E2-E7. So to crack
Amnesia, copy all tracks except track 6 & perform this sector edit:
T9 S2 B$E2: 02 97 EE -> 00 A6 EE
B$E5: 00 A6 EE -> 02 97 EE
EOAPL is also used in The Last Gladiator, Archon, Archon II: Adept, and
probably many other EOA releases.