BadUStudio: “Bad Apple!!” embarcada para o Ulanzi D200 U-Studio
Esse macro pad de streaming é vendido por uma fração do preço do Stream Deck da Elgato. Mas há algo incomum nele: o dispositivo vem de fábrica com acesso root totalmente aberto.
No último dia 11, o Lucas Teske postou no Twitter sobre o Ulanzi D200 U-Studio, um dispositivo vendido como “mesa controladora de streaming” ou macro pad similar ao Stream Deck da Elgato—mas disponível a um preço bem menor.
O Teske destacou que o aparelho disponibiliza uma shell root através do adb, sem necessidade de qualquer tipo de autenticação ou modificação do dispositivo. Basta plugar o cabo USB, executar o adb e pronto.
Intrigado, adquiri uma unidade. Ela foi entregue em mais ou menos uma semana e, de fato, também veio com o acesso via adb completamente aberto. Dei, então, início à minha própria jornada com o aparelho.
Explorando o dispositivo
Uma vez conectado à shell, comecei a executar alguns comandos para saber mais sobre o dispositivo.
Primeiramente, reparei no SoC utilizado: o Rockchip RK3308HS—que já aparecia nas imagens publicadas pelo Teske.
root@rk3308hs-buildroot:/# cat /proc/device-tree/model
Rockchip RK3308HS Voice Module Board V10 (AArch32)Uma busca na internet revela que o RK3308 é projetado especificamente para dispositivos de assistente de voz, similares aos Echo (Alexa) da Amazon. Escolha peculiar para um aparelho que sequer conta com autofalantes.
A CPU conta com quatro núcleos de até 1,3 GHz. De acordo com a documentação disponível, é de 64-bits; mas, por motivos misteriosos, o sistema embarcado no D200 roda em 32-bits.
root@rk3308hs-buildroot:/# cat /proc/cpuinfo
processor : 0
model name : ARMv7 Processor rev 2 (v7l)
Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
[...mais 3 núcleos...]
Hardware : Generic DT based systemO sistema operacional é Linux baseado no Buildroot. Entretanto, o próprio uso do adb e as mensagens que aparecem no dmesg são evidências de kernel Android. É provável que a fabricante tenha desenvolvido a partir de um BSP disponibilizado pela Rockchip, mantendo o kernel mas customizando o userspace.
[ 0.000000] Kernel command line: coherent_pool=4k user_debug=31 storagemedia=nand androidboot.storagemedia=nand androidboot.mode=normal androidboot.serialno=01C16A015B3401745 rootwait earlycon=uart8250,mmio32,0xff0c0000 console=ttyFIQ0 root=PARTUUID=614e0000-0000 rootfstype=ext2 snd_aloop.index=7
[...]
[ 10.824043] dwc2 ff400000.usb: bound driver configfs-gadget
[ 11.010489] dwc2 ff400000.usb: new address 1
[ 11.023028] android_work: sent uevent USB_STATE=CONNECTED
[ 11.184199] android_work: sent uevent USB_STATE=DISCONNECTED
[ 11.260851] dwc2 ff400000.usb: new address 1
[ 11.273068] android_work: sent uevent USB_STATE=CONNECTED
[ 11.279736] android_work: sent uevent USB_STATE=CONFIGUREDE por que “Bad Apple!!”?
Faz mais de uma década que existe o meme de colocar “Bad Apple!!” nos mais variados meios e dispositivos. Basta uma breve pesquisa para encontrar exemplos que vão desde a reprodução da animação na clássica calculadora TI-84+ SE até stop motion em uma maçã real.
Mas a escolha vem também do meu sentimento pessoal em relação à música e ao vídeo: além de ambos serem obviamente excelentes, sempre achei marcantes as circunstâncias relacionadas à criação e à popularização da obra.
Muitos não sabem, mas a “Bad Apple!!” original é uma música de Touhou 4 Lotus Land Story, lançado no ano de 1998. O ZUN, criador da franquia, é conhecido por ter desenvolvido os primeiros jogos por conta própria, realizando desde a composição das músicas até o desenho dos sprites e a programação em si.
Não bastasse a realização técnica, ZUN sempre apoiou a criação, por terceiros, de trabalhos derivados de Touhou, com pouquíssimas restrições que dizem respeito principalmente à atribuição e à comercialização.
Foi essa abertura que permitiu que a Alstroemeria Records lançasse em 2007 a versão remixada com letras e vocais que viria a superar a original em popularidade. Já em 2009, o usuário Anira (あにら) do antigo NicoNicoDouga, site japonês de vídeos, fez upload do vídeo da animação de sombras que viralizou.
A “Bad Apple!!” como é hoje conhecida não existiria sem a decisão do ZUN de permitir abertamente a criação de variantes de seu trabalho, e tampouco sem a vontade e a dedicação da comunidade para construir sobre a obra de ZUN—tudo coordenado e divulgado principalmente através da internet.
Nesse sentido, vejo em “Bad Apple!!” uma representação dos valores daquilo que se conhece como cultura hacker, em especial o impulso de criar e de compartilhar, bem como de customizar e de redistribuir. Trazê-la a um dispositivo que não deveria ser capaz de reproduzí-la é, mais do que uma excelente maneira de demonstrar a execução de código arbitrário, um ato simbólico, tal qual fincar uma bandeira de liberdade.
Player de vídeo
Para levar “Bad Apple!!” ao D200, escrevi um player de vídeo simples: o BadUStudio, cujo código-fonte encontra-se disponível no GitHub.
O desenvolvimento passou por várias iterações. Na primeira prova de conceito, pensei em uma abordagem ingênua envolvendo ter cada frame codificado em JPEG sendo decodificado e enviado ao framebuffer do dispositivo. Logo encontrei na capacidade de armazenamento do D200 o primeiro desafio.
Filesystem Size Used Avail Use% Mounted on
/dev/root 95M 93M 0 100% /
devtmpfs 59M 0 59M 0% /dev
tmpfs 59M 2.2M 57M 4% /tmp
tmpfs 59M 76K 59M 1% /run
tmpfs 59M 56K 59M 1% /var/log
tmpfs 59M 0 59M 0% /dev/shm
/dev/rkflash0p7 27M 347K 25M 2% /oem
/dev/rkflash0p8 52M 6.0M 43M 13% /userdataIdentifiquei a /userdata como melhor candidata para armazenar o player e a animação; afinal, ela parece existir especificamente para guardar de forma persistente dados do usuário. Nessa partição, há aproximadamente 43 MB disponíveis.
Na listagem, percebe-se também que há alguns diretórios montados na RAM. Preferi não utilizá-los, uma vez que eu queria manter a demo no aparelho ao invés de ter que enviá-la novamente a cada uso.
A princípio, consegui ótimos tamanhos para os frames recorrendo a PNGs com 1 bit de profundidade de cor por pixel. Daí vieram os problemas com decodificação e renderização: uma das primeiras versões do BadUStudio rodava a apenas 8 FPS. Mas, mesmo com a baixa frame rate, decidi postar um vídeo de demonstração preliminar no meu Instagram (a seguir).
Depois, continuei iterando o código existente para melhorar diversos aspectos. Após otimizar as escritas no framebuffer e migrar para um formato de dados brutos, consegui melhorar significativamente a performance.
Surgiu, então, outro problema: quedas ocasionais da frame rate que, embora visualmente muito discretas, faziam com que a animação exibida no aparelho deixasse de seguir o timing esperado, ficando desincronizada da música e do vídeo de referência sobreposto na pós-edição.
Resolvi primeiro o problema da desincronização implementando um mecanismo para que o player não tentasse renderizar todos os frames, mas sim adotasse frame drops ocasionais ao identificar que a exibição estava desviando do timing esperado.
Depois, continuei investigando o que estava causando as reduções esporádicas da frame rate. Descobri que o carregamento dos frames para o buffer não estava acontecendo realmente em paralelo com a execução do vídeo. O código acabava pausando para aguardar a conclusão das operações de leitura—pausas essas que deveriam estar sendo utilizadas para renderizar os frames.
Resolvidas essas e outras questões, e após realizar alguns testes, decidi concluir com o armazenamento de cada frame no formato de dados brutos, com compressão RLE, em 360x640—metade da resolução nativa da tela do aparelho, de 720x1280—e upscaling realizado em tempo de execução. Dessa forma, consegui um resultado equilibrado entre tamanho de armazenamento necessário e performance da exibição.
No final, o BadUStudio (player) compilado ficou com aproximadamente 2 MB, enquanto a combinação dos dados de todos os frames ficou por volta de 25 MB.
O executável provavelmente poderia ser reduzido. Daria pra evitar a compilação estática e remover a decodificação de PNG, que não está mais sendo usada mas deixei implementada para comparação de performance. Mas realmente não tentei buscar essa redução; pessoalmente, estou satisfeito com o tamanho atual.
Uma nota sobre segurança
O nome “BadUStudio” é um triplo jogo de palavras: a combinação de “Bad Apple!!” com “UStudio” é óbvia, mas o nome é também uma referência sutil a “BadUSB”.
A funcionalidade pretendida do D200 inclui atuar como um dispositivo de interface humana (USB HID). Em muitos casos, ele atua como teclado para realizar ações que incluem digitar textos ou comandos na caixa “Executar” do Windows.
Naturalmente, como macro pad, essa funcionalidade é intencional. Mas, combinada com a segurança frágil do dispositivo, torna-se uma bomba-relógio.
Não observei pessoalmente nenhum comportamento suspeito do dispositivo desde que o recebi. Mas a questão é a seguinte: também não fiz uma auditoria profunda do firmware, e mesmo que a fabricante não possua qualquer intenção maliciosa, a completa ausência de qualquer proteção no dispositivo traz implicações sinistras.
O D200 é um alvo extremamente fácil para modificação maliciosa por qualquer um que obtenha acesso físico ao dispositivo durante alguns segundos. Ou seja: pessoas em qualquer ponto da cadeia de logística e distribuição, incluindo funcionários de lojas revendedoras (autorizadas ou não), bem como qualquer amigo para quem você o empreste, a sua empregada doméstica, a sua namorada e até o seu cachorro.
Não seria inteligente deixá-lo nas mãos de qualquer outra pessoa, e tampouco levá-lo a espaços como ambientes de coworking, estúdios de gravação e quartos de hotel.
Mesmo sem o acesso físico, há o risco de que ele funcione como vetor de propagação de malware—caso você venha a ligá-lo em uma máquina infectada e, posteriormente, em uma limpa—ou mesmo de persistência—caso a sua máquina venha a ser comprometida, o atacante comprometa o D200 através dela, você a formate e volte a ligar nela o D200, que permanece infectado.
Pra mim, a possibilidade de modificação do D200 é um grande diferencial em relação aos demais dispositivos desse tipo disponíveis no mercado. Porém, é alarmante que a abertura do aparelho não envolva em qualquer momento intencionalidade por parte do usuário.
No formato atual, com o dispositivo aberto de fábrica, a esmagadora maioria dos usuários não tem qualquer conhecimento do risco a que se expõe. A maneira correta seria enviar o dispositivo em um estado razoavelmente seguro, mas possibilitando o desbloqueio de maneira intencional, de forma que deixasse claro para o usuário que ele está realizando a escolha por um modo menos seguro—tal como costuma ser, por exemplo, quando ativamos o modo de desenvolvimento em dispositivos Android, ou o desbloqueio de bootloader em smartphones das fabricantes que ainda o permitem.
Pra finalizar
O BadUStudio foi um projeto bem divertido, e me deixou pensando no quanto faz falta ter mais aparelhos hackáveis no mercado. Hackeáveis não por acidente, mas sim por princípio; com opção para que o usuário possa tomar a decisão informada de habilitar um “modo de desenvolvimento” que retira as proteções existentes.
Fica a esperança de que a Ulanzi, nesse e em seus futuros dispositivos, mantenha a possibilidade de modificação mas implemente algum tipo de mecanismo seguro de desbloqueio. O potencial está lá.



