
生のカーネルからカーネルシンボルテーブル(kallsyms)を抽出することで、完全に解析可能な.ELFを復元するツール
このツールは、vmlinux/vmlinuz/bzImage/zImage カーネルイメージ(生のバイナリブロブまたは既存のストリップ済み .ELF ファイル)から、関数および変数シンボルを復元した完全に解析可能な .ELF ファイルを取得することを可能にします。
そのために、このツールはカーネルシンボルテーブル(kallsyms)をカーネル内でスキャンします。これは、ほとんどすべてのカーネルにほぼそのままの形で存在する圧縮シンボルテーブルです。
対象のシンボルテーブルは元々圧縮されているため、元のバイナリでは見えない文字列も復元できるはずです。
出力は、IDA Pro や Ghidra で解析できる .ELF ファイルです。したがって、このツールは組み込みシステムのリバースエンジニアリングに役立ちます。
使用方法:
# 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
インストール:
# 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
ローカル開発環境のセットアップ:
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]
ANDROID! または UNCOMPRESSED_IMG マジックで始まる特定の種類の Android boot.img ファイルを展開する [OK]「kallsyms」シンボルテーブルの簡単な歴史は、「kallsyms.py」ファイルの冒頭にあります。簡単に言うと、これは約2004年に現在の形で Linux カーネルに導入され、とりわけ「Kernel oops」メッセージを表示するために使用されています。
このテーブルには「シンボル名」「シンボルアドレス」「シンボルタイプ」のタプルが含まれています(シンボルタイプは nm ユーティリティと同様に1文字で指定されます)。この情報は単純な圧縮アルゴリズムで密にパックされています。
以下のスキーマは、この情報がカーネル内にどのようにシリアライズされるかを示しています。各構造体のオフセットは vmlinux-to-elf によってヒューリスティックで検出されます。
| 配列名 | 説明 | サンプル内容 |
|---|---|---|
kallsyms_addresses (または kallsyms_offsets + kallsyms_relative_base) | 各シンボルのアドレス(最近のカーネルではベースからのオフセット)を配列として格納 | 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 | シンボルの総数を整数として格納(エンディアン、アライメント、シンボルテーブルの正しいデコードを確認するのに役立ちます) | 54 D4 00 00 |
kallsyms_names | 圧縮され、長さで区切られたシンボル名そのもの。圧縮されたシンボル文字列の各バイトは「kallsyms_token_index」配列のインデックスを参照し、そのインデックス自体は「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 | 「kallsyms_names」内の圧縮シンボル名のおおよそのオフセットを素早く見つけるためのルックアップテーブル。256シンボルごとに、対象シンボルへのオフセットが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 | このルックアップテーブル(6.2+ カーネルのみに存在)には、パックされた3バイト整数の配列シーケンスが含まれます。配列インデックスは特定のシンボル名のアルファベット順に対応し、配列値は kallsyms_addresses と kallsyms_names 配列の対応するエントリインデックスに対応します。 | |
kallsyms_token_table | カーネルシンボル名に含まれる可能性のある、ヌル終端の文字列フラグメントまたは文字。最大256個の文字列フラグメントまたは文字を含めることができます。任意のカーネルシンボルで実際に使用されるASCIIコードポイントに対応するインデックスは該当するASCII文字に対応し、他の位置には統計的に選択された文字列フラグメントが含まれます。このツールは、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個のワード。それぞれが「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 ... |
これらのフィールドは可変のアライメントとフィールドサイズを持ちます。フィールドサイズはアーキテクチャやカーネルのバージョンによっても異なる場合があります。そのため、vmlinux-to-elf はさまざまなケースでテストされています。
OpenWRT は2013年以降、デフォルトで kallsyms テーブルの圧縮を解除するパッチを適用しています(ユーザーが kallsyms のビルドを有効にした場合)。これは、LZMA を使用してカーネルを再圧縮する際にスペースを節約するためです。
つまり、kallsyms_token_table と kallsyms_token_address のエントリはなくなり、代わりにシンボル名はプレーンテキストの ASCII が使用されます。このケースもサポートされています。
標準的な Linux 6.2 カーネルでは、kallsyms 配列は次の順序でエンコードされています。
kallsyms_addresses (または kallsyms_offsets + kallsyms_relative_base)kallsyms_num_symskallsyms_nameskallsyms_markerskallsyms_seqs_of_names (6.2+ のみ)kallsyms_token_tablekallsyms_token_indexLinux 6.4+ カーネルでは、このレイアウトは次のように変更されています。
kallsyms_num_symskallsyms_nameskallsyms_markerskallsyms_token_tablekallsyms_token_indexkallsyms_addresses (または kallsyms_offsets + kallsyms_relative_base)kallsyms_seqs_of_names一方、vmlinux-to-elf の解析アルゴリズムはこれらを次の順序で解析します。
kallsyms_token_table (最後から2番目の構造)kallsyms_token_index (最後の構造、順方向)kallsyms_markers (逆方向)kallsyms_names (再度逆方向)kallsyms_num_syms (再度逆方向)kallsyms_addresses (または kallsyms_offsets + kallsyms_relative_base) (再度逆方向)バージョン 2.6.10(2004年12月)から現在の 6.4(2023年8月時点)までのカーネルをサポートします。サポートされないのは、CONFIG_KALLSYMS を明示的に無効化して構成されたカーネルのみです。このカーネル設定変数がビルド時に設定されていない場合、次のエラーが発生します: KallsymsNotFoundException: No embedded symbol table found in this kernel.