Почему люди разбирают двоичные файлы .NET (CLR)? - PullRequest
4 голосов
/ 30 мая 2009

Я немного новичок в .NET, но не новичок в программировании, и я несколько озадачен тенденцией и волнением по поводу разборки скомпилированного кода .NET. Это кажется бессмысленным.

Именно из-за простоты использования .NET я использую его. Я написал C и реальную (аппаратный процессор) сборку в средах с ограниченными ресурсами. Это и стало причиной того, что мы потратили много усилий на детали, для повышения эффективности. Находясь в среде .NET, он как бы побеждает цель иметь высокоуровневый объектно-ориентированный язык, если вы тратите время на погружение в самые загадочные детали реализации. В ходе работы с .NET я отлаживал обычные проблемы с производительностью в странных условиях гонки, и я сделал все это, читая свой собственный исходный код, никогда не задумываясь о том, какой промежуточный язык генерирует компилятор. Например, довольно очевидно, что цикл for (;;) будет быстрее, чем foreach () в массиве, учитывая, что foreach () будет использовать перечисление object с вызовом метода переходить к каждому следующему разу вместо простого приращения переменной, и это легко доказать, если несколько миллионов раз выполнить тугой цикл (разборка не требуется).

Что действительно делает разборку IL глупой, так это то, что это не настоящий машинный код. Это код виртуальной машины. Я слышал, что некоторым людям нравится перемещать инструкции, чтобы оптимизировать их. Ты шутишь, что ли? Скомпилированный точно в срок код виртуальной машины не может даже выполнить простой цикл for (;;) со скоростью скомпилированного кода. Если вы хотите выжать каждый последний цикл из вашего процессора, то используйте C / C ++ и потратьте время на изучение реальной сборки. Таким образом, время, потраченное на понимание множества деталей низкого уровня, будет действительно полезным.

Итак, кроме того, что у них слишком много времени, почему люди разбирают двоичные файлы .NET (CLR)?

Ответы [ 13 ]

7 голосов
/ 30 мая 2009

Понимание того, что на самом деле делают компиляторы для различных языков высокого уровня с вашими источниками, является важным навыком, который вы приобретаете, когда вы переходите к овладению определенной средой, так же как, скажем, понимание того, как механизмы БД планируют выполнять различные виды SQL-запросы вы можете бросить на них. Мастерски использовать определенный уровень абстракции, знакомство с (по крайней мере) уровнем ниже его - довольно хорошая вещь для приобретения; см. например некоторые заметки в моем выступлении на тему абстракции и слайды для этого выступления , а также «закон утечек абстракций» Джоэла Спольски, на который я ссылаюсь в выступлении.

3 голосов
/ 31 мая 2009

Я использовал его, когда исходный код был утерян или то, что находится в системе управления версиями в конкретной версии с тегами, похоже, не соответствует поставляемому двоичному файлу.

2 голосов
/ 31 мая 2009

Чтобы понять, как использовать плохо документированный интерфейс.

(к сожалению, в инструментах, основанных на .net, таких как BizTalk или WCF, это слишком часто, чтобы иметь только сгенерированную документацию общего характера, поэтому иногда необходимо разобраться с C #, чтобы увидеть, что делает метод, в каком контексте его использовать) *

2 голосов
/ 31 мая 2009

После завершения 4-дневного курса по безопасной разработке программного обеспечения я бы сказал, что многие люди будут декомпилировать исходный код, чтобы найти в нем какие-либо уязвимости. Знание источника клиентского приложения может помочь в планировании атаки на сервер.

Конечно, маленьких утилит и тому подобного не было бы.

Если я правильно помню, есть приложение, которое запутывает ваши .net двоичные файлы. Я полагаю, это называлось dotfuscator.

1 голос
/ 30 октября 2009

Учиться.

Статьи хороши, но они не представляют производственный код. Без .NET Reflector мне понадобилось бы пару недель, чтобы понять, как Microsoft реализовала события в компоненте FileSystemWatcher. Вместо этого прошло всего несколько часов, и я смог закончить свой FileSystemSearcher компонент.

1 голос
/ 31 мая 2009

На самом деле, foreach над int [] компилируется в оператор 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)));
    }
}
1 голос
/ 31 мая 2009

Судя по вашему вопросу, вы не знаете, что Reflector разбирает сборки CLR обратно на C # или VB, так что вы в значительной степени видите оригинальный код, а не IL!

1 голос
/ 31 мая 2009

Чтобы найти ошибки библиотеки и выяснить, как их обойти.

Например: без отражения вы не можете удалить исключение и сбросить его, не убив его обратный след. Однако рамки могут это сделать.

1 голос
/ 31 мая 2009

Каждый язык .NET реализует свое собственное подмножество функций CLR. Знание о том, что CLR способен на то, чего нет у языка, который вы используете в данный момент, может позволить вам принять осознанное решение о том, менять язык или использовать IL, или найти другой способ.

Ваше предположение, что единственная причина, по которой люди делают подобные вещи, заключается в том, что у них слишком много времени, оскорбительно и необразованно.

0 голосов
/ 26 октября 2009

Что-то, что люди не упомянули, это то, что рефлектор очень полезен, если вы используете AOP-фреймворк во время компиляции, такой как PostSharp.

...