Skip to content

第 2 章 通用序列化基类 structure.py

impacket 根目录的 structure.py 定义了 Structure 基类——keytab.py、ccache.py、smb3structs.py 等文件中的每个类都继承自它,是全书后续所有协议包结构的基础。文件开头的大段注释解释了一种数据格式描述语言:可以理解为对标准 struct 格式的扩充,数据类型的写法有点像正则,pack / unpack 则负责按格式对变量进行组包 / 解包(如有理解偏差,欢迎指正)。它被用来描述 SMB、RPC、Kerberos 等域内通信协议的请求包结构。

    """ sublcasses can define commonHdr and/or structure.
        each of them is an tuple of either two: (fieldName, format) or three: (fieldName, ':', class) fields.
        [it can't be a dictionary, because order is important]

        where format specifies how the data in the field will be converted to/from bytes (string)
        class is the class to use when unpacking ':' fields.

        format specifiers:  # 与 struct 模块一致(x c b B h H l L i I q Q s p f d = @ ! < >)
          some additional format specifiers:
            :       just copy the bytes from the field into the output string (input may be string, other structure, or anything responding to __str__()) (for unpacking, all what's left is returned)
            z       same as :, but adds a NUL byte at the end (asciiz)  [asciiz string]
            u       same as z, but adds two NUL bytes at the end  [unicode string]
            w       DCE-RPC/NDR string (it's a macro for [  '<L=(len(field)+1)/2','"\\x00\\x00\\x00\\x00','<L=(len(field)+1)/2',':' ]
            ?-field length of field named 'field', formatted as specified with ?
            ?1*?2   array of elements. Each formatted as '?2', the number of elements is stored as specified by '?1'
            'xxxx / "xxxx   literal xxxx (field's value doesn't change the output)
            # printf 风格(%08x、%s 等)与 _ / ?=packcode / ?&fieldname 等
            # 更冷门的说明符此处略,完整说明见 structure.py 源码
    """

这里以 SMB 协议举例:

# eg./impacket/smb3structs.py

class SMB2Negotiate(Structure):
    structure = (
        ('StructureSize','<H=36'),
        ('DialectCount','<H=0'),
        ('SecurityMode','<H=0'),
        ('Reserved','<H=0'),
        ('Capabilities','<L=0'),
        ('ClientGuid','16s=""'),
        ('ClientStartTime','8s=""'),  # or (NegotiateContextOffset/NegotiateContextCount/Reserved2) in SMB 3.1.1
        ('Dialects','*<H'),
        # SMB 3.1.1
        ('Padding',':=""'),
        ('NegotiateContextList',':=""'),
    )

同样的应用也可以在 ccache.py 中看到——它用于解析 Kerberos 凭据的二进制缓冲文件:

class Header(Structure):
    structure = (
        ('tag','!H=0'),
        ('taglen','!H=0'),
        ('_tagdata','_-tagdata','self["taglen"]'),
        ('tagdata',':'),
    )