首页 > 解决方案 > 如何在 python 中膨胀这个 zlib 字节字符串?

问题描述

我正在编写一个与流行的数据仓库 SaaS 交互的工具。他们的在线 sql 编辑器将 sql 工作表序列化为 JSON,但 SQL 工作表的主体是使用 pako.js 对 zlib 进行压缩的。我正在尝试从 python 读取和扩充这些 zlib 字符串,但我只能解码包含短的字节串

带有 sql 文本的示例是字母a

bytestring = b'x\xef\xbf\xbdK\x04\x00\x00b\x00b\n'
zlib.decompress(bytestring[4:-4], -15).decode('utf-8')
>>> "a"

如果我包含分号a;,则无法解压缩:

bytestring = b'x\xef\xbf\xbdK\xef\xbf\xbd\x06\x00\x00\xef\xbf\xbd\x00\xef\xbf\xbd\n'
zlib.decompress(bytestring[4:-4], -15).decode('utf-8')
*** UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8f in position 1: invalid start byte

注意:我还尝试使用 'punycode' 解码这些示例,我在 javascript 实现中找到了参考。

我对 zlib 的理解非常有限,但我发现 zlib 字符串的前两个和最后四个字节是页眉/页脚,如果我们使用幻数 -15 运行 zlib 可以修剪。完全有可能有 zlib 幻数可以解压缩这些字符串而无需剥离页眉和页脚,但是当从 -64 循环到 64 时,我无法让任何组合起作用。

我已经通过在线 sql 工作表编辑器的保存和加载功能设置了断点,发现它们正在使用 pako zlib 库pako.deflate(a, {to: 'string'})pako.inflate(b['body'], {to: 'string'}) 并且我可以使用该pako库在浏览器中对 sql 字符串进行充气/放气,但一直无法在 python 中重现相同的结果。

标签: pythonzlibunicode-stringpako

解决方案


我同意这是一个数据损坏问题。 zlib并且pako应该能够在没有任何剥离字段或添加幻数的情况下读取彼此的数据。

为了证明这一点,我放了几个演示脚本,一个pako用于压缩数据,一个zlib用于再次膨胀:

// deflate.js
var pako = require("./pako.js");
console.log(escape(pako.deflate(process.argv[2], {to: "string"})));
# inflate.py
import urllib.parse, zlib, sys
print(zlib.decompress(urllib.parse.unquote_to_bytes(sys.stdin.read())).decode("utf-8"))

使用 . 在命令行上运行它们node deflate.js "Here is some example text" | inflate.py。预期的输出是传递给的参数node deflate.js

值得指出的一件事是pako使用该to: "string"选项时的行为。此选项的文档如下:

to(String) - 如果等于 'string',则结果将是“二进制字符串”(每个字符代码 [0..255])

正是出于这个原因,我escape在上面的 JavaScript 函数中使用。Usingescape确保在 JavaScript 和 Python 之间传递的字符串不包含任何非 ASCII 字符。(请注意,这不起作用encodeURIComponent,因为字符串包含二进制数据。)然后我在 Python 中使用来撤消这种转义。urllib.parse.unquote_to_bytes

如果您可以escapepako浏览器中使用 -deflate 数据,您可能会将其传递给 Python 以再次对其进行充气。


推荐阅读