Рейтинг темы:
  • 0 Голос(ов) - 0 в среднем
  • 1
  • 2
  • 3
  • 4
  • 5
Обфускация при помощи proguard
#1
Небольшой гайд для разработчиков, решивших немного защитить свои труды. Мы конечно рассмотрим обфускацию сервера л2.
Многие конечно уже озаботились вопросом, но если нет - вам это пригодится.
ProGuard - мощный гибкий и главное бесплатный обфускатор. Для л2 сервера, с большим количество использования рефлекшнов*, подходит отлично.
Забираем тут ProGuard Java Optimizer and Obfuscator
По нему в принципе есть документация, но не могу сказать, что она очень подробная и многое приходится проверять самому.
Покажу встраивание на примере Ant build, по нему меньше всего документации(а вообще на офф. сайте есть примеры и для gradle и с формированием отдельнго конфига)
Для начала вам понадобится добавить задание. resouce ссылается на classpath внутри jar архива - т.е. если используете готовый билд можете не менять.
Код:
<taskdef resource="proguard/ant/task.properties" classpath="path_to_proguard\proguard.jar" />
Далее делаете новый target и вставляете в него инициализацию задания(в моем примере отключены чистки кода, это может вызывать проблемы)
Код:
<proguard
        shrink="false"
        optimize="false"
        allowaccessmodification="false"
        usemixedcaseclassnames="false"
        defaultpackage=""
        skipnonpubliclibraryclasses="false"
        printseeds="out/obfuscateseeds.txt"
        printusage="out/obfuscateusage.txt"
        printmapping="out/obfuscatemapping.txt">
Добавляете все нужные библиотеки, которые используются у вас, а также библиотеки компилятора.
Код:
<libraryjar name="${java.home}/lib/rt.jar"/>
            <libraryjar name="${java.home}/lib/ext/jfxrt.jar"/> -- это для jdk версии явы
            <libraryjar name="${commons.jar.file}"/> --эта ссылка на путь commons.jar, у вас может называться по другому
            <libraryjar refid="library.lib.classpath"/>
library.lib.classpath - это сборник путей с внешними библиотеками. Создается так:
Код:
<path id="library.lib.classpath">
        <pathelement location="${basedir}/lib/annotations-3.0.1.jar"/>
         .....
        <pathelement location="${basedir}/lib/xmlrpc-server-3.1.3.jar"/>
    </path>
Далее указываем файлы на вход и выход. Тут нужно понимать, что если у вас есть внешние скрипты, которые компилируются в Runtime(т.е. лежат в датапаке) - то их взаимодействие с ядром после обфускации будет невозможным, ведь в ядре будет все переименовано. Поэтому нужно либо переносить их все - в ядро; либо описывать все методы и поля классов, что в них используются- в исключения; либо собрать из скриптов отдельный архив, с новыми ссылками на ядро(если понадобится добавлю внизу как их собрать в архив)
Поэтому у меня на вход подается готовый архив gameserver.jar и scripts.jar
На выход можно указать папку, тогда входные архивы сохранятся раздельно. Это удобно)
Код:
<injar name="${game.jar.file}"/>
            <injar name="${scripts.jar.file}"/>

            <!-- the output jar file that should be created with the obfuscated java class files -->
            <outjar dir="out\protected"/>
Далее добавляет главный метод\точку доступа в приложение в исключения
Код:
<keep name="org.mmocore.gameserver.GameServer">
                <method name="main"/>
            </keep>
На этом этапе можете запускать задание обфускации и смотреть на ошибки и уведомления. И начинать думать, какой код вам нужно сохранить, чтобы все работало.
Что получилось у меня:
- отключаем лишнее целиком, что ценности не несет
Код:
<keep name="org.jts.**">
                <method/>
                <field/>
            </keep>
            <keep name="ru.akumu.smartguard.**">
                <method/>
                <field/>
            </keep>
- отключаем классы, которые инициализируются с помощью рефлекшнов
Код:
<keep name="org.mmocore.gameserver.object.*">
                <constructor parameters="int,***"/>
            </keep>
            <keep name="org.mmocore.gameserver.**" extends="org.mmocore.gameserver.model.entity.events.Event">
                <constructor parameters="org.mmocore.commons.collections.MultiValueSet"/>
            </keep>
            <keep name="org.mmocore.gameserver.model.entity.residence.*">
                <constructor parameters="org.mmocore.gameserver.templates.StatsSet"/>
            </keep>
            <keep name="org.mmocore.gameserver.skills.effects.*">
                <constructor parameters="org.mmocore.gameserver.object.Creature, org.mmocore.gameserver.object.Creature, org.mmocore.gameserver.skills.SkillEntry, org.mmocore.gameserver.skills.effects.EffectTemplate"/>
            </keep>
            <keep name="org.mmocore.gameserver.skills.skillclasses.*">
                <constructor parameters="org.mmocore.gameserver.templates.StatsSet"/>
            </keep>
            <keep name="org.mmocore.gameserver.stats.funcs.*">
                <constructor parameters="org.mmocore.gameserver.templates.StatsSet, int, org.mmocore.gameserver.stats.Stats, java.lang.Object, double"/>
            </keep>
- отключаем классы, методы\поля которых вызываются рефлекшнами
Код:
<keep name="org.mmocore.gameserver.handler.bypass.Bypass">
                <method/>
            </keep>
            <keep name="org.mmocore.gameserver.model.base.PlayerAccess">
                <method/>
                <field/>
            </keep>
-отключаем конфиги
Код:
<keep name="org.mmocore.gameserver.configuration.**">
                <method/>
                <field/>
            </keep>
-отключаем парсеры\холдеры файлов датапака, а также все enum классы, т.к. все шаблоны данных привязываются парсерами обычно к enum типам.
includedescriptorclasses можно не указывать, у меня почему то без него были проблемы с чтением скриптов
Код:
<keep name="org.mmocore.gameserver.data.**" includedescriptorclasses="true">
                <method/>
                <field/>
            </keep>
<keep extends="java.lang.Enum">
                <method/>
                <field/>
            </keep>
- отключаем скрипты из датапака
Код:
<keep name="handler.**" includedescriptorclasses="true">
                <method/>
                <field/>
            </keep>
            <keep name="services.**" includedescriptorclasses="true">
                <method/>
                <field/>
            </keep>
- отключаем переменные всех ai, потому что они парсятся из ai.obj и npcpos.txt. хотя, у вас наверное этого нету.
Код:
<keep name="**" extends="org.mmocore.gameserver.scripts.ai.pts.default_npc" includedescriptorclasses="true">
                <field/>
            </keep>
- и наконец отключаем все атрибуты(аннотация, эксепшны, вложенные классы), папки ресурсов\кода и имена всех классов.
Код:
<keepattributes name="*"/>
            <keepdirectories name="**"/>
            <keepnames name="**"/>
Имена классов можно также отключать выборочно.
Также можно перемешать названия пакетов c помощью опции flattenpackagehierarchy и оставить только те, что используются рефлекшнами.

*рефлекшн - библиотека java.lang.reflect. Позволяет искать, получать доступ и взаимодействовать с объектами классов снаружи класса и напрямую с ними.
Ответ
#2
Я бы конечно сказал если бы не писал на публичном ресурсе - очко себе обфусцируй. Но такого я делать конечно же не буду. Есть ряд последствий при таком решении, с которыми описав вы видимо совсем не знакомы
Ответ
#3
При таком решении чего? Какие другие варианты решения? И с чем таким я не знаком?))
Ответ


Перейти к форуму:


Пользователи, просматривающие эту тему: 1 Гость(ей)