
Uno strumento per recuperare un .ELF completamente analizzabile da un kernel grezzo, estraendo la tabella dei simboli del kernel (kallsyms)
Questo strumento consente di ottenere un file .ELF completamente analizzabile da un'immagine kernel vmlinux/vmlinuz/bzImage/zImage (sia un blob binario grezzo che un file .ELF preesistente ma privo di simboli), con simboli di funzioni e variabili recuperati.
A tale scopo, esegue una scansione del kernel per individuare una tabella dei simboli del kernel (kallsyms), una tabella dei simboli compressa presente in quasi tutti i kernel, per lo più invariata.
Poiché la tabella dei simboli in questione è originariamente compressa, dovrebbe recuperare stringhe che non sono visibili nel binario originale.
Produce un file .ELF che è possibile analizzare con IDA Pro e Ghidra. Questo strumento è quindi utile per il reverse engineering di sistemi embedded.
Utilizzo:
# Command line:
vmlinux-to-elf <input_kernel.bin> <output_kernel.elf>
# Command line, list symbol addresses only:
kallsyms-finder <input_kernel.bin> # If installed with uv
vmlinux-to-elf.kallsyms-finder # If installed with snap
# Command line, just decompress the kernel:
vmlinuz-decompressor <input_kernel.bin> <output_kernel.bin> # If installed with uv
vmlinux-to-elf.vmlinuz-decompressor # If installed with snap
# Graphical:
vmlinux-to-elf-gui # If installed with uv
vmlinux-to-elf.gui # If installed with snap
flatpak run re.fossplant.vmlinux-to-elf # If installed with flatpak
Installazione:
# Install CLI+GUI with Snap (recommended on Ubuntu)
sudo snap install vmlinux-to-elf
# Install CLI+GUI with yay (recommended on Arch, Manjaro)
yay -S vmlinux-to-elf libadwaita python-gobject
# Install CLI+GUI with uv (example with 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 # Install .desktop file
# Install CLI with uv and GUI with Flatpak (recommended on
# distributions with 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
Configurazione dell'ambiente di sviluppo locale:
sudo snap install --classic astral-uv
sudo apt install git
git clone [email protected]:marin-m/vmlinux-to-elf.git
# Dependencies for the GTK-4 GUI
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/
# Download Python modules and initialize virtualenv (creates ".venv",
# call "source .venv/bin/activate" to set up)
uv sync --extra gui
# Add vmlinux-to-elf to $PATH, so that the commands are callable
# system-wide (creates a symlink to the source in "~/.local/bin")
uv tool install -e .[gui]
boot.img Android, che iniziano con una magic ANDROID! o UNCOMPRESSED_IMG [OK]Una breve storia della tabella dei simboli "kallsyms" si trova all'inizio del file "kallsyms.py". In breve, è stata introdotta nel kernel Linux nella sua forma attuale intorno al 2004 e viene utilizzata, tra le altre cose, per stampare i messaggi "Kernel oops".
Contiene tuple di "nome simbolo", "indirizzo simbolo", "tipo simbolo" (i tipi di simbolo sono designati con una singola lettera in modo simile all'utility nm); queste informazioni sono compattate con un semplice algoritmo di compressione.
Lo schema seguente mostra come queste informazioni vengono serializzate nel kernel; l'offset di ciascuna struttura viene rilevato da vmlinux-to-elf tramite euristiche:
Questi campi hanno allineamento e dimensione variabili. Anche le dimensioni dei campi possono variare in base all'architettura e alla versione del kernel. Per questo motivo, vmlinux-to-elf è stato testato su una varietà di casi.
OpenWRT dal 2013 ha una patch che rimuove la compressione della tabella kallsyms per impostazione predefinita (quando la compilazione di kallsyms è stata abilitata dall'utente). Lo fanno per risparmiare spazio quando si ricomprime il kernel con LZMA.
Ciò significa che le voci kallsyms_token_table e kallsyms_token_address scompaiono e che i nomi dei simboli utilizzano invece ASCII in testo semplice. Anche questo caso è supportato.
Nei kernel Linux 6.2 standard, le array kallsyms sono codificate nel seguente ordine:
kallsyms_addresses (o kallsyms_offsets + kallsyms_relative_base)kallsyms_num_symskallsyms_nameskallsyms_markerskallsyms_seqs_of_names (solo 6.2+)kallsyms_token_tablekallsyms_token_indexPer i kernel Linux 6.4+, questo layout cambia in:
kallsyms_num_symskallsyms_nameskallsyms_markerskallsyms_token_tablekallsyms_token_indexkallsyms_addresses (o kallsyms_offsets + kallsyms_relative_base)kallsyms_seqs_of_namesQueste vengono invece analizzate nel seguente ordine dall'algoritmo di parsing di vmlinux-to-elf:
kallsyms_token_table (penultima struttura)kallsyms_token_index (ultima struttura, in avanti)kallsyms_markers (all'indietro)kallsyms_names (di nuovo all'indietro)kallsyms_num_syms (di nuovo all'indietro)kallsyms_addresses (o kallsyms_offsets + kallsyms_relative_base) (di nuovo all'indietro)Dovrebbe supportare kernel dalla versione 2.6.10 (dicembre 2004) fino all'attuale 6.4 (ad agosto 2023). Solo i kernel configurati esplicitamente senza CONFIG_KALLSYMS non dovrebbero essere supportati. Se questa variabile di configurazione del kernel non è stata impostata in fase di compilazione, si otterrà: KallsymsNotFoundException: No embedded symbol table found in this kernel.
Per i kernel grezzi, è possibile rilevare le seguenti architetture (utilizzando le magic di binwalk): MIPSEL, MIPSEB, ARMEL, ARMEB, PowerPC, SPARC, x86, x86-64, ARM64, MIPS64, SuperH, ARC.
I seguenti formati di compressione del kernel possono essere rilevati automaticamente: XZ, LZMA, GZip, BZ2, LZ4, LZO e Zstd.
È inoltre possibile ottenere un output solo testo dei nomi, degli indirizzi e dei tipi dei simboli del kernel utilizzando l'utility kallsyms-finder, inclusa anch'essa in questo strumento. Il formato del suo output sarà simile al file procfs /proc/kallsyms.
Alcuni parametri che dovrebbero essere dedotti automaticamente dallo strumento (come il set di istruzioni o l'indirizzo base) possono essere sovrascritti in caso di problemi. La specifica completa degli argomenti che consentono di farlo è presentata di seguito:
$ 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
Non esitare ad aprire una issue per qualsiasi suggerimento di miglioramento.
Ti preghiamo di privilegiare le issue e le pull request del repository GitHub attuale per segnalare bug, fare domande, ecc.
In alternativa, puoi usare questo canale Matrix se hai bisogno di contattare direttamente l'autore del progetto, ma ti preghiamo di riservarlo come canale secondario, ad esempio per l'invio di campioni di kernel; qualsiasi altro contenuto rischia altrimenti di andare perso.
| Nome array | Descrizione | Contenuti di esempio |
|---|
kallsyms_addresses (o kallsyms_offsets + kallsyms_relative_base) | Gli indirizzi (o offset relativi a una base, nei kernel recenti) di ciascun simbolo, come array | 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 | Il numero totale di simboli, come intero (utile per verificare endianness, allineamento e corretta decodifica della tabella dei simboli) | 54 D4 00 00 |
kallsyms_names | I nomi dei simboli compressi, separati per lunghezza. Ogni byte nelle stringhe dei simboli compressi fa riferimento a un indice nell'array "kallsyms_token_index", che a sua volta fa riferimento all'offset di un carattere o frammento di stringa nell'array "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 | Una tabella di ricerca che consente di trovare rapidamente l'offset approssimativo di un nome di simbolo compresso in "kallsyms_names": ogni 256 simboli, viene aggiunto a questa tabella un offset (come long) relativo al simbolo interessato in "kallsyms_names". | 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 | Questa tabella di ricerca (presente solo nei kernel 6.2+) contiene una sequenza di array di interi compattati a 3 byte, dove gli indici dell'array corrispondono all'ordine alfanumerico per un determinato nome di simbolo, e i valori dell'array corrispondono agli indici delle voci corrispondenti nelle array kallsyms_addresses e kallsyms_names | |
kallsyms_token_table | Frammenti di stringa o caratteri terminati da null che possono essere contenuti nei nomi dei simboli del kernel. Può contenere al massimo 256 frammenti di stringa o caratteri. Gli indici corrispondenti ai punti di codice ASCII effettivamente usati in un qualsiasi simbolo del kernel corrisponderanno al carattere ASCII interessato, mentre le altre posizioni conterranno un frammento di stringa scelto statisticamente. Questo strumento cerca di individuare euristicamente questa array nel file fornito per prima cosa, al fine di trovare la tabella dei simboli 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 word, ciascuna associata agli offset dei caratteri o frammenti di stringa designati dai rispettivi indici in "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 ... |