Гайд Байткод. Семантика. LLM: декомпиляция, и разбор Melonity Spoofer

Разработчик
Статус
Оффлайн
Регистрация
1 Сен 2018
Сообщения
1,597
Реакции[?]
881
Поинты[?]
116K
Как обычно, более удобно на Notion:
Пожалуйста, авторизуйтесь для просмотра ссылки.


Всем привет, сегодня мы препарируем Melonity Spoofer, и, поверьте, это будет интереснее, чем звучит.

Почему Melonity Spoofer?
Честно? Просто попался под руку.

Введение
Первым шагом в анализе любого исполняемого файла является изучение его сигнатур. Это могут быть визуальные признаки (названия секций, нестандартная точка входа) или алгоритмические подходы (расчет энтропии, поиск специфических последовательностей байтов).
1721251452141.png
И что же видим? Иначально он был написан на Python, а затем упакован в единый исполняемый файл. Это типичная практика, преследующая две цели:
  1. Избавить пользователей от головной боли с зависимостями (как мило с их стороны).
  2. Обфускация: усложнение анализа кода посторонними.
Что же такое PyInstaller?
Теперь, когда мы знаем, что имеем дело с PyInstaller'ом, давайте разберемся, что у него внутри:
1721251525236.png
Ключевые вещи, на что стоит взглянуть:
  1. CArchive: Содержит упакованные файлы, включая Python скрипты и модули.
  2. Table of Contents (TOC): Список всех файлов и их метаданные.
  3. Cookie: Важная информация для распаковки, метаданные условно

Чтобы распаковать наш файл нам нужно написать скрипт, который сделает пару этапов:
  • Поиск магического числа:
    • Ищем последовательность байтов MEI\\014\\013\\012\\013\\016 с конца файла.
    • Это указывает на начало данных PyInstaller.
  • Чтение Cookie:
    • Извлекаем информацию о версии PyInstaller, позиции TOC, длине пакета.
    • Для PyInstaller 2.0: 24 байта, для 2.1+: 24 + 64 байта.
  • Парсинг TOC:
    • TOC содержит записи фиксированной структуры.
    • Каждая запись включает: позицию, размер сжатых/несжатых данных, флаги сжатия, тип данных, имя файла.
  • Извлечение файлов:
    • Для каждой записи в TOC:
      • Читаем данные с указанной позиции.
      • Если данные сжаты (флаг == 1), распаковываем через zlib.
      • Сохраняем файл, восстанавливая структуру каталогов.
  • Постобработка:
    • Для .pyc файлов восстанавливаем корректный заголовок.
    • Отдельно обрабатываем PYZ-архивы (специальные архивы Python-модулей).
В целом процесс достаточно простой, ознакомиться с исходным кодом можно
Пожалуйста, авторизуйтесь для просмотра ссылки.
.

Проблема шифрования
Закинув наш файл в этот скрипт, мы столкнёмся с интересной ситуацией:
Код:
[!] Error: Failed to decompress /expat.pyc in PYZArchive, likely encrypted. Extracting as is

[!] Error: Failed to decompress /sax/__init__.pyc in PYZArchive, likely encrypted. Extracting as is

[!] Error: Failed to decompress /xml/sax/_exceptions.pyc in PYZArchive, likely encrypted. Extracting as is

[!] Error: Failed to decompress /xml/sax/expatreader.pyc in PYZArchive, likely encrypted. Extracting as is

[!] Error: Failed to decompress /xml/sax/handler.pyc in PYZArchive, likely encrypted. Extracting as is

[!] Error: Failed to decompress /xml/sax/saxutils.pyc in PYZArchive, likely encrypted. Extracting as is

[!] Error: Failed to decompress /xml/sax/xmlreader.pyc in PYZArchive, likely encrypted. Extracting as is

[!] Error: Failed to decompress /zipfile.pyc in PYZArchive, likely encrypted. Extracting as is

[+] Successfully extracted pyinstaller archive: MelonitySpoofer.exe
Большинство файлов не смогли распаковаться, скрипт подсказывает, что они упакованы. Взглянув на исходный код распаковщика Pyinstaller, можно увидеть, что файлы шифруются с помощью AES, а ключ хранится в отдельном
Пожалуйста, авторизуйтесь для просмотра ссылки.
, под названием “pyimod00_crypto_key”.

Открываем папку, и замечаем его, закидываем в дизассемблер виртуальной машины пайтон, и видим заветный ключ.
1721251756968.png

Хотя он со странным названием “0000qwemelox”, может автор спуфера на что-то намекает… Но нам это не важно, давайте резюмируем, что у нас есть:
  1. Структура зашифрованного файла:
    • Первые 16 байт: Вектор инициализации (IV)
    • Остальная часть: Зашифрованные и сжатые данные
  2. Ключ шифрования: Фиксированный ключ: 00000000qwemelox

Получается процесс дешифрования будет примерно таким: a. Чтение зашифрованного файла b. Отделение IV от зашифрованных данных c. Дешифрование с использованием AES в режиме CTR d. Декомпрессия расшифрованных данных с помощью zlib e. Добавление стандартного заголовка .pyc файла f. Сохранение расшифрованного .pyc файла

Пример ключевой части кода:
Python:
key = b"00000000qwemelox"
header = b"\\xA7\\x0D\\x0D\\x0A\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00"

def decrypt_file(input_path: Path, output_path: Path) -> None:
    with input_path.open("rb") as en_f, output_path.open("wb") as de_f:
        encrypted_data = en_f.read()
        iv, ciphertext = encrypted_data[:16], encrypted_data[16:]

        cipher = Cipher(algorithms.AES(key), modes.CTR(iv), backend=default_backend())
        decryptor = cipher.decryptor()
        decrypted_data = decryptor.update(ciphertext) + decryptor.finalize()

        plaintext = zlib.decompress(decrypted_data)
        de_f.write(header + plaintext)
LLM как декомпилятор
Получив полностью расшифрованные скомпилированные пайтон файлы:


Первая же идея это закинуть в декомпилятор, тех которые действительно поддерживаются всего два:
  1. Uncompyle6: Очень медленно появляется поддержка новых версий Python, наш файл он вовсе отказывается обрабатывать из-за версии.
  2. Пожалуйста, авторизуйтесь для просмотра ссылки.
    : Активно поддерживается сообществом, написан на С++, но к сожалению декомпиляции нашей версии ( 3.11 ) написана всего лишь на 35%.
Можно просто сидеть, и анализировать инструкции руками, смотря на подобную картину:

А что если использовать Language Model (LLM) для декомпиляции? Спойлер: это сработало, и вот как.



Подробнее:
  1. Дизассемблирование:
    • Используем pycdc для преобразования .pyc файлов в ассемблероподобный код.
    • Пример вывода:
      0 RESUME 0
      2 LOAD_CONST 0: '\\\\n@echo off\\\\n\\\\n:Cleaner\\\\nset "steam=$steam"\\\\n...'
      4 STORE_NAME 0: script
      6 LOAD_CONST 1: None
      8 RETURN_VALUE
  2. Предобработка:
    • Удаление лишней информации (номера строк, адреса в памяти).
  3. Подготовка промпта:
    • Создание детального промпта, объясняющего задачу LLM.
    • Пример части промпта:
      You are an expert Python reverse engineer. Your task is to analyze the following disassembled Python bytecode and reconstruct the original source code. Pay attention to the logic flow, variable names, and function structures. If you're unsure about certain parts, provide your best guess and mark it with a comment.
  4. Использование LLM (Claude API):
    • Отправка подготовленного промпта и дизассемблированного кода в API.
    • Использование нескольких итераций для уточнения результатов.
  5. Анализ вывода с помощью другого LLM:
    • Проверка сгенерированного кода на синтаксические ошибки.
    • Сравнение логики с дизассемблированной версией.
Результаты и анализ
Использование LLM для декомпиляции принесло удивительные результаты:
  1. Высокая точность: LLM смогла воссоздать весь код, включая структуру функций и логику.
  2. Восстановление имен переменных: Удивительно, но модель часто предлагала семантически верные имена переменных и функций.
  3. Комментарии и документация: LLM даже добавила комментарии, объясняющие сложные части кода.
  4. Обработка сложных конструкций: Модель успешно восстановила циклы, условные операторы и даже некоторые паттерны проектирования.
Пример восстановленного кода
Вот фрагмент кода, восстановленного с помощью LLM:

Но нельзя исключать возможность галлюцинаций у LLM, поэтому проверяйте, но всё же впечатляет.

Теперь собрав все файлы скрипта попробуем запустить, и убеждаемся, что всё идеально функционирует:


Как бонус разбор самого спуфера
Спуфер фундаментальный. Основной функционал:
  1. Вывод логотипа (важнейшая функция, конечно).
  2. Завершение процессов Steam и Dota 2.
  3. Проверка прав администратора.
  4. Создание и выполнение batch-файла.
  5. Предложение перезагрузки системы.
Batch-файл делает:
  • Очистка конфигураций Steam и Dota 2 (удаление папок и файлов).
  • Удаление записей реестра, связанных со Steam.
  • Генерация нового MAC-адреса.

Заключение
В целом это больше небольшое пособие по PyInstaller, и пример применения LLM в реверс-инженеринге.

Мой шиза-блог ( единственный щитпост блог по реверсу!! ):
Пожалуйста, авторизуйтесь для просмотра ссылки.
 
Последнее редактирование:
Эксперт
Статус
Онлайн
Регистрация
29 Мар 2021
Сообщения
1,605
Реакции[?]
607
Поинты[?]
48K
на правой стороне ринга: скармливатель байткода в ллм
на левой стороне ринга: ебаный jit, который это всё контрит

бесполезная хуйня ура победа

но идея забавная
 
Разработчик
Статус
Оффлайн
Регистрация
1 Сен 2018
Сообщения
1,597
Реакции[?]
881
Поинты[?]
116K
на правой стороне ринга: скармливатель байткода в ллм
на левой стороне ринга: ебаный jit, который это всё контрит

бесполезная хуйня ура победа

но идея забавная
В целом у тебя какие-то завышенные ожидания от статьи, она была упрощена намеренно, чтобы зацепить больше аудитории ( ну типа ачё нет? ). Основная тема статьи всё же остается разбор структуры PyInstaller, а LLM лишь один из способов декомпила, который показан в конце, в целом он всегда применим к PyInstaller.

Можно было бы конечно детальнее, и сложнее сделать статью, и думаю ты был бы доволен, но... оно того не стоит =)
 
@removespread
Пользователь
Статус
Оффлайн
Регистрация
13 Янв 2018
Сообщения
352
Реакции[?]
147
Поинты[?]
0
вы чеж все на спуферы напали, сначала самый ржачный за всю историю форума арбитраж, сейчас это, что дальше?

по треду: время реверсить очередной щит
 
practice makes perfect
Пользователь
Статус
Оффлайн
Регистрация
16 Мар 2019
Сообщения
89
Реакции[?]
68
Поинты[?]
20K
на правой стороне ринга: скармливатель байткода в ллм
на левой стороне ринга: ебаный jit, который это всё контрит

бесполезная хуйня ура победа

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

обкакаться по полной программе и не воспринимать или терять контекст ура победа

но посмеяться с тебя можно продолжай
 
Эксперт
Статус
Онлайн
Регистрация
29 Мар 2021
Сообщения
1,605
Реакции[?]
607
Поинты[?]
48K
на правой стороне ринга: определение протектора по размеру файла
на правой стороне ринга абсолютно ебаная идея, ты это лучше меня знать должен ахахах
 
practice makes perfect
Пользователь
Статус
Оффлайн
Регистрация
16 Мар 2019
Сообщения
89
Реакции[?]
68
Поинты[?]
20K
Сверху Снизу