Защита приложений на платформе Eclipse RCP

Наконец наступил момент, когда вы готовы показать ваше творение миру. И если это коммерческое приложение, то желательно сразу же позаботиться о защите программного кода от взлома злоумышленниками. Для написанных на языке java программ это существенная проблема, так как существует несколько программ, которые позволяют декомпилировать java-байт-код обратно в тестовый формат java-файлов проекта. Одним из наиболее известных и популярных декомпиляторов на данный момент является продукт Павла Кузнецова (Pavel Kouznetsov) под названием JAD. Для того, чтобы научиться защищать свой труд от взлома, желательно освоить хотя бы базовые приемы, которые используют злоумышленники.

Пример взлома java-программы на Eclipse RCP

Используя автоматически генерируемый шаблон приложения, создадим простой Eclipse RCP проект. Для этого вызовем мастер из меню: File -> New -> Plug-in Development -> Plugin Project. Во второй закладке мастера дадим имя проекту "com.berdaflex.obfuscatedmail". На следующей странице выберем радиокнопку для указания того, что это Rich Client Application. На последней странице мастера выберем шаблон проекта RCP Mail Template и нажимаем кнопку Finish. Для удобства развертывания (создания автономного) приложения создадим файл конфигурации продукта. Для этого указываем мышкой на проект в панели навигатора и нажатием правой кнопки мыши вызываем контекстное меню. В этом меню выбираем New -> Product Configuration. В настройках задаем имя продукта "obfuscatedmail" и из возможных вариантов инициализации выбираем вариант инициализации на базе готового продукта Use an existing product, указав продукт "com.berdaflex.obfuscatedmail.product". При открытии данного файла у нас появляется возможность экспорта продукта (линк Eclipse product export wizard.). Выполним экспорт продукта и проанализируем, что у нас получилось.

В ходе экспорта продукта создается каталог продукта с файлом для его запуска, а также несколько дополнительных папок, среди которых нас интересует содержимое папки plugins. В данной папке наряду с jar-пакетами, от которых зависит ваше приложение, будет создан пакет com.berdaflex.obfuscatedmail_1.0.0.jar, который содержит основной код приложения и который мы сейчас взломаем, а потом будем защищать от злоумышленников. Распаковываем данный jar-архив в отдельную папку (можно воспользоваться любым архиватором, который позволяет работать с zip- архивами). Для удобства декомпиляции сразу множества классов рекурсивно в дочерних каталогах автор написал простую утилиту RecurseExecute.exe, на вход которой подается команда, которую нужно выполнить для всех дочерних каталогов. Данную утилиту, файл декомпилятора jad, скрипты пакетного запуска decJava.bat и delClasses.bat желательно скопировать в каталог, который входит в системные пути, для того, чтобы их можно было вызывать из командной строки. Заходим в каталог с распакованным архивом и набираем команду:

decJava.bat

для декомпиляции классов, а потом команду:

delClasses.bat

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

break MISSING_BLOCK_LABEL_XXX

Но если сравнивать с примерами оригинального кода, то видно, что это обычно переходы по условию, которые в оригинальном коде имеют
противоположное значение, так что вполне можно логически привести код к требуемому виду. Например, блок кода после декомпиляции, имеющий вид: public Object start(IApplicationContext context)
{
Display display = PlatformUI.createDisplay();
Integer integer;
int returnCode = PlatformUI.createAndRunWorkbench(display, new ApplicationWorkbenchAdvisor());
if(returnCode != 1)
break MISSING_BLOCK_LABEL_33;
integer = IApplication.EXIT_RESTART;
display.dispose();
return integer;
integer = IApplication.EXIT_OK;
display.dispose();
return integer;
Exception exception;
exception;
display.dispose();
throw exception;
}

довольно просто можно исправить к работающему блоку вида:

public Object start(IApplicationContext context) {
Display display = PlatformUI.createDisplay();
Integer integer;
int returnCode = PlatformUI.createAndRunWorkbench(display,
new ApplicationWorkbenchAdvisor());
if (returnCode == 1) {
integer = IApplication.EXIT_RESTART;
display.dispose();
return integer;
} else {
integer = IApplication.EXIT_OK;
display.dispose();
return integer;
}
}

В оригинальном приложении данный блок кода имел следующую реализацию:

public Object start(IApplicationContext context) {
Display display = PlatformUI.createDisplay();
try {
int returnCode = PlatformUI.createAndRunWorkbench(display, new ApplicationWorkbenchAdvisor());
if (returnCode == PlatformUI.RETURN_RESTART) {
return IApplication.EXIT_RESTART;
}
return IApplication.EXIT_OK;
} finally {
display.dispose();
}
}

И хотя полученный программный код не полностью соответствует оригинальному, но уже через несколько минут у нас получилось вновь собрать работающее приложение из декомпилированного кода, что и является основной целью злоумышленников (которых в простонародье называют хакерами и пиратами). Причем для пиратов совсем необязательно декомпилировать и заново собирать всю программу. Обычно достаточно заменить лишь небольшой участок критического кода, который отвечает, например, за процесс регистрации программы. Декомпиляция собственных программ имеет дополнительный косвенный эффект, который проявляется в возможности анализа реально сгенерированного кода и последующей его оптимизации.

Пример защиты java-приложения на платформе Eclipse RCP

Для защиты java-приложений применяют так называемые программы-запутывальщики (obfuscators), которые с целью затруднения последующей декомпиляции и анализа позволяют изменить исходный код — как до компиляции, так и после таковой. В основном это переименование переменных, имен пакетов и внутренних классов для того, чтобы злоумышленнику было сложно определить их назначение. Для приложений Eclipse RCP есть ряд проблем по использованию обфускаторов. Основной проблемой является необходимость оставлять классы и методы, которые используются в публичных интерфейсах в том же виде, в котором они описаны. К счастью, это легко решается в соответствии с основными принципами инкапсуляции — например, введением дополнительной иерархии классов с внутренней реализацией, которая не будет доступна извне для внешних подключаемых модулей. В проекте Eclipse принята практика такие классы помещать в дочерние пакеты вида: <имя базового пакета>.internal.<имя пакета> В ходе рефакторинга исходного проекта публичные классы разбиваем на два, например:

package com.berdaflex.obfuscatedmail;

. . .

public class Application implements IApplication {
. . .
}

будет преобразован в два класса:

package com.berdaflex.obfuscatedmail;

. . .

public class Application extends ApplicationInternal {
// реализация перенесена во внутренний класс
}

и

package com.berdaflex.internal.obfuscatedmail;

. . .

public class ApplicationInternal implements IApplication {
. . .
// внутренняя реализация
}

Публичные пакеты, которые могут использоваться другими подключаемыми модулями, добавляем в список публичных пакетов. Это можно сделать при помощи визуального редактора файла манифеста разрабатываемого подключаемого модуля (плагина), открыв закладку Runtime и секцию Exported Packages. После рефакторинга проекта структура пакетов примет показанный на рис. 1 вид.

Рис. 1. Структура пакетов проекта после рефакторинга


Непосредственно для обфускации кода воспользуемся плагином obfuscate4e, который позволяет воспользоваться встроенным бесплатным обфускатором ProGuard либо подключить другой обфускатор. Для установки плагина просто обновим среду Eclipse с адреса
сайт . Для активизации плагина обфускации во время сборки нашего проекта нужно в навигаторе проекта выбрать файл манифеста и вызвать контекстное меню нажатием правой кнопки мыши (см. рис. 2) и выбрав PDE Tools -> Create customBuildCallbacks for Proguard.

Рис. 2. Активизация плагина обфускации obfuscate4e


В результате в корень проекта будут добавлены файл customBuildCallbacks.xml, который является настроечным для сборки при помощи ant, и файл proguard.cfg для настройки параметров обфускации. Дополнительно к этому сам файл проекта будет настроен на компиляцию и обфускацию проекта. Причем в файле настройки proguard.cfg сразу будут прописаны настройки для обфускации пакетов, которые не включены в список публичных (в дальнейшем данный файл можно будет править самостоятельно). Экспортируем проект и повторно анализируем код после декомпиляции. Первое, что бросается в глаза, — это то, что классы из пакета internal будут переименованы в файлы a, b, c... Во-вторых, текст декомпилированных классов становится более трудно читаемым, так как методы и имена переменных также переименованы — например:

final class d
implements Runnable
{

d(f f1, Display display, IWorkbench iworkbench)
{
a = display;
b = iworkbench;
super();
}

public final void run()
{
if(!a.isDisposed())
b.close();
}

private final Display a;
private final IWorkbench b;
}

Причем чем больше внутренних классов в проекте, тем сложнее разобраться, что за что отвечает, и где символ "a" означает имя класса, а где — название метода или переменной. А при очень большом количестве классов получаются наименования, совпадающие с ключевыми словами языка java, например, "do", "if", что очень сильно затрудняет анализ декомпилированного приложения. Дополнительной сложностью для взломщиков является взлом приложения, которое собиралось в ОС Linux. За счет того, что имена переменных и классов могут быть в разных регистрах, классы с именами "a" и "A" просто невозможно декомпилировать в ОС Windows. Анализируя программный код после декомпиляции, можно выявить конструкции, которые формируют наиболее сложные для декомпиляции блоки кода, которые можно с успехом применять для повышения стойкости программ к взлому.

Рекомендуемые ресурсы

. Декомпилятор jad: сайт
. Плагин obfuscate4e: сайт
. Описание плагина obfuscate4e: сайт
. Обфускатор Proguard: сайт
. Утилиты для декомпиляции java-программ: recurse_execute.zip

Сергей Бердачук, сайт


Компьютерная газета. Статья была опубликована в номере 40 за 2008 год в рубрике программирование

©1997-2024 Компьютерная газета