Правовые основы декомпилирования программного обеспечения
Программное обеспечение является объектом интеллектуальных прав, охрана которого осуществляется в соответствии с авторским правом и регламентирована в рамках семидесятой главы Гражданского Кодекса РФ.
Согласно действующему гражданскому законодательству, программное обеспечение, как объект авторских прав приравнивается к литературным произведениям, хотя законодатель выделяет некоторые его особенности.
Это означает, что правовая охрана программного обеспечения производится по правилам охраны литературных произведений, за исключением случаев, когда можно использовать те немногие правила, которые были установлены специально для охраны программного обеспечения.
Правовая охрана программного обеспечения
Как и литературные произведения, программное обеспечение охраняется непосредственно с момента его создания и продолжается в течение всей жизни автора, а также в течение семидесяти лет после его смерти . Основным отличием правовой охраны программного обеспечения от правовой охраны литературных произведений является возможность госрегистрации программного обеспечения, которая отсутствует для литературных произведений. Здесь следует отметить, что госрегистрация программного обеспечения, в свою очередь, отличается и от госрегистрации объектов промышленной собственности.
Знакомство с дизассемблером (ОЧЕНЬ СЛОЖНО)
Отличие состоит в том, что госрегистрация программного обеспечения осуществляется на добровольной основе и служит дополнительной гарантией защиты прав правообладателей программного обеспечения. Таким образом, правовая охрана программного обеспечения осуществляется независимо от наличия или отсутствия у него госрегистрации . Что же касается госрегистрации объектов промышленной собственности, то процедура патентования непосредственно связана с предоставлением объекту промсобственности правовой охраны. Иными словами, без прохождения госрегистрации (без наличия патента) объекту промсобственности правовая охрана не предоставляется . Госрегистрация программного обеспечения предусматривает ведение двух госреестров, один из которых предназначается только для компьютерных программ, а другой только для баз данных. При этом отличий правового статуса компьютерных программ и баз данных практически не наблюдается.
Правовая охрана исключает возможность использования программного обеспечения третьими лицами без согласия правообладателей и без выплаты им соответствующего вознаграждения на весь срок действия правовой охраны.
Однако в некоторых случаях, законодатель предусматривает возможность свободного использования программного обеспечения. Одним из таких случаев является декомпиляция.
Свободная декомпиляция
Под декомпиляцией программного обеспечения законодатель понимает технический прием, в результате которого объектный программный код преобразуется в исходный текст.
Указанный технический прием, как правило, осуществляется в целях изучения компьютерных программ, в том числе их структуры и методов кодирования. Третья часть статьи 1280 Гражданского Кодекса предусматривает, что декомпиляция компьютерных программ может осуществляться свободно, то есть без получения согласия правообладателей программного обеспечения , но для этого требуется соблюдение некоторых условий.
Реверсинг python программы, почему python не безопасен
Условия свободной декомпиляции
- Лицо, желающее осуществить декомпиляцию, должно владеть соответствующей компьютерной программой правомерно, то есть приобрести ее законным путем;
- Целью декомпиляции является достижение взаимодействия программного обеспечения, созданного лицом, правомерно владеющим компьютерной программой, с этой компьютерной программой;
- Информация, которая должна быть получена в результате декомпиляции, не должна быть доступной из открытых или иных источников;
- Действия, направленные на декомпиляцию должны производиться только в отношении тех частей компьютерной программы, которые необходимы для достижения взаимодействия данной компьютерной программы с другим программным обеспечением;
- Информация, полученная в результате декомпиляции, не может быть переданной для использования третьими лицами, за исключением случаев, когда это является необходимым условием взаимодействия декомпилируемой компьютерной программы с другим программным обеспечением;
- Декомпиляция не должна носить неоправданный характер, например декомпиляция, совершенная с целью создания нового программного обеспечения будет считаться незаконной;
- Декомпиляция не должна наносить ущерб компьютерной программе и нарушать исключительные права ее правообладателей.
Источник: 1patent.ru
Декомпиляция EXE-файлов
Декомпиляция подразумевает воссоздание исходного кода программы на том языке, на котором она была написана. Иными словами, это процесс обратный процессу компиляции, когда исходный текст преобразуется в машинные инструкции. Декомпиляцию можно провести, используя специализированный софт.
Способы декомпиляции EXE-файлов
Декомпиляция может быть полезной автору ПО, который потерял исходные коды, или просто пользователям, желающим узнать свойства той или иной программы. Для этого существуют специальные программы-декомпиляторы.
Способ 1: VB Decompiler
Первым рассмотрим VB Decompiler, который позволяет декомпилировть программы, написанные на Visual Basic 5.0 и 6.0.
- Нажмите «Файл» и выберите пункт «Открыть программу» (Ctrl+O).
- Найдите и откройте программу.



Способ 2: ReFox
В плане декомпиляции программ, скомпилированных через Visual FoxPro и FoxBASE+, неплохо себя зарекомендовал ReFox.
- Через встроенный обозреватель файлов найдите нужный EXE-файл. Если его выделить, то справа будет отображаться краткая информация о нём.
- Откройте контекстное меню и выберите пункт «Decompile».
- Откроется окно, где нужно указать папку для сохранения декомпилированных файлов. После нажмите «ОК».
Можно просмотреть результат в указанной папке.
Способ 3: DeDe
А DeDe будет полезна для декомпиляции программ на Delphi.
- Нажмите кнопку «Добавление файла».
- Найдите файл EXE и откройте его.
- Для запуска декомпиляции нажмите кнопку «Процесс».
- При успешном завершении процедуры появится такое сообщение:
В отдельные вкладки будет выведена информация о классах, объектах, формах и процедурах.
Способ 4: EMS Source Rescuer
Декомпилятор EMS Source Rescuer позволяет работать с EXE-файлами, скомпилированными при помощи Delphi и C++ Builder.
- В блоке «Executable File» нужно указать нужную программу.
- В «Project name» пропишите имя проекта и нажмите «Next».
- Выберите необходимые объекты, укажите язык программирования и нажмите «Next».
- В следующем окне исходный код доступен в режиме предпросмотра. Осталось выбрать выходную папку и нажать кнопку «Save».
Мы рассмотрели популярные декомпиляторы для файлов EXE, написанных на разных языках программирования. Если Вам известны другие рабочие варианты, напишите об этом в комментариях.
Мы рады, что смогли помочь Вам в решении проблемы.
Источник: lumpics.ru
Как работает декомпиляция в .Net или Java на примере .Net
Сегодня хотелось бы поговорить про декомпиляцию приложений (все применительно к той же Java, да и любому языку с некоторыми допущениями и ограничениями, но поскольку сам я — .Net разработчик, примеры будут совсем немного MSIL’овизированы 🙂 ).
- JetBrains dotPeek (поддержка R# хоткеев, сервер символов)
- Telerik JustDecompile (также не плохой, множество хоткеев)
- RedGate Reflector (аналог dotPeek, но платный. Изначально был основным в мире .Net, но пока был бесплатным)
- icsharpcode ILSpy (хороший, opensource. Полезен, когда вы сами пишете код, использующий Mono.Cecil, т.к. Это даст лучшее понимание его работы)
- 9rays Spices .Net Decompiler
- Dis# с функцией inplace editor
- Mono.Cecil (основной, самый крутой декомпилятор в мире .Net. На выходе получаете объектное «зеркало» содержимого сборки. Т.е. Максимально-упрощенно, без наворотов типа конвертации массива IL в DOM).
- ICSharpCode.Decompiler (надстройка над mono.cecil, переводящая array[MSIL] в DOM, где есть циклы, switches и if’ы. Является частью SharpDevelop/ILSpy)
- Harmony Core (аналогичное от меня, но сохраняющее информацию о символах. В среднем состоянии, не готова для прода, помощь приветствуется).
А теперь, хотелось бы описать как они работают (вам же интересно, как работает машинка от JetBrains?). Чтобы как минимум понять, насколько это сложно: написать свой декомпилятор .Net сборки обратно в код на C#.
Для начала, полный список выложенных на Хабре статей данного цикла
- Должен принимать на вход любую сборку: от CLR 1.* до 4.*
- Обязан поддерживать не только C# вывод, но и MSIL, VB.NET и вообще — на что фантазии и потребностей хватит.
- Возможность выбирать между различными версиями языка (например, C#), при этом не имея дублирования в реализации.
И теперь, когда требования определены, давайте подумаем, как устроена работа MSIL, и как это поможет нам в быстрой декомпиляции приложения.
В отличии от языка процессора, который вносит для нас некоторые сложности в процесс декомпиляции (регистры, оптимизации, возможность сделать одно действие несколькими способами), в MSIL все максимально просто. Если надо записать в локальную переменную нечто, то для этого есть всего одна команда. Другим способом записать в переменную значение не получится. Это свойство наделяет конечный компилятор (JITter) простотой в реализации с одной стороны… А с другой стороны наделяет простотой в реализации декомпилирующую сторону.
Второе свойство, каким обладает MSIL, это вычисления на стеке. Тут нет регистров. И единственная память, через которую идут все вычисления — это стек. Это абсолютно не значит что конечный процессор также все вычисляет через стек. Нет. Это значит что этой моделью для упрощения пользуется описание всех расчетов и вызовов на MSIL.
Что это значит для нас? Это значит что сложить два числа можно только одной командой, которая вне зависимости от параметров — одна. Это команда, вытащив данные для сложения из стека, складывает их и сохраняет результат не куда-либо, а обратно в стек. Это важно, потому что для нас, как для людей, пишущих декомпилятор это не породит огромного ветвления кода.
Теперь мы подошли к самому главному: как происходит процесс декомпиляции.
Ldc_i4 5 Ldc_i4 4 Add Stloc.1
Sum = 5 + 4;
Первая трудность, которая приходит в голову: положение инструкций может быть различным. Т.е., например, чтобы код выполнился, совсем не обязательно что между ldind_i4 и add не будет других инструкций. Например, совершенно валиден следующий код:
Ldc_i4 5 Ldc_i4 4 Ldc_i4 10 Stloc.2 // sum2 Add Stloc.1 // sum1
Что должно декомпилироваться, например, так:
Sum2 = 10 Sum1 = 5 + 4;
Во-вторых названия переменных в релизе могут отсутствовать. Т.е. без примесей, код будет таким:
= 10 = 5 + 4;
В третьих, что самое сложное, реализации if-else, while, do-while, switch могут отличаться. Этого касаются, в особенности, лямбды, yields, async/awaits и прочие языковые примочки, которые являются опциональными и на самом деле реализуются поверх обычных функций языка. Как все это учесть? На самом деле оба вопроса решаются всего двумя способами.
Стековая модель декомпиляции
Для декомпиляции пишется некий интерпретатор кода на MSIL, у которого есть свой стек и цикл интерпретации команд. На каждой итерации цикла, берется очередная не рассмотренная команда:
-
Если это не инструкция перехода, то мы смотрим, сколько значений на стеке требуется исследуемой командой. Далее мы достаем со стека два вычислительных узла, которые мы положили туда, как результаты вычисления предыдущих команд и создаем новый узел, ветвями которого являются взятые со стека узлы. Для примера выше это будет выглядит так:
Т.е. Сначала у нас есть на входе 4 команды. Первые две ничего не берут на вход, а только отдают — число. Соответственно, мы кладем их на стек (ldind_i4 4, ldind_i4 5). После чего мы берем очередную команду — Add. Она принимает на вход два значения со стека.
Поэтому мы считываем два узла с нашего стека и, схоранив их как параметры этой команды, сохраняем саму команду- на стек, поскольку у команды есть результат. А любой результат сохраняется на стеке.
Далее результат может быть передан в метод, либо участвовать в других арифметических операциях, либо возвращен с помощью инструкции ret.
Соответственно, если бы выражение было бы посложнее:
Ldc_i4 5 Ldc_i4 4 Ldc_i4 10 Mul Add Stloc.1 // value = 5 + (4 * 10)
То процесс создания DOM выглядел бы следующим образом:
После чего осуществляется окончательная сборка дерева:
Таким же образом конструируются вызовы методов. Только в случае методов, со стека будет забираться требуемое под вызов количество параметров и сохраняться в классе ноды вызова метода. Если метод возвращает значение, то нода вызова метода будет сложена в стек. Если нет — добавлена к группе готовых выражений.
Сборка дерева
Это все были подготовительные этапы. Далее, для модульности, создаются классы, которые распознают какую-либо одну конструкцию в дереве и переводят ее в другую. Например, если это if-else, то матчится наличие условного перехода такого, чтобы переход осуществлялся вперед.
Тогда узел преобразуется в if-else ноду, код за переходом помечается как else (negative if) нода, а код между условием и else нодой — как positive if нода. Если матчится как условный переход с переходом на прошлые инструкции, то это матчится как while цикл и дерево также перестраивается.
Соответственно, в зависимости от чистоты исполнения матчеров, на выходе мы получем преобразованное дерево под конкретный язык программирования. Далее, у каждого из языков программирования мы задаем множество матчеров, которые ему подходят. Например, циклы и условия подойдут всем, потому они будут присутствовать почти во всех пакетах. А вот, например, async/await — он только для C#. Потому, будет присутствовать тольк в его пакете.
Для ясности картины, как собираются if-else и while/do-while, рассмотрим примеры:
Сборка IF-ELSE блока
Сборка WHILE блока
Генерация кода
Последний этап матчинга — генерация кода по дереву. Тут не должно быть каких-то сложностей. Идеально, конечно, было бы круто подсасывать правила от R# или StyleCop. Благо, они в XML. Но в простейшем случае, мы пишем генератор, который принимает на вход дерево описания класса. Он сперва обязан проверить все дерево: содержит ли оно не поддерживаемые типы нод.
Если все в порядке, то обходится все дерево и для каждого узла вызывается соответствующий метод по шаблону проектирования Visitor, которому передается StringBuilder и соответствующая нода. Дополнительно, необходимо считать количество пробелов, которые надо отступать с начала каждой строки. На этом этапе все достаточно просто.
Генерация имен переменных
- Имена методов, которые не являются сгенерированными компилятором, в расчетах или результатах расчетов которых они используются. Пример: var . = this.Counterparty; -> . = counterparty.
- Данные, является ли переменная — переменной цикла. Т.е. Считается ли она только в теле цикла. Если она — целочисленная, то кандидаты на имя — index, i, j.
- Если переменная — в цикле foreach является элементом из итерируемой коллекции, то можно назвать ее [collectionName]Item либо просто item.
Источник: habr.com
Создание исходного кода из сборок .NET во время отладки
Область применения:Visual Studio
Visual Studio для Mac
Visual Studio Code
При отладке приложения .NET вам может потребоваться просмотреть исходный код, которого у вас нет. Например, происходит прерывание в исключении, или стек вызовов используется для перехода к исходному расположению.
- Создание исходного кода (декомпиляция) возможно только для приложений .NET и построено на проекте ILSpy с открытым кодом.
- Декомпиляция доступна только в Visual Studio 2019 версии 16.5 и более поздних версий.
- Атрибут SuppressIldasmAttribute, примененный к сборке или модулю, не позволит Visual Studio выполнить декомпиляцию.
Создание исходного кода
Если при выполнении отладки исходный код недоступен, в Visual Studio отображается документ Исходный код не найден, а если отсутствуют символы для сборки, отображается документ Символы не загружены. Оба документа имеют параметр Декомпилировать исходный код, который создает код C# для текущего расположения. Созданный код C# можно использовать так же, как любой другой исходный код. Вы можете просматривать этот код, проверять переменные, устанавливать точки останова и т. д.
Символы не загружены
На следующем рисунке показано сообщение Символы не загружены.
Исходный код не найден
На следующем рисунке показано сообщение Исходный код не найден.
Создание и внедрение исходного кода для сборки
Можно создать не только исходный код для определенного расположения, но и весь исходный код для конкретной сборки .NET. Для этого перейдите в окно Модули и в контекстном меню сборки .NET выберите команду Декомпилировать исходный код. Visual Studio создает файл символов для сборки, а затем внедряет исходный код в файл символов. На последующем этапе можно извлечь внедренный исходный код.
Извлечение и просмотр внедренного исходного кода
Исходные файлы, внедренные в файл символов, можно извлечь с помощью команды Извлечь исходный код в контекстном меню окна Модули.
Извлеченные исходные файлы добавляются в решение как прочие файлы. В Visual Studio функция «Прочие файлы» по умолчанию отключена. Чтобы включить эту функцию, установите флажок Инструменты>Параметры>Среда>Документы>Показывать прочие файлы в Обозревателе решений. Без включения этой функции вы не сможете открыть извлеченный исходный код.
Извлеченные исходные файлы отображаются в разделе прочих файлов в Обозревателе решений.
SourceLink
Для библиотек .NET или пакетов NuGet, включенных для SourceLink, можно также выполнять по шагам исходный код, задавать точки останова и использовать все функции отладчика. Дополнительные сведения см. в разделе Улучшение производительности во время отладки с помощью SourceLink.
Известные ограничения
Требуется режим прерывания выполнения
Создание исходного кода с помощью декомпиляции возможно только в том случае, если отладчик находится в режиме прерывания выполнения и приложение приостановлено. Например, Visual Studio переходит в режим прерывания, попадая в точку останова или в исключение. Вы можете легко активировать прерывание выполнения Visual Studio при следующем запуске кода с помощью команды Прервать все ().
Ограничения декомпиляции
Создание исходного кода из промежуточного языка (IL), используемого в сборках .NET, имеет некоторые внутренние ограничения. Поэтому созданный исходный код не выглядит в точности как оригинальный исходный код. Большая часть различий сосредоточена в тех местах, где информация в оригинальном исходном коде не нужна во время выполнения. Например, во время выполнения не нужна такая информация, как пробелы, комментарии и имена локальных переменных. Рекомендуется использовать созданный исходный код, чтобы понять, как выполняется программа, а не в качестве замены оригинального исходного кода.
Отладка оптимизированных сборок или сборок выпуска
При отладке кода, декомпилированного из сборки, которая была скомпилирована с использованием оптимизаций компилятора, вы можете столкнуться со следующими проблемами:
- точки останова могут не всегда быть привязаны к соответствующим исходным расположениям;
- при пошаговом выполнении шаг может не всегда переходить в правильное место;
- имена локальных переменных могут быть неточными;
- некоторые переменные могут быть недоступны для оценки.
Дополнительные сведения можно найти в описании проблемы GitHub Интеграция ICSharpCode.Decompiler с отладчиком VS.
Надежность декомпиляции
Относительно небольшой процент попыток декомпиляции может привести к сбою. Это происходит из-за ошибки пустой ссылки точки последовательности в ILSpy. Мы устранили этот сбой путем перехвата таких проблем и корректного завершения попытки декомпиляции.
Дополнительные сведения можно найти в описании проблемы GitHub Интеграция ICSharpCode.Decompiler с отладчиком VS.
Ограничения при работе с асинхронным кодом
Результаты декомпиляции модулей с шаблонами кода async/await могут быть неполными или неудачными в целом. Шаблоны кода async/await и машины состояния yield state-machine в ILSpy реализованы только частично.
Дополнительные сведения можно найти в описании проблемы GitHub Состояние генератора PDB.
Только мой код
Параметры режима Только мой код (JMC) позволяют Visual Studio выполнять шаг с обходом системы, платформы, библиотеки и других вызовов непользовательского кода. Во время сеанса отладки в окне Модули отображаются модули кода, которые отладчик воспринимает как «Мой код» (т. е. пользовательский код).
При декомпиляции оптимизированных модулей или модулей выпуска создается непользовательский код. Если отладчик прерывается в декомпилированном непользовательском коде, появляется окно Отсутствует источник. Чтобы отключить режим «Только мой код», перейдите в раздел Инструменты>Параметры (или Отладка>Параметры) >Отладка>Общие и снимите флажок Включить только мой код.
Извлеченный исходный код
Исходный код, извлеченный из сборки, имеет следующие ограничения.
- Имена и расположение созданных файлов нельзя настроить.
- Файлы являются временными и будут удалены Visual Studio.
- Файлы помещаются в одну папку без использования какой-либо иерархии, которая была в оригинальных исходных файлах.
- Имя каждого файла содержит хэш контрольной суммы файла.
Создается только код C#
При декомпиляции создаются только файлы исходного кода на C#. Возможность создавать файлы на каком-либо другом языке отсутствует.
Источник: learn.microsoft.com
Декомпилятор
Декомпиля́тор — это программа, транслирующая исполняемый модуль (полученный на выходе компилятора) в эквивалентный исходный код на языке программирования высокого уровня.
Декомпиля́ция — процесс воссоздания исходного кода декомпилятором.
Декомпиляция, в частности, используется при обратной разработке программ.
Удачность декомпиляции зависит от объема информации, представленной в декомпилируемом коде. Байт-код, используемый большинством виртуальных машин (таких как Java Virtual Machine или .NET Framework Common Language Runtime) часто содержит обширные метаданные, делающие декомпиляцию вполне выполнимой, в то время как машинный код более скуден и сложен в декомпиляции. В частности трудночитаемыми представляются вызовы подпрограмм или функций с косвенной адресацией вызовов (в терминах языков программирования высокого уровня — вызовы через указатели на функции/процедуры).
Если известно на каком языке была написана декомпилируемая программа, то в первую очередь дизассемблируются и анализируются библиотеки времени исполнения (RTL — runtime library) компилятора с этого языка, так как в основном компиляция программы сводится к вызовам с различными параметрами процедур из этих библиотек. Кроме того, многие компиляторы позволяют увидеть, в какой ассемблерный код превращаются операторы программы после компиляции. Эти конструкции становятся шаблонами для декомпилятора, поэтому процесс декомпиляции в некотором смысле похож на распознавание в машинном коде конечного набора подобных шаблонов. Легче всего распознаются вызовы процедур и возвраты из них. Они служат границами для восстановления операторов процедуры.
Некоторые компиляторы и инструменты, используемые после компиляции, подвергают программный код обфускации с целью затруднить декомпиляцию.
Декомпиляторы можно рассматривать как состоящие из ряда фаз, каждая из которых вносит свой вклад в определенные аспекты общего процесса декомпиляции.
Источник: wiki2.org