Depois de destrinchar o Speedlock 1 com o Highway Encounter, eu vou comentar sobre Speedlock 2 com o jogo do mesmo autor (Costa Panayi), o Revolution.
Block 1: header
Saved name: "REV "
Type: BASIC program
Auto-start line: 0
Program size without variables: 186
Total length: 205
Block 2: data bytes
Length: 205
Block 3: header
Saved name: "revolution"
Type: BASIC program
Auto-start line: 0
Program size without variables: 1351
Total length: 1770
Block 4: data bytes
Length: 1770
Block 5: group start
Group name: SpeedLock 2 Block 1
Block 6: pure tone, 2174 pulses of 18 T-state period
Block 7: pulse sequences, 715 T, 715 T
Block 8: pure tone, 2174 pulses of 18 T-state period
Block 9: pulse sequences, 715 T, 715 T
Block 10: pure tone, 2174 pulses of 18 T-state period
Existem dois programas BASIC, ambos com listagens desprotegidas que podem ser examinadas com Basic Lister. A listagem do primeiro programa ("REV") é:
0 PAPER 0: INK 0: BORDER 0: CLS : PRINT USR 23829 : LOAD ""
Eu não vou mostrar o disassembly a partir de 23829 por não ser importante por ora, mas a rotina copia RAM de 23832-23936 para 65432-0.
O segundo programa BASIC ("revolution") é igual ao do Speedlock 1, com a linha mais importante sendo:
0 POKE (PEEK 23613+256*PEEK 23614),PEEK 23627: POKE (PEEK 23613+256*PEEK 23614)+1,PEEK 23628
que irá desviar a execução para o endereço 25244.
O disassembly mostra algumas instruções que servem para confundir a leitura, mas finalmente encontra-se um decodificador, semelhante ao Speedlock 1:
25260 LD A,R
25262 XOR (HL)
25263 LD (HL),A
25264 LDI
25266 RET PO
25267 DEC SP
25268 DEC SP
25269 RET PE
o loop situa-se entre 25620-25269 e sai por 64015.
Prosseguindo a análise do programa a partir de 64015, encontra-se o mesmo decodificador que o acima, entre 64051-64060, que sai por 60461.
Depois de 60461, há um outro decodificador entre 64070-64096.
Finalmente chega-se à parte que carrega os dados da fita:
64689 LD IX,40960 ;Carrega header em 40960.
LD DE,17
CALL 64561
64699 LD IX,16384
LD DE,6911
LD HL,64420
LD (64418),HL
64712 CALL 64179 ;Carrega todo bloco Speedlock.
Apesar do IX=16384 e DE=6911 dar impressão de carregar apenas uma tela, na realidade a sub-rotina em 64179 carrega todos os dados do Speedlock. Depois do carregamento, uma parte da RAM é apagada e finalmente, entra-se na execução do jogo:
64736 LD IY,23610
IM 1
LD HL,10072
EXX
LD SP,24831
64746 JP 34714 ;Entrada para o jogo.
Interessante ver que IY, HL' e o modo de interrupção são restaurados para valores padrões do BASIC. O registrador SP assume valor 24831.
Portanto se pode concluir que Speedlock 1 e 2 são bem parecidos, mas a rotina de carregamento propriamente dito diferem. Do ponto de vista de hacking essa diferença importa pouco, pois em ambos os casos basta usar o debugger do emulador.
Registrador R
Como ocorre com Speedlock 1, o registrador R tem que estar com o bit 7 igual 1. No World of Spectrum consta como um bug, mas na realidade seria uma forma de proteção.
Adaptação para Beta 48
A princípio, poder-se-ia pensar em salvar toda a RAM no disquete, mas isso não é necessário. Uma análise do início do jogo mostra que boa parte da memória não precisa ser salva, pois é apagada:
34714 DI ;Zera RAM 16384-23295.
LD HL,23295
LD DE,23294
LD (HL),0
LD BC,6911
LDDR
CALL 48020 ;Zera RAM 52480-58623.
CALL 48006 ;Zera RAM 59392-65535.
LD A,67
CALL 47998 ;Preenche RAM 58624-59391 com byte 67.
Portanto, basta salvar a tela (16384-23295) e o bloco de bytes em 23296-52479. O bloco de bytes pode ser tranquilamente salvo numa região que não se sobreponha à região do BASIC, para depois ser relocado com um pequeno programa em código de máquina. Este programa deve ainda levantar o bit 7 do registrador R, ajustar valor de SP e executar o jogo.
O Revolution adaptado, com documentação sobre o procedimento, pode ser baixado em um dos links: Google Drive ou 4 Shared.
Atualização em 14/11/2012: nova versão disponível.
Nenhum comentário:
Postar um comentário
Seu comentário é bem vindo, mas peço que use este espaço adequadamente.