01
 ░██▀█████    ░██▀████     ░▀███████     ░██▌  ░██     ░█▀████     ██   ░▀▀██████
  ░░░██       ░██░░░░█▌    ░██░░░░██     ░███ ░███    ░██░░░░██   ░██   ░██░░░░██
    ░██       ░██   ░█▌    ░██   ░██     ░██ ██░██    ░██   ░██   ░▓█   ░██   ░██
    ░██       ░██████▀     ░████████     ░██ 01░█▀    ░██   ░██   ░█▀   ░██████▀█
    ░█·       ░██   ▀█     ░▓█   ░██     ░▓█   ░██    ░▓█   ░██   ░█▓   ░▓█   ░██
    ░██       ░██   ░█     ░█▓   ░█▓     ░▒    ░█▓    ░░▓   ░▒▓   ░█▓   ░█▓   ░█▓
    ░▓▓       ░▓▓   ░▓▌    ░▓▓   ░▓▒     ░▓▒   ░▓▒    ░▒░   ░▓░   ░▒▒   ░▓▓   ░▓▒
    ░▒▓       ░▓    ░▓▌    ░▓▒   ░▓▓     ░░▒   ░░▓     ░▒████░    ░▓░   ░▓▒   ░░▓
    ░▓░       ░▒░   ░░▌    ░▒░                 ░▓▒                ░░▒   ░▒░   ░▓█
    ░▒▓       ░░▒          ░▒                  ░▒▓                ░▒░   ░▒·   ░▓▒
    ░▒·       ░▒           ░▒                  ░▓                 ░▒░   ░▒▓   ░░▓
    ░▒▒                                        ░▒░                  ░         ░▒·
    ░░░                                          ░                            ░░▒
    ·░░                                                                       ░░░
    ░░░  Anya Lain apresenta                                                  ░░░
    ░░░                                                                       ░░░
    ░░░  |\___/|                                                              ░░░
    ░░░  | 0.0 |                                                              ·░░
    ░░░  | ()()|                                                              ·░░
    ░░░  |      \                                                             ░░░
    ░░░  |       \                                                            ░░░
    ░░░  ---------=======                                                     ░░░
    ░░░                                                                       ░░░
    ░░░  Um hacking inacabado de verão                                        ·░░
    ░░░                                                                       ░░░
    ░░░  Ou - como tentei rootear um Chromecast                               ░░░
    ·░░                                                                       ░░░
    ·░░  Versão Brasileira, Anya Lain                                         ░░░
    ·░░                                                                       ░░░
    ░░░  ------------------------------------------------------------         ·░░
    ░░░  Aparelhos espiões de big techs são coisas muito divertidas. O        ·░░
    ░░░  trade-off para o roubo de dados e rombo na segurança de rede é       ░░░
    ·░░  conseguir automatizar sua casa.                                      ░░░
    ·░░                                                                       ░░░
    ░░░  OK Google, Alexa, me faz um sanduíche. Esse é o futuro e ele já      ░░░
    ░░░  começou.                                                             ░░░
    ░░░                                                                       ░░░
    ·░░  Quando o frenezi dos dispositivos espiões a.k.a. home assistants     ░░░
    ░░░  começou, eu logo comprei um Google Home Mini do MercadoLivre. O      ░░░
    ░░░  aparelho tinha sido importado (talvez ilegalmente? but who cares), o ░░░
    ░░░  firmware dele não suportava português, mas ainda assim era algo bem  ░░░
    ░░░  divertido de se ter em casa, especialmente quando eu pedia para ele  ░░░
    ░░░  expulsar as pessoas da minha casa tocando Nickelback.                ░░░
    ░░░                                                                       ░░░
    ·░░  Eu estava me divertindo com meu aparelho espião da Google quando,    ·░░
    ·░░  num belo dia, o aparelho ficou o dia todo com quatro luzes acessas e ·░░
    ░░░  estáticas e não me respondia mais. Depois de tentar toda forma de    ░░░
    ·░░  reset, o aparelho continuou não dando sinal de vida. Ele estava      ░░░
    ░░░  morto, graças à uma atualização OTA (Over the Air) da Google [1].    ░░░
    ░░░                                                                       ·░░
    ░░░  O aparelho não tinha sido lançado oficialmente no Brasil, a Google   ·░░
    ░░░  se comprometeu a substituir os aparelhos com brick desde que estejam ░░░
    ░░░  nos países em que o aparelho foi oficialmente lançado e, semanas     ░░░
    ░░░  depois, eles lançaram o Nest Mini no Brasil (um aparelho             ░░░
    ░░░  extremamente similar ao Google Home Mini).                           ░░░
    ░░░                                                                       ░░░
    ·░░  O que fazer com esse peso de papel? Por que não entender o porquê    ░░░
    ░░░  dele ter brickado? A partir desse momento, entrei numa rabbit hole   ░░░
    ░░░  de hardware hacking e raw bytes. Muitos raw bytes.                   ·░░
    ░░░                                                                       ░░░
    ░░░  ------------------------------------------------------------         ·░░
    ░░░                                                                       ·░░
    ░░░  Eu assumi que o Google Home rodasse algum tipo de Android ou Chrome  ░░░
    ·░░  OS pois, afinal, é um dispositivo da Google. Tentei buscar alguns    ░░░
    ░░░  sources e até encontrei alguns no Google Code [2], mas eles já       ░░░
    ░░░  tinham sumido há muito tempo. Durante um bom tempo não sabia muito o ░░░
    ░░░  que fazer, até que de repente me deparei com um artigo de abzman2k   ░░░
    ░░░  chamado "Google Home Autopsy". [3] Uau!                              ░░░
    ░░░                                                                       ░░░
    ░░░  No artigo, abzman2k também tem o seu Google Home (primeira geração)  ░░░
    ░░░  brickado, então ele descobre dois test points de UART! Conectando    ░░░
    ·░░  num FTDI da vida e usando um screen ou picocom, ele obteve os logs   ░░░
    ·░░  do Google Home brickado dele e publicou eles no blog [3]. Buscando   ░░░
    ·░░  algumas coisas dos logs no Google eu também encontrei o código do    ░░░
    ░░░  bootloader num Pastebin [4].                                         ░░░
    ░░░                                                                       ░░░
    ░░░  > O que são test points afinal?                                      ░░░
    ░░░  >> Test points, ou test pads, são pequenos círculos que existem nas  ░░░
    ·░░  >> placas de circuito que permitem que                               ░░░
    ░░░  >> sinais sejam injetados para teste desses aparelhos, geralmente na ·░░
    ░░░  >> fábrica.                                                          ░░░
    ░░░  >> Normalmente esses test points não devem existir em dispositivos   ░░░
    ░░░  >> de produção, ou talvez existam somente para                       ░░░
    ░░░  >> QA.                                                               ░░░
    ░░░                                                                       ·░░
    ░░░  Vendo teardowns do Google Home Mini e do Chromecast, descobrimos que ░░░
    ░░░  os dois tem o mesmo processador ARMADA 1500 Mini Plus da Marvell.    ░░░
    ░░░  Isso significa que podemos pwnar qualquer device da família Google   ·░░
    ░░░  Home/Chromecast. Temos um teardown do Google Home Mini em [5] e um   ░░░
    ░░░  do Chromecast 2 e Chromecast Audio em [6]. Eu não achei test pads no ░░░
    ░░░  Google Home Mini, então meu próximo device tinha que ser o Chromecast░░░
    ·░░                                                                       ░░░
    ░░░  2.                                                                   ░░░
    ░░░                                                                       ░░░
    ░░░  Eu arrebentei o Chromecast 2 inteiro para descobrir que não, ele não ░░░
    ░░░  tem também os test pads. Porém, olhando no iFixit, o Chromecast      ░░░
    ░░░  Audio tinha algo muito interessante: dois test pads, bem próximos ao ░░░
    ░░░  processador! Fui no MercadoLivre de novo e achei o último Chromecast ░░░
    ░░░  Audio já vendido (provavelmente). Comprei, arrebentei ele todinho,   ░░░
    ░░░  achei os pads e soldei dois fios da forma mais porca possível.       ·░░
    ·░░  Comprei um CP2102 e                                                  ░░░
    ░░░                                                                       ░░░
    ░░░  ep3tsa01rp>sys_init start. boot_strap=0x000005c7 (source=NAND),      ░░░
    ░░░  boot_state=0x0                                                       ░░░
    ░░░                                                                       ░░░
    ░░░  ------------------------------------------------------------         ░░░
    ░░░                                                                       ░░░
    ░░░  Okay, o source do Pastebin [4] parece shady, mas ele na verdade foi  ░░░
    ░░░  disponibilizado em diversos lugares de forma completamente legal.    ░░░
    ░░░  Vamos para nossa estratégia clean room aqui [7].                     ░░░
    ·░░                                                                       ░░░
    ░░░  Na página de open source do Chromecast [8], há um link que leva para ░░░
    ░░░  um Google Drive. Nesse drive, temos até a versão 1.56 do source do   ░░░
    ░░░  kernel, da SDK e do bootloader. Para obter esses arquivos, é só ir   ░░░
    ░░░  em:                                                                  ░░░
    ░░░                                                                       ░░░
    ·░░  Chromecast Opensource Code > 1.56 > Kernel Bootloader SDK            ·░░
    ░░░  partner%2F1.56_sdk%2Fcombined-sdk-kernel-bootloader%2F253616%2Foss%2F·░░
    ·░░  chromecast_sdk_oss.tgz                                               ░░░
    ░░░                                                                       ·░░
    ░░░  (bootloader e kernel estão aqui)                                     ░░░
    ·░░                                                                       ·░░
    ░░░  Chromecast Opensource Code > 1.56 > Google Home Mini                 ·░░
    ░░░  internal%2F1.56%2Fmushroom-user%2F259165%2Fchromecast_oss.tgz        ░░░
    ░░░                                                                       ░░░
    ·░░  (Chromium e arm toolchain estão aqui)                                ░░░
    ░░░                                                                       ░░░
    ░░░  Depois de um tempo, eu descobri também que o source do Nest/         ░░░
    ·░░  Chromecast/Google Home é disponibilizado em [9] e que alguém         ░░░
    ░░░  esqueceu que arquivos do Git são para sempre [10].                   ·░░
    ·░░                                                                       ░░░
    ░░░  Uma coisa legal desse source é que eu descobri que é possível bootar ░░░
    ░░░  uma imagem do USB nos aparelhos. Antes de descobrir o lance do test  ·░░
    ·░░  pad, eu tentei cegamente descobrir em quais USB reads do código ele  ░░░
    ·░░  parava usando o LED de um pendrive como side channel. [11]           ░░░
    ░░░                                                                       ░░░
    ·░░  ------------------------------------------------------------         ░░░
    ░░░                                                                       ·░░
    ░░░  Vamos dar uma breve olhadela no source code do bootloader do Google  ·░░
    ░░░  Home aqui. [11]                                                      ░░░
    ░░░                                                                       ░░░
    ·░░  O nosso entrypoint é a função Image_Load_And_Start. Ela primeiro     ░░░
    ░░░  verifica se o modo de boot foi USB ou recovery. Se não for nenhum    ░░░
    ░░░  desses (o usuário não apertou e segurou o botão de reset do          ░░░
    ░░░  aparelho), é feito o boot pela NAND.                                 ░░░
    ░░░                                                                       ░░░
    ░░░  Eu não ligo pra boot pela NAND aqui, vamos de USB. A função          ░░░
    ·░░  load_android_image então é chamada. Nessa função, seguindo as macros ·░░
    ░░░  de USB, temos o scan e o load do dispositivo USB, que pode ser um    ·░░
    ·░░  pendrive conectado via OTG (um OTG que tenha uma ponta para          ·░░
    ░░░  micro-usb e outra para USB-A, permitindo assim ligar o dispositivo e ░░░
    ░░░  conectar o pendrive). Depois de ler algumas coisas e jogar tudo pra  ░░░
    ·░░  memória, é feita uma verificação de header na função                 ░░░
    ░░░  bootimg_hdr_verify. Temos isso aqui:                                 ░░░
    ·░░                                                                       ░░░
    ░░░      if (boot_src == BOOT_SRC_USB){                                   ░░░
    ·░░          /* TODO(kolla): Enable checks for ver, mkt_id etc.*/         ░░░
    ░░░          if (img_magic != CPU_IMG_CODE_MAGIC)                         ·░░
    ░░░              return -1;                                               ░░░
    ░░░          if (code_type != BCM_IMG_USBIMG_TYPE)                        ░░░
    ·░░              return -1;                                               ░░░
    ░░░          if (img_udata != CPU_IMG_USB_USRDATA)                        ░░░
    ░░░              return -1;                                               ·░░
    ░░░                                                                       ░░░
    ░░░  Os defines são:                                                      ░░░
    ░░░                                                                       ·░░
    ░░░      #define CPU_IMG_CODE_MAGIC       0xC0DE                          ░░░
    ·░░      #define BCM_IMG_KERNEL_TYPE  4                                   ░░░
    ░░░      #define BCM_IMG_USBIMG_TYPE  5                                   ░░░
    ░░░      #define CPU_IMG_USB_USRDATA      0xA33A                          ░░░
    ░░░                                                                       ░░░
    ░░░  No [Apêndice B] eu incluí um script que faz os patches para que a    ·░░
    ·░░  boot.img tenha essas configurações no header.                        ░░░
    ░░░                                                                       ░░░
    ░░░  Voltando à função load_android_image, quando passamos da verificação ░░░
    ░░░  dos headers, entramos na verificação do BCM (Base Crypto Module).    ░░░
    ░░░                                                                       ░░░
    ░░░      /* Verify image header */                                        ·░░
    ░░░      ret = bootimg_hdr_verify(k_buff_img, boot_src);                  ░░░
    ·░░      if (ret) {                                                       ░░░
    ░░░        lgpl_printf("ERROR: Boot image verify header failed!           ░░░
    ░░░                    └►ret=0x%x\n", ret);                               ░░░
    ·░░        return -1;                                                     ░░░
    ░░░      }                                                                ░░░
    ░░░      ret = bcm_image_verify(bcm_img_type, (unsigned) k_buff,          ░░░
    ░░░                             └►(unsigned) k_buff);                     ░░░
    ·░░      if (ret) {                                                       ░░░
    ░░░          lgpl_printf("ERROR: Verify k_buff image                      ░░░
    ░░░                     └►failed!ret=0x%x\n", ret);                       ░░░
    ░░░          return -1;                                                   ░░░
    ░░░      }                                                                ░░░
    ░░░                                                                       ·░░
    ░░░  A função bcm_image_verify é a mais... chata!                         ░░░
    ·░░                                                                       ░░░
    ░░░  int bcm_image_verify(unsigned int type, unsigned int src, unsigned   ░░░
    ░░░  int dst)                                                             ░░░
    ░░░                                                                       ░░░
    ░░░  É recebido aqui o image type (no caso, 5 para USB, 4 para NAND       ░░░
    ░░░  [BCM_IMG_KERNEL_TYPE]), um source e um destination.                  ░░░
    ░░░                                                                       ░░░
    ░░░  A interface do BCM é definida em [10], e pelo que entendi isso       ░░░
    ░░░  funciona da seguinte maneira:                                        ░░░
    ░░░                                                                       ░░░
    ░░░     ----------   bus  -----------                                     ░░░
    ░░░    | Main SoC |------| trustzone |                                    ░░░
    ░░░     ----------        -----------                                     ░░░
    ░░░         |                |                                            ░░░
    ░░░         V                V                                            ░░░
    ░░░      ------------------------                                         ░░░
    ░░░     |        memory          |                                        ░░░
    ░░░      ------------------------                                         ░░░
    ░░░                                                                       ░░░
    ·░░  No início da função bcm_image_verify, temos o seguinte:              ░░░
    ░░░                                                                       ░░░
    ░░░  #define BCM_MAILBOX          MEMMAP_BCM_REG_BASE //0xF7930000        ░░░
    ░░░                                                                       ░░░
    ░░░  ...                                                                  ░░░
    ░░░                                                                       ░░░
    ░░░  volatile NOT_MAILBOX volatile *mb = (NOT_MAILBOX *) BCM_MAILBOX;     ░░░
    ·░░                                                                       ░░░
    ·░░  Ou seja, mapeamos um endereço de memória em comum entre o TrustZone (·░░
    ░░░  onde operações criptográficas executam) e o SoC principal (onde o    ░░░
    ░░░  bootloader está executando).                                         ░░░
    ░░░                                                                       ░░░
    ░░░  Depois, mandamos o tipo de imagem (lembra, 5 para USB, 4 para NAND), ·░░
    ·░░  os buffers onde vamos armazenar coisas e o comando a ser executado   ·░░
    ░░░  no TrustZone                                                         ░░░
    ░░░                                                                       ░░░
    ░░░  #define BCM_PI_IMAGE_VERIFY  0x004E                                  ░░░
    ░░░                                                                       ░░░
    ░░░  ...                                                                  ·░░
    ░░░                                                                       ░░░
    ░░░      mb->primitive_command_parameter0 = type;                         ░░░
    ░░░      mb->primitive_command_parameter1 = src;                          ·░░
    ░░░      mb->primitive_command_parameter2 = dst;                          ░░░
    ░░░      mb->secure_processor_command = BCM_PI_IMAGE_VERIFY;              ·░░
    ·░░                                                                       ░░░
    ░░░                                                                       ░░░
    ░░░  Depois, existe um loop que espera até um hardware interrupt          ·░░
    ░░░  acontecer:                                                           ░░░
    ░░░                                                                       ░░░
    ░░░      for (waitCount=0; ; waitCount++) // Wait_For_WTM_Complete(       ░░░
    ░░░      0x10000, pCtrl );                                                ░░░
    ░░░      {                                                                ░░░
    ░░░          //if ((mb->command_fifo_status & BCM_STATUS_BCM_CMD_FLIP) != ░░░
    ░░░          status)                                                      ░░░
    ░░░              //break;                                                 ░░░
    ░░░          // wait for "command complete" or timeout                    ░░░
    ░░░          if( mb-> host_interrupt_register & 0x1 )                     ·░░
    ░░░              break;                                                   ░░░
    ░░░          berlin_delay(100);                                           ·░░
    ░░░      }                                                                ░░░
    ░░░                                                                       ░░░
    ░░░  Por vim, a gente retorna o status                                    ·░░
    ░░░                                                                       ░░░
    ░░░  status = mb->command_return_status;                                  ░░░
    ░░░                                                                       ·░░
    ·░░  Lá na função load_android_image, é verificado se o retorno disso é   ░░░
    ░░░  zero, e se for, prossegue pro boot.                                  ░░░
    ░░░                                                                       ░░░
    ░░░      if (ret) {                                                       ·░░
    ░░░          lgpl_printf("ERROR: Verify k_buff image failed!ret=0x%x\n",  ░░░
    ░░░           ret);                                                       ░░░
    ░░░          return -1;                                                   ░░░
    ░░░      }                                                                ·░░
    ░░░                                                                       ░░░
    ·░░                                                                       ░░░
    ·░░  Uma coisa interessante do [13] é que, de acordo com os hackers do    ░░░
    ░░░  Exploitee.rs [14] (minuto 25:26), o retorno da verificação de        ░░░
    ·░░  assinatura não era validado, fazendo com que o bypass fosse          ·░░
    ░░░  extremamente simples :) Hoje é bem difícil, e eu não sei exatamente  ░░░
    ░░░  como hackear a partir desse ponto...                                 ░░░
    ░░░                                                                       ·░░
    ░░░  ------------------------------------------------------------         ░░░
    ·░░                                                                       ░░░
    ░░░  Bom, nessa talk da DEFCON 27 [12], é exibido como baixar uma OTA do  ░░░
    ░░░  Google Home Mini. Seguindo o passo a passo da apresentação deles, eu ░░░
    ░░░  obtive o zip:                                                        ░░░
    ░░░                                                                       ░░░
    ░░░  ota.375114.tz_stable-channel.joplin-b4.5b07d2aee0cb1d0               ░░░
    ░░░  └►602930fa2d18f930dbb81463.zip                                       ░░░
    ░░░                                                                       ░░░
    ░░░    inflating: META-INF/MANIFEST.MF                                    ·░░
    ░░░    inflating: META-INF/CERT.SF                                        ░░░
    ░░░    inflating: META-INF/CERT.RSA                                       ░░░
    ░░░    inflating: META-INF/com/android/metadata                           ·░░
    ░░░    inflating: META-INF/com/google/android/update-binary               ·░░
    ░░░    inflating: META-INF/com/google/android/updater-script              ░░░
    ░░░    inflating: boot.img                                                ░░░
    ░░░    inflating: bootloader.joplin-b4                                    ░░░
    ░░░    inflating: post-bootloader.joplin-b4                               ░░░
    ░░░    inflating: system.img                                              ·░░
    ░░░    inflating: tz_en.joplin-b4                                         ·░░
    ░░░                                                                       ░░░
    ░░░  O Apêndice A contém um script que verifica, a partir do código do    ░░░
    ·░░  bootloader, quais bytes estão setados na imagem.                     ░░░
    ░░░                                                                       ·░░
    ·░░  ./img-info.sh extracted/boot.img                                     ·░░
    ░░░  Magic: c0de (should be c0de) at offset 4                             ░░░
    ░░░  User data 0000 (should be a33a for USB) at offset 10                 ░░░
    ░░░  Code Type: 04 (5 is USB, 4 is kernel) at offset 7                    ░░░
    ░░░  Header Type: 00000001 at offset 0                                    ░░░
    ·░░  Market ID: 00000001 at offset 28                                     ░░░
    ░░░  Market ID Mask: ffffffff at offset 32                                ░░░
    ░░░  Version ID: 01 at offset 36                                          ░░░
    ░░░  Version ID Mask: ff at offset 35                                     ░░░
    ░░░  Image size: 003e9000 at offset 40                                    ·░░
    ░░░  Android Magic: ANDROID! at offset 332                                ░░░
    ░░░                                                                       ░░░
    ·░░  Algumas dessas coisas foram tiradas da ferramenta ./sign_image do    ·░░
    ░░░  chromecast_sdk_oss                                                   ░░░
    ░░░                                                                       ░░░
    ░░░  (partner%2F1.56_sdk%2Fcombined-sdk-kernel-bootloader%2F253616%2Foss%2░░░
    ░░░  Fchromecast_sdk_oss.tgz)                                             ░░░
    ░░░                                                                       ░░░
    ░░░  No apêndice B temos um script que gera um formato de imagem pronto   ░░░
    ░░░  para o USB. Porém, essa imagem não vai funcionar por conta das       ░░░
    ░░░  assinaturas necessárias :c                                           ░░░
    ░░░                                                                       ░░░
    ·░░  ./generate_bootimg.sh extracted/boot.img extracted/boot.img.mbr      ░░░
    ░░░  Patching extracted/boot.img                                          ░░░
    ░░░  Patching BCM_IMG_USBIMG_TYPE (5) at offset 7                         ░░░
    ░░░  1+0 records in                                                       ░░░
    ░░░  1+0 records out                                                      ░░░
    ·░░  1 byte copied, 7.1324e-05 s, 14.0 kB/s                               ░░░
    ·░░  Patching CPU_IMG_USB_USRDATA (0xA33A) at offset 10                   ·░░
    ░░░  2+0 records in                                                       ░░░
    ░░░  2+0 records out                                                      ░░░
    ░░░  2 bytes copied, 6.5483e-05 s, 30.5 kB/s                              ░░░
    ░░░  Creating 4KB zero padding from extracted/boot.img to extracted/      ·░░
    ░░░  boot.img.mbr                                                         ░░░
    ·░░  1+0 records in                                                       ·░░
    ░░░  1+0 records out                                                      ░░░
    ·░░  4096 bytes (4.1 kB, 4.0 KiB) copied, 7.2947e-05 s, 56.2 MB/s         ░░░
    ░░░  8008+1 records in                                                    ·░░
    ░░░  8008+1 records out                                                   ░░░
    ░░░  4100428 bytes (4.1 MB, 3.9 MiB) copied, 0.0677137 s, 60.6 MB/s       ░░░
    ░░░                                                                       ░░░
    ░░░  Com isso, é só fazer um dd do boot.img.mbr para um pendrive e plugar ·░░
    ░░░  no Google Home/Chromecast usando um OTG powered (um OTG que tem      ░░░
    ░░░  entrada USB A e micro USB, que vai na energia) e segurar o botão de  ░░░
    ░░░  reset do aparelho.                                                   ·░░
    ·░░                                                                       ·░░
    ░░░  Temos um artigo mega foda em [15] sobre mais hacks do Google Home    ░░░
    ░░░  Mini e em [16] mais análises de HW do Nest.                          ░░░
    ░░░                                                                       ░░░
    ░░░  ------------------------------------------------------------         ·░░
    ·░░                                                                       ░░░
    ░░░  Temos várias possibilidades de futuros trabalhos com o Chromecast e  ░░░
    ·░░  o Google Home. Uma delas seria fazer uma análise de voltage          ░░░
    ░░░  glitching para fazer o bypass da verificação de assinatura de imagem ░░░
    ░░░  USB. Com isso, poderíamos bootar nossa própria imagem do kernel :)   ░░░
    ·░░                                                                       ░░░
    ░░░  Outra coisa que eu queria muito testar é como carregar o firmware do ░░░
    ░░░  Chromecast no QEMU. Pra isso, preciso tentar entender o layout da    ░░░
    ░░░  NAND e como traduzir isso pro QEMU. É provável que os binários de tz ·░░
    ░░░  loader e outros disponíveis no chromecast_sdk_oss estejam            ░░░
    ░░░  criptografados também.                                               ░░░
    ░░░                                                                       ·░░
    ░░░  Espero que essa jornada tenha sido interessante para vocês como foi  ░░░
    ░░░  pra mim. Até a próxima!                                              ·░░
    ░░░                                                                       ·░░
    ░░░  ------------------------------------------------------------         ░░░
    ░░░                                                                       ░░░
    ░░░  Pesquisas futuras                                                    ░░░
    ░░░                                                                       ·░░
    ░░░  [17] possui um pouco sobre o modelo de Trusted Firmware da ARM, em   ·░░
    ░░░  que o bootloader depende de alguns stages para executar.             ░░░
    ░░░                                                                       ░░░
    ░░░  [18] possui o código do atf-marvell, do trusted firmware que a       ·░░
    ░░░  Marvell usa.                                                         ░░░
    ·░░                                                                       ·░░
    ░░░  Entender isso é crucial para próximos desenvolvimentos.              ░░░
    ░░░                                                                       ·░░
    ░░░  ------------------------------------------------------------         ░░░
    ░░░                                                                       ░░░
    ░░░  Referências                                                          ░░░
    ░░░                                                                       ░░░
    ░░░  [1] https://www.cnet.com/home/smart-home/your-google-home-is-brick   ·░░
    ·░░                                                                       ░░░
    ░░░  [2] https://code.google.com/archive/p/chromecast-mirrored-source     ░░░
    ░░░                                                                       ░░░
    ░░░  [3] https://abzman2k.wordpress.com/2020/02/20/google-home-autopsy/   ░░░
    ░░░                                                                       ░░░
    ░░░  [4] https://pastebin.com/3c1BUieq                                    ░░░
    ░░░                                                                       ░░░
    ·░░  [5] https://justlv.medium.com/google-home-mini-teardown-comparison  ·░░
    ·░░                                                                       ░░░
    ·░░  [6] https://www.ifixit.com/News/7431/chromecast-2015-audio           ░░░
    ░░░                                                                       ░░░
    ░░░  [7] https://en.wikipedia.org/wiki/Clean_room_design                  ░░░
    ░░░                                                                       ░░░
    ░░░  [8] https://support.google.com/product-documentation/answer          ░░░
    ░░░                                                                       ░░░
    ·░░  [9] https://nest-open-source.googlesource.com/manifest_repos/bootl   ░░░
    ░░░                                                                       ░░░
    ░░░  [10] https://nest-open-source.googlesource.com/.../.../bcm_hal.c     ░░░
    ·░░                                                                       ░░░
    ░░░  [11] https://nest-open-source.googlesource.com/.../bootloader.c#889  ░░░
    ░░░                                                                       ░░░
    ░░░  [12] https://www.youtube.com/watch?v=YBwT7PU6QU4                     ░░░
    ░░░                                                                       ░░░
    ░░░  [13] https://nest-open-source.googlesource.com/...bootloader.c#1977  ░░░
    ░░░                                                                       ░░░
    ░░░  [14] https://www.youtube.com/watch?v=_FxJJ2eDC_I                     ░░░
    ░░░                                                                       ·░░
    ░░░  [15] https://courk.cc/running-custom-code-google-home-mini-part1     ░░░
    ░░░                                                                       ░░░
    ░░░  [16] https://chromium.googlesource.com/external/...firmware-design.md░░░
    ░░░                                                                       ·░░
    ░░░  [18] https://github.com/MarvellEmbeddedProcessors/atf-marvell        ░░░
    ·░░                                                                       ░░░
    ░░░  ------------------------------------------------------------         ░░░
    ··░                                                                       ░··


    
    Apêndice A

    img-info.sh

    BOF
    #!/bin/bash

    INPUT_FILE=$1

    IMG_START=0
    MKBOOTIMG_START=332
    MAGIC_OFFSET=`expr $IMG_START + 4`

    MAGIC=`xxd -e -l 2 -s $MAGIC_OFFSET $INPUT_FILE | awk '{print $2}'`
    if [ "$MAGIC" != "c0de" ]; then
        echo "Will change IMG_START to 4096"
        IMG_START=4096
        MAGIC_OFFSET=`expr $IMG_START + 4`
        MAGIC=`xxd -e -l 2 -s $MAGIC_OFFSET $INPUT_FILE | awk '{print $2}'`
        [ "$MAGIC" == "c0de" ] || echo "Still couldn't find magic :("
    fi

    echo "Magic: $MAGIC (should be c0de) at offset $MAGIC_OFFSET"

    USR_DATA_OFFSET=`expr $IMG_START + 10`
    USR_DATA=`xxd -e -l 2 -s $USR_DATA_OFFSET $INPUT_FILE | awk '{print $2}'`
    echo "User data $USR_DATA (should be a33a for USB) at offset $USR_DATA_OFFSET"

    CODE_TYPE_OFF=`expr $IMG_START + 7`
    CODE_TYPE=`xxd -e -l 1 -s $CODE_TYPE_OFF $INPUT_FILE | awk '{print $2}'`
    echo "Code Type: $CODE_TYPE (5 is USB, 4 is kernel) at offset $CODE_TYPE_OFF"

    HEADER_TYPE_OFF=`expr $IMG_START`
    HEADER_TYPE=`xxd -e -l 4 -s $HEADER_TYPE_OFF $INPUT_FILE | awk '{print $2}'`
    echo "Header Type: $HEADER_TYPE at offset $HEADER_TYPE_OFF"

    MARKET_ID_OFF=`expr $IMG_START + 28`
    MARKET_ID=`xxd -e -l 4 -s $MARKET_ID_OFF $INPUT_FILE | awk '{print $2}'`
    echo "Market ID: $MARKET_ID at offset $MARKET_ID_OFF"

    MARKET_ID_MASK_OFF=`expr $IMG_START + 32`
    MARKET_ID_MASK=`xxd -e -l 4 -s $MARKET_ID_MASK_OFF $INPUT_FILE | awk '{print $2}'`
    echo "Market ID Mask: $MARKET_ID_MASK at offset $MARKET_ID_MASK_OFF"

    VERSION_ID_OFF=`expr $IMG_START + 36`
    VERSION_ID=`xxd -e -l 1 -s $VERSION_ID_OFF $INPUT_FILE | awk '{print $2}'`
    echo "Version ID: $VERSION_ID at offset $VERSION_ID_OFF"

    VERSION_ID_MASK_OFF=`expr $IMG_START + 35`
    VERSION_ID_MASK=`xxd -e -l 1 -s $VERSION_ID_MASK_OFF $INPUT_FILE | awk '{print $2}'`
    echo "Version ID Mask: $VERSION_ID_MASK at offset $VERSION_ID_MASK_OFF"

    IMAGE_SIZE_OFF=`expr $IMG_START + 40`
    IMAGE_SIZE=`xxd -e -l 4 -s $IMAGE_SIZE_OFF $INPUT_FILE | awk '{print $2}'`
    echo "Image size: $IMAGE_SIZE at offset $IMAGE_SIZE_OFF"

    ANDROID_MAGIC_OFF=`expr $IMG_START + 332`
    ANDROID_MAGIC=`xxd -e -l 8 -s $ANDROID_MAGIC_OFF $INPUT_FILE | awk '{print $4}'`
    echo "Android Magic: $ANDROID_MAGIC at offset $ANDROID_MAGIC_OFF"

    if [ "$IMG_START" -ne 0 ]; then
        echo "Will also check crypto headers"
        ./check_encrypted_header.sh $INPUT_FILE
    fi
    EOF

    ------------------------------------------------------------

    Apêndice B

    generate_bootimg.sh

    BOF
    #!/bin/bash

    INPUT_FILE=$1
    OUTPUT_FILE=$2

    echo "Patching $INPUT_FILE"

    echo "Patching BCM_IMG_USBIMG_TYPE (5) at offset 7"
    printf '\x05' | dd of=$INPUT_FILE bs=1 seek=7 conv=notrunc

    echo "Patching CPU_IMG_USB_USRDATA (0xA33A) at offset 10"
    printf '\x3a\xa3' | dd of=$INPUT_FILE bs=1 seek=10 conv=notrunc

    echo "Creating 4KB zero padding from $INPUT_FILE to $INPUT_FILE.mbr"
    dd if=/dev/zero of=$OUTPUT_FILE bs=4096 count=1
    dd if=$INPUT_FILE >> $OUTPUT_FILE
    EOF