Making a Decode PHP 7.2

  • Автор темы Автор темы f4r0fA
  • Дата начала Дата начала

f4r0fA

Созидатель (II)
Сообщения
4
Реакции
0
Баллы
34
Hello community!

I was recently browsing around looking for a decoder for PHP 7.2 and found a file that seems to work fine for version 5.2. However, I'm having trouble updating it to PHP 7.2 and would like to ask for your help.

---------------------
Plataform Windows 10
:acute:Included in File
PHP 5.2 - 7.2 - 7.3 - 7.4
BusyBox not necessary if u use W10 with Linux Kernel
Shell and BAT File
--------------------

We know that PHP 7.2 has brought a number of important improvements and features, and it's essential that we keep our code up to date to take advantage of these benefits. A decoder compatible with this version would be extremely useful for the entire community.

If anyone has knowledge and experience with PHP decoders, or knows of a solution that could be adapted for PHP 7.2, please share your ideas and suggestions. Together we can find a way to make this possible.

Remembering that collaboration is fundamental in a community like ours. Every contribution, no matter how small, can make a difference for all of us. So, if you have any knowledge or experience in the area, don't hesitate to share .

Thanks in advance to everyone who can help to update the decoder for PHP 7.2. Let's work together to improve our projects and drive community development.

I count on the participation of all of you!

Thx, f4r0fA - Brazil

Download Link
https://www.sendspace.com/file/i3ezmg

 

Вложения

  • Screenshot_1.png
    Screenshot_1.png
    67,1 КБ · Просмотры: 18
Buddy, this is a very very old decoder, probably 6-8 years old.
No one will make such a decoder for free, especially as a public version.
A private decoder will be expensive, as there are services that make money on decoding
 
Ну у кого нибудь удалось ДЕКОДИРОВАТЬ файл php 7.2? Оно не работает, я уже и через бизибокс проверил.
 
Opcode dumps from ionCube-encoded files for PHP 7.1, PHP 7.2, and PHP 7.4:

идеи давних прошлых лет с того же самого github и лягут в основы очередного сервиса, нового придумать ничего не смогли, плохо тама на западе с идеями. Людям нужен decoder full (working in 1 click, all versions, full decode) without sms and free support, есть над чем еще потрудится (то с++ таскают туда-сюда, то opdumper):yes3:
 
Последнее редактирование:
идеи давних прошлых лет с того же самого github и лягут в основы очередного сервиса, нового придумать ничего не смогли, плохо тама на западе с идеями. Людям нужен decoder full (working in 1 click, all versions, full decode) without sms and free support, есть над чем еще потрудится (то с++ таскают туда-сюда, то opdumper):yes3:
Ну так предложи публике свое решение
 
Ну так предложи публике свое решение
к чему меня должен обязывать этот факт? пусть работает, изя хоть проапргейдится)) мне доказывать что-то никому не нужно, потому что эту публику я знаю как свои 5:yes3:
 
идеи давних прошлых лет с того же самого github и лягут в основы очередного сервиса, нового придумать ничего не смогли, плохо тама на западе с идеями. Людям нужен decoder full (working in 1 click, all versions, full decode) without sms and free support, есть над чем еще потрудится (то с++ таскают туда-сюда, то opdumper):yes3:
Smells like frustration. 😄 Just stay in your lane if you’re not capable of making a better solution public. That’s my recommendation, plain and simple.
 
Smells like frustration. 😄 Just stay in your lane if you’re not capable of making a better solution public. That’s my recommendation, plain and simple.
абсолюно не вижу ничего нового что было предложено, это валялось в паблике лет так 6-7 назад, а самим идеям лет 15, лично вы ничего нового не придумали, просто взяли чужие идеи.
 
And what's the problem exactly? I don't understand.

It would be much better if you came up with a productive comment instead of this kind of poor-taste frustration. We all know the basic idea is "opcodes -> AST -> PHP". If you've reinvented the wheel and you're smarter than everyone else, then please show us your amazing "wow" solution.

Don't come here criticizing me after I've spent hours analyzing loaders, investing my own valuable time, and then making the results public for everyone to benefit from, including from what you call my "bad" solution.

Please.
 
не надо советовать что для меня лучше и рассказывать сказки социалистического коллективизма, я лишь констатирую очевидное - нельзя написать "классику" дважды, так что зачем кому-то что-то "ВАУ доказывать", все уже было доказано до вас (видимо вы еще под стол пешком ходили). Доставать что-то в 26 году из нафталина, и удивляться почему он не Дартаньян:grin:
 
Последнее редактирование:
Ну варианты только дамп опкодов, или патч защиты делать. Я пошел по первому пути да почитал тоже то что скинули выше, интересно. НО пошел по пути немного другому без расширении и патчей, пока пытаюсь все собрать из памяти. Есть определенные наработки не буду обманывать сыровато но двигаюсь :) может что то и получиться а если нет то все равно будет опыт :)

Декодер ionCube — как работает сейчас и что осталось

Задача

Есть зашифрованные ionCube-файлы PHP (модули CMS, аддоны). Нужен читаемый исходник, чтобы разбираться с логикой и править её. Локально доступен только лоадер ionCube — «выпотрошить» файл без запуска не удалось: формат не документирован.

Цель — не привязка к одной версии PHP, а универсальный разбор: чтобы одна и та же логика работала на любой установленной версии с соответствующим лоадером. Поэтому всё, что зависит от версии, вынесено в отдельные профили, а ядро остаётся общим.

Главная идея: не ломать шифр, а подсмотреть

Первая мысль — расшифровать контейнер офлайн, разобрать файл как структуру данных. Она упирается в принципиальный момент: внутри не лежит исходник и даже не нормальный байткод Zend. Файл скомпилирован в байткод и зашифрован, и при запуске лоадер расшифровывает его на лету, исполняя через собственную виртуальную машину, а не через штатный механизм PHP. Исходника в памяти нет ни в каком виде — ни обфусцированного, ни частичного. Искать его бессмысленно, ловить в куче или в opcache тоже: компиляция идёт мимо Zend, кэш её не видит.

Поэтому стратегия другая: запустить файл в обычном PHP с обычным лоадером и снимать данные в момент, когда лоадер их уже расшифровал. Файл при этом исполняется штатно, а мы ставим наблюдение в самый горячий участок — в тот момент, когда виртуальная машина лоадера выбирает обработчик очередной инструкции. Это единственная точка, где одновременно доступны номер инструкции, её адрес, сырые байты записи и выбранный обработчик. Отсюда снимается всё остальное.

Конвейер концептуально состоит из четырёх слоёв:

Подсмотр. Перехват в цикле виртуальной машины лоадера: снимаем содержимое всех служебных структур — массивов инструкций, пулов литералов, ключевых потоков.
Расшифровка. Восстановление номеров операций: сырой байтовый поток превращается в таблицу «обработчик → номер операции».
Реконструкция. Сборка структуры: имена методов, строки, аргументы, ветвления — обратно в PHP-код.
Проверка. Синтаксическая проверка результата и сравнение с эталоном, если он есть.
Ядро (слои 1, 3, 4) от версии PHP не зависит. Версионное — только слой 2: набор номеров операций у каждой версии свой, поэтому он хранится как сменяемый профиль.

Ключевые находки
1. Ключевой поток. Номера операций в файле не хранятся открытыми. Вместо них лежит «обработчик» — адрес функции виртуальной машины, зашифрованный потоком байтов, уникальным для каждой функции. Формула восстановления найдена и подтверждена на всех проверенных сэмплах: ключ двойного слова собирается из четырёх байт потока по простой формуле, а сама операция получается обратным XOR. Один этот шаг дал полную статическую расшифровку всех операций без всякого исполнения файла — то есть по сути найден способ читать содержимое файла, даже не запуская его.

2. Карта «обработчик → операция». У Zend для каждой операции существует своя функция-обработчик, значит, их адреса можно сопоставить с распознанными обработчиками. Так составлена карта соответствий; редкие операции ветвлений размечены по контексту, потому что напрямую они не идентифицируются. Дополнительно используется автоякорь: первая операция любой функции всегда одна и та же (приём аргументов), и она служит проверкой «плавающей базы» между прогонами — если якорь съехал, весь последующий разбор сдвинут. Эта же схема — то есть сам способ построения карты, а не сама карта — переносится на любую версию: для нового профиля нужно только пересобрать соответствия.

3. Пул литералов — это поток исполнения. Главный сюрприз и главная потеря времени. Литералы (строки, имена) материализуются лениво: в памяти они появляются только тогда, когда до них дошла исполняющаяся функция. Ранний дамп снимал пулы до исполнения, и в 97 из 103 функций они были пустыми. После переноса снятия дампа после исполнения с принудительным вызовом всех методов пулы заполнились полностью.

Дальше выяснилось, что порядок литералов в пуле совпадает с порядком их первого использования в коде. Отсюда появился принцип «курсора»: разбор идёт по инструкциям, и при каждом обращении к литералу берётся следующий по порядку. Простые правила: строка и её вариант в нижнем регистре — один литерал; одиночная нижняя копия — мусорный дубль прошлой строки; скаляр занимает один слот; дальше граница, за которой начинается чужая память, — стоп.

4. Ветвления. Операнды переходов зашифрованы в статическом дампе, но истинные значения видны только в момент исполнения. Поэтому значения снимаются отдельным наблюдением и складываются в отдельный слой данных. Цель перехода при этом считается по простой формуле от индекса инструкции и второго операнда — подтверждено 28 парами трассировки. Сами обработчики ветвлений опознаются по трём семействам значений.

5. Имена вызовов. В самих операциях имён методов нет вообще. Они берутся из литералов по эвристике «ближняя пара имя/имя-метода» — для чистых методов она попадает точно. Отдельно вскрыт паттерн одного из форматов: последний вызов аргумента в нём физически стоит после вызова функции, то есть при разборе его нужно забирать «взглядом вперёд».

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

Что реально работает сейчас

Этап Статус
Формат контейнера, дескриптор, заголовок разобран полностью
Расшифровка операций (ключевой поток) 100%
Карта «обработчик → операция» ~94% операций именовано
Пулы литералов 52/52 и 103/103 функций полные
Ветвления (if / else) восстанавливаются, но только по исполненным веткам
Генерация PHP-кода оба файла проходят синтаксическую проверку
Совместимость со старым форматом ionCube 10.2 работает без изменений конвейера
Ядро конвейера версионно-независимо; проверено на нескольких установленных версиях PHP с соответствующими лоадерами, переключение сводится к смене профиля операций.

Качество на реальных файлах

Чтобы мерить точность, взяты референсные декоды тех же самых файлов сторонним платным декодером. Сравнение смысловой близости — по вызовам, строкам, числам и ветвлениям:

Образец Формат Методов Средняя точность
A — большой CRUD-модуль 45bfa667 101/101 84% (57 методов ≥95%)
B — модуль авторизации 45bfa667 51 / 41 в референсе 34%
C — маленький служебный класс ionCube 10.2 6 / 11 36%
Отдельные методы восстанавливаются почти идеально. Например, HTTP-хелпер из образца B повторяет референс один в один по структуре (инициализация сессии, семь вызовов настройки, два условия) — расходятся только имена переменных. Простой метод-вставка из образца A — 100%.

По форматам выяснилось важное: в старом ionCube 10.2 имена переменных лежат открытыми и извлекаются тривиально, в новом 45bfa667 они зашифрованы отдельным слоем — при одинаковом коде конвейера это разные объёмы работы.

Что не решено

1. Имена переменных в формате 45bfa667 — главный открытый вопрос. Записи имён зашифрованы даже в рантайме: длина фиксированная, содержимое — мусор. Два пути: либо реверс формулы расшифровки (нужны известные plaintext-примеры и ключевые потоки для подбора), либо перехват в момент, когда виртуальная машина сама использует имя — например, при выводе ошибки или фатального сообщения, где имя попадает в текст. Второй путь выглядит реалистичнее, но это отдельный проект по наблюдению.

2. Аргументы вызовов в формате v11. В образце B константы и имена идут не напрямую из пула, а через промежуточные кэш-слоты; слоты монотонно убывают, а группы литералов идут в порядке потока. Правило «k-й слот соответствует k-й группе» пока не подтверждено на всём файле — отсюда 34% по образцу B при 84% по образцу A. Это не дефект генератора, а нерешённая задача разбора.

3. Аргументы строго по номеру позиции. Сейчас раскладка идёт по порядку потока исполнения, из-за чего аргументы местами съезжают — заметнее всего на длинных методах вроде отмены подписки и приёма платежа. Нужна строгая раскладка по номеру аргумента, который операция передачи знает точно.

4. Неисполненные ветки. Значения операндов берутся из пробы, а проба не может покрыть всё: нужна реальная сессия, пользователь, база. Ветка, которая не исполнилась, остаётся закомментированной. Сейчас сделано 5 проходов аргументов (пусто / единица / строка / массив / истина); дальше нужны пробы с состоянием CMS.

5. Константы вида C0x и пустые значения. Индексы из общей таблицы констант виртуальной машины, которая лежит вне литерального пула. Часть значений вытаскивается из трассы исполнения — так вскрылись языковые константы и набор эндпоинтов внешнего OAuth-провайдера, — но остальное осталось нетронутым.

6. Циклы foreach/fetch. Операторы цикла в декодированном наборе отсутствуют: соответствующие опкоды не восстановлены, поэтому циклы в выводе не появляются.

7. Неполнота карты операций. Часть редких обработчиков размечена по контексту с риском ошибки — например, метки одной операции внутри HTTP-вызова стоят неверно, а роль части обработчиков подтверждена только трассировкой, а не формулой.

8. Профили под остальные версии PHP. Ядро и способ построения карты уже версионно-независимы, но набор профилей покрывает не все установленные версии. Чтобы расширить покрытие, для каждой новой версии нужно пересобрать карту соответствий и повторить контрольный декод одного файла — процедура отработанная и не требует изменений в логике разбора.

9. Альтернативный формат обмена с готовым лифтером — не начат. Собственный генератор покрывает текущие задачи, поэтому отдельный слой сериализации пока не нужен.

Практический итог

Декод пригоден для анализа логики, но пока не для продакшена. Типичный результат: структура класса, сигнатуры, имена методов, строки, SQL-подобные вызовы и логика ветвлений читаются; для точного воспроизведения поведения нужна ручная доводка конкретного файла. По референсу: образец A — 84% при 100% покрытии методов, образец B — 34%. Это честная картина.

Два практических совета:

декодировать имеет смысл файлы старого формата (ionCube 10.2 и раньше) — там имена переменных сразу открыты и результат заметно чище;
архитектура конвейера не привязана к версии PHP: переход на другую версию — это смена профиля операций, а не переписывание разбора.


Можно закидать тапками сказать что я тупой нуб и лучше заняться чем то еще :)
 
Последнее редактирование:
Hey, thought this might be useful for your research: IonCube PHP 8.1–8.4 — Static Opcode Extraction Without Execution.

It documents a static approach based on reverse engineering the loaders, covering the container format, opcode decoding, and profiles for different PHP versions. It also includes Python scripts.

The tested loaders and formats may differ from yours, but some of the findings could be useful for comparison, especially given your work on opcode mapping and version-independent parsing. Would be interesting to hear whether any of it lines up with what you’ve found :)
 
Назад
Верх