J'essaie de désassembler un fichier composé composé de plusieurs parties, dont l'une est un noyau non compressé pris en sandwich entre plusieurs autres fichiers. J'essaie de trouver la longueur exacte de la partie noyau, ce qui s'avère difficile.
Y a-t-il une indication dans l'en-tête vmlinux de la quantité de données que le chargeur de démarrage est censé lire avant de s'exécuter, ou est-il supposé que tout le contenu du fichier vmlinux doit être chargé lors du transfert depuis le chargeur de démarrage ?
Réponse acceptée :
La réponse rapide est "non", mais s'il s'agit d'une image ELF, avec un peu de piratage, vous pouvez probablement trouver le noyau. Voir le readelf
pirater ci-dessous.
Le chargeur de démarrage est chargé de connaître le format de tout fichier dans lequel résident le noyau et le système de fichiers racine. Cela inclut la connaissance de la taille du fichier du noyau, quel que soit son format. Sur PowePC et Blackfin, le chargeur de démarrage est chargé de décompresser l'intégralité du noyau s'il est compressé et de l'écrire à son emplacement final dans la RAM. Sur ARM, le noyau peut se décompresser automatiquement et le chargeur de démarrage n'a qu'à copier le fichier brut du noyau dans un emplacement pratique de la RAM et lancer l'exécution.
Si le noyau se décomprime automatiquement, les symboles qui indiquent la taille du fichier du noyau compressé peuvent ou non se trouver quelque part dans le code de décompression au début du fichier, selon l'algorithme de décompression utilisé, mais vous n'avez aucun moyen de savoir où sans carte de liaison pour la construction spécifique du noyau. Le chargeur de démarrage n'a certainement aucun moyen de le savoir.
Le code du noyau non compressé lui-même est entouré de deux symboles, _stext
et _end
dont les adresses sont le début et la fin du noyau lui-même, mais n'incluent pas l'étendue de tout initramfs inclus, si un initramfs a été lié au binaire du noyau. L'étendue de l'initramfs est définie par l'éditeur de liens dans deux symboles du noyau, __initramfs_start
et __initramfs_end
. Les chargeurs de démarrage n'ont généralement pas la capacité de lire la table des symboles du noyau (elle se trouve dans le System.map
file), et sans cette capacité, ils n'auraient aucun moyen de savoir où le _end
et __initrams_end
les symboles sont dans le fichier du noyau. Autrement dit, la position des symboles n'est pas un décalage fixe par rapport au début du fichier binaire. Il est déterminé au moment de la liaison et peut varier en fonction de la configuration de la construction du noyau.
Pour un noyau non compressé au format ELF, vous pouvez probablement identifier le début du fichier vmlinux en recherchant l'en-tête ELF (177 E L F
dans le od -c
dump du fichier composé). Vous pouvez alors faire readelf -e
ou objdump -h
sur le reste du fichier à partir de ce point pour trouver la section avec le décalage de fichier le plus élevé (.shstrtab
). Ajoutez la taille de la section à ce décalage et cela vous amène à la fin de vmlinux. J'ai testé cette méthode en utilisant un vmlinux PPC non dépouillé et j'ai obtenu une taille qui correspondait exactement à la taille du fichier vnlinux autonome. Après avoir supprimé le noyau, cette méthode a donné un résultat inférieur de 1 283 octets à la taille de l'image supprimée.
Les systèmes embarqués utilisent généralement un format de fichier tel que mkimage
pour emballer le noyau, rootfs, l'arborescence des périphériques et d'autres composants. U-boot, par exemple, est compatible avec mkimage, il sait donc où commence et se termine le binaire du noyau dans le fichier mkimage et il sait si le noyau est compressé ou non et à quelle adresse RAM écrire le fichier du noyau.