4

私は .NET については多少初心者ですが、プログラミングについては初心者ではありません。また、コンパイル済みの .NET コードを逆アセンブルすることについての傾向と興奮にやや戸惑っています。無意味に思えます。

.NET の高度な使いやすさが、私が .NET を使用する理由です。リソースが限られている環境で、C および実際の (ハードウェア プロセッサ) アセンブリを作成しました。それが、効率のために非常に多くの細心の注意を払うことに労力を費やす理由でした. .NET の世界では、実装の最も不可解な詳細を掘り下げて時間を無駄にすると、高レベルのオブジェクト指向言語を使用するという目的が無効になります。.NET を使用する過程で、通常のパフォーマンスの問題と奇妙な競合状態をデバッグしました。コンパイラが生成している中間言語について考えたことは一度もありませんでした。たとえば、 foreach() が列挙型を使用することを考えると、 for(;;) ループが配列の foreach() よりも高速になることは明らかです。変数を単純にインクリメントするのではなく、次に進むたびにメソッド呼び出しを使用してオブジェクトを作成します。これは、タイトなループを数百万回実行することで簡単に証明できます (逆アセンブルは不要です)。

IL の逆アセンブルを馬鹿げているのは、実際のマシン コードではないという事実です。仮想マシンコードです。実際に命令を移動して最適化するのが好きな人もいると聞きました。私をからかってるの?ジャストインタイムでコンパイルされた仮想マシン コードは、ネイティブにコンパイルされたコードの速度では単純なタイトな for(;;) ループを実行することさえできません。プロセッサから最後のサイクルをすべて絞り出したい場合は、C/C++ を使用して、実際のアセンブリの学習に時間を費やしてください。そうすれば、多くの低レベルの詳細を理解するのに費やす時間は、実際には価値があります。

では、時間に追われる以外に、人々はなぜ .NET (CLR) バイナリを逆アセンブルするのでしょうか?

4

13 に答える 13

7

さまざまな高級言語のコンパイラがソースに対して実際に何を行っているかを理解することは、特定の環境の習得に向けて移行する際に習得する重要なスキルです。たとえば、DB エンジンがさまざまな種類の SQL クエリを実行するためにどのように計画するかを理解するのと同じです。それらを投げることができます。あるレベルの抽象化を巧みに使用するには、(少なくとも) その下のレベルに精通していることは非常に良いことです。たとえば、抽象化に関する私の講演のメモとその講演のスライド、および講演で言及している Joel Spolsky の「漏れやすい抽象化の法則」を参照してください。

于 2009-05-30T19:55:10.587 に答える
3

ソースコードが失われた場合、または特定のタグ付きリリースのバージョン管理にあるものが出荷されたバイナリに対応していないように見える場合に使用しました。

于 2009-05-30T20:06:58.987 に答える
2

セキュアなソフトウェア開発の 4 日間のコースを修了したばかりで、多くの人がソースを逆コンパイルして脆弱性を見つけると思います。クライアント アプリケーションのソースを知ることは、サーバーへの攻撃を計画するのに役立ちます。

もちろん、ユーティリティなどはほとんどありませんが、そのような問題はありません。

私の記憶が正しければ、.net バイナリを難読化するアプリがあります。それは dotfuscator と呼ばれていたと思います。

于 2009-05-30T20:41:23.007 に答える
2

十分に文書化されていないインターフェースの使用方法を理解する。

(残念ながら、BizTalk や WCF などの .net ベースのツールでは、生成された一般的なドキュメントしか持たないことが頻繁にあるため、C# に逆アセンブルして、メソッドが何を行っているか、どのコンテキストで使用するかを確認する必要がある場合があります)

于 2009-05-30T22:40:00.253 に答える
1

あなたの質問から、Reflector が CLR アセンブリを逆アセンブルして C# または VB に戻すことを知らないように見えるので、IL ではなく元のコードがほとんど表示されます。

于 2009-05-30T21:08:49.377 に答える
1

実際には、int[] に対する foreach は for ステートメントにコンパイルされます。それを列挙型にキャストすると、その通りです。列挙子を使用します。 ただし、temp int をインクリメントしないため、奇妙に高速になります。 これを証明するために、デコンパイラと組み合わせたベンチマークを使用して理解を深めます...

ですから、この質問をすることで、あなたは本当に自分で答えたと思います。

このベンチマークがあなたのものと異なる場合は、その方法を教えてください。オブジェクト配列、ヌルなどで試してみました...

コード:

    static void Main(string[] args)
    {

        int[] ints = Enumerable.Repeat(1, 50000000).ToArray();

        while (true)
        {
            DateTime now = DateTime.Now;
            for (int i = 0; i < ints.Length; i++)
            {
                //nothing really
            }
            Console.WriteLine("for loop: " + (DateTime.Now - now));

            now = DateTime.Now;
            for (int i = 0; i < ints.Length; i++)
            {
                int nothing = ints[i];
            }
            Console.WriteLine("for loop with assignment: " + (DateTime.Now - now));

            now = DateTime.Now;
            foreach (int i in ints)
            {
                //nothing really
            }
            Console.WriteLine("foreach: " + (DateTime.Now - now));

            now = DateTime.Now;
            foreach (int i in (IEnumerable<int>)ints)
            {
                //nothing really
            }
            Console.WriteLine("foreach casted to IEnumerable<int>: " + (DateTime.Now - now));
        }

    }

結果:

for loop: 00:00:00.0273438
for loop with assignment: 00:00:00.0712890
foreach: 00:00:00.0693359
foreach casted to IEnumerable<int>: 00:00:00.6103516
for loop: 00:00:00.0273437
for loop with assignment: 00:00:00.0683594
foreach: 00:00:00.0703125
foreach casted to IEnumerable<int>: 00:00:00.6250000
for loop: 00:00:00.0273437
for loop with assignment: 00:00:00.0683594
foreach: 00:00:00.0683593
foreach casted to IEnumerable<int>: 00:00:00.6035157
for loop: 00:00:00.0283203
for loop with assignment: 00:00:00.0771484
foreach: 00:00:00.0771484
foreach casted to IEnumerable<int>: 00:00:00.6005859
for loop: 00:00:00.0273438
for loop with assignment: 00:00:00.0722656
foreach: 00:00:00.0712891
foreach casted to IEnumerable<int>: 00:00:00.6210938

逆コンパイル (空の foreach には変数の割り当てを追加する必要があることに注意してください...空の for ループには追加されませんでしたが、明らかに必要なもの):

private static void Main(string[] args)
{
    int[] ints = Enumerable.Repeat<int>(1, 0x2faf080).ToArray<int>();
    while (true)
    {
        DateTime now = DateTime.Now;
        for (int i = 0; i < ints.Length; i++)
        {
        }
        Console.WriteLine("for loop: " + ((TimeSpan) (DateTime.Now - now)));
        now = DateTime.Now;
        for (int i = 0; i < ints.Length; i++)
        {
            int num1 = ints[i];
        }
        Console.WriteLine("for loop with assignment: " + ((TimeSpan) (DateTime.Now - now)));
        now = DateTime.Now;
        int[] CS$6$0000 = ints;
        for (int CS$7$0001 = 0; CS$7$0001 < CS$6$0000.Length; CS$7$0001++)
        {
            int num2 = CS$6$0000[CS$7$0001];
        }
        Console.WriteLine("foreach: " + ((TimeSpan) (DateTime.Now - now)));
        now = DateTime.Now;
        using (IEnumerator<int> CS$5$0002 = ((IEnumerable<int>) ints).GetEnumerator())
        {
            while (CS$5$0002.MoveNext())
            {
                int current = CS$5$0002.Current;
            }
        }
        Console.WriteLine("foreach casted to IEnumerable<int>: " + ((TimeSpan) (DateTime.Now - now)));
    }
}
于 2009-05-31T19:12:33.053 に答える
1

ライブラリのバグを見つけて、それらを回避する方法を見つけます。

例: リフレクションがなければ、バックトレースを破棄せずに例外をリモートして再スローすることはできません。ただし、フレームワークはそれを行うことができます。

于 2009-05-30T21:02:08.393 に答える
1

各 .NET 言語は、CLR 機能の独自のサブセットを実装しています。CLR には、現在使用している言語にはない機能があることを知っていれば、言語を変更するか、IL を出力するか、別の方法を見つけるかについて、十分な情報に基づいた決定を下すことができます。

人々がこのようなことをする唯一の理由は、時間がありすぎるからであるというあなたの仮定は、侮辱的で教育を受けていません。

于 2009-05-30T20:00:43.320 に答える
1

学ぶために。

記事は素晴らしいものですが、製品コードは紹介されていません。.NET Reflectorがなければ、Microsoft がFileSystemWatcherコンポーネントにイベントをどのように実装したかを理解するのに数週間かかったでしょう。代わりに、わずか数時間でFileSystemSearcherコンポーネントを完成させることができました。

于 2009-10-29T23:06:14.660 に答える
0

人々が言及していないことは、PostSharpのようなコンパイル時のウィービングAOPフレームワークを使用する場合、リフレクターが非常に役立つということです。

于 2009-10-26T05:38:37.770 に答える
0

私はそれを次の、さらに多くの場合に使用しました:

  1. ソースコードがない内部アセンブリで問題が発生しました。
  2. 特定のサードパーティのコントロールライブラリがランタイムライセンスを探す方法を理解する必要があります。
  3. .Netライセンスコンパイラがどのように機能するかを調べる必要があります。(リフレクター内にlc.exeを配置するだけです)
  4. 特定のライブラリが正しくビルドされていることを確認するために使用しました。
于 2009-05-30T22:15:35.187 に答える
0

基礎となるシステムがどのように実装されているかを理解するには、IL の高レベル コードに相当するものを理解し、ライセンスを回避します...

于 2009-05-30T21:06:24.077 に答える
0

私自身、これについてよく疑問に思います... :)

特定のライブラリ メソッドがどのように機能するか、またはなぜこのように正確に機能するのかを理解する必要がある場合があります。この関数に関するドキュメントが曖昧であるか、調査が必要な奇妙な動作がある場合があります。この場合、ライブラリを逆アセンブルして、特定のメソッド内でどのような呼び出しが行われたかを調べる人もいます。

最適化に関しては、私はこれについて聞いたことがありません。MIL を最適化しようとするのは最終的にはばかげていると思います。なぜなら、それはかなり効率的に実際のマシン コードを生成するトランスレータに送られ、とにかく「最適化」が失われる可能性があるからです。

于 2009-05-30T19:56:41.160 に答える