sábado, 27 de agosto de 2022

Proteção contra acesso ao código-fonte BASIC

Os programas em BASIC das fitas numeradas da CCESOFT (F-18 a F-30) são autoexecutáveis (salvos sem nome) e trazem uma proteção para impedir que o usuário possa visualizar o código-fonte. Os programas começam com as instruções:

1  REM ~3E~C3~32~20~01~3E~E9~32~21~01~3E~03~32~22~01~3A~1B~01~FE~03~C0~3E~F4~32~21~01~3E~01~32~44~03~C9
2  CALL 986
...

(Nesta listagem, cada sequência hexadecimal ~XX corresponde a um byte/caracter.)

A rotina em código de máquina do Z80 codificada na linha REM é:

        ; Variáveis do sistema:
KEY0:   equ $011b ; Última tecla pressionada.
JOB:    equ $0120 ; Hook chamado durante a leitura do teclado.
OUTFLG: equ $0344 ; Desabilita impressão se diferente de zero.
 
        ; Programa começa no primeiro byte
        ; após o token da instrução REM da linha 1.
        org $03da ; =986.
init:
        ; Inicialmente JOB contém uma instrução RET.
        ; Coloca em JOB um JP para a rotina "checa".
        ld  a,$c3 ; Opcode de JP.
        ld  (JOB),a
        ld  a,$e9 ; LSB do endereço da rotina "checa".
        ld  (JOB+1),a
        ld  a,$03 ; MSB do endereço da rotina "checa".
        ld  (JOB+2),a
checa:
        ; Retorna se a última tecla pressionada
        ; não for <CTRL>+<C>.
        ld  a,(KEY0)
        cp  $03 ; <CTRL>+<C>
        ret nz
desvia:
        ; O usuário pressionou <CTRL>+<C>.
        ; Desvia JOB para a rotina "oculta".
        ld  a,$f4 ; LSB do endereço da rotina "oculta".
        ld  (JOB+1),a
oculta:
        ; Desabilita a impressão de caracteres.
        ld  a,$01
        ld  (OUTFLG),a
        ret

A parte inicial da rotina (init), chamada logo no início do programa em BASIC pelo CALL na linha 2, configura o hook JOB ($0120 / 288) (vide variáveis do sistema). A partir daí, continuamente, a cada leitura de teclado, é chamada a segunda parte da rotina (checa), que checa se o usuário pressionou <CTRL>+<C>. Se isso acontecer, a terceira parte (desvia) reconfigura JOB para chamar a parte final da rotina (oculta), de modo que, continuamente, a cada leitura de teclado, seja colocado o valor 1 na variável OUTFLG ($0344 / 836), o que desabilita a impressão de caracteres.

O efeito disso é que, depois que se interrompe o programa em BASIC com <CTRL>+<C>, não se veem na tela nem os caracteres sendo digitados, nem os resultados das instruções PRINT e LIST (o que é o objetivo da rotina). Veem-se apenas o "OK" que aparece ao final da execução das instruções e as mensagens de erro. No modo DEBUG, porém, tudo continua visível.

Como contornar

Simplesmente mudar o valor de OUTFLG para zero (POKE 836,0) não adianta, pois a rotina oculta que muda OUTFLAG para 1 está atrelada ao hook JOB e é chamada a cada leitura de teclado, frustrando essa tentativa.

A solução é primeiro desabilitar o hook JOB (colocando aí uma instrução RET do Z80) e, então, zerar OUTFLAG.

POKE 288,201: POKE 836,0

Ou, alternativamente, via DEBUG (onde se pode ver o que se está digitando):

DEBUG
>S120
0120 C3 C9
0121 F4 
>S344
0344 01 0
0345 FF
>Q

Depois disso podem-se apagar as linhas 1 e 2 do programa em BASIC para rodá-lo novamente sem reativar a proteção.

Nenhum comentário:

Postar um comentário

"MC-1000", "MC 1000" ou "MC1000"?

No gabinete do computador, nos acessórios e nos materiais impressos (caixa, capas dos manuais, rótulos e capas das fitas, propagandas etc.) ...