Войти или зарегистрироваться
  • Вы находитесь в сообществе Rubukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на различные языки плагины наших коллег из других стран.

[Решено] Скины 1.8+

Статус
Закрыто для дальнейших ответов.

Reality_SC

Старожил
Пользователь
Баллы
123
Имя в Minecraft
Reality_SC
Сервер в online-mode.
Методы authenticate / join / hasJoined / profile переписаны на адреса моих скриптов.
Скрипты выдают корректные профили, в том числе текстурки (скины/плащи).
JavaScript:
...,
"textures": {
   "SKIN": {
      "url": "<действующий url скина>"
   },
},
...
В клиенте ссылки тоже заменены, вижу это по логу.

Игрок начинает коннектиться на сервер, шлёт join, сервер запрашивает hasJoined и получает в ответ скин игрока, который отдаёт клиенту. Когда игрок видит других (spawn entity), сервер посылает их blob-ы клиенту.

Это в теории. На практике клиент после подключения показывает дефолтную Алекс несколько секунд, потом в логе видно, что он обратился к подменённому скрипту и скачал свой скин — с этого момента каждый игрок видит свой скин, как и должно быть. Когда в поле зрения появляются другие игроки, клиент не видит их скинов, показывает всех как Алекс.

Я грешу на проверку сигнатуры, она ведь в 1.8 обязательная?
Java:
    @Override
    public Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> getTextures(GameProfile profile, boolean requireSecure)
    {
        Property textureProperty = (Property)Iterables.getFirst(profile.getProperties().get("textures"), null);
        if(textureProperty == null)
            return new HashMap();
        if(requireSecure)
        {
            if(!textureProperty.hasSignature())
            {
                LOGGER.error("Signature is missing from textures payload");
                throw new InsecureTextureException("Signature is missing from textures payload");
            }
            if(!textureProperty.isSignatureValid(publicKey))
            {
                LOGGER.error("Textures payload has been tampered with (signature invalid)");
                throw new InsecureTextureException("Textures payload has been tampered with (signature invalid)");
            }
        }
        MinecraftTexturesPayload result;
        try
        {
            String json = new String(Base64.decodeBase64(textureProperty.getValue()), Charsets.UTF_8);
            result = (MinecraftTexturesPayload)gson.fromJson(json, MinecraftTexturesPayload.class);
        } catch(JsonParseException e) {
            LOGGER.error("Could not decode textures payload", e);
            return new HashMap();
        }

        return result.getTextures() == null ? new HashMap() : result.getTextures();
    }
Property
Java:
public boolean isSignatureValid(PublicKey publicKey)
{
    try
    {
        Signature signature = Signature.getInstance("SHA1withRSA");
        signature.initVerify(publicKey);
        signature.update(value.getBytes());
        return signature.verify(Base64.decodeBase64(this.signature));
    } catch(NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
    }
    return false;
}
Что-то мне не по глазам, где именно это вызывается. Проблема в сервере, что он не принимает неподписанные скины от hasJoined, или у клиента? (хотя клиент даже не подаёт желания скачать чьи-то скины).
Не могли бы Вы помочь найти это место?

@Shevchik @alexandrage

Соответсвенно, когда будет найдено место, встаёт второй вопрос: как вырезать проверку сигнатуры? Я хочу делать это в рантайме, по крайней мере на сервере 100%. Из вариантов наиболее лёгким выглядит генерация своего yggdrasil_session_pubkey.der ключа, которым буду подписывать скин на скриптах, и вставить его в сервер/клиент.
 
Последнее редактирование:
Клиент не принимает неподписанные скины. Все скины игроку посылает сам сервер кроме своего собственного, в 1.8 - вообще все.
 
Клиент не принимает неподписанные скины.
Есть идеи по вариантам, как это вырезать в рантайме?
Я через рефлексию заменяю константные поля authlib, через подмену URLStreamHandler (стырил из твоего MojangAPIProxy) подменяю все остальные обращения клиента и сервера к Mojang API, но тут всё выглядит так, что узким местом является подмена одного из методов:
  • в HttpAuthenticationService метод getTextures(GameProfile profile, boolean requireSecure),
  • в Property метод isSignatureValid(PublicKey publicKey),
  • в Signature статический вызов getInstance("SHA1withRSA"),
  • ну либо действительно заменять ключ .der.
Заменой методов (трансформерами, через ASM) ещё пока никогда не занимался.
Может быть я упускаю какой-то более лёгкий способ обмана клиента?


Проблема временно решена (ну мы знаем, нет ничего более постоянного ...)

Т.к. клиенты у меня патчатся враппером, я просто добавил к нему Property-заглушку, которую сам вызываю заранее, чтобы разместить в текущем ClassLoader-е.

Если кому-то в голову придёт ещё более простое и/или надёжное решение, прошу излагать ниже не стесняясь.
 
Отстаешь от жизни как обычно, я уже давно пролечил аутчлибу чтоб не проверять сигну :).
ae53b36c33fdd3db56bf43d806ef7458.png

Клиент не принимает неподписанные скины. Все скины игроку посылает сам сервер кроме своего собственного, в 1.8 - вообще все.
А ты всегда все усложняешь, а всего то нужно передать requireSecure = false, ибо затычка от сигны уже имеется в аутчлибе. Она включается в одиночной игре.
 
Последнее редактирование:
Отстаешь от жизни как обычно, я уже давно пролечил аутчлибу чтоб не проверять сигну :).
Отучить её не проблема, мне интересно решить задачу не трогая AuthLib :)
@alexandrage, подскажи, верно ли утверждение, что ClassLoader ищет .class в перечне переданных его конструктору URL[] в порядке их следования в списке? или где-то внутри они могут быть раскидываны по Set-у и порядок осмотра более случаен?

P.S. Тема закрыта.
 
Последнее редактирование:
Статус
Закрыто для дальнейших ответов.

Поделиться этой страницей

Назад
Верх