Modificando e Reconstruindo o boot.img e o initrd.img no Android
Um guia prático e detalhado para extrair, modificar e reconstruir o boot.img e o initrd.img no Android, permitindo personalizações avançadas e otimizações no sistema.
Introdução
A imagem boot.img é um arquivo que contém todos os componentes necessários para o processo de inicialização de um sistema operacional, como o kernel e o ramdisk, sendo que o initrd está incluído no ramdisk.
boot.img: Esta imagem contém o kernel, que gerencia o hardware do dispositivo e executa os processos do sistema operacional, e o ramdisk, que é um sistema de arquivos temporário utilizado para carregar os componentes necessários até que o sistema de arquivos real seja montado.
initrd.img: Este arquivo também contém arquivos temporários e scripts necessários para o processo de inicialização, mas sua função é garantir que o sistema operacional tenha o ambiente adequado antes que o sistema de arquivos raiz seja montado.
Sumário
Extração do initrd.img
Modificação do initrd.img
Reconstrução do boot.img
Teste do boot.img
Dispositivo
Neste tutorial, utilizarei o smartphone LG L70 (codename lg-w5), rodando Android 4.4.2 com o kernel versão 3.4.0.
Requisitos
Para seguir este tutorial, recomendo o uso de uma distribuição Linux, preferencialmente Debian.
No entanto, você pode utilizar qualquer outra distribuição, desde que seja capaz de instalar ou compilar e utilizar as ferramentas que apresentaremos a seguir.
boot.img
Para extrair o initrd.img do seu dispositivo, precisaremos do arquivo boot.img. Em uma publicação anterior, abordei diferentes formas de extrair o boot.img de seu dispositivo. Se ainda não tiver o seu arquivo boot.img, sugiro a leitura do capítulo “Como obter o boot.img”.
Pacotes necessários
Para a execução deste tutorial, você precisará dos seguintes pacotes, assumindo que esteja utilizando uma distribuição Linux:
abootimg: Ferramenta para extrair e modificar imagens de inicialização (boot.img) em dispositivos Android.
mkbootimg: Ferramenta para criar imagens de inicialização a partir de um kernel e ramdisk.
Para instalar os pacotes necessários, execute o comando abaixo:
sudo apt install abootimg adb fastboot
Extraindo o initrd.img
Para manter a organização, recomendo criar um diretório e copiar o boot.img para ele. Dentro desse diretório, executaremos o comando que extrai os arquivos do boot.img:
abootimg -x boot.img
Após a execução do comando, você verá os arquivos extraídos do boot.img:
boot.img bootimg.cfg initrd.img zImage
Agora, para modificar o initrd.img, precisamos extraí-lo. Vamos criar um diretório para extrair seus arquivos usando o zcat e o cpio:
mkdir initrd_temp
cd initrd_temp
zcat ../initrd.img | cpio -idv
Explicando o comando:
zcat: Descompacta o arquivo initrd.img.
Pipe (|): Passa o conteúdo descompactado para o cpio.
cpio: Extrai os arquivos e os coloca no diretório atual, criando subdiretórios, se necessário, e exibindo os nomes dos arquivos enquanto os extrai.
Agora, você deve ver o conteúdo extraído do initrd.img no diretório initrd_temp. Execute o comando abaixo para confirmar:
ls
Você verá uma estrutura de diretórios e arquivos, como:
charger init.gammaw.class_core.sh init.gammaw.usb.rc init.rc property_contexts
data init.gammaw.cmm.usb.sh init.gammaw.usb.sh init.trace.rc res
default.prop init.gammaw.early_boot.sh init.lge.early.rc init.usb.rc sbin
dev init.gammaw.factory.sh init.lge.log.rc init.w5ds_product.rc seapp_contexts
file_contexts init.gammaw.rc init.lge.rc init.w5ds.rc sepolicy
fstab.w5ds init.gammaw.ril.sh init.lge.svelte.rc init.w5ds.usb.rc sys
init init.gammaw.sh initlogo_hvga.rle lgdms.fota.rc system
init.class_main.sh init.gammaw.ssr.sh initlogo_wvga.rle lgdms.fota_update.rc ueventd.rc
init.environ.rc init.gammaw.syspart_fixup.sh init.mdm.sh proc ueventd.w5ds.rc
Agora, você pode fazer as modificações necessárias. No próximo capítulo, veremos como reconstruir o initrd.img e, em seguida, o boot.img com o initrd.img modificado.
Reconstruindo o initrd.img
Após realizar as modificações no initrd, e mantendo-se no diretório onde o initrd foi extraído (initrd_temp), vamos utilizar o cpio para reempacotar o arquivo modificado:
find . | cpio --create --format='newc' | gzip -9 > ../new_initrd.img.gz
Explicando o comando::
find .: Localiza todos os arquivos e diretórios no diretório atual (initrd_temp).
cpio --create --format='newc': Cria um arquivo de arquivo (cpio) com o formato newc.
gzip -9: Compacta o arquivo gerado usando o método de compressão gzip com o nível de compressão máximo (-9).
> ../new_initrd.img.gz: Redireciona a saída para um novo arquivo chamado new_initrd.img.gz no diretório anterior, onde você extraiu os arquivos do boot.img.
Ao final, o arquivo new_initrd.img.gz será gerado no diretório anterior, contendo as modificações que você fez no initrd.
Detalhe Importante
Utilizamos a compactação máxima (nível 9), para reempacotar o arquivo new_initrd.img.gz. No entanto, mesmo sem modificações, ele pode acabar ficando maior que o original, o que pode causar problemas caso o arquivo bootimg.cfg não seja ajustado. Um boot.img maior também pode gerar falhas se a partição de boot não tiver espaço suficiente. Fique atento a esses detalhes.
Você pode usar o binwalk (como instalar) ou o pmbootstrap (com o argumento bootimg_analyze) para examinar a estrutura de boot.img, ou qualquer outra ferramenta similar.
Ajustando o tamanho de new_initrd.img.gz
Agora, vamos comparar o tamanho do nosso arquivo new_initrd.img.gz com o initrd.img original:
ls -l initrd.img new_initrd.img.gz
No meu caso, o arquivo original (initrd.img) tem 2.531.488 bytes, enquanto o new_initrd.img.gz tem 2.563.144 bytes, ou seja, ficou maior que o original. Isso pode causar erros caso o bootimg.cfg não seja atualizado para refletir essa mudança.
No arquivo bootimg.cfg, a variável bootsize indica, em formato hexadecimal, o tamanho total do arquivo boot.img:
$ cat bootimg.cfg | grep bootsize
bootsize = 0x1600000
Anteriormente, nosso initrd.img tinha 2.531.488 bytes, mas agora ele possui 2.563.144 bytes, resultando em uma diferença de 31.656 bytes (2563144 - 2531488 = 31656). Portanto, precisamos adicionar esses 31.656 bytes ao valor atual de bootsize.
Atualmente, o bootsize é 0x1600000, ou 23.068.672 bytes em decimal. O novo valor do bootsize será:
23.068.672 + 31.656 = 23.100.328 bytes, que em hexadecimal é 0x1607BA8.
initrd menor que o original
Se o seu new_initrd.img.gz for menor que o original, você pode preenchê-lo até atingir o tamanho correto com o seguinte comando, ou então ajustar o bootimg.cfg:
truncate -s 2531488 new_initrd.img.gz
Nesse caso, se ele for menor, estamos utilizando o truncate para preencher o restante de new_initrd.img.gz até ele ficar do tamanho original (2.531.488 bytes).
Reconstruindo o boot.img
Agora que temos o initrd modificado, o próximo passo é gerar o novo boot.img usando o arquivo new_initrd.img.gz.
Podemos atualizar as partes específicas do boot.img conforme necessário, utilizando o argumento -u:
abootimg -u <bootimg> [-c "param=value"] [-f <bootimg.cfg>] [-k <kernel>] [-r <ramdisk>] [-s <secondstage>]
Para atualizar exclusivamente o initrd (ramdisk), podemos utilizar o seguinte comando:
abootimg -u boot.img -r new_initrd.img.gz
Ao final, o arquivo boot.img será atualizado com o novo ramdisk.
Se você não quer se preocupar com detalhes avançados, recomendo utilizar essa opção de atualização.
No entanto, é importante garantir que o new_initrd.img.gz tenha o mesmo tamanho do initrd.img original para evitar sobrescrever outras regiões da memória no boot.img.
Caso contrário, você pode acabar sobrescrevendo a região da DTB (device tree blob), que, no meu caso, fica no final do boot.img (QCDT). Em outros dispositivos, a DTB normalmente fica logo após o kernel ou o ramdisk, dependendo da configuração do dispositivo.
Se o seu dispositivo for baseado em QCDT, você pode utilizar o pacote skales, que inclui as ferramentas skales-dtbtool e skales-mkbootimg.
Para obter uma compreensão mais profunda sobre a Device Tree, recomendo a leitura do artigo “Como Extrair e Decompilar a Device Tree de um Dispositivo Android”.
Reconstruindo totalmente o boot.img
Para isso, utilizaremos a ferramenta abootimg da seguinte forma:
abootimg --create new_boot.img.gz -f bootimg.cfg -k zImage -r new_initrd.img.gz
Se for alterar o nome do arquivo de saída (new_initrd.img.gz), certifique-se de manter a extensão .img.gz. Em meus testes, a ausência dessa extensão causou erros ao executar o boot.img.
Explicando o comando:
--create new_boot.img: Cria o novo arquivo boot.img, que será chamado de new_boot.img.
-f bootimg.cfg: Utiliza o arquivo de configuração bootimg.cfg para configurar os parâmetros do novo boot.img.
-k zImage: Especifica o kernel a ser utilizado, no caso, o arquivo zImage.
-r new_initrd.img.gz: Inclui o new_initrd.img.gz modificado no novo boot.img.
Com esse comando, criaremos o nosso boot.img, que se chamará new_boot.img. Agora precisamos testar e verificar e realmente funciona.
Testando o boot.img
Agora, vamos testar o arquivo new_boot.img que criamos.
Primeiro, reinicie o dispositivo no modo bootloader:
adb reboot bootloader
Com o dispositivo conectado ao computador, use o comando abaixo para inicializar o dispositivo com o new_boot.img sem gravá-lo permanentemente na memória:
fastboot boot new_boot.img
Isso permite testar as modificações sem riscos, pois, caso haja algum problema, você pode reiniciar e o dispositivo irá inicializar com o boot.img original.
Para reiniciar o dispositivo, basta usar o comando:
fastboot reboot
Se tudo estiver correto, o dispositivo iniciará com as modificações aplicadas.
Caso contrário, se ocorrer algum erro ou comportamento inesperado, basta reiniciar o dispositivo, e ele voltará a iniciar com o boot.img original, sem alterações.
Alteração permanente do boot.img
Para alterar o arquivo boot.img de forma permanente e gravá-lo na memória do dispositivo, você pode usar o fastboot ou, caso tenha root, pode realizar a operação via ADB ou um aplicativo de terminal.
1. Usando o Fastboot
Conecte o dispositivo em modo bootloader:
adb reboot bootloader
Flash o arquivo new_boot.img na partição de boot do dispositivo:
fastboot flash boot new_boot.img
Após o flash, reinicie o dispositivo:
fastboot reboot
2. Usando ADB ou Terminal com Root
Se você tem root no dispositivo, pode transferir o arquivo diretamente para o dispositivo e gravá-lo na partição de boot.
Transfira o new_boot.img para o dispositivo:
adb push new_boot.img /mnt/sdcard
Acesse a shell do ADB (ou use um terminal com privilégios de root):
adb shell
Identifique a partição de boot. Um comando comum para verificar a partição de boot é:
ls -l /dev/block/platform/msm_sdcc.1/by-name/boot
No exemplo, a partição de boot é /dev/block/mmcblk0p16, mas isso pode variar dependendo do dispositivo.
Para gravar o new_boot.img na partição de boot, use o comando dd com privilégios de root:
su dd if=/mnt/sdcard/new_boot.img of=/dev/block/mmcblk0p16 bs=4M
Aguarde até que o processo seja concluído.
Não se preocupe se não houver saída no terminal durante o processo.
O comando será concluído quando o prompt de comando retornar.
Após a gravação, reinicie o dispositivo:
reboot
Aviso Importante
Essa operação é permanente. Se houver algum problema no boot após a modificação, será necessário utilizar um método de recuperação, como o fastboot ou uma recuperação customizada como o TWRP, para restaurar a funcionalidade do dispositivo.
Conclusão
Neste artigo, exploramos o processo completo de extração, modificação e reconstrução do boot.img, incluindo a extração do initrd.img, sua modificação e a recriação.
Alterar o boot.img pode ser extremamente útil para personalizar e otimizar um dispositivo Android. Pequenos erros podem impedir o sistema de inicializar. Por isso, sempre faça um backup do seu boot.img original antes de qualquer modificação e tenha um plano de recuperação, como o fastboot ou um recovery customizado (TWRP).