このツールを使用すると、vmlinux/vmlinuz/bzimage/zimageカーネル画像(生のバイナリブロブまたは既存の存在であるが削除されたファイル)から完全に分析可能な.elfファイルを取得できます。
このためには、カーネルシンボルテーブル(Kallsyms)をスキャンします。これは、ほとんどすべてのカーネルに存在する圧縮シンボルテーブルで、ほとんどが変更されていません。
関係するシンボルテーブルはもともと圧縮されているため、元のバイナリには見えない文字列を回収する必要があります。
IDA ProとGhidraを使用して分析できる.ELFファイルを生成します。したがって、このツールは、組み込みシステムリバースエンジニアリングに役立ちます。
使用法:
./vmlinux-to-elf < input_kernel.bin > < output_kernel.elf >システム全体のインストール(PIPがsetup.pyファイル内の依存関係を見つける必要があるため、2番目のコマンドは必要ない場合があります):
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ファイルを解除してくださいANDROID!またはUNCOMPRESSED_IMGマジック[OK]「Kallsyms_finder.py」ファイルの上部に「Kallsyms」シンボルテーブルの簡単な履歴があります。簡単に言えば、これは2004年頃にLinuxカーネルで現在の形で導入され、「カーネルのoop」メッセージなどの印刷に使用されます。
「シンボル名」、「シンボルアドレス」、「シンボルタイプ」( nmユーティリティと同様の方法で単一の文字で指定されているシンボルタイプ)のタプルが含まれており、この情報には単純な圧縮アルゴリズムがしっかりと詰め込まれています。
以下のスキーマは、この情報がカーネルにシリアル化されている方法を示しています。各構造のオフセットは、ヒューリスティックを通じて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シンボルごとに、「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 | このルックアップテーブル(6.2+カーネルのみに存在する)には、特定のシンボル名のアルファニュメーミュルオーダーと一致する配列インデックスが一致し、 kallsyms_addressesとkallsyms_namesアレイの対応するエントリインデックスとアレイの値が一致する詰め込まれた3バイト整数の配列シーケンスが含まれています。 | |
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さまざまなケースでテストされています。
2013年以降のOpenWRTには、デフォルトで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 (最後の構造前)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 。
生のカーネルの場合、Mipsel、Mipseb、Armel、Armeb、PowerPC、SPARC、X86、X86-64、ARM64、MIPS64、Superh、Arc。
次のカーネル圧縮形式は、XZ、LZMA、GZIP、BZ2、LZ4、LZO、ZSTDの自動的に検出できます。
また、このツールにバンドルされたkallsyms-finderユーティリティを使用して、カーネルのシンボル名、アドレス、タイプのテキストのみの出力を取得することもできます。出力の形式は/proc/kallsyms procfsファイルに似ています。
ツールによって自動的に推測されるべきパラメーター(命令セットやベースアドレスなど)は、発行の場合はオーバーライデンになる場合があります。それを行うことを許可する引数の完全な仕様を以下に示します。
$ 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)
改善の提案のために問題を開くことをheしないでください。