奇怪的 gzip - 几乎提取,但不完全正确
Strange gzip - almost extracted, but not totally correct
一些程序向服务器发送一些以\x1f\xe2\x80\xb9\x08\x00\x00\x00\x00\x00\x04\x00M...
开头的信息并接收文本响应。我需要猜猜这是什么信息。
事实上,我需要将真实字符串转换为相同的 gzip 原始字符串的方法,以便在没有该程序的情况下接收响应。
经过调查,我发现首先我应该将数据从 utf8 解码为 cp1251(之后第一个符号 \x1f\xe2\x80\xb9\x08
将是 \x1fb\x08
,这是典型的 gzip 魔术字符串)。它将损坏 gzip,但如果我将其剪切为 header(前 10 个符号),我可以提取最终可读消息。
但此消息几乎没有损坏(开始正确,但后来一些符号被打乱)。
应该如何正确读取数据?
我猜想在 decode_binary_from_utf8_to_cp1251 期间我丢失了一些信息,因为如果我不使用 on_errors='replace' 数据将无法正确转换(我试过其他编码也执行 \x1f\xe2\x80\xb9\x08
到 \x1fb\x08
魔法但没有成功,没有一种编码能够 100% 无错误地转换)。而且当我剪切 header(gzip 字符串的前 10 个符号)时,一些数据也可能会丢失。
我的代码:
import zlib
import base64
def decode_binary_from_utf8_to_cp1251(data):
enc_from = "utf8"
enc_to = "cp1251"
on_errors = "replace"
# on_errors = ""
return data.decode(enc_from, on_errors).encode(enc_to, on_errors)
def remove_archive_signature_from_start(data):
return data[10:]
def decompress_gzip(body):
args = (-zlib.MAX_WBITS | 16,) # working
return zlib.decompress(body, *args)
def convert_binary_to_normal_text(b, encoding="cp1251"):
b = b.decode(encoding, "replace")
return b
base64_encoded = "L2dldC8f4oC5CAAAAAAABABN4oCZX+KAmdCrIAzQltCH0KLQ ... gMAAA=="
data = base64.b64decode(base64_encoded)[5:]
# data = b'\x1f\xe2\x80\xb9\x08\x00\x00\x00\x00\x00\x04\x00...\x03\x00\x00'
new_data = decode_binary_from_utf8_to_cp1251(data)
new_data = remove_archive_signature_from_start(new_data)
decompressed = decompress_gzip(new_data)
normal_text = convert_binary_to_normal_text(decompressed)
print(f"{normal_text=}")
returns 文字喜欢
...
;btennis,1oatchoomkcom®1i,hoomkcomwilliamhillmkcomwom;bein.zegoalbet.cal;bmosityom;beokt;favet.colpasbein.zeni;bmosbet.learathssityligbetavtchoomkpar)rrathssitnoarathoinfo
...
, 开始是正确的,但后来一些符号被打乱了(因为我确切地知道它应该包括字符串 ;wwin.com;zebet.com;baltbet.ru;winlinebet.com;golpas.com;zenitbet.com;leonbets.ru;ligastavok.com;parimatch.com;fonbet.info®
)
知道我错过了什么吗?
“某些程序”有一个错误需要修复。一般来说,UTF 编码不是无损的,所以原始数据是不可恢复的。该程序需要不进行任何此类转换,而是发送原始二进制文件。
通过在 Windows-1251 Wikipedia page 上使用 table,我能够从示例中恢复原始 gzip 文件,并添加一个。您会注意到 table 与字符 0x98
没有任何关系。我假设 unicode 符号 U+0098
转换为字节 0x98
。应用该转换并删除结果的前五个字节会产生一个有效的 gzip 流,并进行正确的 CRC 和长度检查。
不能保证这会在一般情况下工作,因为提供的示例没有所有可能的字节值。
感谢 @Mark Adler,decode_binary_from_utf8_to_cp1251
的新版本解决了这个问题:
def decode_binary_from_utf8_to_cp1251(data, enc_from="utf8", enc_to="cp1251"):
data = data_correction_before(data)
data = data.decode(enc_from)
data = data.encode(enc_to)
data = data_correction_after(data)
return data
def data_correction_before(data):
return data.replace(b"\xc2\x98", b"__WRONG__")
def data_correction_after(data):
return data.replace(b"__WRONG__", b"\x98")
一些程序向服务器发送一些以\x1f\xe2\x80\xb9\x08\x00\x00\x00\x00\x00\x04\x00M...
开头的信息并接收文本响应。我需要猜猜这是什么信息。
事实上,我需要将真实字符串转换为相同的 gzip 原始字符串的方法,以便在没有该程序的情况下接收响应。
经过调查,我发现首先我应该将数据从 utf8 解码为 cp1251(之后第一个符号 \x1f\xe2\x80\xb9\x08
将是 \x1fb\x08
,这是典型的 gzip 魔术字符串)。它将损坏 gzip,但如果我将其剪切为 header(前 10 个符号),我可以提取最终可读消息。
但此消息几乎没有损坏(开始正确,但后来一些符号被打乱)。
应该如何正确读取数据?
我猜想在 decode_binary_from_utf8_to_cp1251 期间我丢失了一些信息,因为如果我不使用 on_errors='replace' 数据将无法正确转换(我试过其他编码也执行 \x1f\xe2\x80\xb9\x08
到 \x1fb\x08
魔法但没有成功,没有一种编码能够 100% 无错误地转换)。而且当我剪切 header(gzip 字符串的前 10 个符号)时,一些数据也可能会丢失。
我的代码:
import zlib
import base64
def decode_binary_from_utf8_to_cp1251(data):
enc_from = "utf8"
enc_to = "cp1251"
on_errors = "replace"
# on_errors = ""
return data.decode(enc_from, on_errors).encode(enc_to, on_errors)
def remove_archive_signature_from_start(data):
return data[10:]
def decompress_gzip(body):
args = (-zlib.MAX_WBITS | 16,) # working
return zlib.decompress(body, *args)
def convert_binary_to_normal_text(b, encoding="cp1251"):
b = b.decode(encoding, "replace")
return b
base64_encoded = "L2dldC8f4oC5CAAAAAAABABN4oCZX+KAmdCrIAzQltCH0KLQ ... gMAAA=="
data = base64.b64decode(base64_encoded)[5:]
# data = b'\x1f\xe2\x80\xb9\x08\x00\x00\x00\x00\x00\x04\x00...\x03\x00\x00'
new_data = decode_binary_from_utf8_to_cp1251(data)
new_data = remove_archive_signature_from_start(new_data)
decompressed = decompress_gzip(new_data)
normal_text = convert_binary_to_normal_text(decompressed)
print(f"{normal_text=}")
returns 文字喜欢
...
;btennis,1oatchoomkcom®1i,hoomkcomwilliamhillmkcomwom;bein.zegoalbet.cal;bmosityom;beokt;favet.colpasbein.zeni;bmosbet.learathssityligbetavtchoomkpar)rrathssitnoarathoinfo
...
, 开始是正确的,但后来一些符号被打乱了(因为我确切地知道它应该包括字符串 ;wwin.com;zebet.com;baltbet.ru;winlinebet.com;golpas.com;zenitbet.com;leonbets.ru;ligastavok.com;parimatch.com;fonbet.info®
)
知道我错过了什么吗?
“某些程序”有一个错误需要修复。一般来说,UTF 编码不是无损的,所以原始数据是不可恢复的。该程序需要不进行任何此类转换,而是发送原始二进制文件。
通过在 Windows-1251 Wikipedia page 上使用 table,我能够从示例中恢复原始 gzip 文件,并添加一个。您会注意到 table 与字符 0x98
没有任何关系。我假设 unicode 符号 U+0098
转换为字节 0x98
。应用该转换并删除结果的前五个字节会产生一个有效的 gzip 流,并进行正确的 CRC 和长度检查。
不能保证这会在一般情况下工作,因为提供的示例没有所有可能的字节值。
感谢 @Mark Adler,decode_binary_from_utf8_to_cp1251
的新版本解决了这个问题:
def decode_binary_from_utf8_to_cp1251(data, enc_from="utf8", enc_to="cp1251"):
data = data_correction_before(data)
data = data.decode(enc_from)
data = data.encode(enc_to)
data = data_correction_after(data)
return data
def data_correction_before(data):
return data.replace(b"\xc2\x98", b"__WRONG__")
def data_correction_after(data):
return data.replace(b"__WRONG__", b"\x98")