Reversing Center
Дистанционный центр по исследованию защитного ПО.

Интересно Как ломают плагины для 3ds Max

Lopex

Форумчанин
✅ Продавец⠀
Сообщения
74
Реакции
122
Гарант
2
Коммерческие плагины к популярным программам, как и обычные приложения, используют собственные механизмы безопасности. Сегодня мы немного поковыряемся во внутренностях платных расширений для популярного трехмерного редактора 3ds Max и узнаем, какие методы защиты применяют их разработчики.

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

У дизайнеров, активно занимающихся 3D-моделированием, большой популярностью пользуется редактор 3ds Max небезызвестной компании Autodesk. Этот профессиональный редактор уже больше тридцати лет считается лидером отрасли, начиная еще с эпохи DOS. Разумеется, как любой профессиональный редактор, он предоставляет API, на основе которого толковый пользователь может дописывать свои модули под собственные технические задачи (скрипты, плагины и прочее). И конечно же, на рынке программного обеспечения довольно быстро появилась соответствующая ниша, связанная с изготовлением и продажей подобного рода расширений, которые пользуются спросом у профессиональных дизайнеров‑трехмерщиков.

За тридцать с лишним лет Autodesk успела наплодить множество типов расширений, из которых самый старый и часто используемый — скриптинг на MAXScript. MAXScript — собственный, ни на что не похожий (хотя Википедия почему‑то отмечает сходство с BASIC и LISP) язык, имеющий просто чудовищный по современным меркам синтаксис. По сути, это тяжелое наследие лихих девяностых, когда гордыня первопроходцев компьютерного софта заставляла их изгаляться во имя уникальности, лишь бы не как у всех. Самые отмороженные из подобных решений отмерли, заместились общепринятыми технологиями (Python, JavaScript), другие сами стали неким стандартом, предоставив в качестве компромисса интерфейс для вызова более популярных платформ.

Хотя в Autodesk и предприняли робкую попытку заменить MAXScript Python’ом, но на данный момент, похоже, MAXScript все‑таки лидирует — дело и в поддержке старых наработок, и в том, что из MAXScript есть возможность вызывать .NET-библиотеки, в которых можно реализовать любую хотелку.

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

Нужна активация лицензии!


Нужна активация лицензии!

И без регистрации расширение отказывается что‑либо делать дальше. Как отучить программу от этой вредной привычки?

Поначалу нам слегка везет: расширение имеет формат простого текстового скрипта, в котором хоть и напрочь отсутствуют форматирование, пробелы и переводы строк, но логику проследить можно. К слову, могло быть и хуже — это мог бы быть нативный плагин, да и сами скрипты бывают не только прозрачного текстового .MS-формата, но и зашифрованными (.MSE) и даже запакованными (.MZP).

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

Открыв текст скрипта в блокноте, мы видим, что он на девяносто процентов состоит из хаотичного набора латинских символов и цифр, напоминающих Base64 или упомянутый мной в одной из предыдущих статей адобовский JSXBIN.

Содержимое плагина



Мысленно взяв в руки бритву Оккама, предположим, что это все‑таки простейший Base64. Это предположение подтверждает и найденная в открытой текстовой части кода конструкция на «максовском» птичьем языке:
Код:
...last_dll_id!=astrid or :: last_dll_fullname!= sett_dll.fullname then(fn abytes=(dotnetclass"System.Convert").frombase64str ing(fb64(astr()));::sett_dll=dn_assembly.load(abyt es());...
В примерном переводе на понятный человеческий язык это означает, что некая Base64-строка по мере исполнения конвертируется в бинарный массив, который загружается как .NET-библиотека. Полное погружение в дебри этого странного языка в наши планы не входит, мы ориентируемся на конструкции типа sett_dll.createinstance(...), загружающие объекты и функции из этой библиотеки.

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

Начнем с самой длинной строки astr, содержимое которой до боли похоже на закодированный DLL. Оно раскодируется успешно, и результат вроде бы и вправду похож на DLL.
pic3_LHqMyv4.jpg

Содержимое строки astr
Похож‑то он, конечно, похож, но как примерно тот легендарный мотор, который был похож на настоящий, но не работал. Сигнатура правильная, строки частично тоже видны, однако это явно неправильная расшифровка. Придется все‑таки снова нырять в глубины недоязыка MAXScript. Внимательно посмотрев на процитированную выше строку кода, мы обнаруживаем между astr и frombase64string незаметную прокладку — функцию fb64, после чего находим ее код:
Код:
fb64 a b:"axpuger"c:""=(for i=1 to b.count do a=substitutestring(substitutestring(substitutestri ng a(toupper b[i])c)(tolower b[i])(toupper b[i]))c(tolower b[i]);a);fn
Функции toupper и tolower понятны и без справочника — это, соответственно, верхний и нижний регистр символа. Конструкция же substitutestring a b c эквивалентна полной замене в строке с всех подстрок, (выберем для простоты JavaScript). Эту конструкцию можно представить в виде a.replace(new RegExp(b, 'g'), c). То есть этот замысловатый код на самом деле представляет собой серию из вложенных подстановок со сменой регистра символов из строки axpuger через промежуточный символ . На том же JavaScript эта операция эквивалентна следующей функции, которой мы и перекодируем строку до нормального Base64: function fb64(a) { var b="axpuger"; for (var i=0;i
Как видишь, при ближайшем рассмотрении операция оказалась простой и даже самообратимой, как всем известный XOR. Иными словами, чтобы обратно закодировать для вставки в скрипт исправленную Base64-строку, нам надо применить к ней ту же самую функцию. Вообще говоря, для людей, хорошо знакомых с MAXScript и 3ds Max, этот этап не представляет никакой проблемы — вовсе не обязательно разбирать алгоритм перекодировки, саму операцию можно было выполнить, не выходя из 3ds Max, чуть подправив исходный скрипт. В общем‑то, и обратная операция перекодировки исправленного модуля не обязательна — ведь достаточно просто убрать лишнее звено fb64 в технологической цепочке.

Однако мы подходим к следующему серьезному этапу работы: у нас уже есть расшифрованная дотнетовская библиотека, которую надо поправить и закодировать обратно в скрипт. И здесь не все так гладко — при загрузке библиотеки в dnSpy оказывается, что большинство методов имеют безумные имена, а их тела пусты. То есть модуль сурово обфусцирован. Попытаемся идентифицировать и по возможности снять обфускатор при помощи de4dot. Этот инструмент выдает огромное множество ошибок, деобфусцировать напрочь отказывается, однако польза от него есть: он выдал имя обфускатора — это Confuser.

Слегка погуглив, мы обнаруживаем, что наш случай широко известен и небезнадежен: добрые люди создали для него специализированный деобфускатор, причем даже с открытым кодом. Решение практически однокликовое — у деобфускатора всего две опции: -d (динамическая) и -s (статическая) распаковка. Динамическая распаковка на нашем модуле с диким визгом и простыней логов валится, однако статическая создает модуль, хоть и не до конца читабельный в dnSpy, но вполне себе с открытым кодом. Можно его нормально анализировать даже без запуска и найти место для фактически однобайтового патча.
pic5.jpg


Деобфусцированный модуль можно изучить в dnSpy. А вот дальше у нас снова возникают проблемы: перекодированный в Base64 и загруженный в скрипт исправленный модуль работать категорически отказывается. 3ds Max при его загрузке выдает ошибку "Error in DLL -- Runtime error: .NET runtime exception: Could not load type 'Invalid_Token.0x02000000...". Впрочем, такую же ошибку выдает и не патченный, а просто деобфусцированный при помощи ConfuserEx-Unpacker модуль — проблема явно в кривой деобфускации. Это значит, что наши мучения еще не закончены и надо ломать голову в поисках способа внести найденный патч без деобфускации всей библиотеки. Поскольку наше повествование и так уже достаточно затянулось, честно признаюсь, что я таки нашел версию деобфускатора Confuser, корректно обрабатывающую этот динамический модуль и в статическом, и в динамическом режимах. Впоследствии деобфусцированный и патченный модуль нормально работает из злополучного скрипта.

Если читателя не пугает арабская вязь, то вот ссылка на упомянутую версию ConfuserEx Unpacker - https://www.at4re.net/f/thread-1431.html. В заключение я все‑таки в двух словах опишу направление для самостоятельного патча в обфусцированном модуле Confuser. На тот случай, если тебе попадется версия, которая окажется не по зубам всем найденным в интернете деобфускаторам. Соответственно, можно пропатчить найденный фрагмент кода, отксорив его с существующим значением. В Confuser все совсем по‑другому: покопавшись в коде проекта ConfuserEx Unpacker, в модуле Protection/AntiTamper.cs можно найти процедуру DecryptMethods, где находится такой алгоритм:
Код:
for (uint i = 0; i < num; i++) { uint num4 = reader.ReadUInt32(); numArray[i] = num4 ^ arrayKeys[(int)((IntPtr)(i & 15))]; arrayKeys[(int)((IntPtr)(i & 15))] = num4 + 0x3dbb2819; }
Исходя из этого алгоритма нельзя просто так взять и поменять один байт в коде, поскольку изменение одного байта влечет за собой повторное шифрование всей последующей части блока. Тем не менее трудности не помеха для усидчивого хакера, которому, конечно, не составит труда написать маленькую программку для патча и повторного шифрования блока данных на основе приведенного выше алгоритма.

Скрытый контент для зарегистрированных пользователей
 
Последнее редактирование:
telderi.ru
Сверху