皆さんこんにちは、砂漠の果ての狼です。
本記事はDotnet9に初出し、dnSpyを使用してサードパーティの.NETライブラリのソースコードをデバッグする方法を紹介します。目次は以下の通りです。
- dnSpyのインストール
- サンプルプログラムの作成
- サンプルプログラムのデバッグ
- .NETライブラリのネイティブメソッドのデバッグ
- まとめ
1. dnSpyのインストール
dnSpyは強力な.NETプログラム逆コンパイルツールです。.NETプログラムを逆コンパイルでき、ライブラリのドキュメント機能の代わりとして、コードの紛失や破損があっても直接復元可能です。そのため、ソースコードが全くない状態でもプログラムを即座にデバッグでき、さらにプログラムを修正することもできます!
GitHubには実行可能なバイナリのダウンロード先と、ソースコードから自分でコンパイルする方法も用意されています。本記事では前者を使用します。GitHubアドレスは https://github.com/dnSpy/dnSpy です。

2. サンプルプログラムの作成
サンプルはデスクトッププログラムで、数字を入力すると右側に入力した数字が奇数か偶数かを表示します。

サンプルコードは比較的シンプルで、画面のバインディングとViewModelの関係は以下のスクリーンショットをご覧ください。

奇数・偶数の判定は、クラスTestToolのTellMeOddEvenメソッドが返します。表示結果をもう一度見てみると、あれ?0は奇数?1は偶数?
TestToolクラスは他のライブラリで定義されています。あなたはソースコードを持っていないと仮定しますね(実際には持っていますが)。

クラスの具体的な定義は以下の通りです。
namespace TestDll;
public class TestTool
{
public string TellMeOddEven(int number)
{
if (number % 2 == 1)
{
return $"{number}は偶数";
}
return $"{number}は奇数";
}
}
3. サンプルプログラムのデバッグ
dnSpyを開き、メインプログラムが参照するTestDllをドラッグ&ドロップします。

逆コンパイルされたコードが表示されます。

逆コンパイルされたメソッド定義は、サードパーティのソースコードと異なる場合があります。以下は、逆コンパイル結果が異なる原因となるいくつかの要因です。
コンパイラの最適化:コンパイラのバージョンによって異なる最適化(アルゴリズム、データ構造、コードの並び替えなど)が行われることがあります。その結果、逆コンパイルされたコードの構造や順序が変わることがあります。本記事のサンプルは.NET 8で開発されており、.NET Frameworkでコンパイルされたライブラリは元のソースとほぼ同じ結果になることがあります。
逆コンパイルツールの更新:dnSpy自体も新しい.NETバージョンやコンパイラの機能に合わせて更新されます。この更新により逆コンパイルのアルゴリズムや戦略が変わり、dnSpyのバージョンによって結果が異なることがあります。
コードは単純なため、ソースと逆コンパイルされたコードを比較すると、整数の引数を2で割った余りが1なら偶数、そうでなければ奇数と判定しています。もちろんこれは間違いですが、もしコードのロジックが複雑であれば、dnSpyを使ってデバッグできます。
テストプログラムを実行し、dnSpy内のメソッドにブレークポイントを設定し、デバッグメニューからテストプログラムにアタッチします。これはVisual Studioでの操作と似ています。

4. .NETライブラリメソッドのデバッグ
上記のサンプルプログラムのデバッグ方法は、他のサードパーティ.NETライブラリにも使用できます。では、.NET自身のライブラリメソッドはどうでしょうか?
方法は似ています。.NETライブラリの該当クラス、該当メソッドを見つけ、対象プログラムを実行し、ブレークポイントを設定します。.NETライブラリのメソッドを見つけるには、【ファイル】→【GACから開く】をクリックし、対象のライブラリを検索してダブルクリックし、次に目的のメソッドを探します。以降のデバッグ手順は同じです。

5. まとめ
- 技術交流やグループ参加については、ウェブマスターの微信ID:codewf をご追加ください。
- 記事内のサンプルコード:MultiVersionLibrary
dnSpyは非常に強力で、サードパーティのコードの変数の監視や値の変更など、Visual Studioで自分のプログラムを開発するのと同じように行えます。詳しい使い方は、記事の冒頭に記載したリンク https://github.com/dnSpy/dnSpy をご覧ください。こちらの先輩の記事もおすすめです:『神器如 dnSpy,无需源码也能修改 .NET 程序』。
そうそう、サンプルプログラムの奇数偶数判定が間違っています。ソースコードがないので修正したい場合はどうすればいいでしょうか?
この問題を解決するために、上記の先輩の記事をぜひお読みください。次回の記事では、サードパーティライブラリのインターセプトについて解説します。サードパーティライブラリを変更せずにメソッドのロジックや戻り値を変更することを実現できます。事前にこのスキルを学びましょう-.NET APIインターセプト技法をご覧ください。もちろん次回は新しい知識として、非パブリッククラスの非パブリックメソッドのインターセプト技法も紹介します。
元のリポジトリにあったdnSpyでサードパーティライブラリをデバッグする2つのGIF画像で本記事を締めくくります。

