第 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',':'),
)