Por dentro dos formatos de ficheiro binário: cabeçalhos PNG, ZIP e Mach-O explicados
Todos os formatos de ficheiro que usas diariamente, imagem, arquivo, executável, têm uma estrutura definida ao byte, e quase nada dessa estrutura é visível através das ferramentas que costumas usar para abrir esses ficheiros. A Pré-Visualização mostra-te uma imagem. O Utilitário de Arquivo mostra-te ficheiros extraídos. Nenhum te mostra os bytes que tornaram esses resultados possíveis. Aqui fica como três formatos comuns são na realidade por baixo, e como podes olhar para eles tu próprio.
PNG: uma sequência de chunks rotulados
Todos os ficheiros PNG começam com os mesmos oito bytes: 89 50 4E 47 0D 0A 1A 0A. Isso não são dados de imagem, é uma assinatura, deliberadamente escolhida para incluir um byte que fica inutilizável se o ficheiro for transferido por acidente como texto (0x0A e 0x0D são caracteres de nova linha, por isso uma transferência estragada em modo de texto corrompe-os de uma forma fácil de detetar).
Depois da assinatura, tudo num PNG é um chunk, e cada chunk segue a mesma disposição de quatro partes:
- Comprimento (4 bytes): quantos bytes de dados se seguem, sem contar o tipo nem o CRC.
- Tipo (4 bytes, sempre ASCII): um código de quatro letras como
IHDR(cabeçalho da imagem, sempre o primeiro),IDAT(dados de píxeis comprimidos, podem existir vários), ouIEND(marca o fim do ficheiro). - Dados: o que quer que esse tipo de chunk especifique. Os dados do
IHDRsão a largura, a altura, a profundidade de bits e o tipo de cor, sempre com a mesma disposição fixa. - CRC (4 bytes): um checksum do tipo e dos dados, para que um descodificador possa detetar um chunk corrompido em vez de o ler mal em silêncio.
É este o formato inteiro. Um descodificador PNG limita-se a percorrer chunk após chunk, lendo o comprimento para saber quanto avançar, até chegar ao IEND.
ZIP: cabeçalhos locais, depois um diretório no fim
Um arquivo ZIP guarda cada ficheiro com o seu próprio cabeçalho de ficheiro local, marcado pela assinatura 50 4B 03 04 (o PK no início é uma referência a Phil Katz, o criador do formato). Esse cabeçalho inclui o nome do ficheiro, o método de compressão e tanto o tamanho comprimido como o não comprimido, imediatamente seguidos pelos dados comprimidos do ficheiro.
A parte que baralha as pessoas: esses tamanhos e checksums por ficheiro no cabeçalho local estão por vezes a zero, com os valores reais guardados mais à frente num “data descriptor”, porque o ZIP foi concebido para suportar gravações em streaming, onde o tamanho final não é conhecido antes de os dados já terem sido escritos. A lista definitiva do que está de facto no arquivo vive num diretório central mesmo no fim do ficheiro, o que é também a razão pela qual alguns ZIPs corrompidos ou truncados podem parecer ter conteúdo quando os analisas a partir do início, mas falham ao abrir, porque a ferramenta que estás a usar lê primeiro o diretório central e ele está em falta ou danificado.
Mach-O: número mágico, depois load commands
O Mach-O é o formato executável que o macOS usa para binários compilados. Começa com um número mágico que diz ao carregador duas coisas ao mesmo tempo: se é de 32 bits ou de 64 bits, e que ordem de bytes o resto do ficheiro usa. 0xFEEDFACE é 32 bits, 0xFEEDFACF é 64 bits, e se vires os bytes invertidos (0xCEFAEDFE ou 0xCFFAEDFE), significa que o ficheiro foi escrito na ordem de bytes oposta à da máquina que o está a ler.
A seguir ao número mágico vem um cabeçalho fixo (tipo de CPU, tipo de ficheiro e uma contagem de load commands), seguido desse número de load commands em sequência. Os load commands são a forma como um ficheiro Mach-O descreve tudo aquilo de que o carregador precisa: que segmentos mapear para a memória, que bibliotecas dinâmicas ligar, onde está o ponto de entrada. É uma ideia parecida com a dos chunks do PNG: um cabeçalho fixo, depois uma sequência de registos autodescritivos, cada um a dizer ao leitor quanto deve avançar para chegar ao seguinte.
Olhar para isto tu próprio
Nada disto exige escrever um interpretador. Abre qualquer ficheiro PNG, ZIP ou Mach-O no Hexter e o separador Analisar reconhece o formato automaticamente, percorrendo a estrutura real de chunks ou de load commands e mostrando-a como uma árvore ao lado do hex em bruto, para que possas clicar num campo e ver exatamente de que bytes veio. É só de leitura por predefinição, por isso isto é genuinamente seguro de fazer num ficheiro real, um binário de uma app, uma captura de ecrã, um arquivo que transferiste, sem qualquer risco de o alterar.
Se preferires verificar à mão o que está descrito acima: abre um PNG e confirma que os primeiros oito bytes coincidem com a assinatura, depois olha para os bytes 8 a 11 (o comprimento do primeiro chunk) e para os bytes 12 a 15 (o seu tipo, que deve ler-se IHDR). É um exercício pequeno o suficiente para fazer em poucos minutos, e é uma forma genuinamente útil de compreender um formato de ficheiro que usaste a vida toda mas nunca chegaste a espreitar.