【发布时间】:2014-04-03 03:20:38
【问题描述】:
我打算在 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 不断警告我 Given final block not proper padding。
所以我的问题是:
- 有谁熟悉 Blowfish 算法和 PKCS5Padding 的吗?我应该阅读这些二进制文件的哪一部分来解密两个连续的 RESTful URL?我是否使用正确的密钥来解密? (元数据中的 32 字节加密密钥)
- 鉴于每个 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 的十六进制)
我的问题是:
需要包含块的哪一部分?我需要在最后一个 URL 之后包含“0a”吗?是否需要在下一个 URL 前加上“000000”?
我是否使用了正确的填充算法(Blowfish/ECB/PKCS5Padding)?
我的测试 lrf 文件可以下载到:https://www.dropbox.com/s/yl1havphnb3z86d/game1.lrf
编辑@6.18
感谢迪维斯!使用上面的 sn-p,我成功地解密了一些块信息而没有错误。编写自己的 getChunkContent() 时有两件事值得注意:
块内容在“前一个 url 0a 的十六进制”之后开始。
当块的大小恰好达到 8 的倍数时,块内容的结尾会尽可能接近“0000000(下一个 url 的十六进制)”。
但我还有两个问题要问:
-
这是我为两个 .../getKeyframe/... RESTful url 之间的内容解码的示例。
39117e0cc2f7e4bb1f8b080000000000000bed7d0b5c15d5 ... 7f23a90000根据RFC doc,我知道 Gzip 压缩数据以“1f8b08...”开头。我可以丢弃“39117e0cc2f7e4bb”并开始 gzip 解压缩正在进行的内容吗? (其实我已经尝试过从“1f8b08..”开始解码,至少可以解压不出错)
gzip解压后,结果还是一长串二进制(有一些可读的字符串,比如召唤师名字,英雄名字等)。看wiki,好像很远从完成。我期望以可读字符串读取每个项目、符文或动作。我如何准确地从中读取这些游戏事件?或者我们只是需要一些耐心来自己与社区一起解决这些问题?
万分感谢!
【问题讨论】:
-
很多“?”您的示例中的字符意味着首先您需要解决数据编码问题 - 数据是文本但不是您尝试使用的编码,或者数据是原始二进制文件,不应通过简单的字节转换为文本 -字符转换。
-
我知道我不能简单地将这些字节转换为字符。我粗暴地打印它们的原因是查看这些字节中是否存在某种模式。我尝试了几种编码方法,例如UTF-8 和 US-ASCII,最终都会打印出不可读的字符。老实说,在我解密它们之前,我不知道如何转换这些字节。
-
听起来是个超级好玩的项目。我正在通过拦截和分析网络流量来做我自己的英雄联盟相关项目。如果您克服了当前的障碍并希望其他开发人员参与您的项目,请联系我。
-
还没有。我尝试了很多方法来解密它,但它们都不起作用。 @dhalsim2
-
@czxttkl 您是否有适用于您的示例 rlf 文件或至少适用于解密和解压缩数据示例的代码?我试图让它适用于 .rofl 文件,但我完全迷失了
标签: java algorithm encryption web-scraping restful-url