英雄联盟通过其RESTful API阅读Chunks / Keyframes

时间:2014-04-03 03:20:39

标签: java algorithm encryption web-scraping restful-url

我打算在LOL中进行游戏数据挖掘,但坚持解析重放文件。我发现最受欢迎的重播录音机是LOL Replay,用于记录.lrf文件中的游戏。它们保存为二进制文件。我尝试打印一个lrf文件来查找其中的一些模式。据我所知,该文件有两部分:

  1. 初始部分是元数据。它是人类可读的。最后,它显示了此.lrf文件的加密密钥(32字节)和客户端哈希。

  2. 第二部分有几个部分。每个部分都在" 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

  3. 我已关注此link和此wiki。看起来他们在使用GZIP压缩内容后使用BlowFish ECB算法加上PKCS5Padding进行加密。但我无法使用元数据中的32字节加密密钥解密内容。而且我不确定我应该从哪里开始阅读以及在哪里停止因为JVM一直警告我给定最后一个块没有正确填充

    所以我的问题是:

    1. 是否有人熟悉Blowfish算法和PKCS5Padding?我应该读取哪些二进制文件的哪一部分在两个连续的RESTful URL之间解密?我是否使用正确的密钥进行解密? (元数据中的32字节加密密钥)
    2. 鉴于每个RESRful URL周围的模式,是否有人可以猜测LOL使用哪种算法来加密/解密内容?是Blowfish算法吗?
    3. 任何帮助将不胜感激。谢谢你们。



      编辑@ 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"中返回" Exception。 javax.crypto.IllegalBlockSizeException:当使用填充密码"解密时,输入长度必须是8的倍数。

      或者

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

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

      我的问题是:

      1. 需要包含哪部分块?我是否需要包含" 0a"在最后一个URL之后?我是否需要包含" 000000"在下一个URL之前?

      2. 我使用正确的填充算法(Blowfish / ECB / PKCS5Padding)吗?

      3. 我的测试lrf文件可以在https://www.dropbox.com/s/yl1havphnb3z86d/game1.lrf

        上下载



        编辑@ 6.18

        感谢Divis!使用上面的代码片段,我成功地解密了一些块信息而没有错误。当你编写自己的 getChunkContent()

        时,有两点值得注意
        1. 块内容在"十六进制之后开始,用于上一个网址0a"。

        2. 块内容尽可能接近" 0000000(下一个网址为十六进制)"当它的大小恰好达到8的倍数时。

        3. 但我还有两个问题要问:

          1. 以下是我为两个... / getKeyframe / ... RESTful网址之间的内容解码的示例。

            39117e0cc2f7e4bb1f8b080000000000000bed7d0b5c15d5 ... 7f23a90000
            

            我知道Gzip压缩数据以" 1f8b08开始......"根据这个RFC doc。我可以放弃" 39117e0cc2f7e4bb"并启动gzip解压缩正在进行的内容? (实际上我已经尝试从" 1f8b08开始解码..",至少它可以毫无错误地解压缩)

          2. 在gzip解压缩之后,结果仍然是一个很长的二进制序列(有一些可读的字符串,如召唤者名字,冠军名称等)当我查看wiki时,它看起来像它远未结束。我期望阅读每个项目,符文或可读字符串中的移动。我怎样才能从中读取这些游戏事件?或者我们需要一些耐心才能将自己与社区联系起来?

          3. 数百万的感谢!

2 个答案:

答案 0 :(得分:3)

此处的存储库开发者贡献者,根据维基,关键是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
希望它会有所帮助:)

答案 1 :(得分:1)

据我所知,您使用Blowfish解密了块和关键帧。为了获得解密所述块和关键帧的密钥,您可以使用给定的加密密钥base64对其进行编码,然后使用游戏ID作为密钥使用Blowfish,以获取块和关键帧的实际加密密钥