Au cœur des formats de fichiers binaires : les en-têtes PNG, ZIP et Mach-O expliqués
Chaque format de fichier que vous utilisez au quotidien, image, archive, exécutable, possède une structure définie à l’octet près, et presque rien de cette structure n’est visible à travers les outils que vous employez d’ordinaire pour ouvrir ces fichiers. Aperçu vous montre une image. L’Utilitaire d’archive vous montre des fichiers extraits. Ni l’un ni l’autre ne vous montre les octets qui ont rendu ces résultats possibles. Voici à quoi ressemblent réellement trois formats courants en dessous, et comment les regarder vous-même.
PNG : une suite de chunks étiquetés
Chaque fichier PNG commence par les mêmes huit octets : 89 50 4E 47 0D 0A 1A 0A. Ce ne sont pas des données d’image, c’est une signature, délibérément choisie pour inclure un octet qui devient inutilisable si le fichier est transféré par accident comme du texte (0x0A et 0x0D sont des caractères de saut de ligne, donc un transfert en mode texte défaillant les corrompt d’une façon facile à détecter).
Après la signature, tout dans un PNG est un chunk, et chaque chunk suit la même disposition en quatre parties :
- Longueur (4 octets) : combien d’octets de données suivent, sans compter le type ni le CRC.
- Type (4 octets, toujours en ASCII) : un code de quatre lettres comme
IHDR(en-tête d’image, toujours en premier),IDAT(données de pixels compressées, il peut y en avoir plusieurs) ouIEND(marque la fin du fichier). - Données : ce que ce type de chunk spécifie. Les données d’
IHDRsont la largeur, la hauteur, la profondeur de bits et le type de couleur, toujours la même disposition fixe. - CRC (4 octets) : une somme de contrôle du type et des données, pour qu’un décodeur puisse détecter un chunk corrompu au lieu de le mal interpréter silencieusement.
Voilà tout le format. Un décodeur PNG parcourt simplement chunk après chunk, lisant la longueur pour savoir jusqu’où sauter, jusqu’à atteindre IEND.
ZIP : des en-têtes locaux, puis un répertoire à la fin
Une archive ZIP stocke chaque fichier avec son propre en-tête de fichier local, marqué par la signature 50 4B 03 04 (le PK au début est une référence à Phil Katz, le créateur du format). Cet en-tête inclut le nom de fichier, la méthode de compression, ainsi que la taille compressée et la taille non compressée, immédiatement suivi des données compressées du fichier.
Ce qui déroute souvent : ces tailles et sommes de contrôle par fichier dans l’en-tête local sont parfois à zéro, les vraies valeurs étant stockées plus loin dans un « descripteur de données », car ZIP a été conçu pour prendre en charge l’écriture en flux, où la taille finale n’est pas connue tant que les données n’ont pas déjà été écrites. La liste définitive de ce qui se trouve réellement dans l’archive vit dans un répertoire central tout à la fin du fichier, ce qui explique aussi pourquoi certains ZIP corrompus ou tronqués peuvent sembler avoir du contenu quand on les parcourt depuis le début, mais ne s’ouvrent pas, parce que l’outil que vous utilisez lit d’abord le répertoire central, et qu’il est manquant ou endommagé.
Mach-O : un nombre magique, puis des commandes de chargement
Mach-O est le format d’exécutable que macOS utilise pour les binaires compilés. Il s’ouvre par un nombre magique qui indique deux choses à la fois à un chargeur : s’il s’agit de 32 bits ou de 64 bits, et quel ordre d’octets le reste du fichier utilise. 0xFEEDFACE est du 32 bits, 0xFEEDFACF du 64 bits, et si vous voyez les octets inversés (0xCEFAEDFE ou 0xCFFAEDFE), cela signifie que le fichier a été écrit dans l’ordre d’octets opposé à celui de la machine qui le lit.
Après le nombre magique vient un en-tête fixe (type de CPU, type de fichier et un décompte des commandes de chargement), suivi d’autant de commandes de chargement en séquence. Les commandes de chargement sont la façon dont un fichier Mach-O décrit tout ce dont le chargeur a besoin : quels segments mapper en mémoire, quelles bibliothèques dynamiques lier, où se trouve le point d’entrée. C’est une idée semblable aux chunks de PNG : un en-tête fixe, puis une suite d’enregistrements auto-descriptifs, chacun indiquant au lecteur combien il faut sauter pour atteindre le suivant.
Regarder cela vous-même
Rien de tout cela ne nécessite d’écrire un analyseur. Ouvrez n’importe quel fichier PNG, ZIP ou Mach-O dans Hexter et l’onglet Analyser reconnaît le format automatiquement, parcourant la structure réelle de chunks ou de commandes de chargement et l’affichant sous forme d’arborescence à côté de l’hexadécimal brut, pour que vous puissiez cliquer sur un champ et voir exactement de quels octets il provient. C’est en lecture seule par défaut, donc faire cela sur un vrai fichier est réellement sans danger, un binaire d’application, une capture d’écran, une archive que vous avez téléchargée, sans aucun risque de l’altérer.
Si vous voulez plutôt vérifier ce qui précède à la main : ouvrez un PNG et vérifiez que les huit premiers octets correspondent à la signature, puis regardez les octets 8 à 11 (la longueur du premier chunk) et les octets 12 à 15 (son type, qui devrait se lire IHDR). C’est un exercice assez petit pour se faire en quelques minutes, et c’est une façon vraiment utile de comprendre un format de fichier que vous utilisez depuis toujours mais que vous n’avez jamais réellement regardé.