Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Способы обхода триала в различных программах — одна из самых интересных тем прикладного реверс‑инжиниринга, и я не уже не раз посвящал ей свои статьи. Настало время вернуться к этой тематике снова. Наш сегодняшний пациент — приложение, выполненное в виде JAR-модуля, которое мы исследуем без полного реверса и пересборки проекта.
warning
Статья имеет ознакомительный характер и предназначена для специалистов по безопасности, проводящих тестирование в рамках контракта. Автор и редакция не несут ответственности за любой вред, причиненный с применением изложенной информации. Распространение вредоносных программ, нарушение работы систем и нарушение тайны переписки преследуются по закону.
В заметке «В обход стражи. Отлаживаем код на PHP, упакованный SourceGuardian» мы рассматривали программу, реализованную в виде локального веб‑интерфейса. Работает она так: под Windows запускается локальный сервер Apache c набором PHP-модулей, а пользователь взаимодействует с приложением через браузер, в котором набирает адрес localhost
. Программа, взломом которой мы займемся сегодня, действует похожим образом, только написана она на Java и поставляется в виде файла .JAR
. Наша задача — отучить приложение от деморежима.
По счастью, нам известно, где лежат стартующие в виде сервиса исполняемые модули программы в формате .EXE
и соответствующий JAR-файл. По своей сути JAR — это обычный ZIP-архив, в который упакованы части проекта. Поскольку мы собираемся править код, нас интересуют модули *.CLASS
, содержащие откомпилированный JVM-байт‑код. Декомпиляторов и способов их применения множество, существуют даже инструменты вроде JD-GUI, способные полностью восстановить проект из исполняемого файла. Чаще всего взломщики используют общеизвестный JAD, который из‑за его распространенности ловкие обфускаторы давно научились обманывать, что, в свою очередь, стало причиной появления более продвинутых декомпиляторов вроде CFR. Эта война щитов и мечей, пуль и бронежилетов обещает быть долгой, нам остается только запастись попкорном. Но не будем тут останавливаться, а вместо этого предположим, что мы декомпилировали проект одним из описанных способов до Java-исходников и даже проанализировали полученный код.
Применительно к нашему подопытному приложению это выглядело примерно так. Декомпилировав все‑все‑все CLASS-файлы, мы так и не обнаружили ничего похожего на обращение к лицензии, однако в подкаталоге BOOT-INF/lib
нашего JAR-архива нашлось множество упакованных JAR-библиотек, среди которых сразу бросилась в глаза библиотека license-1.2.12.jar
. Распаковав и декомпилировав ее, мы наткнулись на два CLASS-модуля, содержащих две любопытные функции. Одна возвращает демонстрационный режим, вторая активирует опцию 1 по умолчанию:
public boolean isDemo() { return this.getPublicDataHash().isEmpty();}public void setDefault() { if (this.hasModule(1)) { Iterator iter = this.modulesItems.entrySet().iterator(); while (iter.hasNext()) { Map.Entry item = iter.next(); if ((Integer)item.getKey() == 1) continue; ((BaseModule)item.getValue()).close(); iter.remove(); this.onModuleUpdated((Integer)item.getKey()); } } else { this.closeModules(); if (!this.modulesConfig.containsKey(1)) { return; } BaseModule mod = this.getModule(1); if (mod != null) { mod.setEnabled(true); this.modulesItems.put(1, mod); log.info("Default module loaded {}", (Object)mod.getName()); this.onModuleUpdated(1); } }}
Наша задача — сделать так, чтобы функция isDemo
всегда возвращала false
, а в функции setDefault
нужно заменить опцию 1
опцией 256
. Вот здесь и начинается самое интересное, то, ради чего и написана эта статья.
Ты спросишь: раз у нас имеются в наличии все исходники и код, то почему бы просто не перекомпилировать весь проект, поменяв эти две процедуры на нужные? К сожалению, прямой метод не всегда самый простой. В нашем случае в интересующих нас модулях много зависимостей, а проект очень большой, многие модули сильно обфусцированы. Кроме того, код восстановился частично с кучей ошибок, из‑за чего проект полностью не соберется. Можно, конечно, покопать обфускацию и попробовать руками вытащить исходный текст программы, но решать эту (возможно, даже, гораздо более сложную) задачу ради двух простых патчей в коде как‑то лень. Вдобавок, пересборке проекта может помешать отсутствие установленного JDK на компьютере. Устанавливать его и разбираться в особенностях компиляции Java-проектов мне тоже неохота. Поэтому мы, как обычно, ищем самый простой путь — патч откомпилированного JVM-кода.
В этом нам поможет интересная, но малоизвестная утилита dirtyJOE. Открываем в ней наш CLASS-модуль, на вкладке Methods видим полный список методов класса. Находим в нем искомую isDemo
и тыкаем в нее, открывая окно редактирования.
Окно редактирования dirtyJOE
Это, конечно, не исходник на Java, но здесь хотя бы можно редактировать байт‑код, сверяясь с логикой исходника. Возможности программы минималистичны: редактировать можно только в виде hex-значений кодов инструкций. По счастью, мнемоника и описание текущей исправленной инструкции отображается в окошке над окном кода, а сам список инструкций с описанием каждой имеется в хелпе (причем только список, без опкодов: явно, чтобы хакерам жизнь медом не казалась и пришлось искать шестнадцатеричные опкоды инструкций самостоятельно). По сути, нам надо закоротить данную функцию, сделав возвращаемым значением 0 (false)
. Находим в таблице инструкцию помещения 0
на стек (iconst_0
), ее опкод (3
) и ставим ее в самое начало метода, а после нее — сразу возврат (ireturn
).
Исправляем инструкцию
Закрываем окно редактирования, сохраняем CLASS-модуль, затем меняем исправленный модуль в архиве license-1.2.12.jar
, который, в свою очередь, копируем на место старого в основном JAR-модуле. С предвкушением перезапускаем программу и обнаруживаем, что она не работает. Мы что‑то сделали не так.
Источник: xakep.ru