奇怪的gzip几乎被提取,但并不完全正确

2024-09-28 21:13:24 发布

您现在位置:Python中文网/ 问答频道 /正文

一些程序向服务器发送一些以\x1f\xe2\x80\xb9\x08\x00\x00\x00\x00\x00\x04\x00M...开头的信息,并接收文本响应。我要猜猜是什么信息

事实上,我需要将真实字符串转换为相同的gzip原始字符串的方法,以便在没有该程序的情况下接收响应

在调查之后,我发现首先我应该将数据从utf8解码到cp1251(之后,第一个符号\x1f\xe2\x80\xb9\x08将是\x1f\8b\x08,这是典型的gzip魔术字符串)。它将被破坏gzip,但如果我剪切它的头(前10个符号),我可以提取最终可读的消息

但此消息几乎没有损坏(正确启动,但稍后一些符号被洗牌)

如何正确读取数据

我猜在将二进制代码从utf8解码到cp1251的过程中,我丢失了一些信息,因为如果我不使用on-errors='replace',数据就无法正确转换(我尝试过其他编码,也使用了\x1f\xe2\x80\xb9\x08\x1f\8b\x08的魔法,但没有成功,没有一种编码能够100%无误地转换)。而且,当我剪切标题(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=}")

返回类似于

...
;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®

你知道我遗漏了什么吗


Tags: to字符串fromcomdataon符号utf8
2条回答

“某些程序”有一个需要修复的bug。通常,UTF编码不是无损的,因此原始数据是不可恢复的。该程序需要而不是执行任何此类转换,而是发送原始二进制文件

通过使用Windows-1251 Wikipedia page上的表,我能够从示例中恢复原始gzip文件,并添加了一个。您将注意到该表中没有字符0x98。我假设unicode符号U+0098转换为字节0x98。应用该转换并删除结果的前五个字节,将得到一个具有正确CRC和长度检查的有效gzip流

由于所提供的示例没有所有可能的字节值,因此不能保证这在一般情况下都会起作用

多亏了@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")

相关问题 更多 >