Сегодня мы будем сочетать приятное с полезным, а именно погрузимся в две наши любимые темы — разные экзотические интерпретаторы и деобфускация. Я уже достаточно злословил на тему того, сколько в последнее время понапридумывали средств разработки для чайников, чтобы каждый школьник после просмотра ознакомительного тиктоковского ролика мог закодить свою первую программу.
Наверное, ты удивился, почему я до сих пор не упоминал такое распространенное условно‑бесплатное поделие, как AutoIt? Судя по всему, он задумывался как мечта любой дрессированной обезьяны — ничего не надо программировать, просто вози мышкой по экрану и тыкай по кнопкам, все твои действия автоматически скриптуются, причем совершенно безвозмездно, то есть даром. Для тех, кто чуть поумнее, наскоро придумали урезанную версию бейсика для добавления в скрипты простенькой логики.
Дальше, по мере роста популярности технологии, ее создатели пошли по накатанной схеме — придумали механизм компоновки из простецких текстовых скриптов исполняемых файлов, и вот уже целые коммерческие проекты пишутся исключительно на AutoIt. Причем изначально в политике конторы сохранялось некое фриварно‑опенсорсное фрондерство: пакет, помимо «компилятора» Aut2Exe, преобразовывающего скрипт в исполняемый модуль, содержал «декомпилятор», проворачивающий фарш назад, — Exe2Aut.
Однако с версии 3.2.5.1 эти вредные веяния упразднили и теперь грозят всяческими карами наглецам, посмевшим заикнуться о восстановлении кода из «скомпилированного» исполняемого файла. Конечно же, угрозами дело не ограничилось — была предпринята и программная защита исходного кода (местами довольно забавная): прекомпиляция исходников в байт‑код, который потом упаковывали, зашифровывали и даже навешивали сверху UPX, а кроме того, использовали весьма примитивную обфускацию. Естественно, такая защита эффективна исключительно от честных людей, точнее, от школьников, незнакомых с основами реверс‑инжиниринга.
Я давно хотел написать разбор одного из таких проектов, но никак не мог найти подходящий коммерческий продукт. И вот кандидат на роль подопытного кролика наконец отыскался. Итак, у нас имеется некий программный пакет автоматизации, записывающий и воспроизводящий ряд действий пользователя с клавиатурой и мышью. Detect It Easy красноречиво указывает на его происхождение.
Exeinfo PE более конкретно называет версию — AutoIt v3.3.13.15. Пакет работает, но без регистрации существует ряд раздражающих ограничений: при определенных действиях программа выдает сообщения вида «Unregistered version can not ..., to register?» с предложением, понятное дело, зарегистрироваться.
Лицензионный ключ программа запрашивает на сайте разработчика, там же этот ключ и валидирует, что дополнительно характеризует авторов с не очень хорошей стороны. Раз так, попробуем сами вытащить исходники из исполняемого файла. Поскольку версия нашего AutoIt выше 3.2.5.1, штатного декомпилятора для нее не существует.
По счастью, имеются и сторонние декомпиляторы, и деобфускаторы AutoIt, и Exeinfo PE даже указывает нам на них: это Exe2Aut decomp. v0.10 2014 и AU3Stripper v19.x 2019 or myAutToExe 2.15 CW2K@gmx.de.
Первая ссылка уже мертва, а со второй явно что‑то не то, однако проект myAutToExe вполне существует и поддерживается на GitHub. Можно нагуглить еще, к примеру, питоновский скрипт AutoIt-Ripper, но нам вполне подходит и myAutToExe — он самый актуальный, да еще и со множеством заявленных дополнительных фич, поэтому им и воспользуемся.
Действительно, этот инструмент восстановил нам исходный au3-файл, сэкономив кучу времени и нервов на разбор виртуальной машины и системы команд AutoIt, которых мы на этот раз касаться не будем. Возможно, у нас когда‑нибудь появится задача, для которой это будет необходимо, но пока что для дальнейших действий вполне достаточно и восстановленного кода. Желающие могут самостоятельно углубиться в эту тему, более детально исследовав исходники приведенных выше гитхабовских проектов.
У нас же, даже несмотря на наличие восстановленного кода, веселье только начинается. При первом взгляде становится очевидно, что полученный код совершенно нечитаем.
Начисто отсутствуют имена идентификаторов, численные и строковые константы. Судя по обилию функций EXECUTE(
, вероятно, зашифрованы особо критичные фрагменты кода — налицо явная обфускация с целью осложнить нам жизнь. Причем обфускация какая‑то самописно‑кастомная, поскольку в использованном нами myAutToExe деобфускация известных инструментов заявлена прямо «из коробки». В readme.
даже перечислен список поддерживаемых обфускаторов:
Supported Obfuscators:
'Jos van der Zande AutoIt3 Source Obfuscator v1.0.14 [June 16, 2007]' ,
'Jos van der Zande AutoIt3 Source Obfuscator v1.0.15 [July 1, 2007]' ,
'Jos van der Zande AutoIt3 Source Obfuscator v1.0.20 [Sept 8, 2007]' ,
'Jos van der Zande AutoIt3 Source Obfuscator v1.0.22 [Oct 18, 2007]' ,
'Jos van der Zande AutoIt3 Source Obfuscator v1.0.24 [Feb 15, 2008]' ,
'EncodeIt 2.0' and
'Chr() string encode'
Причем содержащиеся в примерах обфусцированные файлы этим самым Jos van der Zande AutoIt3 Source Obfuscator до боли напоминают наш код, но что‑то неуловимое мешает myAutToExe корректно его детектировать и деобфусцировать. Не будем искать ответ на вопрос, что именно и как починить myAutToExe, — у нас сейчас есть конкретная цель, и нет смысла отвлекаться на побочные квесты. Попробуем придать программе читабельности своими руками.
Благо мы уже изрядно поднаторели в гораздо более мрачной деобфускации. В качестве примеров можешь посмотреть другие мои статьи:
- Зелье для Zelix. Изучаем обфускатор для Java и придумываем собственный деобфускатор
- Разгадайка. Пишем собственный деобфускатор для JavaScript
- JSFuck. Разбираем уникальный метод обфускации JS-кода
Вдобавок умные люди уже давно занимаются делом деобфускации скриптов AutoIt и пишут об этом статьи. В общем, как говорится, глаза боятся, а руки делают.
Начнем с восстановления текстовых строк. По обилию в восстановленном коде присваиваний выражений вида A2E00001A18(
можно предположить, что строковые константы каким‑то образом закодированы через эти функции и массив. Находим функцию A2E00001A18
в самом конце кода:
FUNC A2E00001A18($A2E00001A18)
LOCAL $A2E00001A18_
FOR $X=1 TO STRINGLEN($A2E00001A18)STEP 2
$A2E00001A18_&=CHR(DEC(STRINGMID($A2E00001A18,$X,2)))
NEXT
RETURN $A2E00001A18_
ENDFUNC
Ничего сложного, типичная криптография для младших школьников: каждый символ закодирован двумя Hex-символами своего 8-битного шестнадцатеричного кода. Осталось понять, как формируется огромный (несколько тысяч элементов) массив исходных строк для этой функции $OS[
. Если глянуть на предыдущий скриншот, то становится очевидно, что его заполняет функция A2E00001A18_(
, тоже расположенная в конце кода.
В ней также нет ничего сложного: она зачем‑то целых пять раз подряд сохраняет в файл временного каталога со случайным названием (генерируемым функцией a2e00001a18x_(
) огромный массив текстовых данных, захардкоженный в предшествующей функции _igrf4d27dqc(
. Немного смущают вот эти «зашифрованные» строки кода:
Global $a2e00001a18, $os = Execute(BinaryToString("0x457865637574652842696E617279746F737472696E672827...
И вот такие:
Execute(BinaryToString("0x457865637574652842696E617279746F737472696E672827307834353738363536333735373...
Первая из них заполняет искомый массив $OS
, но, судя по использованию функции BinaryToString(
, других криптоалгоритмов автор обфускатора пока не выучил, поэтому пишем простенькую программку на шарпе и раскодируем первую строку:
string newline = "";for (int j = 0; j < sline.Length; j += 2){ string charcode = sline.Substring(j, 2); try { byte bt = Convert.ToByte(charcode, 16); newline += (char)(bt); } catch (Exception e) { break; }}
Продолжение доступно только участникам
Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».
Присоединяйся к сообществу «Xakep.ru»!
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее