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