
FLAREチームによる、共通中間言語(CIL)命令を逆アセンブルするためのオープンソースライブラリ。

dncil は、Python で書かれた共通中間言語 (CIL) 逆アセンブリライブラリであり、.NET マネージドメソッドのヘッダー、命令、例外ハンドラの解析をサポートしています。解析されたデータはオブジェクト指向 API を通じて公開され、dncil を使用して CIL 解析ツールを迅速に開発するのに役立ちます。
なぜ Python なのか? CIL 逆アセンブリをサポートする既存のライブラリ(dnLib など)は C# で書かれています。これらのツールを活用するには、C# アプリケーションを構築する必要があり、C# の開発経験が必要です。純粋な Python の代替である dncil を使用すると、次のことが可能です:
CIL をプログラム的に解析するために C# の経験は必要ありません。CIL 解析ツールを迅速に開発およびテストできます。CIL 解析ツールを既存の Python プロジェクトと簡単に統合できます。サンプルスクリプト print_cil_from_dn_file.py は、dncil と .NET 解析ライブラリ dnfile を併用して、.NET 実行ファイル内のマネージドメソッドを逆アセンブルします。何ができるか見てみましょう。
まず、次の C# ソースコードをコンパイルします。
using System;
public class HelloWorld
{
public static void Main(string[] args)
{
Console.WriteLine ("Hello World!");
}
}
コンパイルすると、.NET メタデータを含む PE 実行ファイルが生成されます。このメタデータは、Common Language Runtime (CLR) にコードの実行方法を指示します。dnfile を使用してこのメタデータを解析し、マネージドメソッド Main のオフセットを取得します。次に、dncil を使用して、この場所に格納されている CIL 命令を逆アセンブルして表示します。
上記の動作を見てみましょう。
$ python scripts/print_cil_from_dn_file.py hello-world.exe
Method: Main
0000 00 nop
0001 72 01 00 00 70 ldstr "Hello World!"
0006 28 04 00 00 0a call System.Console::WriteLine
000B 00 nop
000C 2a ret
メソッド Main は、CilMethodBody クラスによって表現されます。このクラスは、指定されたマネージドメソッドのヘッダー、CIL 命令、例外ハンドラを含むデータを保持します。また、さまざまなヘルパー関数を公開しています。
> main_method_body.flags
SmallFormat : false
TinyFormat : false
FatFormat : false
TinyFormat1 : true
MoreSects : false
InitLocals : false
CompressedIL : false
> main_method_body.size
14
> hexdump.hexdump(main_method_body.get_bytes())
00000000: 36 00 72 01 00 00 70 28 04 00 00 0A 00 2A 6.r...p(.....*
> hexdump.hexdump(main_method_body.get_header_bytes())
00000000: 36 6
> hexdump.hexdump(main_method_body.get_instruction_bytes())
00000000: 00 72 01 00 00 70 28 04 00 00 0A 00 2A .r...p(.....*
マネージドメソッド Main 内の各 CIL 命令は、Instruction クラスによって表現されます。このクラスは、指定された CIL 命令のオフセット、ニーモニック、オペコード、オペランドを含むデータを保持します。また、さまざまなヘルパー関数を公開しています。
> len(main_method_body.instructions)
5
> insn = main_method_body.instructions[1]
> insn.offset
1
> insn.mnemonic
'ldstr'
> insn.operand
token(0x70000001)
> insn.is_ldstr()
True
> insn.size
5
> hexdump.hexdump(insn.get_bytes())
00000000: 72 01 00 00 70 r...p
> hexdump.hexdump(insn.get_opcode_bytes())
00000000: 72 r
> hexdump.hexdump(insn.get_operand_bytes())
00000000: 01 00 00 70 ...p
dncil をインストールするには、pip を使用して dncil モジュールを取得します。
$ pip install dncil
サンプルスクリプトを実行するには、dnfile をインストールしてください。あるいは、下記の Development セクションで説明されている開発用依存関係とともに dncil をインストールします。
.NET マネージドメソッドを含むバイトストリーム内の CIL 命令を出力する dncil の簡単な例については、print_cil_from_bytes.py を参照してください。
dncil のソースコードをレビューまたは変更する場合は、GitHub からダウンロードしてローカルにインストールする必要があります。
次のコマンドを使用して、開発用依存関係とともに dncil をローカルにインストールします。
$ pip install /local/path/to/src[dev]
テストとリンティングを実行するには、以下で説明する dncil の開発用依存関係が必要です。
次のコマンドでテストを実行します。
$ pytest /local/path/to/src/tests
次のコマンドでフォーマットエラーを特定します。
$ black -l 120 -c /local/path/to/src
$ isort --profile black --length-sort --line-width 120 -c /local/path/to/src
$ mypy --config-file /local/path/to/src/.github/mypy/mypy.ini /local/path/to/src/dncil/ /local/path/to/src/scripts/ /local/path/to/src/tests/
dncil は、dnLib にある CIL 解析コードに基づいています。