Можно ли декомпилировать dll

Обновлено: 02.07.2024

Начинающие реверсеры, еще не познавшие все прелести чистого ассемблера, постоянно спрашивают на хакерских форумах, где бы им раздобыть
декомпилятор для Си или Паскаля. Декомпиляторов-то много, но вот результат. без дизассемблера все равно ну никак не обойтись. И вот, наконец, свершилось!
Ильфак (автор легендарного дизассемблера IDA Pro) выпустил декомпилятор нового поколения
HexRays, делающий то, что другим не под силу. Мир вздрогнул от восторга (реклама вообще обещала чудо), порождая сейсмические волны впечатлений: от оргазма до полного отвращения. Истина же, как водится, где-то посередине, и стоит обозначить эту середину, рассмотрев слабые и сильные стороны
декомпилятора, а также
области его применения.

Почему у Ильфака получилось то, что упорно не желало получаться у других? Начнем с того, что
HexRay представляет собой всего лишь плагин к IDA Pro — интерактивному дизассемблеру более чем с десятилетней историей, первая версия которой увидела свет 6 мая 1991 года. Спустя некоторое время к работе над ней подключился удивительный человек, гениальный программист и необычайно креативный кодер Юрий Харон. Вместе с Ильфаком (не без помощи других талантливых парней, конечно) они начали работать в том направлении, куда еще никто не вкладывал деньги. До этого дизассемблеры писались исключительно на пионерском энтузиазме параллельно с изучением ассемблера и довольно быстро забрасывались. Ильфак и
Юрий Харон решили рискнуть. В итоге IDA Pro стал не только основным, но и, пожалуй, единственным продуктом фирмы
DataRescue (мелкие утилиты и прочие ответвления не в счет). Стоит ли удивляться, что парням удалось решить практически все фундаментальные проблемы дизассемблирования, над которыми просто не хотели работать остальные разработчики, зная, что быстрой отдачи не будет и проект потребует десятилетий упорного труда. Самое время выяснить, что же это за проблемы такие, откуда они берутся и как решаются.

Фундаментальные проблемы декомпиляции

Компиляция — процесс однонаправленный и необратимый, в ходе которого теряется огромное количество лишней информации, совершенно ненужной процессору. Это не шутка! Исходный текст, написанный на языке высокого уровня, чрезвычайно избыточен, что с одной стороны упрощает его понимание, а с другой — страхует программиста от ошибок. Взять хотя бы информацию о типах. На низком уровне процессор оперирует базовыми типами: байт, слово, двойное слово. Строки превращаются в последовательности байтов, и, чтобы догадаться, что это строка, приходится прибегать к эвристическим алгоритмам.

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

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

Что в имени твоем

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

К счастью, современные программы наполовину (а то и более) состоят из библиотечных и API-функций, которые распознаются классическим сигнатурным поиском. Главное — собрать обширную базу библиотек всех популярных (и непопулярных) компиляторов с учетом многообразия их версий.

IDA Pro уже давно поддерживает технологию FLIRT (Fast Library Identification and Recognition Technology), не только распознающую библиотечные функции, но также восстанавливающую их прототипы вместе с прототипами API-функций, которые, кстати говоря, могут импортироваться не только по имени, но еще и по ординалу, то есть по номеру. Чтобы превратить бессловесный номер в имя, понятное человеку, опять-таки требуется база.

Почему реконструкция прототипов так важна для декомпилятора? А потому, что она позволяет восстанавливать типы передаваемых функциями переменных, назначая им хоть и обезличенные, но все же осмысленные имена в стиле: hWnd, hModule, X, Y, nWidth, nHeight, hCursor, hMenu, hDlg. Согласись, это намного лучше, чем dword_1008030, dword_1008269, dword_1006933, что характерно для подавляющего большинства остальных
декомпиляторов.

Даже если часть переменных распознана, то это уже упрощает анализ программы и реконструкцию оставшихся переменных.

Константа или смещения

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

А какая между этими двумя сущностями разница? Очень большая! Вот, например, в регистр EAX загружается число 106996h. Если это указатель на ячейку памяти или массив данных, то дизассемблер должен воткнуть по этому адресу метку (label) и написать MOV EAX, _offset_ lab_106996 (естественно, имя метки дано условно, и совпадение с ее численным значением абсолютно случайно — при повторной компиляции она может оказаться расположенной по совершенно другому адресу). А вот если 106996h — это константа, выражающая, например, среднюю плотность тушканчиков на один квадратный метр лесополосы или количество полигонов на морде монстра, то ставить offset ни в коем случае нельзя, поскольку это введет нас в
заблуждение при анализе, а еще, как уже говорилось, при повторной компиляции смещение может уплыть, превращая число 106996h черт знает во что. Программа либо будет работать неправильно, либо сразу рухнет (особенно, если путаница между константами и смещениями происходит не единожды, а совершается на протяжении всего листинга).

Так как же все-таки определить, кто есть кто? На первый взгляд, все достаточно просто. Если данная сущность используется как указатель (то есть через нее происходит обращение к памяти по заданному адресу: mov eax, 106996h/mov ebx,[eax]), тут и
дизассемблеру ясно, что это смещение. Но стоит лишь немного усложнить пример, скажем, передать 106996h какой-нибудь функции или начать производить с ней сложные манипуляции, то дизассемблеру потребуется высадиться на полную реконструкцию всей цепочки преобразований. Но даже тогда его решение может оказаться неверным, поскольку в языке Си индексы (то есть константы) и указатели (то есть смещения) полностью взаимозаменяемы и конструкция buf[69] не
только равносильна 69[buf], но и транслируется в идентичный машинный код, при реконструкции которого возникает очевидная проблема.

У нас есть два числа A и B, сумма которых представляет указатель (то есть существует возможность определить, что это указатель, да и то если попыхтеть), но вот что из них индекс? Увы. Формальная математика не дает ответа на этот вопрос, и дизассемблеру приходится полагаться лишь на свою интуицию да эвристику. Указатели в win32, как правило, велики, поскольку минимальный базовый адрес загрузки файла равен 100000h. Индексы же, как правило (опять! как правило!), малы и много меньше указателей, однако если у нас имеется массив, расположенный по адресу 200000h и состоящий из 3 145 728 (300000h) элементов (а почему бы, собственно, и нет?!), то тут индексы старших элементов становятся больше
базового указателя на массив, что вводит дизассемблер в заблуждение.

Код или данные

Вот так проблема! Наверное, даже самый тупой дизассемблер разберется, что ему подсунули: код или данные, тем более что в PE-файлах (основной формат исполняемых файлов под Windows) они разнесены по разным секциям. Ну, это в теории они разнесены, а на практике компиляторы очень любят пихать данные в секцию кода (особенно этим славиться продукция фирмы Borland).

С другой стороны, практически все компиляторы (особенно на Си++) сплошь и рядом используют вызовы функций типа CALL EBX. Чтобы понять, куда ведет такой вызов, необходимо установить значение регистра EBX, что требует наличия более или менее полного эмулятора процессора, отслеживающего всю историю содержимого EBX с момента его инициализации и до непосредственного вызова.

Но непосредственные вызовы - ерунда. Вот косвенные - это да! Реконструкция CALL dword ptr DS:[EBX] требует не только эмуляции процессора (то есть набора машинных команд), но и эмуляции памяти! Естественно, это на порядок усложняет дизассемблерный движок, зато нераспознанные массивы данных мгновенно превращаются в функции и, что самое главное, дизассемблер показывает, кто именно и откуда их вызывает!

Наличие эмулятора процессора и памяти позволяет также отслеживать положение регистра ESP, используемого для адресации локальных переменных и аргументов, передаваемых функциям. Если же эмулятора нет (а в IDA он есть), дизассемблер способен распознавать лишь простейшие формы адресации/передачи аргументов. Механизм, ответственный за распознание и отслеживание аргументов, носит красивое название PIT, но эта аббревиатура отнюдь не расшифровывается как «Пивоваренный [завод] Ивана Таранова», а происходит от
Parameter Identification and Tracking — идентификация и отслеживание параметров, то есть аргументов. Тех, что бывают у функций. А еще бывают функции без аргументов, но это уже другая история.

Реконструкция потока управления

Языки высокого уровня оперируют такими конструкциями, как циклы, операторы выбора, ветвления и т.д., что делает программу простой и наглядной. Собственно говоря, именно отсюда и пошло структурное программирование. А ведь когда-то, давным-давно, в Бейсике (и других языках того времени), кроме примитивного GOTO, ничего не было и программа, насчитывающая больше сотни строк, превращалась в сплошные «спагетти», лишенные всякой логики, внутренней организации и следов цивилизации.

Начиная с пятой версии в IDA Pro появился механизм графов, позволяющий автоматически реконструировать циклы, ветвления и прочие «кирпичи» языков высокого уровня. Впрочем, польза от графов была небольшой, и в реальности они только замедляли анализ, поскольку подобрать адекватный механизм визуализации и навигации Ильфаку так и не удалось… Но ведь не пропадать же труду?!

У истоков HexRays

К пятой версии IDA Pro имела в своем арсенале все необходимое для автоматической декомпиляции, причем не просто декомпиляции, а очень
качественной декомпиляции, декомпиляции принципиально нового уровня, до которого не дотягивает ни один другой существующих
декомпилятор.

Вот так и родилась идея дописать к IDA еще небольшую (на самом деле очень большую) порцию кода, переводящую китайскую ассемблерную грамоту в доступный и понятный листинг на языке Си. Закипела напряженная работа, по ходу которой выявлялись все новые и новые подводные камни, обход которых требовал времени, усилий и мозговой активности. А всякая (или практически всякая) работа упирается в деньги, тем более что у Ильфака фирма!

Включать декомпилятор в дистрибутив IDA Pro Ильфак не стал. Тому было несколько причин. Первая и главная — основной массе текущих пользователей IDA декомпилятор не сильно нужен, если они им и будут пользоваться, то лишь из чистого любопытства, запустят пару раз, плюнут и вернутся к привычному стилю жизни - анализу дизассемблерного листинга. Второе — зарабатывать на жизнь (Ильфаку) и содержать фирму как-то же надо?!

Все это привело к тому, что декомпилятор, получивший название (HexRays), был выпущен отдельным продуктом, но - внимание на экран - требующим
обязательного присутствия IDA, поскольку HexRays — всего лишь плагин. Таким образом, реверсеру, желающему упростить свою жизнь за счет автоматической декомпиляции, необходимо прибрести как саму IDA, так и
HexRays. Причем приобретать этот комплект будет совсем другая пользовательская аудитория, совсем не та, что приобретала ИДУ и почитала ее как самый лучший интерактивный дизассемблер. Интерактивный — значит, тесно взаимодействующий с пользователем (в смысле с хакером). В противовес ей, пакетные дизассемблеры стремятся к максимальной автоматизации
реверсинга, лишая пользователя возможности вмешиваться в процесс и отдавать указания.
HexRays в отличии от IDA Pro интерактивностью не обладает: она у него атрофирована еще в зародыше. Нет даже опций настройки! А там где нет интерактивности, нет и хакеров. И тут мы плавно переходим к ответу на вопрос кому нужен
HexRays.

Боевое крещение

Итак, Hex-Rays у нас на руках. Устанавливаем его туда же, где располагаются все остальные
плагины для IDA Pro, и приступаем к тестированию. В качестве объекта тестирования используется стандартный блокнот (в данном случае из комплекта поставки W2KSP0), на котором обкатываются все вирусы, все упаковщики исполняемых файлов (вместе с распаковщиками), все протекторы. словом, декомпилятор не станет исключением. А что? Блокнот - достаточно простая программа, обуславливающая тот минимум функционала, ниже которого декомпилятор из мощного программного комплекса превращается в дорогостоящую, но абсолютно бесполезную игрушку.

Загрузив notepad.exe в IDA Pro и ответив на ряд несложных вопросов мастера автоанализа, даем дизассемблеру некоторое время поработать и, когда он перейдет в режим ожидания, заходим в меню «File -> Produce File -> Create C file» или нажимаем горячие клавиши <Ctrl-F5>.

Сначала на экране появляется логотип HexRays с предложением провериться на обновления и после нажатия на OK
HexRays думает некоторое время, а когда он закончит заниматься магической деятельностью, на диске образуется файл notepad.c.

Может, мы не тот компилятор выбрали для тестирования? Вообще-то, по идее, декомпилятор должен выдавать листинг на ANSI C, поддерживаемый любым ANSI-совместимым C-компилятором, но… все мы хорошо знаем любовь Ильфака к продукции фирмы Borland. На нем написана сама IDA, на нем же вышло первое SDK… Хорошо, берем последнюю версию
Borland C++ (благо она бесплатна) и что же?! Вновь простыня ошибок и ругательств, приводящих к преждевременному прерыванию компиляции. Оказывается,
чтобы откомпилировать декомпилированный файл, над ним еще предстоит основательно поработать. Вот тебе и раз…

А вот тебе и два! Декомпилятор выдал чистый *.c-файл, проигнорировав тот факт, что notepad.exe содержит еще и секцию ресурсов, но даже если при загрузке блокнота в IDA форсировать обработку ресурсов, мы все равно ничего не получим. Ну не умеет
HexRays с ними работать и все-тут! Возможно, когда-нибудь он этому и научиться, но сейчас - нет.

Другими словами, HexRays не позволяет компилировать декомпилированные программы без дополнительной ручной работы и реально пригоден лишь для анализа. Возникает резонный вопрос: и насколько же он упрощает анализ? Чтобы не быть голословным, приведу два фрагмента кода:

if ( RegOpenKeyExA(
HKEY_CLASSES_ROOT,
"CLSID\\\\InprocServer32",
0,
0x20019u,
&hKey) )
result = 0;
>
else
cbData = 260;
if ( !RegQueryValueExA(hKey, ValueName, 0, 0, lpData, &cbData) ) v1 = 1;
RegCloseKey(hKey);
result = v1;
>
return result;

Просто? Красиво? Понятно? Элегантно? Еще как! А вот как выглядел тот же самый код в чистом дизассемблере:

.text:0100318F push ebp
.text:01003190 mov ebp, esp
.text:01003192 push ecx
.text:01003193 push ecx
.text:01003194 lea eax, [ebp+hKey]
.text:01003197 push esi
.text:01003198 xor esi, esi
.text:0100319A push eax ; phkResult
.text:0100319B push 20019h ; samDesired
.text:010031A0 push esi ; ulOptions
.text:010031A1 push offset SubKey ; lpSubKey
.text:010031A6 push 80000000h ; hKey
.text:010031AB call ds:RegOpenKeyExA
.text:010031B1 test eax, eax
.text:010031B3 jnz short loc_10031E7
.text:010031B5 lea eax, [ebp+cbData]
.text:010031B8 mov [ebp+cbData], 104h
.text:010031BF push eax ; lpcbData
.text:010031C0 push [ebp+lpData] ; lpData
.text:010031C3 push esi ; lpType
.text:010031C4 push esi ; lpReserved
.text:010031C5 push offset ValueName ; lpValueName
.text:010031CA push [ebp+hKey] ; hKey
.text:010031CD call ds:RegQueryValueExA
.text:010031D3 test eax, eax
.text:010031D5 jnz short loc_10031DA
.text:010031D7 push 1
.text:010031D9 pop esi
.text:010031DA
.text:010031DA loc_10031DA: ; CODE XREF: sub_100318F+46?j
.text:010031DA push [ebp+hKey] ; hKey
.text:010031DD call ds:RegCloseKey
.text:010031E3 mov eax, esi
.text:010031E5 jmp short loc_10031E9
.text:010031E7
.text:010031E7 loc_10031E7: ; CODE XREF: sub_100318F+24?j
.text:010031E7 xor eax, eax
.text:010031E9
.text:010031E9 loc_10031E9: ; CODE XREF: sub_100318F+56?j
.text:010031E9 pop esi
.text:010031EA leave
.text:010031EB retn 4

Согласись, что сравнение отнюдь не в пользу дизассемблера, но не спеши радоваться. Рассмотрим еще один пример:

Что делает этот код? Совершенно непонятно. То есть не то чтобы совсем непонятно, но смысл как-то ускользает. Тут требуется проанализировать, что это за переменные такие, кто еще (помимо этой функции) их модифицирует и зачем? В дизассемблере листинг выглядит схожим образом, но мощная система навигации по коду вкупе с перекрестными ссылками и подсветкой одноименных переменных/функций сокращает время анализа на несколько порядков, причем ни в одном текстовом редакторе, ни в одной среде программирования подобной системы навигации по коду нет!

А это вид в дизассемблере:

.text:01002306 loc_1002306: ; CODE XREF: sub_1002239+C4?j
.text:01002306 mov eax, dword_1008028
.text:0100230B push ebx
.text:0100230C push edi
.text:0100230D mov dword_1008BCC, eax
.text:01002312 push dword_10087D0
.text:01002318 call sub_10059A3
.text:0100231D test eax, eax
.text:0100231F jz short loc_1002328

Наш вердикт

HexRays – это, безусловно, большой шаг вперед и неплохое подспорье для начинающих, но… он не стоит тех денег, которые за него просят, к тому же (это касается начинающих), однажды потратив время на изучение ассемблера, мы обретаем возможность реверсировать что угодно и в чем угодно (на худой конец с помощью утилиты DUMPBIN.EXE, входящей в состав SDK), а обольщенные возможностями автоматической декомпиляции, мы становимся заложниками
HeyRays со всеми вытекающими отсюда последствиями.



Полную версию статьи
читай в февральском номере Хакера! Демонстрационную версию IDA ты найдешь на нашем диске. К сожалению, мы не можем выложить HexRays по правовым соображениям. На нашем диске будет видеоролик, демонстрирующий возможности HexRays.

Скажите, есть ли сегодня механизмы написания DLL на Delphi, которую невозможно было бы декомпилировать - если да, то дайте пожалуйста информацию или какие-то правильные ссылки на информацию, на какой версии Delphi и как это можно сделать?


3,590 2 2 золотых знака 15 15 серебряных знаков 31 31 бронзовый знак Возможно, вы имели ввиду устойчивость к взлому? Потому что на любой версии Delphi привести исполняемый код к исходному виду pas-файлов не получится, если отключить отладочную информацию. Компилятор Delphi создает нативный, а не интерпретируемый код, так что можно считать что компиляция - это "путь в один конец" Декомпилировать в исходный код невозможно будет dll, созданную в любой версии Delphi (если не включать в неё отладочную информацию, как сказали выше). Однако декомпилировать в псевдо-код или в ассемблер - можно любое приложение. И защиты от этого не существует, иначе приложение не сможет выполняться. Однако можно затруднить взлом, но это решается усложнением алгоритма работы приложения и слабо зависит от среды разработки. Ещё есть такая вещь как полиморфный код, который изменяет сам себя в процессе выполнения, но это с вероятностью 99% заставит делать стойку на ваше приложение все антивирусы. Я делаю DLL, с которой будет работать коммерческая обработка 1С, конечно же смысл данной DLL в том, чтобы она выполняла часть сложного функционала, а так-же проверяла лицензии на неком веб-ресурсе. Т.е.коммерческая обработка 1С будет использовать методы из DLL. И вот нужно защититься от того, чтобы не могли вскрыть алгоритм того функционала, который делает DLL. Ну тут можно попробовать шифровать код, как делают, например, всякие asprotect (AFAIR) и защиты на игрушках. Но при наличии желания, времени и средств вскрыть возможно любую защиту, поэтому весь вопрос в балансе - стоимость приложения/трудозатраты на взлом. Раз вы не знаете, как защитить ваше приложение - лучше не пытаться изобрести велосипед, в противном случае очень велика вероятность того, что у вас будет навешана куча проверок, но все они легко нивелируются всего одной заменой jz на jnz (к примеру). Возьмите готовое решение - ASProtect, VMProtect и т.п. Это будет гораздо правильнее.

В дополнение к сказаномому @Alekcvp и @cpp_user могу вот, что добавить:

Вариант №1.

Вырезаем всю отладочную инфу и компилим в релиз версии. В добавок вырезаем весь rtti. Это делает ваш код относительно "чистым". Ну тут есть не большие "огрешности":

  • Компилятор все равно вставит rtti от стадартных библеотек. Это можно вылечить перекомпилацией rtl, но это сложно.
  • В коде могут использоваться такие процедуры как SetLength/New/Dispose и тд. Всем им нужен rtti типа передаваемой переменой, то есть rtti для таких переменых будет в бинарнике.
  • Сами классы внутри бинарников имеют некую информацию без rtti, такие как имя класса, список полей(без имен) для авто освобождения.

Отсеивает совсем линивых

  • Разбирающейся хоть немного спец разберет бинарник без всяких проблем

Вариант №2

Берем другой язык. Например С++ или подобный. Мало чем отличается от предыдущего в плане взлома но, инфы в бинарнике как правило на порядок меньше, поумолчанию.

За счет всяких оптимизации С++ может не много усложнить процесс разбора бинарника в сравнении с предыдущим вариантом.

Профессионал разберется без проблем

Сложнее писать код для С++ (язык сложнее)

Вариант №3

Берем стороние средства защиты. Тут нужно выбирать средства, которые реализуют защиту посредством виртуальной машины в ядре операционки. Всё остальные(шифраторы или упаковщики) ломаются очень лекго. Это пожалуй самый надежный метод если защита строится локально. Но тут нужно понимать, что такое решение для всего своего кода может очень сильно снизить производительность.

  • Для взлома понадобится очень не плохой спец и это спецу понадобится возможно много времени, а это много денег и есть шанс, что ломать изза этого не станут.

Стоит денег(может даже не мальньких).

Если виртуалка была взломана(и особенно метод взлома лежит в интернэтах) все пиши пропало.

Вариант №4

Можно постараться реализовать секретную логику на своем сервере. Тут правда нужен свой сервер и если клиентов много, то нужен мощный сервер.

Почему был сгенерирован этот код? Можно ли защитить dll от декомпиляции или dll была опубликована как realease?

enter image description here

Та же проблема возникает при декомпиляции пробной версией Reflector.

enter image description here

2 ответа

Во-первых, вы нарушаете лицензионное соглашение, пытаясь реконструировать их код.

f. Разборка. Вы не имеете права подвергать обратному проектированию, декомпилировать, дизассемблировать или каким-либо иным образом пытаться получить доступ к информации, касающейся конструкции ПРОДУКТА.

Посмотрев с помощью других инструментов или перейдя в шестнадцатеричный формат, вы увидите, что переменные были скрыты и представляют собой такие вещи, как , который на самом деле является символом ACK ^ F, за которым следует символ «НАЧАЛО ТЕКСТА», который выглядит как пробел, но не пробел. Другие используемые символы включают символ возврата.

IL для приведенного выше кода будет чем-то вроде

Вы уловили идею.

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

Может, этот декомпилятор просто не очень хорош?

«Умный» обфускатор может сделать что-то забавное, чтобы сбить с толку людей, например, используя невидимые символы Юникода в качестве имен идентификаторов, но, видя, что ему удалось сгенерировать такое имя, как param0 , более вероятно, что декомпилятор просто не не работает должным образом. Вы можете проверить это, просмотрев файл в текстовом редакторе, предназначенном для программирования, который отображает каждый символ.

Создание исходного кода

Символы не загружены

Снимок экрана: документ "Символы не загружены"

Исходный код не найден

Снимок экрана: документ "Исходный код не найден"

Создание и внедрение исходного кода для сборки

Снимок экрана: контекстное меню сборки в окне "Модули" с командой "Декомпилировать исходный код".

Извлечение и просмотр внедренного исходного кода

Исходные файлы, внедренные в файл символов, можно извлечь с помощью команды Извлечь исходный код в контекстном меню окна Модули.

Снимок экрана: контекстное меню сборки в окне "Модули" с командой "Извлечь исходный код".

Извлеченные исходные файлы добавляются в решение как прочие файлы. В Visual Studio функция "Прочие файлы" по умолчанию отключена. Чтобы включить эту функцию, установите флажок Инструменты > Параметры > Среда > Документы > Показывать прочие файлы в Обозревателе решений. Без включения этой функции вы не сможете открыть извлеченный исходный код.

Снимок экрана: страница параметров инструментов с установленным флажком для включения прочих файлов.

Извлеченные исходные файлы отображаются в разделе прочих файлов в Обозревателе решений.

Снимок экрана. Обозреватель решений с прочими файлами.

Известные ограничения

Требуется режим прерывания выполнения

значок "Прервать все"

Создание исходного кода с помощью декомпиляции возможно только в том случае, если отладчик находится в режиме прерывания выполнения и приложение приостановлено. Например, Visual Studio переходит в режим прерывания, попадая в точку останова или в исключение. Вы можете легко активировать прерывание выполнения Visual Studio при следующем запуске кода с помощью команды Прервать все ().

Ограничения декомпиляции

Отладка оптимизированных сборок или сборок выпуска

При отладке кода, декомпилированного из сборки, которая была скомпилирована с использованием оптимизаций компилятора, вы можете столкнуться со следующими проблемами:

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

Дополнительные сведения можно найти в описании проблемы GitHub Интеграция ICSharpCode.Decompiler с отладчиком VS.

Надежность декомпиляции

Относительно небольшой процент попыток декомпиляции может привести к сбою. Это происходит из-за ошибки пустой ссылки точки последовательности в ILSpy. Мы устранили этот сбой путем перехвата таких проблем и корректного завершения попытки декомпиляции.

Дополнительные сведения можно найти в описании проблемы GitHub Интеграция ICSharpCode.Decompiler с отладчиком VS.

Ограничения при работе с асинхронным кодом

Результаты декомпиляции модулей с шаблонами кода async/await могут быть неполными или неудачными в целом. Шаблоны кода async/await и машины состояния yield state-machine в ILSpy реализованы только частично.

Дополнительные сведения можно найти в описании проблемы GitHub Состояние генератора PDB.

Только мой код

Параметры режима Только мой код (JMC) позволяют Visual Studio выполнять шаг с обходом системы, платформы, библиотеки и других вызовов непользовательского кода. Во время сеанса отладки в окне Модули отображаются модули кода, которые отладчик воспринимает как "Мой код" (т. е. пользовательский код).

При декомпиляции оптимизированных модулей или модулей выпуска создается непользовательский код. Если отладчик прерывается в декомпилированном непользовательском коде, появляется окно Отсутствует источник. Чтобы отключить режим "Только мой код", перейдите в раздел Инструменты > Параметры (или Отладка > Параметры) > Отладка > Общие и снимите флажок Включить только мой код. .

Извлеченный исходный код

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

  • Имена и расположение созданных файлов нельзя настроить.
  • Файлы являются временными и будут удалены Visual Studio.
  • Файлы помещаются в одну папку без использования какой-либо иерархии, которая была в оригинальных исходных файлах.
  • Имя каждого файла содержит хэш контрольной суммы файла.

Читайте также: