繁体   English   中英

使用python的gzip出现问题/“如何知道正在使用哪种压缩?”

[英]Trouble using python's gzip/“How do I know what compression is being used?”

好的,所以我有一个使用数据包进行通信的开源Java客户端/服务器程序。 我正在尝试为上述程序编写python客户端,但数据包的内容似乎已压缩。 快速浏览源代码建议使用gzip作为压缩模式(因为这是我在代码中可以找到的唯一导入的压缩模块),但是当我将其中一个数据包中的数据保存到wireshark中并尝试执行时,

import gzip
f = gzip.open('compressed_file')
f.read()

它告诉我这不是gzip文件,因为标题错误。 有人可以告诉我我在这里做错了什么吗? 保存后是否更改或弄乱了格式? 在尝试在数据包上运行此块之前,是否需要从数据包中剥离一些多余的数据?

    if (zipped) {

        // XML encode the data and GZIP it.
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        Writer zipOut = new BufferedWriter(new OutputStreamWriter(
                new GZIPOutputStream(baos)));
        PacketEncoder.encodeData(packet, zipOut);
        zipOut.close();

        // Base64 encode the commpressed data.
        // Please note, I couldn't get anything other than a
        // straight stream-to-stream encoding to work.
        byte[] zipData = baos.toByteArray();
        ByteArrayOutputStream base64 = new ByteArrayOutputStream(
                (4 * zipData.length + 2) / 3);
        Base64.encode(new ByteArrayInputStream(zipData), base64, false);

编辑:好的,抱歉,我在这里要求提供信息。 这是使用Wireshark收集的,以侦听不同计算机上原始程序的两个运行副本之间的通信。 为了获得下面的十六进制流,我在Wireshark中使用了“复制->十六进制(字节流)”选项。

001321cdc68ff4ce46e4f00d0800450000832a85400080061e51ac102cceac102cb004f8092a9909b32c10e81cb25018f734823e00000100000000000000521f8b08000000000000005bf39681b59c85818121a0b4884138da272bb12c512f27312f5dcf3f292b35b9c47ac2b988f902c59a394c0c0c150540758c250c5c2ea5b9b9950a2e89258900aa4c201a3f000000

我知道这将在其中包含字符串“虚拟数据”。 我相信它还应该包含“ Jonathanb”(我用来发送消息的玩家名称)和整数80(就我从代码中收集的而言,“ 80”是“ Chat”的命令#)。

您可以尝试直接使用标准库模块zlibgzip将其用于压缩/解压缩部分。 如果整个数据包不被喜欢的解压缩功能,你可以尝试使用不同的值wbits和/或割掉该数据包的前几个字节(如果你可以“反向工程”究竟是如何在Java代码压缩该包-甚至只是了解正在使用的wbits数,或者是否在压缩数据之前放置了任何前缀-当然,这将极大地帮助您。

您可能会对文件本身造成的唯一“损坏”是在Windows上,如果您在未指定'wb'使用二进制模式的情况下编写了该文件-在Windows上以“文本模式”编写该文件将使该文件无法使用。 只是说...!-)

如果您泄露以下内容,将大有帮助:

(0)导致您得出以下结论:“数据包的内容似乎已压缩”

(1)用于写数据包的软件包的(a)源和(b)文档的URL

(2)样本包的内容

(a) print repr(open('file_saved_from_wireshark', 'rb').read())

(b)万一通过Wireshk进行的长途旅行使水变得浑浊,请将其插入您的Python客户端中:

print repr(a_sample_packet)

(3)您收到的确切错误消息(复制/粘贴)

OP提供了数据包的十六进制转储后进行更新

这段代码:

import binascii, sys, cStringIO, gzip, struct, zlib
# guff is allegedly a "packet", formatted as 2 hex characters per byte
guff = "001321cdc68ff4ce46e4f00d0800450000832a85400080061e51ac102cceac102cb004f8092a9909b32c10e81cb25018f734823e00000100000000000000521f8b08000000000000005bf39681b59c85818121a0b4884138da272bb12c512f27312f5dcf3f292b35b9c47ac2b988f902c59a394c0c0c150540758c250c5c2ea5b9b9950a2e89258900aa4c201a3f000000"
guff2 = binascii.unhexlify(guff)
print "raw input: len=%d repr=%r" % (len(guff2), guff2)
# gzip spec: http://www.faqs.org/rfcs/rfc1952.html
GZIP_HDR = "\x1F\x8B\x08"
gzpos = guff2.find(GZIP_HDR)
if gzpos == -1:
    print "Can't find gzip header"
    sys.exit(1)
print gzpos, "bytes before gzipped data"
gzipped = guff2[gzpos:]
packet_crc, packet_orig_len = struct.unpack("<II", gzipped[-8:])
print "packet_crc, packet_orig_len:", hex(packet_crc), packet_orig_len
fobj = cStringIO.StringIO(gzipped)
zf = gzip.GzipFile(fileobj=fobj)
payload = zf.read()
print "payload: len=%d repr=%r" % (len(payload), payload)
print "crc32(payload):", hex(zlib.crc32(payload))

当使用Python 2.6.4运行时,产生了此输出(由Windows的“命令提示符”终端在col 80处包装):

raw input: len=145 repr="\x00\x13!\xcd\xc6\x8f\xf4\xceF\xe4\xf0\r\x08\x00E\x00\x
00\x83*\x85@\x00\x80\x06\x1eQ\xac\x10,\xce\xac\x10,\xb0\x04\xf8\t*\x99\t\xb3,\x1
0\xe8\x1c\xb2P\x18\xf74\x82>\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00R\x1f\x8b\x0
8\x00\x00\x00\x00\x00\x00\x00[\xf3\x96\x81\xb5\x9c\x85\x81\x81!\xa0\xb4\x88A8\xd
a'+\xb1,Q/'1/]\xcf?)+5\xb9\xc4z\xc2\xb9\x88\xf9\x02\xc5\x9a9L\x0c\x0c\x15\x05@u\
x8c%\x0c\\.\xa5\xb9\xb9\x95\n.\x89%\x89\x00\xaaL \x1a?\x00\x00\x00"
63 bytes before gzipped data
packet_crc, packet_orig_len: 0x1a204caa 63
payload: len=63 repr='\xac\xed\x00\x05w\x04\x00\x00\x00Pur\x00\x13[Ljava.lang.Ob
ject;\x90\xceX\x9f\x10s)l\x02\x00\x00xp\x00\x00\x00\x01t\x00\nDummy Data'
crc32(payload): 0x1a204caa

评论/问题:

  1. 该数据包长145个字节。 一个数据包约为2900字节的想法发生了什么?

  2. 该数据包是尚未分析的63字节数据,后跟一个82字节的gzip流,该流将(!)解压缩为63字节。 gzip流之后没有数据-通过将数据包的最后8个字节与计算出的gzip值进行比较来验证。 它包含预期的“虚拟数据”,但用户标识“ johnathonb”不存在(或混淆或加密)。

  3. 数据包结构与我们猜测正在使用的代码不匹配(没有XML,没有base64)。

  4. 压缩后的数据包含字符串“ java.lang.Object”,这可能是某些Java序列化协议的症状。 Lasciate ogni speranza,voi qu'entrate

这可能与RFC之一兼容1950年1951年1952年

由于名称为GZIP,因此我首先检查1952。然后尝试ZLIB,1950。最后是DEFLATE(1951)。

DotNetZip是一个.NET库,它允许.NET应用程序读取符合任何这些格式的数据流。 如果您有一个符合以上条件之一的流,则可以通过依次尝试使用每个DotNetZip的流读取该流来非常快速地确定是哪个流。 GZipStreamZlibStreamDeflateStream 其中一个将工作,而其他则不会。

我不知道有那些流的Java库。 并不意味着它不存在。 只是我不知道一个。

DotNetZip是免费的,可在Windows + Mono,Linux + Mono以及Windows + .NET上运行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM