💾 Archived View for mirrors.apple2.org.za › active › 4am › images › games › action › aliens › Aliens… captured on 2024-08-19 at 03:41:11.
View Raw
More Information
-=-=-=-=-=-=-
-----------------Aliens----------------
A 4am crack 2015-08-26
-------------------. updated 2015-09-06
|___________________
Name: Aliens
Genre: arcade
Year: 1987
Credits: game by Steve Cartwright, Glyn
Anderson, Peter Kaminski, Gene Smith;
Apple version by Alan Clark, Robert
Friele, Michael Ormsby, Hanley and
Associates
Publisher: Activision, Inc.
Media: single-sided 5.25-inch floppy
OS: DOS 3.3
Previous cracks:
The Dragon Lord / Digital Gang
Hex and Taxi / Distant Tower
~
Chapter 0
In Which Various Automated Tools Fail
In Interesting Ways
COPYA
no errors, but copy hangs on boot
(after showing DOS prompt)
Locksmith Fast Disk Backup
ditto
EDD 4 bit copy (no sync, no count)
ditto
Copy ][+ nibble editor
nothing suspicious
Disk Fixer
looks like unmodified DOS 3.3
T11 -> regular disk catalog
T01,S09 -> startup program is named
"STARTUP"
Why didn't my copies work?
Probably a nibble check called by the
startup program. Activision loves
"invisible" nibble checks that don't
fail immediately but have a side
effect.
To verify my intuition that the DOS is
unmodified (and the copy protection is
self-contained somewhere else), I'll
boot from a DOS 3.3 master disk and try
to run the program.
[S6,D1=original disk]
[S5,D1=DOS 3.3 master disk]
]PR#5
...
]RUN STARTUP,S6
...works...
[S6,D1=non-working copy]
[S5,D1=DOS 3.3 master disk]
]PR#5
...
]RUN STARTUP,S6
...fails identically to booting the
non-working copy directly...
Next steps:
1. Trace the startup program
2. Find the nibble check and document
any side effects
3. Disable the nibble check while
maintaining the side effects
~
Chapter 1
In Which It All Starts So Innocently
[S6,D1=original disk]
]PR#6
...
[<Ctrl-C> immediately after prompt]
BREAK
]CATALOG
DISK VOLUME 254
A 002 STARTUP
B 031 ULTRA.OBJ
B 015 MAIN
B 009 SMALL.60
B 009 AL0.OBJ
B 028 TITLE.S
B 022 AL1.OBJ
B 019 SULACO.CMP
B 012 TAILS.S
B 008 EQUIP.CMP
B 004 EQUIP.S
B 013 AL2.OBJ
B 016 COCKPIT.CMP
B 024 AIRLOCK.DAT
B 009 CIRCLE
B 009 TUNNEL.TMP
B 010 AL7.OBJ
B 022 RIPLEY.CMP
B 004 DOOR.CMP
B 002 DECOMP2
B 035 ONEON.S
B 004 ONEON.TMP
B 042 LOADBAY.CMP
B 036 QUEEN.S
B 038 BISHOP.CMP
B 022 DREAM.CMP
B 043 ARMS.S
B 003 CHNGREY
B 004 ALIENS.MUS
]LIST
10 PRINT CHR$ (4);"BLOAD MAIN,
A$4000": PRINT CHR$ (4);"BR
UN ULTRA.OBJ": END
]BLOAD MAIN,A$4000
]BLOAD ULTRA.OBJ
]CALL -151
AA72- 00 08
0800- 4C 03 22 JMP $2203
; set reset vector
2203- A9 12 LDA #$12
2205- 8D F2 03 STA $03F2
2208- A9 24 LDA #$24
220A- 8D F3 03 STA $03F3
220D- 49 A5 EOR #$A5
220F- 8D F4 03 STA $03F4
; an address? ($FA) -> $2415
2212- A9 15 LDA #$15
2214- 85 FA STA $FA
2216- A9 24 LDA #$24
2218- 85 FB STA $FB
; suspicious
221A- A9 C5 LDA #$C5
221C- 48 PHA
; selective memory moves
221D- A9 00 LDA #$00
221F- 85 FC STA $FC
2221- A2 03 LDX #$03
2223- BC 40 22 LDY $2240,X
; ah, it was an address
2226- 91 FA STA ($FA),Y
2228- CA DEX
2229- 10 F8 BPL $2223
; suspicious
222B- 8A TXA
222C- 48 PHA
We've now pushed $C5/$FF to the stack,
so an RTS right now would jump to $C600
and reboot slot 6. Let's try to avoid
that.
222D- 20 44 22 JSR $2244
; ah, the memory moves we were doing
; around $2223 were setting values in
; an RWTS parameter table, which we are
; now using to position the drive head
; (not shown: it was a "seek" command)
2244- A5 FB LDA $FB
2246- A4 FA LDY $FA
2248- 20 B5 B7 JSR $B7B5
224B- A9 00 LDA #$00
224D- 85 48 STA $48
224F- 90 02 BCC $2253
; if the RWTS command failed, pop the
; real return address and leave $C5/$FF
; at the top of the stack, then RTS to
; reboot
2251- 68 PLA
2252- 68 PLA
2253- 60 RTS
My non-working copy didn't reboot, so I
guess it got past this.
Continuing from $2230...
; get slot number (x16) into X
2230- A0 01 LDY #$01
2232- 8C 21 24 STY $2421
2235- B1 FA LDA ($FA),Y
2237- AA TAX
; here we go
2238- 20 54 22 JSR $2254
We're closing in on the copy protection
routine. Can you feel it? I swear I can
feel it. The random PHA instructions
are a good clue. Disk seeks for no
apparent reason. The no-second-chances
approach to error handling. This is
unfriendly territory.
~
Chapter 2
In Which We Forge Into
Unfriendly Territory
; turn on drive motor manually
; (literally never not suspicious)
2254- BD 89 C0 LDA $C089,X
; initialize Death Counters
2257- A9 56 LDA #$56
2259- 85 FD STA $FD
225B- A9 08 LDA #$08
225D- C6 FC DEC $FC
225F- D0 04 BNE $2265
2261- C6 FD DEC $FD
; if Death Counter hits 0, jump forward
; (more on this in a second)
2263- F0 34 BEQ $2299
; look for a specific nibble ($FB)
2265- BC 8C C0 LDY $C08C,X
2268- 10 FB BPL $2265
226A- C0 FB CPY #$FB
226C- D0 ED BNE $225B
226E- F0 00 BEQ $2270
; kill a few cycles (not pointless,
; because the disk spins independently
; of the CPU, so all of these low-level
; disk reads are highly time-sensitive)
2270- EA NOP
2271- EA NOP
; read data latch (note: no BPL loop
; here, we're just reading it once)
2272- BC 8C C0 LDY $C08C,X
; do a compare to set or clear the
; carry bit (among other things, but
; it's the carry bit we care about)
2275- C0 08 CPY #$08
; rotate the carry into the low bit of
; the accumulator
2277- 2A ROL
; if we just rolled a "1" bit out of
; the high bit of the accumulator, take
; this branch
2278- B0 0B BCS $2285
; next nibble needs to be $FF
227A- BC 8C C0 LDY $C08C,X
227D- 10 FB BPL $227A
; ...otherwise we start over
227F- C0 FF CPY #$FF
2281- D0 D8 BNE $225B
; loop back to get next nibble
2283- F0 EB BEQ $2270
; execution continues here (from $2278)
; get another nibble
2285- BC 8C C0 LDY $C08C,X
2288- 10 FB BPL $2285
; stash it in zero page
228A- 84 FC STY $FC
; if the accumulator is anything but
; %00001010, start over
228C- C9 0A CMP #$0A
228E- D0 CB BNE $225B
I got lost several times trying to
follow this routine. I think the
easiest way to explain it is to show
the difference between the original
disk and my non-working copy.
Here is the original disk, as seen by
the Copy II+ nibble editor. Nibbles
with extra "0" bits (timing bits) after
them are displayed in inverse on an
original machine, marked here with a
"+" after the nibble.
--v--
COPY ][ PLUS BIT COPY PROGRAM 8.4
(C) 1982-9 CENTRAL POINT SOFTWARE, INC.
---------------------------------------
TRACK: START: 1B1E LENGTH: 17C1
1C70: 9F EB E5 FC D7 D7 D7 EE VIEW
1C78: FA E6 E6 FF FE F2 ED FD
1C80: FF EF ED BA BB DD AF E6
1C88: B7 A7 CB B7 DE AA EB FF
1C90: FF FF FF FB+FF FF+FF FF+
1C98: FD FF+FF+FF+FF+FF+FF+FF+
1CA0: FF+FF+D5 AA 96 AA AB AA
1CA8: AA AA AB AA AA DE AA EB+
1CB0: FF+FF+FF+FF+FF+FF D5 AA
---------------------------------------
A TO ANALYZE DATA ESC TO QUIT
? FOR HELP SCREEN / CHANGE PARMS
Q FOR NEXT TRACK SPACE TO RE-READ
--^--
It's easy to understand why a simple
sector copy failed. The sequence that
this code is looking for starts at
offset $1C93, which is between the end
of one sector and the beginning of the
next. (The data epilogue is at $1C8C;
the next address prologue is at $1CA2.)
Sector copiers discard everything
between those delimiters and rebuild
the track with a default pattern of
sync bytes. That pattern doesn't
include an $FB nibble, so the nibble
check fails.
But the EDD bit copy also failed. Here
is the original disk's pattern at
offset $1C93:
- $FB + timing bit
- $FF
- $FF + timing bit
- $FF
- $FF + timing bit
And here is what the same part of the
track looks like on my failed EDD copy:
--v--
COPY ][ PLUS BIT COPY PROGRAM 8.4
(C) 1982-9 CENTRAL POINT SOFTWARE, INC.
---------------------------------------
TRACK: START: 1B1E LENGTH: 17C1
1C70: 9F EB E5 FC D7 D7 D7 EE VIEW
1C78: FA E6 E6 FF FE F2 ED FD
1C80: FF EF ED BA BB DD AF E6
1C88: B7 A7 CB B7 DE AA EB FF
1C90: FF FF FF FB+FF FF FF+FF+
1C98: FD FF+FF+FF+FF+FF+FF+FF+
1CA0: FF+FF+D5 AA 96 AA AB AA
1CA8: AA AA AB AA AA DE AA EB+
1CB0: FF+FF+FF+FF+FF+FF D5 AA
---------------------------------------
A TO ANALYZE DATA ESC TO QUIT
? FOR HELP SCREEN / CHANGE PARMS
Q FOR NEXT TRACK SPACE TO RE-READ
--^--
A subtle difference! The sequence at
offset $1C93 now looks like this:
- $FB + timing bit
- $FF
- $FF
- $FF + timing bit
- $FF + timing bit
This code is looking for $FF bytes with
an alternating pattern of timing bit,
no timing bit, timing bit, no timing
bit. It doesn't find that on the bit
copy, so it knows it's not running on
an original disk.
Continuing the code listing...
; get a nibble
2290- BD 8C C0 LDA $C08C,X
2293- 10 FB BPL $2290
; more bit twiddling
2295- 38 SEC
2296- 2A ROL
; AND it with the previously stashed
; nibble
2297- 25 FC AND $FC
; Success path falls through to here,
; but the failure path is also here
; (from $2263, when the Death Counters
; hit zero). In other words, we will
; always end up here regardless of
; whether the nibble check "passed,"
; but the value in the accumulator will
; be wrong if the nibble check failed.
2299- 49 AA EOR #$AA
; The difference between the original
; disk and my non-working copy is right
; here, in the value stored in $22C0.
; It's not used right away, but I'll
; bet it will be used soon.
229B- 8D C0 22 STA $22C0
; "This nibble check will self-destruct
; in ten seconds..."
229E- A9 00 LDA #$00
22A0- A8 TAY
22A1- 99 44 22 STA $2244,Y
22A4- C8 INY
22A5- C0 5D CPY #$5D
22A7- D0 F8 BNE $22A1
22A9- 60 RTS
And that's it. Whether the nibble check
succeeds or fails, this routine returns
to the caller. It doesn't even set a
flag. The only difference is the value
of $22C0.
~
Chapter 3
In Which We See How
It All Fits Together
Continuing from $223B (the next
instruction after calling the
nibble check)...
; pop $C5/$FF off the stack
223B- 68 PLA
223C- 68 PLA
; continue elsewhere
223D- 4C AA 22 JMP $22AA
; a memory move
22AA- A9 12 LDA #$12
22AC- 85 FA STA $FA
22AE- A9 22 LDA #$22
22B0- 85 FB STA $FB
22B2- A9 AA LDA #$AA
22B4- 85 FC STA $FC
22B6- A9 22 LDA #$22
22B8- 85 FD STA $FD
22BA- 20 FA 23 JSR $23FA
; continue elsewhere
22BD- 4C CF 22 JMP $22CF
22CF- AD CC 22 LDA $22CC
22D2- 18 CLC
22D3- 6D C0 22 ADC $22C0
22D6- 85 02 STA $02
22D8- AD CD 22 LDA $22CD
22DB- 38 SEC
22DC- ED C0 22 SBC $22C0
22DF- 85 03 STA $03
22E1- AD CE 22 LDA $22CE
22E4- 4D C0 22 EOR $22C0
22E7- 85 04 STA $04
There you go: three operations that
rely on the correct value in $22C0.
Luckily, this code is not obfuscated or
even difficult to patch. I can do it
right now without rebooting.
; break to monitor after we've stored
; the magic value in $22C0
<beep>
22C0- 55
The magic value is $55. Now I can write
that value to disk.
[Disk Fixer]
--> "D" for directory mode
--> select file "ULTRA.OBJ"
--> arrows to follow the binary
T0B,S0E,$C4 change "00" to "55"
I'll skip the nibble check by changing
the JMP at $0800 from $2203 (the nibble
check) to $22AA (the post-check success
path):
T11,S07,$05 change "03" to "AA"
Quod erat liberandum.
~
Changelog
2015-09-06
- Vastly improved explanation of the
actual protection routine. Thanks to
qkumba for pointing out that my
original explanation was inaccurate.
2015-08-26
- initial release
---------------------------------------
A 4am crack No. 425
------------------EOF------------------