Проблема с использованием Python gzip / "Как я знаю, какое сжатие используется?" - PullRequest
0 голосов
/ 23 января 2010

Хорошо, у меня есть клиент / серверная программа с открытым исходным кодом, которая использует пакеты для связи. Я пытаюсь написать 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);

EDIT: Хорошо, извините, у меня есть информация, запрошенная здесь. Это было собрано с помощью Wireshark для прослушивания связи между двумя работающими копиями исходной программы на разных компьютерах. Чтобы получить шестнадцатеричный поток ниже, я использовал опцию «Copy -> Hex (Byte Stream)» в Wireshark.

001321cdc68ff4ce46e4f00d0800450000832a85400080061e51ac102cceac102cb004f8092a9909b32c10e81cb25018f734823e00000100000000000000521f8b08000000000000005bf39681b59c85818121a0b4884138da272bb12c512f27312f5dcf3f292b35b9c47ac2b988f902c59a394c0c0c150540758c250c5c2ea5b9b9950a2e89258900aa4c201a3f000000

Я знаю, что в нем будет строка "Dummy Data". Я считаю, что он также должен содержать «Jonathanb» (имя игрока, которое я использовал для отправки сообщения) и целое число 80 (80 - это команда # для «Чата», насколько я могу судить по коду).

Ответы [ 3 ]

1 голос
/ 23 января 2010

Это очень помогло бы, если бы вы обнародовали:

(0) Что приводит вас к выводу, что «содержимое пакета кажется сжатым»

(1) URL-адреса источника (a) и (b) документации пакета, который пишет пакеты

(2) Содержимое образца пакета

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

(b) на случай, если длительное путешествие по проволочной акуле приведет к загрязнению воды, вставьте это в свой клиент 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))

произвел этот вывод (обернутый в столбец 80 терминалом командной строки Windows) при запуске с Python 2.6.4:

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 .

1 голос
/ 23 января 2010

Вы можете попробовать использовать стандартный библиотечный модуль zlib напрямую - это то, что gzip использует для сжатия / распаковки. Если функция распаковка не понравилась всему пакету, вы можете попробовать использовать различные значения wbits и / или отрезать несколько байтов от фронта пакета (если вы могли бы точно "выполнить обратный инжиниринг") как код Java сжимает этот пакет - даже просто понимает, сколько wbits использует или выдает какой-либо префикс перед сжатыми данными - это, конечно, очень помогло бы.

Единственный вероятный «ущерб», который вы могли бы нанести самому файлу, был бы в Windows, если бы вы написали его без указания 'wb' для использования двоичного режима - запись его в «текстовом режиме» на окнах файл непригоден для использования. Просто говорю ...! -)

0 голосов
/ 23 января 2010

Вероятно, он будет соответствовать одному из RFC 1950 , 1951 или 1952 .

Поскольку имя GZIP, я сначала проверил 1952. Затем я попробовал ZLIB, 1950. Наконец, DEFLATE (1951).

DotNetZip - это библиотека .NET, которая позволяет приложению .NET считывать потоки данных, соответствующие любому из этих форматов. Если у вас есть поток, который соответствует одному из вышеперечисленных, вы можете очень быстро определить, какой это был поток, пытаясь читать поток с каждым из потоков DotNetZip подряд; GZipStream , ZlibStream , DeflateStream . Один из них будет работать, а другие нет.

Я не знаю библиотеки Java, в которой есть эти потоки. Это не значит, что его не существует. Просто я не знаю ни одного.

DotNetZip бесплатен и работает на Windows + Mono, Linux + Mono, а также Windows + .NET.

...