【问题标题】:League of Legends Read Chunks/Keyframes through its RESTful API英雄联盟通过其 RESTful API 读取块/关键帧
【发布时间】:2014-04-03 03:20:38
【问题描述】:

我打算在 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

我关注了这个link 和这个wiki。似乎他们在使用 GZIP 压缩内容后使用 BlowFish ECB 算法加上 PKCS5Padding 进行加密。但我未能使用元数据中的 32 字节加密密钥解密内容。而且我不确定我应该从哪里开始阅读以及从哪里停止,因为 JVM 不断警告我 Given final block not proper padding

所以我的问题是:

  1. 有谁熟悉 Blowfish 算法和 PKCS5Padding 的吗?我应该阅读这些二进制文件的哪一部分来解密两个连续的 RESTful URL?我是否使用正确的密钥来解密? (元数据中的 32 字节加密密钥)
  2. 鉴于每个 RESRful URL 周围的模式,谁能猜出 LOL 究竟使用哪种算法来加密/解密内容?是 Blowfish 算法吗?

任何帮助将不胜感激。谢谢各位。



编辑@6.17:

按照 Divis 和 avbor 的回答,我尝试了以下 Java sn-p 来解码块:

    // 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 要么返回“线程“主”中的异常”javax.crypto.IllegalBlockSizeException:使用填充密码解密时输入长度必须是 8 的倍数”

或者

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

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

我的问题是:

  1. 需要包含块的哪一部分?我需要在最后一个 URL 之后包含“0a”吗?是否需要在下一个 URL 前加上“000000”?

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

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



编辑@6.18

感谢迪维斯!使用上面的 sn-p,我成功地解密了一些块信息而没有错误。编写自己的 getChunkContent() 时有两件事值得注意:

  1. 块内容在“前一个 url 0a 的十六进制”之后开始。

  2. 当块的大小恰好达到 8 的倍数时,块内容的结尾会尽可能接近“0000000(下一个 url 的十六进制)”。

但我还有两个问题要问:

  1. 这是我为两个 .../getKeyframe/... RESTful url 之间的内容解码的示例。

    39117e0cc2f7e4bb1f8b080000000000000bed7d0b5c15d5 ... 7f23a90000
    

    根据RFC doc,我知道 Gzip 压缩数据以“1f8b08...”开头。我可以丢弃“39117e0cc2f7e4bb”并开始 gzip 解压缩正在进行的内容吗? (其实我已经尝试过从“1f8b08..”开始解码,至少可以解压不出错)

  2. gzip解压后,结果还是一长串二进制(有一些可读的字符串,比如召唤师名字,英雄名字等)。看wiki,好像很远从完成。我期望以可读字符串读取每个项目、符文或动作。我如何准确地从中读取这些游戏事件?或者我们只是需要一些耐心来自己与社区一起解决这些问题?

万分感谢!

【问题讨论】:

  • 很多“?”您的示例中的字符意味着首先您需要解决数据编码问题 - 数据是文本但不是您尝试使用的编码,或者数据是原始二进制文件,不应通过简单的字节转换为文本 -字符转换。
  • 我知道我不能简单地将这些字节转换为字符。我粗暴地打印它们的原因是查看这些字节中是否存在某种模式。我尝试了几种编码方法,例如UTF-8 和 US-ASCII,最终都会打印出不可读的字符。老实说,在我解密它们之前,我不知道如何转换这些字节。
  • 听起来是个超级好玩的项目。我正在通过拦截和分析网络流量来做我自己的英雄联盟相关项目。如果您克服了当前的障碍并希望其他开发人员参与您的项目,请联系我。
  • 还没有。我尝试了很多方法来解密它,但它们都不起作用。 @dhalsim2
  • @czxttkl 您是否有适用于您的示例 rlf 文件或至少适用于解密和解压缩数据示例的代码?我试图让它适用于 .rofl 文件,但我完全迷失了

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


【解决方案1】:

这里的存储库开发贡献者,根据 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
希望它会有所帮助:)

【讨论】:

  • 嗨@Divi 我更新了我的进度。你能帮我解决这个问题吗?非常感谢。我的项目真的很需要像你这样的人的帮助。
  • 我编辑了我的答案。您的 gameId 必须转换为字符串。不要忘记 gzdecode 您解密的块/关键帧内容。我不知道从 LOLReplay 软件中检索块或关键帧,因为我直接从官方 REST 服务下载它们。
  • 回答你上次的编辑:解密一个关键帧,你应该能看到像召唤师名字、英雄名字、中立怪物名字等字符串。然后,如果你能看到这些字符串,你成功了:)
  • 嘿Divis,谢谢!解码后我可以在字符串中看到这些名称!然而,剩下的二进制内容仍然让我很困惑。我认为 wiki 远没有得到所有项目、符文等的完整映射。我希望(天真地)在我的研究项目中使用的是将所有内容都放在可读的字符串中,以便我们可以了解玩家的所有内容。我们能做到这一点,还是我们还在路上?谢谢。
  • 你总是有一个空字符串。可能是因为过去 Riot 将这些数据保存在 REST API 中。但是现在,您必须从 RTMP API(从服务:retrieve_in_progress_spectator_game_info)获取它。我做了一个开源的 RTMP API,看看这里:github.com/EloGank/lol-php-api/blob/master/doc/…
【解决方案2】:

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

【讨论】:

  • 嗨@avbor,我已按照您的步骤获取实际的加密密钥。但是我在解码块时仍然遇到一些问题。你能帮我解决这个问题吗?谢谢!
猜你喜欢
  • 2020-12-21
  • 2021-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多