1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
local p = Proto("pictochat", "PictoChat")
p.fields.unknown = ProtoField.uint16("pictochat.unknown", "Unknown")
p.fields.msg_type = ProtoField.uint8("pictochat.msg_type", "Message type", base.DEC, {
[0] = "???",
[1] = "???",
[10] = "Message start", -- sent before a message packet
[24] = "Message end", -- sent after multi-frame message body packets
[48] = "User join", -- these packets contain a username
[52] = "Keepalive", -- constantly spammed (keep alive?)
[86] = "Message body", -- contains tile data for drawing
[184] = "???", -- user leave??
})
p.fields.length = ProtoField.uint16("pictochat.length", "Length")
p.fields.host = ProtoField.ether("pictochat.host", "Room host")
p.fields.src = ProtoField.ether("pictochat.src", "Source")
p.fields.dst = ProtoField.ether("pictochat.dst", "Destination")
p.fields.payload_len = ProtoField.uint16("pictochat.payload_len", "Payload length")
p.fields.data_len = ProtoField.uint8("pictochat.data_len", "Data length")
p.fields.data_end = ProtoField.bool("pictochat.data_end", "Data end")
p.fields.data_offset = ProtoField.uint16("pictochat.data_offset", "Data offset")
p.fields.data_sequence = ProtoField.uint16("pictochat.data_sequence", "Data sequence")
p.fields.data = ProtoField.bytes("pictochat.data", "Data")
p.fields.sequence = ProtoField.uint16("pictochat.sequence", "Packet sequence")
p.fields.magic_trailer = ProtoField.bytes("pictochat.magic_trailer", "Magic (trailer)")
p.fields.user_mac = ProtoField.ether("pictochat.user.mac", "Address")
p.fields.user_name = ProtoField.string("pictochat.user.name", "Nickname")
p.fields.user_msg = ProtoField.string("pictochat.user.msg", "Message")
p.fields.user_color = ProtoField.uint16("pictochat.user.color", "Color", base.DEC, {
[0] = "Greyish blue",
[1] = "Brown",
[2] = "Red",
[3] = "Light pink",
[4] = "Orange",
[5] = "Yellow",
[6] = "Lime",
[7] = "Light green",
[8] = "Dark green",
[9] = "Turqoise",
[10] = "Light blue",
[11] = "Blue",
[12] = "Dark blue",
[13] = "Dark purple",
[14] = "Light purple",
[15] = "Dark pink",
})
p.fields.user_bday_month = ProtoField.uint8("pictochat.user.bday_month", "Month")
p.fields.user_bday_day = ProtoField.uint8("pictochat.user.bday_day", "Day")
p.fields.msg_start_len = ProtoField.uint8("pictochat.msg.start_len", "Total length")
local pc_src_field = Field.new("pictochat.src")
local pc_dst_field = Field.new("pictochat.dst")
local data_remaining = 0
local state = {}
function p.init()
-- register pictochat as a subdissector for nifi
local dt = DissectorTable.get("nifi")
dt:add(0xfffd, p) -- CMD messages
-- dt:add(0x7dcb, p) -- ACK messages
end
function p.dissector(buffer, pinfo, tree)
local subtree = tree:add(p, buffer(), string.format("%s: %d bytes", p.description, buffer():len()))
subtree:add_le(p.fields.unknown, buffer(0x00, 2))
subtree:add_le(p.fields.unknown, buffer(0x02, 2))
subtree:add_le(p.fields.dst, buffer(0x04, 6))
subtree:add_le(p.fields.src, buffer(0x0a, 6))
subtree:add_le(p.fields.host, buffer(0x10, 6))
subtree:add_le(p.fields.sequence, buffer(0x16, 2))
subtree:add_le(p.fields.unknown, buffer(0x18, 2))
subtree:add_le(p.fields.unknown, buffer(0x1a, 2))
subtree:add_le(p.fields.msg_type, buffer(0x1c, 1))
local msg_type = buffer(0x1c, 1):le_uint()
subtree:add_le(p.fields.unknown, buffer(0x1d, 1))
subtree:add_le(p.fields.unknown, buffer(0x1e, 2))
buffer = buffer(0x20)
-- pretty wireshark shit
pinfo.cols.protocol = p.name
pinfo.cols.src = tostring(pc_src_field())
pinfo.cols.dst = tostring(pc_dst_field())
subtree:add_le(p.fields.payload_len, buffer(0x00, 2))
local payload_length = buffer(0x00, 2):le_uint()
buffer = buffer(0x02)
local payload = subtree:add(buffer(0x00, payload_length), "Payload: " .. payload_length .. " bytes")
local buffer_next = buffer(payload_length)
if
msg_type == 48 -- user join
then
payload:add_le(p.fields.user_mac, buffer(0x0a, 6)) -- endianness is fucked
payload:add(p.fields.user_name, buffer(0x10, 20), buffer(0x10, 20):le_ustring())
payload:add(p.fields.user_msg, buffer(0x24, 52), buffer(0x24, 52):le_ustring())
payload:add_le(p.fields.user_color, buffer(0x58, 2))
local bday = payload:add(buffer(0x5a, 2), string.format("Birthday: %02d/%02d", buffer(0x5a, 1):uint(), buffer(0x5b, 1):uint()))
bday:add(p.fields.user_bday_month, buffer(0x5a, 1))
bday:add(p.fields.user_bday_day, buffer(0x5b, 1))
end
if
msg_type == 10 -- msg start
then
payload:add_le(p.fields.msg_start_len, buffer(0x04, 2))
data_remaining = buffer(0x04, 2):le_uint()
local segment = buffer(0):bytes()
local buf = ByteArray.tvb(segment, "Complete message???")
end
if
msg_type == 24 or -- msg end
msg_type == 86 -- msg body
then
payload:add_le(p.fields.unknown, buffer(0x00, 2))
payload:add_le(p.fields.data_len, buffer(0x02, 1))
local data_length = buffer(0x02, 1):le_uint()
if data_remaining > 0 then
data_remaining = data_remaining - data_length
pinfo.cols.info = string.format("Message body [remaining 0x%04x (%d) bytes]", data_remaining, data_remaining)
end
payload:add_le(p.fields.data_end, buffer(0x03, 1))
-- This appears to be some kind of offset for indicating where to store the
-- current frame's data in a larger buffer. Messages sent in multiple parts
-- increment this value by 160 for each new original (p.fields.original ==
-- True) message.
payload:add_le(p.fields.data_offset, buffer(0x04, 2))
payload:add_le(p.fields.unknown, buffer(0x06, 2)) -- usually 0
buffer = buffer(0x08)
-- This appears to be the actual message data (the drawing) sent as an
-- array of 8x8 tiles.
payload:add(p.fields.data, buffer(0, data_length))
buffer = buffer(data_length)
payload:add_le(p.fields.data_sequence, buffer(0x00, 2))
payload:add_le(p.fields.unknown, buffer(0x02, 2)) -- copy
subtree:add_le(p.fields.unknown, buffer(0x04, 2))
buffer = buffer(0x06)
end
buffer = buffer_next -- after payload
subtree:add_le(p.fields.magic_trailer, buffer(0x02, 2)) -- const 0xb8b6
end
|