
Un outil pour récupérer un .ELF entièrement analysable à partir d'un noyau brut, en extrayant la table des symboles du noyau (kallsyms)
Cet outil permet d'obtenir un fichier .ELF entièrement analysable à partir d'une image kernel vmlinux/vmlinuz/bzImage/zImage (qu'il s'agisse d'un blob binaire brut ou d'un fichier .ELF préexistant mais dépouillé de ses symboles), avec les symboles de fonctions et de variables récupérés.
Pour ce faire, il analyse votre kernel à la recherche d'une table de symboles kernel (kallsyms), une table de symboles compressée présente dans presque tous les kernels, la plupart du temps non modifiée.
Comme la table de symboles concernée est compressée à l'origine, il devrait récupérer des chaînes qui ne sont pas visibles dans le binaire d'origine.
Il produit un fichier .ELF que vous pouvez analyser avec IDA Pro et Ghidra. Cet outil est donc utile pour la rétro-ingénierie de systèmes embarqués.
Utilisation :
# Ligne de commande :
vmlinux-to-elf <input_kernel.bin> <output_kernel.elf>
# Ligne de commande, lister uniquement les adresses des symboles :
kallsyms-finder <input_kernel.bin> # Si installé avec uv
vmlinux-to-elf.kallsyms-finder # Si installé avec snap
# Ligne de commande, décompresser simplement le kernel :
vmlinuz-decompressor <input_kernel.bin> <output_kernel.bin> # Si installé avec uv
vmlinux-to-elf.vmlinuz-decompressor # Si installé avec snap
# Interface graphique :
vmlinux-to-elf-gui # Si installé avec uv
vmlinux-to-elf.gui # Si installé avec snap
flatpak run re.fossplant.vmlinux-to-elf # Si installé avec flatpak
Installation :
# Installer CLI+GUI avec Snap (recommandé sur Ubuntu)
sudo snap install vmlinux-to-elf
# Installer CLI+GUI avec yay (recommandé sur Arch, Manjaro)
yay -S vmlinux-to-elf libadwaita python-gobject
# Installer CLI+GUI avec uv (exemple avec Fedora)
sudo dnf install -y uv glib2-devel libadwaita-devel gtk4-devel \
gobject-introspection-devel python3-gobject-devel \
python3-devel cairo-devel @development-tools
uv tool install vmlinux-to-elf[gui]
vmlinux-to-elf-gui --install-metadata # Installer le fichier .desktop
# Installer CLI avec uv et GUI avec Flatpak (recommandé sur
# les distributions avec libadwaita < 1.6)
sudo dnf install -y uv flatpak @development-tools
uv tool install vmlinux-to-elf
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
flatpak install re.fossplant.vmlinux-to-elf
Configuration de l'environnement de développement local :
sudo snap install --classic astral-uv
sudo apt install git
git clone [email protected]:marin-m/vmlinux-to-elf.git
# Dépendances pour l'interface graphique GTK-4
sudo apt install libgirepository-2.0-dev libadwaita-1-dev \
gir1.2-adw-1 gir1.2-gtk-4.0 python3-dev blueprint-compiler
cd vmlinux-to-elf
cp -a .github/hooks/* .git/hooks/
# Télécharger les modules Python et initialiser virtualenv (crée « .venv »,
# appeler « source .venv/bin/activate » pour l'activer)
uv sync --extra gui
# Ajouter vmlinux-to-elf au $PATH, afin que les commandes soient appelables
# à l'échelle du système (crée un lien symbolique vers la source dans « ~/.local/bin »)
uv tool install -e .[gui]
boot.img, commençant par une signature magique ANDROID! ou UNCOMPRESSED_IMG [OK]Un bref historique de la table de symboles « kallsyms » se trouve en haut du fichier « kallsyms.py ». En bref, elle a été introduite vers 2004 dans le kernel Linux sous sa forme actuelle et sert, entre autres, à afficher les messages « Kernel oops ».
Elle contient des tuples « nom du symbole », « adresse du symbole », « type du symbole » (les types de symboles étant désignés par une seule lettre, d'une manière similaire à l'utilitaire nm), ces informations étant densément empaquetées avec un algorithme de compression simple.
Le schéma ci-dessous montre comment ces informations sont sérialisées dans le kernel, le décalage de chaque structure respective étant détecté par vmlinux-to-elf via des heuristiques :
Ces champs ont un alignement et une taille de champ variables. Les tailles de champs peuvent également varier selon l'architecture et la version du kernel. Pour cette raison, vmlinux-to-elf a été testé sur une variété de cas.
OpenWRT depuis 2013 dispose d'un patch qui supprime la compression de la table kallsyms par défaut (lorsque la compilation de kallsyms a été activée par l'utilisateur). Ils font cela afin d'économiser de l'espace lors de la recompression du kernel avec LZMA.
Cela signifie que les entrées kallsyms_token_table et kallsyms_token_address disparaissent et que les noms de symboles utilisent du texte ASCII brut à la place. Ce cas est également pris en charge.
Dans les kernels Linux 6.2 standard, les tableaux kallsyms sont encodés dans l'ordre suivant :
kallsyms_addresses (ou kallsyms_offsets + kallsyms_relative_base)kallsyms_num_symskallsyms_nameskallsyms_markerskallsyms_seqs_of_names (uniquement 6.2+)kallsyms_token_tablekallsyms_token_indexPour les kernels Linux 6.4+, cette disposition est modifiée comme suit :
kallsyms_num_symskallsyms_nameskallsyms_markerskallsyms_token_tablekallsyms_token_indexkallsyms_addresses (ou kallsyms_offsets + kallsyms_relative_base)kallsyms_seqs_of_namesTandis qu'ils sont analysés dans l'ordre suivant par l'algorithme d'analyse de vmlinux-to-elf :
kallsyms_token_table (avant-dernière structure)kallsyms_token_index (dernière structure, en avant)kallsyms_markers (en arrière)kallsyms_names (encore en arrière)kallsyms_num_syms (encore en arrière)kallsyms_addresses (ou kallsyms_offsets + kallsyms_relative_base) (encore en arrière)Il devrait prendre en charge les kernels de la version 2.6.10 (décembre 2004) jusqu'à la version actuelle 6.4 (en date d'août 2023). Seuls les kernels explicitement configurés sans CONFIG_KALLSYMS ne devraient pas être pris en charge. Si cette variable de configuration du kernel n'a pas été définie lors de la compilation, vous obtiendrez : KallsymsNotFoundException: No embedded symbol table found in this kernel.
Pour les kernels bruts, les architectures suivantes peuvent être détectées (en utilisant les signatures magiques de binwalk) : MIPSEL, MIPSEB, ARMEL, ARMEB, PowerPC, SPARC, x86, x86-64, ARM64, MIPS64, SuperH, ARC.
Les formats de compression de kernel suivants peuvent être automatiquement détectés : XZ, LZMA, GZip, BZ2, LZ4, LZO et Zstd.
Vous pouvez également obtenir une sortie textuelle uniquement des noms, adresses et types de symboles du kernel en utilisant l'utilitaire kallsyms-finder, également fourni avec cet outil. Le format de sa sortie sera similaire au fichier procfs /proc/kallsyms.
Certains paramètres qui devraient être automatiquement déduits par l'outil (tels que le jeu d'instructions ou l'adresse de base) peuvent être remplacés en cas de problème. La spécification complète des arguments permettant de le faire est présentée ci-dessous :
$ vmlinux-to-elf -h
usage: vmlinux-to-elf [-h] [--e-machine DECIMAL_NUMBER] [--bit-size BIT_SIZE]
[--file-offset HEX_NUMBER] [--base-address HEX_NUMBER]
[--bss-size BSS_SIZE] [--use-absolute]
input_file output_file
Turn a raw or compressed kernel binary, or a kernel ELF without symbols, into a fully analyzable ELF whose symbols were extracted from the kernel symbol table
positional arguments:
input_file Path to the vmlinux/vmlinuz/zImage/bzImage/kernel.bin/kernel.elf file to make into an analyzable .ELF
output_file Path to the analyzable .ELF to output
options:
-h, --help show this help message and exit
--e-machine DECIMAL_NUMBER
Force overriding the output ELF "e_machine" field with this integer value (rather than auto-detect)
--bit-size BIT_SIZE Force overriding the input kernel bit size, providing 32 or 64 bit (rather than auto-detect)
--file-offset HEX_NUMBER
Consider that the raw kernel starts at this offset of the provided raw file or compressed stream (rather than 0, or the beginning of the ELF
sections if an ELF header was present in the input)
--base-address HEX_NUMBER
Force overriding the output ELF base address field with this integer value (rather than auto-detect)
--bss-size BSS_SIZE Size in megabytes of the .bss section in the binary
--use-absolute Assume kallsyms offsets are absolute addresses
N'hésitez pas à ouvrir un ticket pour toute suggestion d'amélioration.
Veuillez privilégier en priorité les tickets et les pull requests du dépôt Github actuel pour signaler des bugs, poser des questions, etc.
Vous pouvez également utiliser ce canal matrix si vous avez besoin de contacter directement l'auteur du projet, mais veuillez réserver cela comme canal secondaire, par exemple pour envoyer des échantillons de kernels ; ce qui y est envoyé autrement risque plus probablement d'être perdu.
| Nom du tableau | Description | Exemple de contenu |
|---|
kallsyms_addresses (ou kallsyms_offsets + kallsyms_relative_base) | Les adresses (ou les décalages relatifs à une base, dans les kernels récents) de chaque symbole, sous forme de tableau | 80 82 00 C0 80 82 00 C0 80 82 00 C0 0C 84 00 C0 B4 84 00 C0 5C 85 00 C0 60 85 00 C0 60 85 00 C0 ... |
kallsyms_num_syms | Le nombre total de symboles, sous forme d'entier (utile pour vérifier l'endianness, l'alignement et le décodage correct de la table de symboles) | 54 D4 00 00 |
kallsyms_names | Les noms de symboles compressés eux-mêmes, séparés par leur longueur. Chaque octet des chaînes de symboles compressées référence un index dans le tableau « kallsyms_token_index », qui référence lui-même le décalage d'un caractère ou d'un fragment de chaîne dans le tableau « kallsyms_token_table ». | 09 54 64 6F 5F E1 F1 66 F5 25 05 54 F3 74 AB 74 0E 54 FF AB ... |
kallsyms_markers | Une table de correspondance permettant de trouver rapidement le décalage approximatif d'un nom de symbole compressé dans « kallsyms_names » : tous les 256 symboles, un décalage vers le symbole concerné dans « kallsyms_names » est ajouté à cette table sous forme d'un long. | 00 00 00 00 03 0C 00 00 0C 18 00 00 1B 24 00 00 0F 31 00 00 DA 3D 00 00 CF 4A 00 00 ... |
kallsyms_seqs_of_names | Cette table de correspondance (présente uniquement dans les kernels 6.2+) contient une séquence de tableaux d'entiers compressés de 3 octets, où les index du tableau correspondent à l'ordre alphanumérique d'un nom de symbole donné, et les valeurs du tableau correspondent aux index d'entrée correspondants dans les tableaux kallsyms_addresses et kallsyms_names | |
kallsyms_token_table | Fragments de chaînes ou caractères terminés par un octet nul pouvant être contenus dans les noms de symboles du kernel. Cela peut contenir au maximum 256 fragments de chaînes ou caractères. Les index correspondant aux points de code ASCII réellement utilisés dans un symbole du kernel correspondront au caractère ASCII concerné, les autres positions contenant un fragment de chaîne choisi statistiquement. Cet outil tente d'abord de trouver ce tableau de manière heuristique dans le fichier fourni afin de trouver la table de symboles kallsyms. | 73 69 00 67 70 00 74 74 00 79 6E 00 69 6E 74 5F 00 66 72 00 ... |
kallsyms_token_index | 256 mots, chacun correspondant aux décalages des caractères ou fragments de chaînes désignés par leurs index respectifs dans « kallsyms_token_table ». | 00 00 03 00 06 00 09 00 0C 00 11 00 14 00 1B 00 1E 00 22 00 2C 00 30 00 35 00 38 00 ... |