Python从tcp套接字解压缩二进制流

时间:2013-04-25 18:42:03

标签: python sockets struct

好的,所以我认为熟悉Python是个好主意。 (我有Java,php,perl,VB等经验,不是任何掌握,但是中级知识)

所以我试图编写一个脚本,它将从套接字中获取数据,并将其转换为屏幕。粗略的开始代码:

我的代码似乎正确地从套接字读取二进制信息,但我无法解压缩它,因为我无法访问原始结构。

我使用不同的程序输出此流的输出(这是我写的很糟糕的原因)

当我打印出recv时,就像这样......

b'L\x00k\x07vQ\n\x01\xffh\x00\x04NGIN\x04MAIN6Product XX finished reprocessing cdc XXXXX at jesadr 0c\x00k\x07vQ\n\x01\xffF\x00\x06CSSPRD\x0cliab_checkerCCheckpointed to XXXXXXXXXXXXXXXX:XXXXXXX.XXX at jesadr 0 (serial 0)[\x00l\x07vQ\n\x00\xff\x01\x00\x05MLIFE\x06dayendBdayend 1 Copyright XXXX XXXXXXX XXXXXXX XXXXX XXX XXXXXX XXXXXXXX.

从这个看,并将它与其他程序的输出进行比较,我猜想它应该被分解为......

b'L\x00k\x07vQ\n\x01\xffh\x00\x04NGIN\x04MAIN6Product XX finished reprocessing cdc XXXXX at jesadr 0'

带有相应的信息

04-23
00:00:43
10
1
NGIN
MAIN
255
104
Product XX finished reprocessing cdc XXXXX at jesadr 0

现在,根据我的研究,看起来我需要使用“struct”并解压缩它,但是我不知道它的原始结构,我只知道它可以获得什么信息,并且是老实说,我有一段时间搞清楚这一点。

我已经使用python解释器试图解开该行的各个部分,但这是一种令人沮丧的练习。

如果有人能帮助我开始,我会非常感激。

由于

4 个答案:

答案 0 :(得分:2)

好。我想我已经设法解码它,虽然我不确定中间的16位值。

这个Python 2.7代码......

from cStringIO import StringIO
import struct
import time

def decode(f):

    def read_le16(f):
        return struct.unpack('<h', f.read(2))[0]

    def read_timestamp(f):
        ts = struct.unpack('<l', f.read(4))[0]
        return time.ctime(ts)

    def read_byte(f):
        return ord(f.read(1))

    def read_pascal(f):
        l = ord(f.read(1))
        return f.read(l)

    result = []

    # Read total length
    result.append('Total message length is %d bytes' % read_le16(f))

    # Read timestamp
    result.append(read_timestamp(f))

    # Read 3 x byte
    result.append(read_byte(f))
    result.append(read_byte(f))
    result.append(read_byte(f))

    # Read 1 x LE16
    result.append(read_le16(f))

    # Read 3 x pascal string
    result.append(read_pascal(f))
    result.append(read_pascal(f))
    result.append(read_pascal(f))

    return result

s = 'L\x00k\x07vQ\n\x01\xffh\x00\x04NGIN\x04MAIN6Product XX finished reprocessing cdc XXXXX at jesadr 0c\x00k\x07vQ\n\x01\xffF\x00\x06CSSPRD\x0cliab_checkerCCheckpointed to XXXXXXXXXXXXXXXX:XXXXXXX.XXX at jesadr 0 (serial 0)[\x00l\x07vQ\n\x00\xff\x01\x00\x05MLIFE\x06dayendBdayend 1 Copyright XXXX XXXXXXX XXXXXXX XXXXX XXX XXXXXX XXXXXXXX.'

f = StringIO(s)
print decode(f)
print decode(f)
print decode(f)

... ...产量

['Total message length is 76 bytes', 'Tue Apr 23 05:00:43 2013', 10, 1, 255, 104, 'NGIN', 'MAIN', 'Product XX finished reprocessing cdc XXXXX at jesadr 0']
['Total message length is 99 bytes', 'Tue Apr 23 05:00:43 2013', 10, 1, 255, 70, 'CSSPRD', 'liab_checker', 'Checkpointed to XXXXXXXXXXXXXXXX:XXXXXXX.XXX at jesadr 0 (serial 0)']
['Total message length is 91 bytes', 'Tue Apr 23 05:00:44 2013', 10, 0, 255, 1, 'MLIFE', 'dayend', 'dayend 1 Copyright XXXX XXXXXXX XXXXXXX XXXXX XXX XXXXXX XXXXXXXX.']

时间戳超出了5个小时,所以我认为这是时区的事情。

答案 1 :(得分:0)

我会说你使用struct是正确的,但结构很糟糕的是,你总是必须知道原始结构。

也许阅读tcp规范和isos会对所有人有所帮助,虽然现在仍然很难搞清楚:/

答案 2 :(得分:0)

如果不知道二进制流的结构,虽然有足够的时间对其进行逆向工程,但很难解析,你可能会接近或幸运。

虽然如果客户端程序使用了pickle协议,那么你很幸运。

答案 3 :(得分:0)

到目前为止,我只是反向设计的代码,而不是二进制流,所以我远远不是你挑战的专家。但是,我想分享一下我将如何解决你的问题的想法。也许有人在那里发现有用(也许我自己在某个时间)。

TL; DR相关教育视频:Harald Welte at 27C3

路线图

1。上下文

获取有关该程序的更多信息(编程语言,已知的序列化器/序列化格式,已知的怪癖等),域,该领域的任何规范,......

2。集合

收集流中足够长的部分,或者,如果您知道消息的外观(任何消息开头/消息结束标记),请收集一组适当的消息。还要收集参考程序的相应输出。

3。低垂的水果

尝试识别可在线路协议和相应输出中轻松发现的字符串和数字。记下哪些部分不太清楚。

4。睁大眼睛

通过查找有线协议消息的重复和差异来扩展您的知识。尝试将这些“有趣的点”与记录输出中的重复和差异相匹配。

5。假设

根据您所知道的内容创建有关电汇格式的假设。特别要考虑步骤#1中可能对您有所帮助的信息。另外,考虑一下时间戳,序列号,校验和,消息头,元数据等内容。

6。验证

在代码中实现您的假设。根据您记录的数据集运行它,以测试它是否按预期工作。然后,反对一堆(可能更长)的新鲜样本 - 即使你以前没有见过 - 来支持你的假设。如果出现故障,请返回步骤#5。

7。全力以赴

根据需要循环执行上述步骤,直到您可以提取所需的所有信息,甚至可以提取更多信息。

结束语

我认为,为了确保您对线路协议的理解是正确的,我们需要进行密集测试。这包括A)单元测试,以确保您在测试新假设时不会破坏脆弱代码中的内容,并且B)在验证步骤中提到,将新样本抛给代码并检查您的期望是否仍然有效。 / p>

但即便如此,您可能也错了。即使经过全面测试,这也不是保证您的假设是正确的。总是准备以新的方式思考,因为事实证明,看起来如此清晰的事实上是完全不同的。

如果有必要,请大胆了解电线格式中可能隐藏的内容或事物的排列和/或相关方式。

在我的这个可能无用的文字之后,让我完成一个关于逆向工程现实世界RFID支付系统的视频:Harald Welte at 27C3