Войти или зарегистрироваться

Туториал Своя авторизация без изменения authlib при помощи javaagent

Интересно?

  • Да

    Голосов: 9 56,3%
  • Я ничего не понял

    Голосов: 3 18,8%
  • Автор, ты зря потратил время

    Голосов: 4 25,0%

  • Всего проголосовало
    16

Andrey96

Активный участник
Баллы
61
Своя авторизация без изменения authlib при помощи javaagent

Что понадобится:
  • JDK 1.8
  • PHP
Для корректной работы скинов:
  • OpenSSL (будем подписывать скины своим сертификатом)
  • PHP расширение OpenSSL

Предыстория:
Началось все довольно просто. Решил собрать друзьям (приватный серв) сборку на новой версии майна.
Но очередная новая версия майна тащит за собой очередную новую версию authlib, которую нужно патчить. А патчить вручную мне ее лень.
После недолгих исследований было выяснено что authlib и minecraft в целом производит HTTP запросы при помощи метода URL.openConnection(proxy).
Почему бы не пропатчить его, подумал я и накидал coremod. Но класс URL загружается куда раньше coremod-а.
Решил не разбираться с переопределением загруженных классов coremod-ами, а перенес код в javaagent который это точно знает и умеет.
Получилась тулза никак не связанная с майном, в теории ее можно применить к любому java приложению.
Пишу я этот текст исключительно ради фана, он полон технических подробностей и будет интересен не только лишь всем.
Иными словами, инструкция не рассчитана на новичка, но может быть интересна тем кто уже представляет как работает авторизация в майне.

Инструкция:
1. Качаем jar файл отсюда https://bitbucket.org/Andrey96/ultra-core-agent/downloads/, либо компилим его самостоятельно, исходный код покрытый unit-тестами в этом же репозитории.
Для компиляции достаточно запустить команду 'gradlew build', результат будет лежать в build/libs.
2. Достаем клиент и сервер любой версии. Я взял последнюю на данный момент 1.12.2, но работать будет любая версия начиная с 1.7.10. А вот с более старыми придется экспериментировать, мой конфиг к ним не подойдет.
3. Пишем простенькие bat файлы для запуска того и другого или достаем свой любимый лаунчер.
На этом этапе в строку запуска клиента и сервера добавляем аргумент JVM '-javaagent:ultra-core-agent.jar', это обеспечит загрузку нашего агента.
(логично что jar файл агента должен лежать в рабочей директории запускаемого приложения, либо к нему должен быть прописан полный/относительный путь)
4. Создаем в рабочей директории по файлу 'ultra-core.urls' для клиента и для сервера. Это конфиг который подскажет агенту какие запросы нужно подменять.
(можно назвать файл иначе или положить его по другому пути, но тогда нужно будет указать его аргументом JVM '-Dultra.core.config=vash_config')
Пример содержимого файлов и описание формата, которое подскажет как настраивать агента https://bitbucket.org/snippets/Andrey96/KenkXz
Теперь все запросы к серверам моджанг перенаправляются на наши сервера. Пора научиться их обрабатывать и заодно обойти защиту с подписью текстур.
5. Пишем или правим существующие скрипты авторизации на php. Основа для скриптов https://bitbucket.org/snippets/Andrey96/7e6Mpn
Основа служит исключительно для понимания того что должны возвращать скрипты, в них нет проверок на входные данные и другого вспомогательного/связующего кода.

Про обход защиты скинов:
Скины защищены двумя способами. Первый - whitelist доменов с которых они могут грузиться.
Это обходится очень легко, наши PHP скрипты должны возвращать моджанговский url в который вставлено наше название файла скина (см. profile_utils.php функцию get_textures),
а дальше агент подменяет и эти запросы тоже (см. конфигурацию ultra-core.urls для клиента).
Второй способ защиты - подпись ссылки на скин своим сертификатом. Это тоже обходится не сложно, нужно сгенерировать свой сертфикат просто запустив скрипт generate_certificates.php
В итоге мы получим 3 файла:
yggdrasil_session_private.pem - закрытая часть ключа которая используется сервером для подписания ссылки на скин (см. profile_utils.php функцию get_profile)
yggdrasil_session_public.pem - открытая часть ключа представленная в текстовом виде, сохраняется на всякий случай и нигде не используется, если все идет по плану
yggdrasil_session_public.der - то же самое (открытая часть ключа), но представленная уже в двоичном виде. Такой её хавает authlib.
И вот последний файл нам нужно добавить в classpath нашего клиента, обязательно до authlib.
Это можно сделать, например, создав обычный zip архив с этим файлом и переименовав его расширение в jar. К примеру у нас получился файл certificate.jar.
Допустим classpath в строке запуска клиента выглядит так '-cp "forge.jar;minecraft.jar;libs\*"'. Нужно сделать так '-cp "certificate.jar;forge.jar;minecraft.jar;libs\*"'.
На всякий случай вот мой сертификат https://bitbucket.org/snippets/Andrey96/qe6dXR

И еще немного про агента:
При работе агент создает в рабочей директории лог по пути logs/ultra-core.log, в нем можно увидеть какие запросы делает клиент и сервер и на что их заменяет агент.
После того как агент корректно настроен и стабильно работает, можно отключить логи добавив к аргументам JVM '-Dultra.core.log=0'.
И есть еще одна фича - очень опциональная и созданная исключительно во имя моей лени.
Возможность добавить ко всем заменам до десяти своих значений при помощи аргументов JVM от '-Dultra.core.arg1=значение' до '-Dultra.core.arg10=значение'.
Я это использую вот так https://bitbucket.org/snippets/Andrey96/4eygXG там же написано как это работает (см. ultra-core.urls)
 
Аж орнул. Столько магии. Когда все делается одной рефлексией
Код:
  private static String unsetURLStreamHandlerFactory()
  {
    try
    {
      Field e = URL.class.getDeclaredField("factory");
      e.setAccessible(true);
      Object curFac = e.get(null);
      e.set(null, null);
      URL.setURLStreamHandlerFactory(null);
      return curFac.getClass().getName();
    }
    catch (Exception var2) {}
    return null;
  }
 
  static
  {
    unsetURLStreamHandlerFactory();
    URL.setURLStreamHandlerFactory(new NewURLStreamHandlerFactory());
  }
 
Последнее редактирование:
А вот подпись скинов полезно, относительно.
 
Аж орнул. Столько магии. Когда все делается одной рефлексией
Код:
  private static String unsetURLStreamHandlerFactory()
  {
    try
    {
      Field e = URL.class.getDeclaredField("factory");
      e.setAccessible(true);
      Object curFac = e.get(null);
      e.set(null, null);
      URL.setURLStreamHandlerFactory(null);
      return curFac.getClass().getName();
    }
    catch (Exception var2) {}
    return null;
  }
 
  static
  {
    unsetURLStreamHandlerFactory();
    URL.setURLStreamHandlerFactory(new NewURLStreamHandlerFactory());
  }
Рад стараться) Решение и правда упоротое. Кстати, на форуме хоть раз предлагали подписывать текстурки или все тупо отключают проверку?
 
Рад стараться) Решение и правда упоротое. Кстати, на форуме хоть раз предлагали подписывать текстурки или все тупо отключают проверку?
Подпись ресурсозатрантая вроде как, лучше без нее.
 
Назад
Верх