
Деобфускатор ConfuserEx2 с поддержкой анти-тампера, компрессора, констант, потока управления и восстановления ресурсов.
Улучшенный форк UnconfuserEx с расширенной поддержкой современных вариантов ConfuserEx2, восстановлением анти-взлома, удалением компрессора, восстановлением потока управления и реконструкцией ресурсов.
https://github.com/user-attachments/assets/de2c7fd9-6736-4f39-83c0-3c25aa9c1f24
Если вы когда-нибудь работали с образцами вредоносного ПО, некоторые из них обфусцированы с помощью ConfuserEx. Я пробовал некоторые публичные деобфускаторы против последних версий, но они просто не работали, поэтому я решил форкнуть один публичный, который работал с последней версией, и просто модифицировать его под свои нужды.
Этот репозиторий — форк MadMin3r/UnconfuserEx. Заслуги принадлежат ему. Оригинальный проект сделал сложную работу по созданию целенаправленного деобфускатора для ConfuserEx2, который действительно мог удалять настоящие защиты.
Этот проект делает именно это. Он запускает список удалителей в фиксированном порядке, перезаписывает тела методов/ресурсы/метаданные там, где может, и записывает новую сборку обратно. Важен порядок. Компрессор и анти-взлом должны выполняться рано, потому что остальная часть модуля может даже не быть настоящим IL.
Версия из апстрима уже была полезной, но несколько случаев постоянно всплывали.
Один из них — путь LZMA. Некоторые образцы передают байты, которые выглядят как полезная нагрузка констант/ресурсов, но свойства LZMA — бессмыслица. Если передать их напрямую декодеру, вы получите нелепые размеры словаря и в итоге исключения вроде выхода размеров массива за допустимый диапазон. Поэтому эта версия проверяет свойства, ограничивает размер словаря, ограничивает размер несжатых данных и выходит до того, как декодер выделит что-то нелепое.
LZMA properties => CE FD 62 5F 9F
Invalid LZMA properties byte 0xCE or unreasonable dictionary size
У констант была ещё одна тупая, но реальная проблема. Большая часть кода разрешения хочет, чтобы ID, расположенный перед вызовом геттера, был ldc.i4. Иногда это уже не одна инструкция. Это крошечное арифметическое выражение.
ldc.i4 0x1234
ldc.i4 0x55
xor
call string <const getter>(int32)
Оригинальный форк видит xor, вызывает GetLdcI4Value() и умирает, потому что xor явно не загрузка целого числа. Эта версия проходит обратно по небольшой арифметической последовательности, эмулирует стек, сворачивает её обратно в один ldc.i4, а затем позволяет нормальному решателю продолжать.
Таким образом, вместо того чтобы рассматривать это как совершенно другую защиту констант, она превращается в это:
ldc.i4 0x1261
call string <const getter>(int32)
Затем существующий путь обычного/x86 решателя констант может выполнять свою работу.
Поток управления — вот где было неважно
Удалитель switch может обрабатывать обычную форму switch-диспетчера ConfuserEx. Он обходит блоки, восстанавливает следующий целевой блок, удаляет мёртвые блоки и выдает нормальное тело метода. Но есть образцы, где понимается только часть метода. Если вы мутируете половину метода, а затем обнаруживаете, что он всё ещё обфусцирован, результат хуже бесполезного, потому что теперь у вас сломанный IL и нет чистого способа понять, что произошло.
Поэтому эта версия делает снимок тела метода перед его изменением:
инструкции
обработчики исключений
Если деобфускация выбрасывает исключение или если метод после этого всё ещё выглядит обфусцированным, исходное тело восстанавливается. Журнал всё ещё может сказать «этот метод не решён», но сборка не будет молча повреждена только из-за того, что один метод имел странный диспетчер.
Управление потоком с прыжками/трамплинами также получило свой собственный проход. Некоторые методы — это не просто switch-диспетчеры. Это небольшие цепочки трамплинов, соединённых до тех пор, пока не будет достигнут реальный блок. Теперь они обнаруживаются и сворачиваются, вместо того чтобы игнорироваться на пути только switch.
Удалитель компрессора — это часть, которая должна запускаться раньше всех.
Заглушки компрессора ConfuserEx обычно хранят настоящую сборку сжатой, загружают крошечный загрузчик, распаковывают полезную нагрузку и загружают её во время выполнения.
Удалитель находит форму загрузчика, извлекает встроенную полезную нагрузку, распаковывает её и заменяет модуль на настоящую сборку. Обработаны как нормальные, так и компактные макеты компрессора.
[+] Обнаружен компрессор
[+] Извлечена полезная нагрузка сжатого модуля
[+] Распакован реальный модуль
[+] Продолжение конвейера на распакованной сборке
Анти-взлом теперь имеет два пути.
Обычный/динамический анти-взлом дешифрует тела методов из защищенных секций и записывает восстановленные тела обратно в модуль. JIT анти-взлом более раздражает, потому что тела должны материализоваться, когда время выполнения запрашивает их.
Примерная форма:
найти init
извлечь ключи
найти зашифрованную секцию JIT-тел
вывести ключ для каждого метода
прочитать тело
записать CilBody обратно
Это всё ещё основано на шаблонах. Если заглушка изменилась достаточно сильно, это, очевидно, не сработает.
Ресурсы обрабатываются аналогично константам: найти зашифрованный блок ресурсов, восстановить ключ/форму дешифратора, расшифровать, при необходимости распаковать, затем вернуть ресурсы туда, где их ожидают обычные инструменты .NET.
Также есть опциональный путь перестроения встроенного PE. Некоторые защищенные образцы содержат управляемый PE внутри ресурса. С включенной перестройкой удалитель пытается разобрать и перезаписать эту полезную нагрузку, вместо того чтобы оставлять деобфусцированную внешнюю сборку с нетронутой внутренней.
UnConfuserEx.exe sample.exe sample.clean.exe --rebuild-embedded-pe
Используйте это, если знаете, что образец прячет другую управляемую сборку внутри ресурсов. Если полезная нагрузка не является управляемым PE, путь перестроения должен оставить её в покое.
Сборка:
dotnet build .\UnConfuserEx.sln -c Release
Запуск:
.\UnConfuserEx\bin\Release\net9.0\UnConfuserEx.exe .\protected.exe
Или укажите явный путь вывода:
.\UnConfuserEx\bin\Release\net9.0\UnConfuserEx.exe .\protected.exe .\protected.clean.exe
Если вы не укажете путь вывода, он создаст файл рядом с входным с добавлением -deobfuscated к имени.
Для встроенных управляемых полезных нагрузок:
.\UnConfuserEx\bin\Release\net9.0\UnConfuserEx.exe .\protected.exe .\protected.clean.exe --rebuild-embedded-pe
Это текущий список поддерживаемых защит. Это не означает, что каждый возможный форк ConfuserEx работает. Это означает, что конвейер знает, как искать эти формы.
Возможно, в коде спрятано ещё что-то, что я забыл перечислить xD.
Полезные журналы — те, которые сообщают, какой этап не удался, а не просто то, что вывод не запустился.
Пример исправленного пути констант:
Constants detected, attempting to remove
Found 3 constant getter(s)
Detected constant decryption type is Dynamic
Decompressed constants blob to 18492 byte(s)
Resolving getter <Module>::???????? as String with 41 call site method(s)
Removed all instances of getter <Module>::????????
Пример метода потока управления, который был намеренно оставлен нетронутым:
Removing obfuscation from method System.Void Example::Run()
Method System.Void Example::Run() still appears obfuscated after deobfuscation -- left original body intact
Removed obfuscation from 42 methods. Failed to remove from 0 methods. 1 methods left untouched
Этот второй журнал не идеален, но он ПО КРАЙНЕЙ МЕРЕ честен.
Пользовательский форк ConfuserEx, изменяющий форму каждого хелпера.
Геттер констант, вычисляющий свой ID через полный cf-беспорядок, вместо небольшого стекового выражения.
cf-граф, где диспетчер зависит от значений времени выполнения, которые статический эмулятор не знает.
Нативные хелперы, требующие реального выполнения во время выполнения, а не эмуляции IL.
Сборки, которые уже были сломаны до того, как их обфусцировали.
Варианты JIT анти-взлома с другим расположением зашифрованных тел.
Если вы хотите, чтобы проблема была полезной, включите достаточно данных для её воспроизведения.
Удалите расширения файлов из образцов перед их загрузкой.
Заархивируйте всё вместе и включите следующее:
Команда:
UnConfuserEx.exe <цель> <необязательный вывод>
Этап сбоя:
- compressor
- anti tamper
- constants
- control flow
- resources
- writing output
- runtime after deobfuscation
Ожидаемый результат:
Фактический результат:
Вывод консоли:
Ссылка на архив:
Заметки / исследование:
Если вы пришлёте только «не работает», ответ, вероятно, будет «да, не работает».




Небольшие целенаправленные исправления лучше масштабных переписываний.
Если вы добавляете поддержку новой формы защиты, изолируйте её в том удалителе, который ей управляет. Если вы добавляете поведение отката, убедитесь, что сбой не повредит выходную сборку. Если вы затрагиваете поток управления, предполагайте, что исправленный вами странный образец — не единственный странный образец, который существует :DDD.
Только НЕ делайте инструмент более сложным для отладки.
Этот проект основан на MadMin3r/UnconfuserEx.
Оригинальный проект предоставил основу и большую часть основного конвейера деобфускации. Этот форк фокусируется на улучшении надёжности, добавлении поддержки дополнительных вариантов защиты и обработке граничных случаев, наблюдаемых в реальных образцах.
Этот проект начинался как практический инструмент для обратной разработки, а не как упражнение по программной инженерии. Основное внимание всегда уделялось надёжному восстановлению защищённых сборок, а не поддержанию безупречного качества кода.
Этот инструмент предназначен для авторизованного анализа вредоносного ПО, обратной разработки, восстановления программного обеспечения, совместимости и образовательных исследований.
Пользователи несут ответственность за соблюдение применимых законов и получение необходимых разрешений перед анализом, доступом или обработкой программного обеспечения или систем.
Zypherion Technologies не разрешает незаконное использование этого инструмента и отказывается от ответственности за неправомерное использование третьими лицами.
Ничто в этом репозитории или на www.zypherion.tech не является юридической консультацией.