java - 英雄联盟通过其RESTful API阅读 block /关键帧

标签 java algorithm encryption web-scraping restful-url

我打算在LOL中进行游戏数据挖掘,但停留在解析重播文件上。我发现最受欢迎的重放记录器是LOL Replay,它以.lrf文件记录游戏。它们被保存为二进制文件。我尝试打印lrf文件以在其中找到一些模式。据我所知,该文件分为两部分:

  • 初始部分是元数据。这是人类可读的。它的末尾显示了此.lrf文件的加密密钥(32字节)和客户端哈希。
  • 第二部分包含几个部分。每个部分均采用“RESTful URL +加密+填充(可能)”格式。例如:
    ?S4GI____GET /observer-mode/rest/consumer/getGameDataChunk/EUW1/1390319411/1/token
    ?S4GH____?¥?G??,\??1?q??"Lq}?n??&??????l??(?^P???¥I?v??k>x??Z?£??3Gug
    ......
    ??6GI____GET /observer-mode/rest/consumer/getGameDataChunk/EUW1/1390319411/2/token
    

    有些甚至是不可读的字符。3

  • 我遵循了这个link和这个wiki。在使用GZIP压缩内容后,似乎他们使用BlowFish ECB算法和PKCS5Padding进行加密。但是我无法使用元数据中的32个字节的加密密钥解密内容。而且我不确定应该从哪里开始阅读以及从哪里停止,因为JVM不断警告我,给定的最终代码块未正确填充。

    所以我的问题是:
  • 有谁熟悉河豚算法和PKCS5Padding吗?我应该阅读那些二进制文件的哪一部分,以在两个连续的RESTful URL之间解密?我是否使用正确的密钥解密? (元数据中的32个字节的加密密钥)
  • 给定每个RESRful URL周围的模式,有人能猜出LOL用来加密/解密内容的算法是什么吗?是河豚算法吗?

  • 任何帮助,将不胜感激。感谢你们。

    编辑@ 6.17:

    按照Divis和avbor的回答,我尝试了以下Java代码片段来解码块:
        // Decode EncryptKey with GameId
        byte[] gameIdBytes = ("502719605").getBytes();
        SecretKeySpec gameIdKeySpec = new SecretKeySpec(gameIdBytes, "Blowfish");
        Cipher gameIdCipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
        gameIdCipher.init(Cipher.DECRYPT_MODE, gameIdKeySpec);
        byte[] encryptKeyBytes = Base64.decode("Sf9c+zGDyyST9DtcHn2zToscfeuN4u3/");
        byte[] encryptkeyDecryptedByGameId = gameIdCipher.doFinal(encryptKeyBytes);
    
        // Initialize the chunk cipher
        SecretKeySpec chunkSpec = new SecretKeySpec(encryptkeyDecryptedByGameId, "Blowfish");
        Cipher chunkCipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
        chunkCipher.init(Cipher.DECRYPT_MODE, chunkSpec);
    
        byte[] chunkContent = getChunkContent();
        byte[] chunkDecryptedBytes = chunkCipher.doFinal(chunkContent);
    

    使用gameid解码加密密钥时,它没有任何错误。但是,它在后两行中不起作用。目前,我只是硬编码getChunkContent()以返回一个字节数组,其中包含两个RESTful URL之间的字节。但是Java要么返回“线程“main”中的异常”,否则javax.crypto.IllegalBlockSizeException:使用填充密码解密时,输入长度必须是8的倍数”

    要么

    返回“线程“主”中的异常javax.crypto.BadPaddingException:给定的最终块未正确填充”。

    我注意到两个RESTful URL之间的十六进制模式如下:
    (第一个URL的十六进制,例如/ observer-mode / rest / consumer / getKeyFrame / EUW1 / 502719605/2 / token)+ 0a +(大块内容)+ 000000 +(下一个URL的十六进制)

    我的问题是:
  • 需要包括块的哪一部分?我是否需要在最后一个网址之后添加“0a”?我需要在下一个URL之前包括“000000”吗?
  • 我是否使用正确的填充算法(河豚/ ECB / PKCS5Padding)?

  • 我的测试lrf文件可以下载到:https://www.dropbox.com/s/yl1havphnb3z86d/game1.lrf

    编辑@ 6.18

    感谢Divis!使用上面的代码片段,我成功地解密了一些块信息,而没有错误。编写自己的getChunkContent()时需要注意两点:
  • 块内容从“先前URL 0a的十六进制”之后立即开始。
  • 当块内容的大小恰好达到8的倍数时,块内容的结尾应尽可能接近“0000000(十六进制表示下一个URL)”。

  • 但是我还有两个问题要问:
  • 这是我为两个... / getKeyframe / ... RESTful url之间的内容解码的示例。
    39117e0cc2f7e4bb1f8b080000000000000bed7d0b5c15d5 ... 7f23a90000
    

    我知道根据这个RFC doc,Gzip压缩数据以“1f8b08 ...”开头。我可以只丢弃“39117e0cc2f7e4bb”并启动gzip解压缩后续内容吗? (实际上,我已经尝试从“1f8b08 ..”开始解码,至少可以将其解压缩而不会出现错误)
  • 在gzip解压缩之后,结果仍然是一长串二进制文件(带有一些可读的字符串,例如召唤者名称,冠军名称等)。当我查看wiki时,似乎还远远没有完成。我期望以可读的字符串读取每个项目,符文或动作。我如何才能从中准确读取这些游戏事件?还是我们只需要一些耐心就可以在社区中与他们共处?

  • 数百万的感谢!

    最佳答案

    根据Wiki,此处的存储库开发提供者,密钥是base64 Blowfish ECB“encryption_key”(游戏ID为河豚的密钥)。

    然后,使用此解密的密钥对内容进行解码(也可以吹鱼ECB)。然后,gzip解码。

    base64decode encryptionkey = decodedKey
    blowfishECBdecode decodedKey with (string) gameId as key = decodedKey
    
    blowfishECBdecode content with decodedKey as key = decodedContent
    gzipdecode decodedContent = binary
    

    我制作了一个以下载和解码重播文件:https://github.com/EloGank/lol-replay-downloader,并且还提供了 CLI命令:https://github.com/EloGank/lol-replay-downloader-cli
    希望对您有所帮助:)

    关于java - 英雄联盟通过其RESTful API阅读 block /关键帧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22827221/

    相关文章:

    c - 这个倒数计数算法的实现有什么问题呢?

    ajax - Coldfusion 在组件中的函数内加密和解密

    java - 填充JAVA加密blockSizeException

    java - 如何在 Java Swing 中正确设计 MV 应用程序?

    java - Android MyLocationOverlay 与 LocationManager/LocationListener

    java - JBoss 在启动时挂起

    python - 存储应用程序敏感数据

    运行某些小程序时 java 出现不安全消息

    algorithm - 该算法的时间复杂度

    algorithm - 带/不带 Alpha-Beta 修剪的 Minimax 算法