Cet outil permet d'obtenir un fichier .elf entièrement analysant à partir d'une image du noyau VMLinux / VMLINUZ / BZimage / Zimage (soit un blob binaire brut, soit un fichier .ell préexistant mais dépouillé), avec une fonction récupérée et des symboles variables.
Pour cela, il scanne votre noyau pour une table de symboles du noyau (kallsyms), une table de symboles compressée qui est présente dans presque tous les noyaux, principalement inchangés.
Parce que la table de symboles concernées est à l'origine comprimée, elle 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 à l'aide d'Ida Pro et Ghidra. Cet outil est donc utile pour l'ingénierie inverse des systèmes intégrés.
Usage:
./vmlinux-to-elf < input_kernel.bin > < output_kernel.elf > Installation à l'échelle du système (la deuxième commande peut ne pas être nécessaire car PIP doit trouver les dépendances dans le fichier setup.py ):
sudo apt install python3-pip liblzo2-dev
sudo pip3 install --upgrade lz4 zstandard git+https://github.com/clubby789/python-lzo@b4e39df
sudo pip3 install --upgrade git+https://github.com/marin-m/vmlinux-to-elfboot.img , en commençant par un ANDROID! ou UNCOMPRESSED_IMG magique [ok]Une brève histoire de la table de symboles "Kallsyms" peut être trouvée en haut du fichier "kallsyms_finder.py". En bref, cela a été introduit vers 2004 dans le noyau Linux dans sa forme actuelle et est utilisé pour imprimer les messages "oups du noyau", entre autres.
Il contient des tuples de "nom de symbole", "adresse de symbole", "type de symbole" (types de symboles désignés avec une seule lettre d'une manière similaire à l'utilitaire nm ), ces informations étant étroitement remplies d'un algorithme de compression simple.
Le schéma ci-dessous affiche comment ces informations sont sérialisées dans le noyau, le décalage de chaque structure respective détectée par vmlinux-to-elf à travers l'heuristique:
| Nom du tableau | Description | Échantillons de contenu |
|---|---|---|
kallsyms_addresses (ou kallsyms_offsets + kallsyms_relative_base ) | Les adresses (ou compensent par rapport à une base, dans les noyaux récents) de chaque symbole, comme un 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, comme entier (utile pour vérifier l'endienne, l'alignement, le décodage correct du tableau des symboles) | 54 D4 00 00 |
kallsyms_names | Le symbole comprimé et séparé par la longueur se nomme eux-mêmes. Chaque octet dans les chaînes de symboles compressées fait référence à un index dans le tableau "kallsyms_token_index", qui fait référence en elle-même le décalage d'un fragment de caractère ou 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 recherche servant à trouver rapidement le décalage approximatif d'un nom de symbole comprimé dans "Kallsyms_Names": tous les 256 symboles, un décalage du symbole concerné dans "Kallsyms_Names" est ajouté comme un long à ce tableau. | 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 recherche (présente dans 6.2+ noyaux uniquement) contient une séquence de tableau d'entiers emballés de 3 octets, où les index de tableau correspondent à l'ordre alphanumérique pour un nom de symbole donné, et les valeurs du tableau correspondent aux index d'entrée correspondants dans les index kallsyms_addresses et kallsyms_names | |
kallsyms_token_table | Fragments de chaîne à terminaison nulle ou caractères qui peuvent être contenus dans les noms de symboles du noyau. Cela peut contenir au plus 256 fragments ou caractères de chaîne. Les index correspondant aux points de code ASCII qui sont réellement utilisés dans n'importe quel symbole de noyau correspondent au caractère ASCII concerné, d'autres positions contiendront un fragment de chaîne sélectionné statistiquement. Cet outil essaie de trouver heuristiquement ce tableau sur le fichier passé d'abord afin de trouver la table des 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, chaque mappage des décalages des caractères ou des fragments de chaîne 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 ... |
Ces champs ont une alignement variable et une taille de champ. Les tailles de champ peuvent également varier par rapport à l'architecture et à la version du noyau. Pour cette raison, vmlinux-to-elf a été testé dans une variété de cas.
OpenWRT depuis 2013 dispose d'un correctif qui supprime la compression sur la table kallsyms par défaut (lorsque la construction kallsyms a été activée par l'utilisateur). Ils le font afin d'économiser de l'espace lors de la récompression sur le noyau à l'aide de LZMA.
Cela signifie que les entrées kallsyms_token_table et kallsyms_token_address disparaissent et que les noms de symbole utilisent plutôt le texte brut ASCII. Ce cas est également pris en charge.
Dans les noyaux Linux 6.2 standard, les tableaux kallsyms sont codés dans l'ordre suivant:
kallsyms_addresses (ou kallsyms_offsets + kallsyms_relative_base )kallsyms_num_symskallsyms_nameskallsyms_markerskallsyms_seqs_of_names (6.2+ seulement)kallsyms_token_tablekallsyms_token_indexPour les noyaux Linux 6.4+, cette disposition est changée en:
kallsyms_num_symskallsyms_nameskallsyms_markerskallsyms_token_tablekallsyms_token_indexkallsyms_addresses (ou kallsyms_offsets + kallsyms_relative_base )kallsyms_seqs_of_names Bien que ceux-ci soient analysés dans l'ordre suivant par l'algorithme d'analyse de vmlinux-to-elf :
kallsyms_token_table (structure avant la dernière-la-dernière)kallsyms_token_index (dernière structure, attaquants)kallsyms_markers (en arrière)kallsyms_names (à nouveau en arrière)kallsyms_num_syms (à nouveau en arrière)kallsyms_addresses (ou kallsyms_offsets + kallsyms_relative_base ) (à nouveau en arrière) Il devrait prendre en charge les noyaux de la version 2.6.10 (décembre 2004), jusqu'au 6.4 actuel (en août 2023). Seuls les noyaux configurés explicitement sans CONFIG_KALLSYMS ne doivent pas être pris en charge. Si cette variable de configuration du noyau n'a pas été définie sur build, alors vous obtiendrez: KallsymsNotFoundException: No embedded symbol table found in this kernel .
Pour les grains bruts, les architectures suivantes peuvent être détectées (en utilisant des magiques de Binwalk): Mipsel, MIPSEB, Armel, Armeb, PowerPC, SPARC, X86, X86-64, ARM64, MIPS64, Superh, Arc.
Les formats de compression du noyau suivants peuvent être détectés automatiquement: XZ, LZMA, GZIP, BZ2, LZ4, LZO et ZSTD.
Vous pouvez également obtenir une sortie en texte uniquement des noms, des adresses et des types de symboles du noyau en utilisant l'utilitaire kallsyms-finder , également emballé avec cet outil. Le format de sa sortie sera similaire au fichier /proc/kallsyms procfs.
Certains paramètres qui doivent être automatiquement déduits par l'outil (tels que l'ensemble 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é 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]
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
optional arguments:
-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)
$ kallsyms-finder -h
usage: kallsyms-finder [-h] [--bit-size BIT_SIZE] input_file
Find the kernel's embedded symbol table from a raw or stripped ELF kernel
file, and print these to the standard output with their addresses
positional arguments:
input_file Path to the kernel file to extract symbols from
optional arguments:
-h, --help show this help message and exit
--bit-size BIT_SIZE Force overriding the input kernel bit size, providing
32 or 64 bit (rather than auto-detect)
N'hésitez pas à ouvrir un problème pour toute suggestion d'amélioration.