[Гайд] Защита модов от декомпиляции

808
3
124
В коммерческих проектах постоянно возникает необходимость защищать свой код от декомпиляции и от использования другими проектами. Не будем о том, насколько хорошо или плохо зарабатывать на игре, лицензионное соглашение которой этого не особо позволяет.

Для начала разделим проблему на две, серьезную и не очень.
1) Нехорошие люди на самом деле на самом деле декомпилируют мод и получают рабочие сорцы.
2) Нехорошие, но глупые люди думают, что декомпилировали мод, хотя на самом деле полученные сорцы работать как надо не будут. Несмотря на кажущуюся несерьезность проблемы, такие люди способны изрядно подпортить нервы.

Две проблемы - два решения. К счастью, первая проблема решается существенно проще. Я расскажу о том, как защищать серверную часть модов, и чуть-чуть о том, как обфусцировать моды.

[h]Защита серверной части[/h]
Довольно существенная часть кода в мультиплеере никогда не выполняется на клиентской стороне (в моем случае - около 15%). Два самых очевидных примера - обработка пакетов на сервере и подобные куски кода:
Код:
if (!world.isRemote){
//какой-нибудь серверный код
}
Если полностью вырезать такой код из клиента, то даже после успешной декомпиляции восстановить его будет почти невозможно. В большинстве случаев написать аналогичный мод с нуля будет быстрее, чем разбираться в том, каких участков кода где не хватает и что на их месте нужно дописать. Однако, каждый раз вырезать часть кода при сборке мода - сущая мука. К счастью, компилятор javac достаточно умён для того, чтобы нам в этом помочь.

Пишем где-нибудь (желательно - в отдельном классе) вот такую строку:
Код:
public static final boolean SERVER = true; //или false, когда будете делать клиентскую сборку
Допустим, эту константу завели в классе CompilationFlag. Тогда перед каждым серверным куском кода нужно проверить эту константу. Два простых примера:

Код:
public void someMethod(){
//общий код
if (CompilationFlag.SERVER){
 if (!world.isRemote){
 //серверный код
 }
}
}

Код:
//метод, который выполняется только на сервере
public void serverSideMethod(){
if (!CompilationFlag.SERVER) return;
//код метода
}

При компиляции с SERVER == false такие участки кода попросту выбрасываются. Значение этой константы можно менять руками при каждой сборке и собирать по две версии мода - серверную и клиентскую. Когда надоест менять значение руками, напишете собирающий скрипт. Раз написали мод, должны справиться и с этим :D. Свой скрипт выкладывать не вижу смысла, это костыльная поделка конкретно под мой проект.

[h]Обфускация[/h]
Первое решение хорошо своей надежностью и простотой, но у него есть и свои недостатки. Я уже выше жаловался на дурачков, которые хвастаются тем, что "взломали мод", но это не единственная проблема. Есть еще как минимум две.
1) Выкидывание серверной части ломает синглплеер.
2) Иногда хочется защитить не весь мод, а какое-то конкретный элемент, который целиком выполняется на клиенте.

Если все три перечисленные проблемы вас не касаются, то можете смело закрывать гайд и идти реализовывать первое решение. Если же нет, то вам может придти на помощь обфускация.В самом простом варианте обфускация - это просто замена названий классов, полей и методов на не имеющие смысла. Именно такой вид обфускации применяется в Minecraft'e, и, как вы могли заметить, ее успешно "сломали" разработчики MCP :D. Тем не менее, более серьезная обфускация стоит денег, снижает производительность, да и вообще не очень понятно зачем нужна. Ваш мод - не Minecraft, и тратить сотни человекочасов на разбор обфусцированного кода никто не будет. Предупреждаю сразу: с обфускацией возни намного больше, чем с первым способом. Её сложно настраивать, легко сломать и невозможно забыть она усложняет отладку мода.

Я не рискну в подробностях рассказывать про обфускацию модов. Моё нынешнее решение - это велосипед из костылей, и учить кого-то такому мне стыдно. Расскажу лишь в общих чертах, как стоит делать. Я подобный путь не проверял, но оно должно работать.

1) Качаем ProGuard здесь. Он обфусцирует джарники по куче параметров, которые задаются через специальные конфиги. К счастью, вместе с ProGuard идет утилита под названием ProGuardGUI, через которую этот конфиг можно создать. Писать про эту кучу настроек долго, да и там всё более-менее понятно. Расскажу лишь про основные моменты.
2) В либы добавляем майн, либы майна и фордж (если он идет отдельным файлов).
3) В input добавляем джарник с модом, в output его же
4) В список классов, которые не нужно обфусцировать добавляем главный класс и CommonProxy/ClientProxy. Если есть еще какие-то классы, название которых указывается строками в коде, то их тоже добавляем.
5) Выключаем obfuscation -> use mixed-case class names. Ну то есть можно и оставить, но сами же будете страдать.
 
1,683
1
Или же магией поставить пароль,перед этим где-то в MCP сделать ввод этого пароля.И всё равно,кому надо смогут
 
2,955
12
У меня была идея шифровать архив, а ключ получать с сервера как ответ. Но не просто прямо в джава коде это делать, а в C++ либе (Явно ассемблер не разберут) отправлять пост-запрос на сервер с данными клиента (модами, настройками, копирайтами). И только если все эти данные верны, сервер вернет ключ от архива.
 
1,683
1
Достаточно мод проверить например в эвенте,на чексумму.Если нет,то качать мини-программу,выключать игру,с помощью программы заменить изменённый класс,запускать игру.Скажешь ты:"Зачем?".А вдруг пользователь зайдёт с другого лаунчера,который не проверит.Ну и конечно для смертных сделать лаунчер
 
808
3
124
Dragon2488 написал(а):
У меня была идея шифровать архив, а ключ получать с сервера как ответ. Но не просто прямо в джава коде это делать, а в C++ либе (Явно ассемблер не разберут) отправлять пост-запрос на сервер с данными клиента (модами, настройками, копирайтами). И только если все эти данные верны, сервер вернет ключ от архива.
В чем смысл защищать код, который можно просто не давать клиентам?)
 
124
1
Нельзя защитить код, тем более на Java. Но усложнить взлом - можно.
 
1,683
1
Видел один обфускатор,который преобразовывает типо
Код:
@КакаяТо аннотация
public void lal(String s){
System.out.println(s);
}
В
Код:
@КакаяТо аннотация 2(825275257252342)//рандомные цифры
public void lal(){}
Жрёт в 20 раз больше обычного метода
 

svk

1,185
2
У меня вопрос. Если я перед телом класса поставлю @SideOnly(Side.SERVER), то он при компиляции будет на клиенте? Как мне гарантированно вырезать целый класс?​
 
За сколько продашь исход сз? :3
[merge_posts_bbcode]Добавлено: 24.06.2016 00:00:47[/merge_posts_bbcode]

За сколько продашь исход сз? :3
 
7,099
324
1,510
Вопрос по защите серверной части: сделал, как в примере, но не пашет: компиль не убирает код из скобок, если финальная переменная false.
Юзаю scalac, он обворачивает переменные в getter-методы, может, причина в этом?
Тут мало людей используют скалу, помнится, Дракону она нравилась, его уже недели нету в онлайне.


Все решилось, оказывается, нужно использовать модификатор final вместе с val(такого поворота я не ожидал)
 
Сверху