|
|
IDENTIFICATION SERVEUR : 10.0.97.1 - CLIENT : 54.198.164.83 |
|
Voir le sujet précédent :: Voir le sujet suivant |
Auteur |
Message |
qkumba
Inscrit le: 29 Jan 2012 Messages: 171
|
Posté le: Ven 06 Jan 2017, 18:17 Sujet du message: David's Midnight Magic (Broderbund, 1982) |
|
|
This is an pinball game that is incredibly addictive if you love pinball games. Otherwise you'll hate it because it's also soooo difficult! :-)
I spent more time playing it than deprotecting it, but that's certainly not because of the lack of protection.
We start with a hybrid boot-sector. This disk can be booted on old 5-and-3 drives as well as 6-and-2 ones.
Code: | 0801 LDX #0
0803 LDA $0800,X
0806 STA $0200,X
0809 INX
080A BNE $0803
080C JMP $020F |
Copy self out of the way, and then jump to that copy.
Code: | 020F LDY #$AB
0211 TYA
0212 STA $3C
0214 LSR
0215 ORA $3C
0217 CMP #$FF
0219 BNE $0224
021B CPY #$D5
021D BEQ $0224
021F TXA
0220 STA $800,Y
0223 INX
0224 INY
0225 BNE $0211 |
Build 5-and-3 translation table.
Code: | 0227 STY $3D
0229 STY $26
022B LDA #03
022D STA $27 |
Prepare to load 5-and-3 sector 0 to $0300.
Code: | 022F LDX $2B
0231 JSR $025D |
Load.
Decode. The decoder also checks that $300=#$99 (and crashes if not), and returns Y=#$99. This is important.
Run it.
Code: | 0301 STY $0200
0304 LDY $2B
0306 LDX #$00
0308 LDA $0300,X
030B EOR $0200
030E STA $00,X
0310 DEX
0311 BNE $0308 |
Decode onto zpage, using the Y value from previously. If we didn't bother to set it, then it will decode garbage instead.
Code: | 0313 STY $2B
0315 TXA
0316 PHA
0317 PHA
0318 LDA $A2
031A EOR $0200
031D PHA |
Obfuscated entrypoint decodes to $0069.
Code: | 031E LDA $0323
0321 STA $FF
0323 RTS |
So let's go there.
Dernière édition par qkumba le Ven 06 Jan 2017, 18:44; édité 2 fois |
|
Revenir en haut de page |
|
 |
qkumba
Inscrit le: 29 Jan 2012 Messages: 171
|
Posté le: Ven 06 Jan 2017, 18:20 Sujet du message: |
|
|
Code: | 0069 LDA $C083
006C LDA $C083
006F TXA
0070 TAY
0071 TXS
0072 STA $0300,X
0075 DEX
0076 BNE $72
0078 STA $FFFC
007B LDA $2B
007D LSR
007E LSR
007F LSR
0080 LSR
0081 ORA #$C0
0083 STA $FFFD
0086 STA $03F3
0089 EOR #$A5
008B STA $03F4 |
Set up reset vector.
Code: | 008E LDA #$08
0090 STY $00
0092 STA $01
0094 LDA #$A0
0096 STA ($00),Y
0098 INY
0099 BNE $96
009B INC $01
009D LDA $01
009F CMP #$0C
00A1 BNE $94
00A3 LDA $C051
00A6 LDA $C055 |
Erase text screen 2 and then display it (because first text screen is about to be filled with code).
Code: | 00A9 LDX #$04
00AB STX $40
00AD STX $3D
00AF STY $3C
00B1 PHA
00B2 TXA
00B3 PHA
00B4 PHA
00B5 PHA
00B6 LDX $2B
00B8 LDA $C08C,X
00BB BPL $B8
00BD CMP #$D4
00BF BNE $B8
00C1 LDA $C08C,X
00C4 BPL $C1
00C6 CMP #$DB
00C8 BNE $BD
00CA LDA $C08C,X
00CD BPL $CA
00CF CMP #$AF
00D1 BNE $C6
00D3 LDA $C08C,X
00D6 BPL $D3
00D8 ROL
00D9 STA $3F
00DB LDA $C08C,X
00DE BPL $DB
00DE BPL $DB
00E0 AND $3F
00E2 STA ($3C),Y
00E4 INY
00E5 BNE $D3
00E7 INC $3D
00E9 DEC $40
00EB BNE $D3
00ED LDA $C08C,X
00F0 BPL $ED
00F2 CMP #$AE
00F4 BNE $A9
00F6 LDA $C08C,X
00F9 BPL $F6
00FB CMP #$EE
00FD BNE $A9 |
Read prologue D4 DB AF, then 1024 bytes in 4-and-4 encoding to $400+, and epilogue AE EE. No checksum.
Then return to $405.
Code: | 0405 PHA
0406 PHA
0407 PHA
0408 PHA
0409 PHA
040A PHA |
These are important later.
Code: | 040B STX $08
040D LDX #$03
040F LDA $0400,X
0412 STA $00,X
0414 DEX
0415 BPL $040F
0417 JSR $04F0
041A NOP
041B LDA #$40
041D PHA
041E LDX #$0C
0420 JSR $0500
0423 LDA $30
0425 CLC
0426 ADC #$02
0428 JSR $0572 |
Full-track stepping. For now.
Code: | 042B PLA
042C CLC
042D ADC #$0C
042F CMP #$B8
0431 BCC $041D |
Read 4-and-4 data to $4000-B7FF. The step routine is at $572, nothing special, but the read routine at $500...
Code: | 0500 STX $5E
0502 STA $5A
0504 LDX $5E
0506 STX $40
0508 LDY #$00
050A LDA $5A
050C STY $5C
050E STA $5D
0510 LDX $08
0512 JSR $056C
0515 CMP $00
0517 BNE $0512
0519 JSR $056C
051C CMP $01
051E BNE $0515
0520 JSR $056C
0523 CMP $02
0525 BNE $051C |
Variable prologue bytes.
Code: | 0527 LDA $C08C,X
052A BPL $0527
052C ROL
052D STA $5F
052F LDA $C08C,X
0532 BPL $052F
0534 AND $5F
0536 STA ($5C),Y
0538 INY
0539 BNE $0527
053B ASL $C000
053E LDA $C08C,X
0541 BPL $053E
0543 CMP $03
0545 BNE $0504
0547 INC $5D
0549 DEC $40
054B BNE $0527 |
Each sector has a 1-byte variable epilogue.
Code: | 054D JSR $056C
0550 STA $02
0552 JSR $056C
0555 STA $01
0557 JSR $056C
055A STA $00
055C JSR $056C
055F STA $03
0561 JSR $056C |
The prologue and epilogue are part of the sector data!
Code: | 0564 CMP $00
0566 BNE $0569 |
And there's even an epilogue check for the epilogue.
Nothing much to see until we get here:
Code: | 0457 PLA
0458 PLA
0459 PLA
045A PLA
045B EOR #$65
045D PHA
045E EOR #$31
0460 PHA
0461 RTS |
Obfuscated entrypoint decodes to $8BBB.
Code: | 8BBB EOR #$7A
8BBD STA $E7
8BBF TXA
8BC0 EOR #$88
8BC2 STA $E6
8BC4 JSR $8B20 |
Looks okay. It's a strange place to start but okay.
Code: | 8B20 LDX #$07
8B22 LDA $00,X
8B24 STA $90,X
8B26 DEX
8B27 BPL $8B22
8B29 LDA #$90
8B2B PHA
8B2C PHA
8B2D LDY #$08
8B2F LDX #$20
8B31 DEX
8B32 BNE $8B31
8B34 BIT $C030
8B37 DEY
8B38 BNE $8B2F
8B3A RTS |
Plays a sound and then returns. Oh, those PHAs are easy to overlook.
We return to $9091 instead.
Code: | 9091 LDY #$00
9093 LDA $9000,Y
9096 EOR #$EE
9098 STA $0200,Y
909B INY
909C BNE $9093
909E JMP $02DD |
More decoding.
Code: | 02DD LDY #$00
02DF LDA $9000,Y
02E2 EOR $0400,Y
02E5 EOR $0500,Y
02E8 EOR $0600,Y
02EB EOR $0700,Y
02EE EOR #$EE
02F0 STA $9000,Y
02F3 INY
02F4 BNE $02DF
02F6 JMP $9004 |
This one is super annoying. The RWTS is at $400-7FF. Any change that we make to it causes this routine to decode garbage.
That includes after we've put our own RWTS and then found bugs in it that we have to fix. :-( |
|
Revenir en haut de page |
|
 |
qkumba
Inscrit le: 29 Jan 2012 Messages: 171
|
Posté le: Ven 06 Jan 2017, 18:22 Sujet du message: |
|
|
Code: | 9004 LDX $2B
9006 LDA $C08C,X
9009 BPL $9006
900B CMP $00
900D BNE $9006
900F LDA $C08C,X
9012 BPL $900F
9014 CMP $01
9016 BNE $900B
9018 LDA $C08C,X
901B BPL $9018
901D CMP $02
901F BNE $9014
9021 NOP
9022 LDA $C08C,X
9025 BPL $9022
9027 SEC
9028 ROL
9029 STA $FF
902B LDA $C08C,X
902E BPL $902B
9030 AND $FF
9032 NOP
9033 STA $905B
9036 LDA $C08C,X
9039 BPL $9036
903B SEC
903C ROL
903D STA $FF
903F LDA $C08C,X
9042 BPL $903F
9044 AND $FF
9046 STA $905C
9049 NOP
904A LDA $C08C,X
904D BPL $904A
904F SEC
9050 ROL
9051 STA $FF
9053 LDA $C08C,X
9056 BPL $9053
9058 AND $FF
905A STA $FFFF
905D CMP #$FF
905F BNE $9022
9061 LDA $C08C,X
9064 BPL $9061
9066 CMP #$FF
9068 BEQ $906D
906A JMP $0609
906D RTS |
Decode 4-and-4 data that are the *address and value to write*. Yes, the sector data hold both the address and the value.
This routine can't be bypassed because it's used to set critical values that are used everywhere in the game.
Code: | 8BC7 LDY #00
8BC9 LDA ($E6),Y
8BCB LDY #01
8BCD LDA $4E
8BCF PHA
8BD0 JSR $9150
8BD3 JSR $85B4
8BD6 LDY #01
8BD8 LDA ($E6),Y
8BDA LDY #$0C
8BDC JSR $85A8
8BDF DEY
8BE0 BNE $8BDC
8BE2 JSR $8F30 |
Eventually we return. Not much to see here, but it displays the title sequence that almost no-one ever saw before.
Press "ctrl-u" during boot to make it display faster.
There's also a credit and copyright notice in a region of the screen that no-one ever saw before because there's a bug in the title code that never shows it (technically, it's shown but so quickly that it's too hard to read. We learn from it that "David" is "David Snider").
Code: | 8F30 JSR $8F80
8F33 LDY #$07
8F35 STY $82
8F37 JSR $8F00
8F3A LDA $80
8F3C BEQ $8F47
8F3E LDA $C081,X
8F41 LDA $C081,X
8F44 JSR $8F90
8F47 LDY $82
8F49 DEY
8F4A BPL $8F35
8F4C JSR $8F80
8F4F NOP
8F50 JSR $8EA0 |
Nothing here.
Code: | 8EA0 LDY $FFFC
8EA3 LDA $FFFD
8EA6 LDX #$8C
8EA8 CPY #$62
8EAA BNE $8EB2
8EAC EOR #$FA
8EAE BNE $8EF5
8EB0 BEQ $8EBD
8EB2 CPY #$59
8EB4 BNE $8EF5
8EB6 CMP #$FF
8EB8 BNE $8EF5
8EBA INX
8EBB LDA #$50
8EBD STA $00
8EBF STX $01
8EC1 LDY #$02
8EC3 LDA ($00),Y
8EC5 STA $02,Y
8EC8 DEY
8EC9 BPL $8EC3
8ECB LDA #$03
8ECD CLC
8ECE ADC $00
8ED0 STA $00
8ED2 BCC $8ED6
8ED4 INC $01
8ED6 LDY $04
8ED8 BEQ $8EF3
8EDA LDA ($00),Y
8EDC CMP ($02),Y
8EDE BNE $8EF4 |
Ah. This code checks ROM for certain values, because the ROM code will never change, right?
That is, until the enhanced IIe came out. Oops, some of those bytes are different, and the game can't run there.
It's the same mistake that exists in Choplifter. Anyway, if we pass that check, we get here:
The value comes from the routine earlier. If we didn't run it, the game would reboot instead.
Code: | 0400 LDA #$00
0402 JSR $FCA8
0405 LDA #$16
0407 JSR $0572
040A LDY #$00
040C STY $09
040E LDA $04A2,Y
0411 BEQ $0438
0413 CLC
0414 ADC $30
0416 JSR $0572
0419 LDY $09
041B LDA $04A0,Y
041E LDX $04A1,Y
0421 JSR $0500
0424 LDY $09
0426 INY
0427 INY
0428 INY
0429 BNE $040C |
Read more data, but this time the stepping comes from a table.
It's full tracks for the first eight, but then it reads from five consecutive half-tracks.
Finally, we get here:
This routine reads the high-scores, also 4-and-4 encoded, and then runs the game.
What to do about all of that?
Dernière édition par qkumba le Ven 06 Jan 2017, 18:26; édité 1 fois |
|
Revenir en haut de page |
|
 |
qkumba
Inscrit le: 29 Jan 2012 Messages: 171
|
Posté le: Ven 06 Jan 2017, 18:25 Sujet du message: |
|
|
We know that the game reads and writes to the disk, so we need to do the same.
The boot sector looks the same up to this point:
That goes here now:
Code: | 023A LDX #$16
023C STX $00
023E TXA
023F ASL
0240 BIT $00
0242 BEQ $025A
0244 ORA $00
0246 EOR #$FF
0248 AND #$7E
024A BCS $025A
024C LSR
024D BNE $024A
024F TYA
0250 STA $BF40,X
0253 TXA
0254 ORA #$80
0256 STA $BFC0,Y
0259 INY
025A INX
025B BPL $023C |
This routine generates 6-and-2 tables for both reading and writing at the same time.
Then we reach our 6-and-2 read routine, and let the boot continue like before.
For the routine that runs in zpage, we have to make some changes.
Code: | 00B8 LDA $C08C,X
00BB BPL $B8
00BD CMP #$D4
00BF BNE $C1
00C1 LDA $C08C,X
00C4 BPL $C1
00C6 CMP #$DB
00C8 BNE $CA
00CA LDA $C08C,X
00CD BPL $CA
00CF CMP #$AF
00D1 BNE $D3
00D3 LDA $C08C,X
00D6 BPL $D3
00D8 ROL
00D9 STA $3F
00DB LDA $C08C,X
00DE BPL $DB
00E0 AND $3F
00E2 JSR $025D
00E5 INC $27
00E7 INC $3D
00E9 DEC $40
00EB BNE $D3
00ED LDA $C08C,X
00F0 BPL $ED
00F2 CMP #$AE
00F4 BNE $F6
00F6 LDA $C08C,X
00F9 BPL $F6
00FB CMP #$EE
00FD BNE $FF
00FF RTS |
It looks very similar except that the prologue check doesn't branch on mismatch, and we've inserted a JSR at $E2 to read a regular sector.
Here are the only differences that we needed:
Code: | AE: A4->BE
B0: A5->BF
C0: 6E->99
C9: 6A->99
D2: 6A->99
E2: 08->B9
E3: A5->C4
E4: 51->9B
E5: 49->7F
E6: 75->BE
F5: 2A->99
FE: 33->99 |
Yes, we patch the new values directly into the encrypted data to avoid having to decode everything first.
Very surgical. :shock:
Code: | 0519 JSR $056C
051C CMP $01
051E BNE $0520
0520 JSR $056C
0523 CMP $02
0525 BNE $0527
0527 LDA $C08C,X
052A BPL $0527
052C ROL
052D STA $5F
052F LDA $C08C,X
0532 BPL $052F
0534 AND $5F
0536 STA ($5C),Y
0538 JSR $0621
053B ASL $C000
053E LDA $C08C,X
0541 BPL $053E
0543 CMP $03
0545 INC $5E
0547 INC $5D
0549 DEC $40
054B BNE $0527 |
We make similar changes to this routine. The prologue check doesn't branch on mismatch, and we've inserted a JSR at $538 to read a regular sector.
Code: | 9004 LDY #$00
9006 CLC
9007 BCS $9041 ;hides a SEC instruction to set carry for second pass
9009 LDA $9023
900C STA $901C,Y
900F INC $900A
9012 INY
9013 BCC $9008
9015 BMI $901B
9017 LDY #$80
9019 BCS $9009
901B STA $0000 ;self-modifying
901E CMP #$FF
9020 BNE $9004
9022 RTS
9023 .BYTE $4E, $00, $62
9026 .BYTE $4F, $00, $F8
9029 .BYTE $20, $00, $6C
902C .BYTE $21, $00, $4E
902F .BYTE $22, $00, $00
9032 .BYTE $3E, $00, $00
9035 .BYTE $3F, $00, $07
9038 .BYTE $3C, $00, $E8
903B .BYTE $3D, $00, $A8
903E .BYTE $28, $00, $40
9041 .BYTE $29, $00, $91
9044 .BYTE $90, $00, $D5
9047 .BYTE $91, $00, $FD
904A .BYTE $92, $00, $F5
904D .BYTE $93, $00, $D4
9050 .BYTE $16, $05, $90
9053 .BYTE $1D, $05, $91
9056 .BYTE $24, $05, $92
9059 .BYTE $44, $05, $93
905C .BYTE $5B, $05, $90
905F .BYTE $56, $05, $91
9062 .BYTE $51, $05, $92
9065 .BYTE $60, $05, $93
9068 .BYTE $65, $05, $90
906B .BYTE $23, $00, $A0
906E .BYTE $24, $00, $1D
9071 .BYTE $FF, $FF, $FF |
We replace the special sector routine with a load/store sequence that does the same thing.
We change the ROM check so that it exits immediately.
We change the stepping table so it reads from whole tracks.
Code: | 0311 LDA #$02
0313 STA $5D
0315 JSR $0621 |
Load the scores from a regular sector, and the game runs.
As for saving, we replace the existing write routine with the one from DOS.
We have the write table prepared from long ago, and there's a spare page of memory that we can use for encoding the data.
No problem. |
|
Revenir en haut de page |
|
 |
|
|
Vous ne pouvez pas poster de nouveaux sujets dans ce forum Vous ne pouvez pas répondre aux sujets dans ce forum Vous ne pouvez pas éditer vos messages dans ce forum Vous ne pouvez pas supprimer vos messages dans ce forum Vous ne pouvez pas voter dans les sondages de ce forum
|
|