一、创建Symbol对象构建协议symbol
Symbol对象是Netzob协议模型的一个主要组成部分。它代表了从协议的角度来看所有相同类型的消息的抽象。从协议的角度来看,一个Symbol代表了同一类型的所有消息的抽象。符号结构由字段组成。
symbol = Symbol(messages=messages)
# print(symbol.str_data())
# 如下为输出结果
Field
-----------------------------------------------------
'CMDidentify#\x07\x00\x00\x00Roberto'
'RESidentify#\x00\x00\x00\x00\x00\x00\x00\x00'
'CMDinfo#\x00\x00\x00\x00'
'RESinfo#\x00\x00\x00\x00\x04\x00\x00\x00info'
'CMDstats#\x00\x00\x00\x00'
'RESstats#\x00\x00\x00\x00\x05\x00\x00\x00stats'
'CMDauthentify#\n\x00\x00\x00aStrongPwd'
'RESauthentify#\x00\x00\x00\x00\x00\x00\x00\x00'
'CMDencrypt#\x06\x00\x00\x00abcdef'
"RESencrypt#\x00\x00\x00\x00\x06\x00\x00\x00$ !&'$"
"CMDdecrypt#\x06\x00\x00\x00$ !&'$"
'RESdecrypt#\x00\x00\x00\x00\x06\x00\x00\x00abcdef'
'CMDbye#\x00\x00\x00\x00'
'RESbye#\x00\x00\x00\x00\x00\x00\x00\x00'
'CMDidentify#\x04\x00\x00\x00fred'
'RESidentify#\x00\x00\x00\x00\x00\x00\x00\x00'
'CMDinfo#\x00\x00\x00\x00'
'RESinfo#\x00\x00\x00\x00\x04\x00\x00\x00info'
'CMDstats#\x00\x00\x00\x00'
'RESstats#\x00\x00\x00\x00\x05\x00\x00\x00stats'
'CMDauthentify#\t\x00\x00\x00myPasswd!'
'RESauthentify#\x00\x00\x00\x00\x00\x00\x00\x00'
'CMDencrypt#\n\x00\x00\x00123456test'
"RESencrypt#\x00\x00\x00\x00\n\x00\x00\x00spqvwt6'16"
"CMDdecrypt#\n\x00\x00\x00spqvwt6'16"
'RESdecrypt#\x00\x00\x00\x00\n\x00\x00\x00123456test'
'CMDbye#\x00\x00\x00\x00'
'RESbye#\x00\x00\x00\x00\x00\x00\x00\x00'
-----------------------------------------------------
可以看到这些messages都由一个类似于指令的东西,加“#”,再跟上一些值。这便是一次初步的处理。
二、使用分隔符对上述信息再做处理
显而易见上述messages的类似于键值对的东西是用#来区分“键”和“值”的。由此我们可以使用netzob自带的Format.splitDelimiter函数对其进行处理。api文档对其的介绍是:
>>> from netzob.all import *
>>> import binascii
>>> samples = [b"434d446964656e74696679230400000066726564", b"5245536964656e74696679230000000000000000", b"434d44696e666f2300000000", b"524553696e666f230000000004000000696e666f", b"434d4473746174732300000000", b"52455373746174732300000000050000007374617473", b"434d4461757468656e7469667923090000006d7950617373776421", b"52455361757468656e74696679230000000000000000"]
>>> print(len(samples))
8
>>> symbol = Symbol(messages=[RawMessage(binascii.unhexlify(sample)) for sample in samples])
>>> symbol.encodingFunctions.add(TypeEncodingFunction(HexaString))
>>> Format.splitDelimiter(symbol, String('#'))
>>> print(symbol.str_data())
Field-0 | Field-sep-23 | Field-2
---------------------------- | ------------ | ----------------------------
'434d446964656e74696679' | '#' | '0400000066726564'
'5245536964656e74696679' | '#' | '0000000000000000'
'434d44696e666f' | '#' | '00000000'
'524553696e666f' | '#' | '0000000004000000696e666f'
'434d447374617473' | '#' | '00000000'
'5245537374617473' | '#' | '00000000050000007374617473'
'434d4461757468656e74696679' | '#' | '090000006d7950617373776421'
'52455361757468656e74696679' | '#' | '0000000000000000'
---------------------------- | ------------ | ----------------------------
由此,我们便可以使用如下代码对其划分,并进行展示:
Format.splitDelimiter(symbol, String("#"))
print(symbol.str_data())
print(symbol.str_structure()) # 这种方法是使用树状的结构进行统计展示
其输出如下所示:
Field-0 | Field-sep-23 | Field-2
--------------- | ------------ | ------------------------------------------
'CMDidentify' | '#' | '\x07\x00\x00\x00Roberto'
'RESidentify' | '#' | '\x00\x00\x00\x00\x00\x00\x00\x00'
'CMDinfo' | '#' | '\x00\x00\x00\x00'
'RESinfo' | '#' | '\x00\x00\x00\x00\x04\x00\x00\x00info'
'CMDstats' | '#' | '\x00\x00\x00\x00'
'RESstats' | '#' | '\x00\x00\x00\x00\x05\x00\x00\x00stats'
'CMDauthentify' | '#' | '\n\x00\x00\x00aStrongPwd'
'RESauthentify' | '#' | '\x00\x00\x00\x00\x00\x00\x00\x00'
'CMDencrypt' | '#' | '\x06\x00\x00\x00abcdef'
'RESencrypt' | '#' | "\x00\x00\x00\x00\x06\x00\x00\x00$ !&'$"
'CMDdecrypt' | '#' | "\x06\x00\x00\x00$ !&'$"
'RESdecrypt' | '#' | '\x00\x00\x00\x00\x06\x00\x00\x00abcdef'
'CMDbye' | '#' | '\x00\x00\x00\x00'
'RESbye' | '#' | '\x00\x00\x00\x00\x00\x00\x00\x00'
'CMDidentify' | '#' | '\x04\x00\x00\x00fred'
'RESidentify' | '#' | '\x00\x00\x00\x00\x00\x00\x00\x00'
'CMDinfo' | '#' | '\x00\x00\x00\x00'
'RESinfo' | '#' | '\x00\x00\x00\x00\x04\x00\x00\x00info'
'CMDstats' | '#' | '\x00\x00\x00\x00'
'RESstats' | '#' | '\x00\x00\x00\x00\x05\x00\x00\x00stats'
'CMDauthentify' | '#' | '\t\x00\x00\x00myPasswd!'
'RESauthentify' | '#' | '\x00\x00\x00\x00\x00\x00\x00\x00'
'CMDencrypt' | '#' | '\n\x00\x00\x00123456test'
'RESencrypt' | '#' | "\x00\x00\x00\x00\n\x00\x00\x00spqvwt6'16"
'CMDdecrypt' | '#' | "\n\x00\x00\x00spqvwt6'16"
'RESdecrypt' | '#' | '\x00\x00\x00\x00\n\x00\x00\x00123456test'
'CMDbye' | '#' | '\x00\x00\x00\x00'
'RESbye' | '#' | '\x00\x00\x00\x00\x00\x00\x00\x00'
--------------- | ------------ | ------------------------------------------
Symbol
|-- Field-0
|-- Alt
|-- Data (Raw(b'CMDidentify'))
|-- Data (Raw(b'RESidentify'))
|-- Data (Raw(b'CMDinfo'))
|-- Data (Raw(b'RESinfo'))
|-- Data (Raw(b'CMDstats'))
|-- Data (Raw(b'RESstats'))
|-- Data (Raw(b'CMDauthentify'))
|-- Data (Raw(b'RESauthentify'))
|-- Data (Raw(b'CMDencrypt'))
|-- Data (Raw(b'RESencrypt'))
|-- Data (Raw(b'CMDdecrypt'))
|-- Data (Raw(b'RESdecrypt'))
|-- Data (Raw(b'CMDbye'))
|-- Data (Raw(b'RESbye'))
|-- Field-sep-23
|-- Opt
|-- Data (String('#'))
|-- Field-2
|-- Alt
|-- Data (Raw(b'\x07\x00\x00\x00Roberto'))
|-- Data (Raw(b'\x00\x00\x00\x00\x00\x00\x00\x00'))
|-- Data (Raw(b'\x00\x00\x00\x00'))
|-- Data (Raw(b'\x00\x00\x00\x00\x04\x00\x00\x00info'))
|-- Data (Raw(b'\x00\x00\x00\x00\x05\x00\x00\x00stats'))
|-- Data (Raw(b'\n\x00\x00\x00aStrongPwd'))
|-- Data (Raw(b'\x06\x00\x00\x00abcdef'))
|-- Data (Raw(b"\x00\x00\x00\x00\x06\x00\x00\x00$ !&'$"))
|-- Data (Raw(b"\x06\x00\x00\x00$ !&'$"))
|-- Data (Raw(b'\x00\x00\x00\x00\x06\x00\x00\x00abcdef'))
|-- Data (Raw(b'\x04\x00\x00\x00fred'))
|-- Data (Raw(b'\t\x00\x00\x00myPasswd!'))
|-- Data (Raw(b'\n\x00\x00\x00123456test'))
|-- Data (Raw(b"\x00\x00\x00\x00\n\x00\x00\x00spqvwt6'16"))
|-- Data (Raw(b"\n\x00\x00\x00spqvwt6'16"))
|-- Data (Raw(b'\x00\x00\x00\x00\n\x00\x00\x00123456test'))
三、根据键字段进行聚类
当发现类似于“CMDidentify”这种东西并不唯一时,便可以尝试利用其进行聚类,如下为官方文档的描述:
The first field seems interesting, as it contains some kind of commands (‘CMDencrypt’, ‘CMDidentify’, etc.). Let’s thus cluster the symbol according to the first field:
相关代码如下所示,clusterByKeyField也是Format中的函数,可以选择fields进行聚类
symbols = Format.clusterByKeyField(symbol, symbol.fields[0])
print("[+] Number of symbols after clustering: {0}".format(len(symbols)))
print("[+] Symbol list:")
for keyFieldName, s in symbols.items():
print(" * {0}".format(keyFieldName))
其输出如下,由此可以发现,symbols中的内容通过聚类分成了14个簇,每个簇中都有一个类似于指令的uid(eg: CMDidentify)
[+] Number of symbols after clustering: 14
[+] Symbol list:
* b'CMDidentify'
* b'RESidentify'
* b'CMDinfo'
* b'RESinfo'
* b'CMDstats'
* b'RESstats'
* b'CMDauthentify'
* b'RESauthentify'
* b'CMDencrypt'
* b'RESencrypt'
* b'CMDdecrypt'
* b'RESdecrypt'
* b'CMDbye'
* b'RESbye'
四、序列对齐
我们发现以上消息的第三个字段具有动态的长度,由此,我们可以依据其进行对齐,从而获知哪些部分是定长字段,哪些地方可以变长。
然后我们同样可以使用Format中的splitAligned函数,使用第三个字段进行对齐,
for keyFieldName, s in symbols.items():
print(" * {0}".format(keyFieldName))
for symbol in symbols.values():
Format.splitAligned(symbol.fields[2], doInternalSlick=True)
print('[+] Partitionned messages:')
print(symbol.str_data())
输出如下所示
* b'CMDidentify'
* b'RESidentify'
* b'CMDinfo'
* b'RESinfo'
* b'CMDstats'
* b'RESstats'
* b'CMDauthentify'
* b'RESauthentify'
* b'CMDencrypt'
* b'RESencrypt'
* b'CMDdecrypt'
* b'RESdecrypt'
* b'CMDbye'
* b'RESbye'
[+] Partitionned messages:
Field-0 | Field-sep-23 | Field00 | Field01 | Field02
------------- | ------------ | ------- | -------------- | ---------
'CMDidentify' | '#' | '\x07' | '\x00\x00\x00' | 'Roberto'
'CMDidentify' | '#' | '\x04' | '\x00\x00\x00' | 'fred'
------------- | ------------ | ------- | -------------- | ---------
[+] Partitionned messages:
Field-0 | Field-sep-23 | Field00
------------- | ------------ | ----------------------------------
'RESidentify' | '#' | '\x00\x00\x00\x00\x00\x00\x00\x00'
'RESidentify' | '#' | '\x00\x00\x00\x00\x00\x00\x00\x00'
------------- | ------------ | ----------------------------------
[+] Partitionned messages:
Field-0 | Field-sep-23 | Field00
--------- | ------------ | ------------------
'CMDinfo' | '#' | '\x00\x00\x00\x00'
'CMDinfo' | '#' | '\x00\x00\x00\x00'
--------- | ------------ | ------------------
[+] Partitionned messages:
Field-0 | Field-sep-23 | Field00
--------- | ------------ | --------------------------------------
'RESinfo' | '#' | '\x00\x00\x00\x00\x04\x00\x00\x00info'
'RESinfo' | '#' | '\x00\x00\x00\x00\x04\x00\x00\x00info'
--------- | ------------ | --------------------------------------
[+] Partitionned messages:
Field-0 | Field-sep-23 | Field00
---------- | ------------ | ------------------
'CMDstats' | '#' | '\x00\x00\x00\x00'
'CMDstats' | '#' | '\x00\x00\x00\x00'
---------- | ------------ | ------------------
[+] Partitionned messages:
Field-0 | Field-sep-23 | Field00
---------- | ------------ | ---------------------------------------
'RESstats' | '#' | '\x00\x00\x00\x00\x05\x00\x00\x00stats'
'RESstats' | '#' | '\x00\x00\x00\x00\x05\x00\x00\x00stats'
---------- | ------------ | ---------------------------------------
[+] Partitionned messages:
Field-0 | Field-sep-23 | Field00 | Field01 | Field02 | Field03 | Field04
--------------- | ------------ | ------- | -------------- | ---------- | ------- | -------
'CMDauthentify' | '#' | '\n' | '\x00\x00\x00' | 'aStrongP' | 'wd' | ''
'CMDauthentify' | '#' | '\t' | '\x00\x00\x00' | 'myPass' | 'wd' | '!'
--------------- | ------------ | ------- | -------------- | ---------- | ------- | -------
[+] Partitionned messages:
Field-0 | Field-sep-23 | Field00
--------------- | ------------ | ----------------------------------
'RESauthentify' | '#' | '\x00\x00\x00\x00\x00\x00\x00\x00'
'RESauthentify' | '#' | '\x00\x00\x00\x00\x00\x00\x00\x00'
--------------- | ------------ | ----------------------------------
[+] Partitionned messages:
Field-0 | Field-sep-23 | Field00 | Field01 | Field02
------------ | ------------ | ------- | -------------- | ------------
'CMDencrypt' | '#' | '\x06' | '\x00\x00\x00' | 'abcdef'
'CMDencrypt' | '#' | '\n' | '\x00\x00\x00' | '123456test'
------------ | ------------ | ------- | -------------- | ------------
[+] Partitionned messages:
Field-0 | Field-sep-23 | Field00 | Field01 | Field02 | Field03
------------ | ------------ | ------------------ | ------- | -------------- | ------------
'RESencrypt' | '#' | '\x00\x00\x00\x00' | '\x06' | '\x00\x00\x00' | "$ !&'$"
'RESencrypt' | '#' | '\x00\x00\x00\x00' | '\n' | '\x00\x00\x00' | "spqvwt6'16"
------------ | ------------ | ------------------ | ------- | -------------- | ------------
[+] Partitionned messages:
Field-0 | Field-sep-23 | Field00 | Field01 | Field02
------------ | ------------ | ------- | -------------- | ------------
'CMDdecrypt' | '#' | '\x06' | '\x00\x00\x00' | "$ !&'$"
'CMDdecrypt' | '#' | '\n' | '\x00\x00\x00' | "spqvwt6'16"
------------ | ------------ | ------- | -------------- | ------------
[+] Partitionned messages:
Field-0 | Field-sep-23 | Field00 | Field01 | Field02 | Field03
------------ | ------------ | ------------------ | ------- | -------------- | ------------
'RESdecrypt' | '#' | '\x00\x00\x00\x00' | '\x06' | '\x00\x00\x00' | 'abcdef'
'RESdecrypt' | '#' | '\x00\x00\x00\x00' | '\n' | '\x00\x00\x00' | '123456test'
------------ | ------------ | ------------------ | ------- | -------------- | ------------
[+] Partitionned messages:
Field-0 | Field-sep-23 | Field00
-------- | ------------ | ------------------
'CMDbye' | '#' | '\x00\x00\x00\x00'
'CMDbye' | '#' | '\x00\x00\x00\x00'
-------- | ------------ | ------------------
[+] Partitionned messages:
Field-0 | Field-sep-23 | Field00
-------- | ------------ | ----------------------------------
'RESbye' | '#' | '\x00\x00\x00\x00\x00\x00\x00\x00'
'RESbye' | '#' | '\x00\x00\x00\x00\x00\x00\x00\x00'
-------- | ------------ | ----------------------------------
由此我们可见,例如对于符号“CMDencrypt”,最后一个字段的序列对齐产生的格式中可以观察到被两个变量字段包围的“x00x00x00”静态字段。
------------ | ------------ | ------- | -------------- | ------------
'CMDdecrypt' | '#' | '\x06' | '\x00\x00\x00' | "$ !&'$"
'CMDdecrypt' | '#' | '\n' | '\x00\x00\x00' | "spqvwt6'16"
------------ | ------------ | ------- | -------------- | ------------
五、查找每个Symbol中的字段关系
对于每个消息之间的关系。Netzob的API提供了能够确定潜在关系的函数findOnSymbol(),示例代码如下:
for symbol in symbols.values():
rels = RelationFinder.findOnSymbol(symbol)
print("[+] Relations found: ")
for rel in rels:
print(" " + rel["relation_type"] + ", between '" + rel["x_attribute"] + "' of:")
print(" " + str('-'.join([f.name for f in rel["x_fields"]])))
p = [v.getValues()[:] for v in rel["x_fields"]]
print(" " + str(p))
print(" " + "and '" + rel["y_attribute"] + "' of:")
print(" " + str('-'.join([f.name for f in rel["y_fields"]])))
p = [v.getValues()[:] for v in rel["y_fields"]]
print(" " + str(p))
输出如下所示:
[+] Relations found:
SizeRelation, between 'value' of:
Field00
[[b'\x07', b'\x04']]
and 'size' of:
Field02
[[b'Roberto', b'fred']]
[+] Relations found:
[+] Relations found:
[+] Relations found:
[+] Relations found:
[+] Relations found:
[+] Relations found:
SizeRelation, between 'value' of:
Field00
[[b'\n', b'\t']]
and 'size' of:
Field02-Field03-Field04
[[b'aStrongP', b'myPass'], [b'wd', b'wd'], [b'', b'!']]
[+] Relations found:
[+] Relations found:
SizeRelation, between 'value' of:
Field00
[[b'\x06', b'\n']]
and 'size' of:
Field02
[[b'abcdef', b'123456test']]
[+] Relations found:
SizeRelation, between 'value' of:
Field01
[[b'\x06', b'\n']]
and 'size' of:
Field03
[[b"$ !&'$", b"spqvwt6'16"]]
[+] Relations found:
SizeRelation, between 'value' of:
Field00
[[b'\x06', b'\n']]
and 'size' of:
Field02
[[b"$ !&'$", b"spqvwt6'16"]]
[+] Relations found:
SizeRelation, between 'value' of:
Field01
[[b'\x06', b'\n']]
and 'size' of:
Field03
[[b'abcdef', b'123456test']]
[+] Relations found:
[+] Relations found:
rels的内容为:
[+] Relations found:
{'id': '9b3a72cb-7f81-4445-9e6c-8132a6a07791', 'relation_type': 'SizeRelation', 'x_fields': [Field00], 'x_attribute': 'value', 'y_fields': [Field02], 'y_attribute': 'size'}
[+] Relations found:
[+] Relations found:
[+] Relations found:
[+] Relations found:
[+] Relations found:
[+] Relations found:
{'id': '430d8f40-5678-4781-8ae9-ad3c598d207e', 'relation_type': 'SizeRelation', 'x_fields': [Field00], 'x_attribute': 'value', 'y_fields': [Field02, Field03, Field04], 'y_attribute': 'size'}
[+] Relations found:
[+] Relations found:
{'id': '7dfe658d-3d65-4e63-9c3a-5bb7e1563392', 'relation_type': 'SizeRelation', 'x_fields': [Field00], 'x_attribute': 'value', 'y_fields': [Field02], 'y_attribute': 'size'}
[+] Relations found:
{'id': '5fab790e-a389-4344-a2d2-3c7ae2726fb6', 'relation_type': 'SizeRelation', 'x_fields': [Field01], 'x_attribute': 'value', 'y_fields': [Field03], 'y_attribute': 'size'}
[+] Relations found:
{'id': '2bca9215-bb05-44c5-95ed-5bc70620e4b7', 'relation_type': 'SizeRelation', 'x_fields': [Field00], 'x_attribute': 'value', 'y_fields': [Field02], 'y_attribute': 'size'}
[+] Relations found:
{'id': '15d9ad29-6915-4860-93c2-6a12b359a67b', 'relation_type': 'SizeRelation', 'x_fields': [Field01], 'x_attribute': 'value', 'y_fields': [Field03], 'y_attribute': 'size'}
[+] Relations found:
[+] Relations found:
如下是我对以上代码的解释:
# 这是倒数第四个循环中的ref,也就是CMDencrypt
{'id': '2bca9215-bb05-44c5-95ed-5bc70620e4b7', 'relation_type': 'SizeRelation', 'x_fields': [Field00], 'x_attribute': 'value', 'y_fields': [Field02], 'y_attribute': 'size'}
[+] Relations found:
SizeRelation, between 'value' of:
Field00
[[b'\x06', b'\n']]
and 'size' of:
Field02
[[b"$ !&'$", b"spqvwt6'16"]]
在第一个symbol经过findOnSymbol后生成的ref中
'relation_type': 'SizeRelation',意思是第一个symbol中的发现的可能的关系类型是大小关系
'x_fields': [Field00], 'x_attribute': 'value', 'y_fields': [Field02], 'y_attribute': 'size',意思是Field00位置的x变量和Field02位置的y变量存在value和size的关系。
而第一个symbol中,经过序列对齐后,Field00中就是b'\x06', b'\n',Field02中就是"$ !&'$",
"spqvwt6'16" 。如下所示,这个例子中所谓的6和\n(\n的acii码为10)就是Field02的长度。官网文档的解释是1/8,因为每个字符换算成位是8位,也就是1字节。
[+] Partitionned messages:
Field-0 | Field-sep-23 | Field00 | Field01 | Field02
------------ | ------------ | ------- | -------------- | ------------
'CMDdecrypt' | '#' | '\x06' | '\x00\x00\x00' | "$ !&'$"
'CMDdecrypt' | '#' | '\n' | '\x00\x00\x00' | "spqvwt6'16"
------------ | ------------ | ------- | -------------- | ------------
六、应用找到的关系
官方文档提示我们可以通过创建一个 Size 字段,用来修改格式消息以应用我们刚刚找到的关系,该字段的值取决于目标字段的内容。我们还指定了一个因子,基本上是说size字段的值应该是缓冲区字段大小的八分之一(因为默认情况下每个字段大小都以位表示):
for symbol in symbols.values():
rels = RelationFinder.findOnSymbol(symbol)
print(symbol.str_structure())
print("after")
for rel in rels:
# Apply first found relationship
rel = rels[0]
rel["x_fields"][0].domain = Size(rel["y_fields"], factor=1 / 8.0)
print("[+] Symbol structure:")
print(symbol.str_structure())
输出结果如下所示(仅展示部分)
...
Symbol_CMDdecrypt
|-- Field-0
|-- Data (Raw(b'CMDdecrypt'))
|-- Field-sep-23
|-- Data (Raw(b'#'))
|-- Field-2
|-- |-- Field00
|-- Data (Raw(nbBytes=(0,1)))
|-- |-- Field01
|-- Data (Raw(b'\x00\x00\x00'))
|-- |-- Field02
|-- Data (Raw(nbBytes=(0,10)))
after
[+] Symbol structure:
Symbol_CMDdecrypt
|-- Field-0
|-- Data (Raw(b'CMDdecrypt'))
|-- Field-sep-23
|-- Data (Raw(b'#'))
|-- Field-2
|-- |-- Field00
|-- Size(['Field02']) - Type:Integer(0,255)
|-- |-- Field01
|-- Data (Raw(b'\x00\x00\x00'))
|-- |-- Field02
|-- Data (Raw(nbBytes=(0,10)))
Symbol_RESdecrypt
|-- Field-0
|-- Data (Raw(b'RESdecrypt'))
|-- Field-sep-23
|-- Data (Raw(b'#'))
|-- Field-2
|-- |-- Field00
|-- Data (Raw(b'\x00\x00\x00\x00'))
|-- |-- Field01
|-- Data (Raw(nbBytes=(0,1)))
|-- |-- Field02
|-- Data (Raw(b'\x00\x00\x00'))
|-- |-- Field03
|-- Data (Raw(nbBytes=(0,10)))
after
[+] Symbol structure:
Symbol_RESdecrypt
|-- Field-0
|-- Data (Raw(b'RESdecrypt'))
|-- Field-sep-23
|-- Data (Raw(b'#'))
|-- Field-2
|-- |-- Field00
|-- Data (Raw(b'\x00\x00\x00\x00'))
|-- |-- Field01
|-- Size(['Field03']) - Type:Integer(0,255)
|-- |-- Field02
|-- Data (Raw(b'\x00\x00\x00'))
|-- |-- Field03
|-- Data (Raw(nbBytes=(0,10)))
...
对于Symbol_CMDdecrypt,前后的变化仅为Field-2中的Field00,如图所示:

我的理解就是它将Field-2中Field00的原来的数字,改变成了Field02中的长度,而Field01中的内容,在序列对齐中,认为它是定长的,故无需改变。
由此,我们便在CMDdecrypt这一信息中,发现了Field00中存储的是Field02中值的长度,并应用了这一关系。其余的message,也可以通过这种方法一一找到其特殊关系