Modder recria ROM de jogo com sons de travamento do GBA
(arstechnica.com)- TheZZAZZGlitch mostrou que, ao gravar os sons de travamento do Game Boy Advance, é possível identificar os dados do jogo dentro do cartucho e, no fim, reconstruir a mesma ROM
- O ponto central é interpretar o áudio emitido após o travamento como dados da ROM, mas isso exige muitos ajustes conforme o formato da fonte, o que dificulta seu uso como ferramenta genérica de dump
- Em uma gravação de mais de 4 horas, uma forma de onda característica apareceu por volta da marca de 1h50, e depois disso os sons de instrumentos e samples de áudio do jogo passaram a ser ouvidos em sequência
- Com um script em Python e correção de alinhamento, ele chegou a 99,76% de precisão, mas a inicialização falhou; ao combinar 3 gravações com um algoritmo de maioria, o resultado subiu para 99,979%
- Após combinar 7 gravações e filtrar espaços vazios, ele alcançou 100% de correspondência, confirmando experimentalmente a possibilidade de reconstruir uma ROM de GBA apenas a partir dos sons de travamento
Experimento que leu dados da ROM a partir de sons de travamento
- TheZZAZZGlitch demonstrou que o som emitido pelo GBA após um crash de software pode conter dados do jogo
- Um GBA travado pode continuar emitindo som com base nos dados internos do cartucho e, com hardware e código especiais para analisar esse áudio, é possível identificar qual é o jogo
- Ainda assim, esse método não é uma forma simples de fazer dump dos dados do cartucho, nem uma solução pronta para uso
- É necessário bastante ajuste fino para diferentes formatos de origem
A forma de onda revelada em uma gravação longa
- Depois de causar um travamento no GBA, uma gravação de mais de 4 horas revelou uma forma de onda característica por volta de 1h50
- No trecho seguinte, os sons de instrumentos e samples de áudio reais incluídos no jogo podem ser ouvidos em ordem
- O restante dos dados soa como dados de 8 bits a 13.100Hz, e algumas partes soam bastante estranhas
Script em Python e a primeira tentativa de restauração
- TheZZAZZGlitch preparou um script em Python para ler uma gravação limpa de dump por crash do GBA, “depois de passar 2 dias corrigindo bugs”
- Os dados da ROM contêm grandes trechos de bytes 0, e essas partes aparecem como silêncio, o que dificulta o parsing no áudio
- Depois de executar um script separado para realinhar as seções com base em suas posições na ROM original, a ROM restaurada chegou a 99,76% de precisão
- Essa ROM ainda não dava boot, e como o processo usava dados conhecidos da ROM para revelar dados desconhecidos, isso tecnicamente contava como “trapaça”
- Mesmo em um processo totalmente cego, ainda restam hipóteses e estimativas que podem ser aplicadas
Aumentando a precisão com a combinação de várias gravações
- Na etapa seguinte, o foco foi melhorar a qualidade das gravações
- Ao combinar os resultados de 3 gravações com um algoritmo de “maioria”, a precisão subiu para 99,979%
- Essa ROM resultante conseguiu dar boot, mas o texto aparecia corrompido e ocorria um crash na tela de título
- Depois, ao combinar 7 gravações e filtrar os espaços vazios, foi alcançada uma correspondência de 100%
Hardware físico e experimentos adicionais
- Na parte final do vídeo, ele também verifica como esse método funciona em hardware físico
- O experimento foi repetido com outros jogos, enquanto também se investigava um mistério relacionado ao código ARM dentro de cartuchos clonados
- Também foram testadas formas de obter gravações melhores
- Uma delas foi o uso de um “cursed adapter” para fazer um mixdown grosseiro em um único canal
1 comentários
Opiniões no Hacker News
O problema quando há uma longa sequência de 0x00 tem a ver com recuperação de clock (clock recovery)
Alguns fluxos de dados digitais, especialmente dados brutos de cabeças magnéticas de drives de disco ou comunicações seriais de alta velocidade como Ethernet, são transmitidos sem um sinal de clock separado
O receptor cria um clock com base em uma referência aproximada de frequência e, com um loop de bloqueio de fase (PLL), ajusta a fase do clock às transições no fluxo de dados
Para que esse método funcione, as transições de dados precisam ocorrer com frequência suficiente para compensar o drift do oscilador do PLL, e a especificação de quanto tempo ele consegue aguentar sem transições é chamada de máximo de dígitos idênticos consecutivos (CID)
https://en.wikipedia.org/wiki/Clock_recovery
Depois, passou-se para métodos como 64/66b, que anexam um cabeçalho curto a grandes blocos de bits para garantir transições de clock e passam tudo por um scrambler pseudoaleatório
Mesmo que o clock esteja perfeitamente sincronizado, em trechos longos um sinal quase todo 1 e um sinal quase todo 0 acabam ficando iguais
O áudio é analógico e, para decodificá-lo como bitstream, seria necessário um DAC; ele é transmitido em uma frequência fixa, como 44,1 kHz ou 48 kHz, sem sincronização especial
https://en.wikipedia.org/wiki/Wireless_Set_Number_10
Isso me lembrou o hack original do iPodLinux, que há quase 20 anos fez o dump do firmware do iPod de 4ª geração pelo alto-falante piezoelétrico
https://web.archive.org/web/20140810083116/http://www.newscientist.com/article/dn7085
Por coincidência, graças a isso também dava para rodar jogos de GBA no iPod, mas jogar Doom com a click wheel e assistir a vídeos em preto e branco já era satisfatório o bastante
Ainda tenho um iPod Classic e, depois de atualizar a bateria, coloquei nele 4 cartões MicroSD de 256 GB
Recentemente também vi uma modificação que adiciona Bluetooth, mas como exige trocar a carcaça traseira, acho que não vou chegar a esse ponto
Há algo atemporal tanto no design quanto no fato de possuir diretamente cópias dos arquivos de música
Fico feliz que isso esteja recebendo mais atenção aqui
Foi postado alguns dias atrás, mas passou despercebido: https://news.ycombinator.com/item?id=39037104
O vídeo original tem muito conteúdo que não aparece neste texto curto, incluindo um adaptador personalizado que o hacker fez na base do corta-e-cola para obter qualidade de áudio adequada no DS
https://www.youtube.com/watch?v=0-7PSmYYHF0
Zzazz realiza todo ano uma competição/evento de Primeiro de Abril, geralmente envolvendo algum grau de hacking retrô ou engenharia reversa
Recomendo participar
As competições anteriores estão no GitHub
A arquitetura de áudio da Nintendo sempre foi interessante
O NES original tinha um gerador de samples capaz de produzir formas de onda arbitrárias, e ele podia ser acionado de duas maneiras
Uma era fornecer um endereço de memória, ler os bits e processá-los como uma forma de onda muito simples: 1 significava “aumentar o valor em um”, 0 significava “diminuir o valor em um”, então, para criar uma forma de onda plana, era preciso repetir algo como 10101010
A outra era a CPU inserir continuamente um “valor inicial” diretamente, acionando o chip de forma direta; na prática, isso era mais rápido do que um driver de áudio ler bits da RAM
O problema é que esse método consumia todos os ciclos da CPU, então só podia ser usado quando nada mais estava acontecendo
Jogos como Battletoads aproveitaram isso para tocar batidas de bateria com qualidade mais alta enquanto a ação estava parada, na tela de título, no efeito “crocante” em que toda a ação para por um instante ao dar o golpe final em um inimigo, e na memorável música de pausa
Há aqui uma demo em que o jogo alterna entre o modo de acionamento direto e o modo em que o chip lê samples. Retro Game Audio publicou um vídeo modificado em emulador mostrando o momento em que entra na sub-rotina de acionamento direto: https://www.youtube.com/watch?v=JGT0FM3yh-w
Fico curioso sobre por que isso acontece em primeiro lugar
É comum esses jogos despejarem o estado como áudio? É uma ferramenta de depuração intencional para desenvolvedores de jogos?
Basicamente, o som do GBA transmite áudio a partir de um buffer na RAM, e uma interrupção precisa avisar ao hardware para voltar a ler desde o início do buffer
Mas, se a interrupção não acontece, como quando o jogo trava, o fluxo de áudio passa do buffer e começa a ler outras áreas da memória
[1] https://www.youtube.com/watch?v=wSWNkpqjtQY&t=361s
Em teoria, o GBA poderia ter “parado” a arquitetura quando o jogo travasse, ou ter um watchdog que vinculasse a atualização de estado que precisa ser executada periodicamente a uma interrupção não mascarável e reinicializasse quando essa atualização parasse
Mas esse tipo de recurso custaria mais, então não existe no GBA
A Nintendo acabou adotando a abordagem tradicional dos antigos fabricantes de cartuchos de jogos: “se nosso jogo não tiver bugs, não precisamos nos preocupar com o comportamento de estados de hardware indefinidos”
Então, quando um jogo de GBA entra em um estado de travamento, como um loop infinito com interrupções desativadas, o chip de áudio não sabe que o sistema travou e continua fazendo a tarefa simples de ler bits consecutivos da RAM e transformá-los em som
Como a rotina de limpeza que gerenciava as leituras durante o funcionamento normal desaparece, ele continua lendo até finalmente chegar a bits que representam valores da ROM do cartucho
É absurdamente impressionante
Técnicas como o algoritmo de votação por maioria usado aqui provavelmente são subutilizadas em várias indústrias
Mídias de armazenamento magnético funcionam basicamente pelo mesmo princípio desse hack
https://en.wikipedia.org/wiki/Partial-response_maximum-likelihood
A mesma ideia poderia ser aplicada aqui, já que o conteúdo da ROM do GBA deve ter um viés forte
A votação por maioria desperdiça muita informação
Basta sobrepor todas as fotos e manter apenas a mediana de cada pixel[1]
[1]: https://patdavid.net/2013/05/noise-removal-in-photos-with-median_6/
Você fica lendo a imagem do disco e aplicando uma decisão por quórum até obter um resultado que passe no checksum, aí verifica se funciona corretamente
Se houver checksums de nível mais alto, como assinaturas de arquivo, isso ajuda na validação adicional
Também é usado em algumas aplicações aeroespaciais
Como eles lidam não com um master pristine, mas com cópias de exibição em cinema que podem estar danificadas, se fosse possível usar várias cópias para remover riscos e coisas do tipo, isso poderia reduzir enormemente o tempo de retoques manuais na pós-produção
A transformação de 0xFF em 0x00 pode ser causada por um capacitor de bloqueio de corrente contínua ou por filtragem passa-altas
Circuitos de áudio não são muito adequados para conteúdo inaudível
Com sorte, conectar um osciloscópio digital diretamente à saída de áudio do chip poderia melhorar a precisão da captura, mas ainda assim conseguir uma imagem inicializável é bem impressionante
Por isso eles passaram horas fazendo capturas repetidas e calculando a média dos erros, em vez de usar um osciloscópio de registro de dados adequado
Até algo simples como codificação Manchester já ajudaria bastante
Se isso não bastar, também dá para usar NRZ ou até codificação convolucional
Além disso, seria preciso enviar uma senoide ou, se isso não for possível, pelo menos elevar bastante a frequência da onda quadrada para que ela não seja eliminada pelo capacitor de acoplamento AC
A parte mais impressionante disso tudo, para mim, é a forma como os piratas modificaram o código para executar o jogo a partir de uma memória flash gravável em vez de ROM + memória volátil de armazenamento
Na verdade, criar esses patches também não é tão difícil
Os piratas fazem um pouco de engenharia reversa para descobrir onde o código do jogo salva os dados e criam patches específicos por jogo para gravar o conteúdo salvo na flash gravável
Porém, como os jogos oficiais de GBA sempre usam funções do Nintendo SDK para salvar, basta fazer hook dessas funções para que um patch universal que permita salvar qualquer jogo de GBA em cartuchos piratas sem bateria fique bem simples
Escrevi um patcher que faz isso, e ele pode ser visto aqui
https://github.com/metroid-maniac/gba-auto-batteryless-patcher
Alguém sabe o que acontece internamente quando o emulador do TheZZAZZGlitch informa que o jogo está tentando saltar para um endereço inválido?
Não estou familiarizado com o processador ARM7 usado no GameBoy Advance, mas tenho dificuldade de imaginar como é possível construir uma chamada de salto com um valor inválido
Também fico curioso sobre o que aconteceria se uma das ROMs restauradas incorretamente pelo TheZZAZZGlitch fosse executada em um GameBoy real
bxpermite saltar para um endereço arbitrário armazenado em um registradorE, se você executar uma ROM restaurada incorretamente em um GameBoy real, ela vai travar e, por fim, começar a tocar a ROM pelo alto-falante
Esse é o ponto central do vídeo :)
No hardware real, o que aconteceria… quem sabe :)