[comp.sys.apple] EOA boot code

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.