Skip to content

Commit 9c1ed94

Browse files
authored
Merge branch 'Pennyw0rth:main' into main
2 parents 88e9509 + e721917 commit 9c1ed94

6 files changed

Lines changed: 539 additions & 32 deletions

File tree

nxc/helpers/even6_parser.py

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
# SPDX-License-Identifier: GPL-2.0+
2+
3+
import struct
4+
import uuid
5+
6+
from datetime import datetime
7+
8+
class Substitution:
9+
def __init__(self, buf, offset):
10+
(sub_token, sub_id, sub_type) = struct.unpack_from("<BHB", buf, offset)
11+
self.length = 4
12+
13+
self._id = sub_id
14+
self._type = sub_type
15+
self._optional = sub_token == 0x0e
16+
17+
def xml(self, template=None):
18+
value = template.values[self._id]
19+
if value.type == 0x0:
20+
return None if self._optional else ""
21+
if self._type == 0x1:
22+
return value.data.decode("utf16")
23+
elif self._type == 0x4:
24+
return str(struct.unpack("<B", value.data)[0])
25+
elif self._type == 0x6:
26+
return str(struct.unpack("<H", value.data)[0])
27+
elif self._type == 0x8:
28+
return str(struct.unpack("<I", value.data)[0])
29+
elif self._type == 0xa:
30+
return str(struct.unpack("<Q", value.data)[0])
31+
elif self._type == 0x11:
32+
# see http://integriography.wordpress.com/2010/01/16/using-phython-to-parse-and-present-windows-64-bit-timestamps/
33+
return datetime.utcfromtimestamp(struct.unpack("<Q", value.data)[0] / 1e7 - 11644473600).isoformat()
34+
elif self._type == 0x13:
35+
# see http://www.gossamer-threads.com/lists/apache/bugs/386930
36+
revision, number_of_sub_ids = struct.unpack_from("<BB", value.data)
37+
iav = struct.unpack_from(">Q", value.data, 2)[0]
38+
sub_ids = [struct.unpack("<I", value.data[8 + 4 * i:12 + 4 * i])[0] for i in range(number_of_sub_ids)]
39+
return "S-{}-{}-{}".format(revision, iav, "-".join([str(sub_id) for sub_id in sub_ids]))
40+
elif self._type == 0x15 or self._type == 0x10:
41+
return value.data.hex()
42+
elif self._type == 0x21:
43+
return value.template.xml()
44+
elif self._type == 0xf:
45+
return str(uuid.UUID(bytes_le=value.data))
46+
else:
47+
print("Unknown value type", hex(value.type))
48+
49+
class Value:
50+
def __init__(self, buf, offset):
51+
token, string_type, length = struct.unpack_from("<BBH", buf, offset)
52+
self._val = buf[offset + 4:offset + 4 + length * 2].decode("utf16")
53+
54+
self.length = 4 + length * 2
55+
56+
def xml(self, template=None):
57+
return self._val
58+
59+
class Attribute:
60+
def __init__(self, buf, offset):
61+
struct.unpack_from("<B", buf, offset)
62+
self._name = Name(buf, offset + 1)
63+
64+
(next_token) = struct.unpack_from("<B", buf, offset + 1 + self._name.length)
65+
if next_token[0] == 0x05 or next_token == 0x45:
66+
self._value = Value(buf, offset + 1 + self._name.length)
67+
elif next_token[0] == 0x0e:
68+
self._value = Substitution(buf, offset + 1 + self._name.length)
69+
else:
70+
print("Unknown attribute next_token", hex(next_token[0]), hex(offset + 1 + self._name.length))
71+
72+
self.length = 1 + self._name.length + self._value.length
73+
74+
def xml(self, template=None):
75+
val = self._value.xml(template)
76+
return None if val is None else f'{self._name.val}="{val}"'
77+
78+
class Name:
79+
def __init__(self, buf, offset):
80+
hashs, length = struct.unpack_from("<HH", buf, offset)
81+
82+
self.val = buf[offset + 4:offset + 4 + length * 2].decode("utf16")
83+
self.length = 4 + (length + 1) * 2
84+
85+
class Element:
86+
def __init__(self, buf, offset):
87+
token, dependency_id, length = struct.unpack_from("<BHI", buf, offset)
88+
89+
self._name = Name(buf, offset + 7)
90+
self._dependency = dependency_id
91+
92+
ofs = offset + 7 + self._name.length
93+
if token == 0x41:
94+
struct.unpack_from("<I", buf, ofs)
95+
ofs += 4
96+
97+
self._children = []
98+
self._attributes = []
99+
100+
while True:
101+
next_token = buf[ofs]
102+
if next_token == 0x06 or next_token == 0x46:
103+
attr = Attribute(buf, ofs)
104+
self._attributes.append(attr)
105+
ofs += attr.length
106+
elif next_token == 0x02:
107+
self._empty = False
108+
ofs += 1
109+
while True:
110+
next_token = buf[ofs]
111+
if next_token == 0x01 or next_token == 0x41:
112+
element = Element(buf, ofs)
113+
elif next_token == 0x04:
114+
ofs += 1
115+
break
116+
elif next_token == 0x05:
117+
element = Value(buf, ofs)
118+
elif next_token == 0x0e or next_token == 0x0d:
119+
element = Substitution(buf, ofs)
120+
else:
121+
print("Unknown intern next_token", hex(next_token), hex(ofs))
122+
break
123+
124+
self._children.append(element)
125+
ofs += element.length
126+
127+
break
128+
elif next_token == 0x03:
129+
self._empty = True
130+
ofs += 1
131+
break
132+
else:
133+
print("Unknown element next_token", hex(next_token), hex(ofs))
134+
break
135+
136+
self.length = ofs - offset
137+
138+
def xml(self, template=None):
139+
if self._dependency != 0xFFFF and template.values[self._dependency].type == 0x00:
140+
return ""
141+
142+
attrs = filter(lambda x: x is not None, (x.xml(template) for x in self._attributes))
143+
144+
attrs = " ".join(attrs)
145+
if len(attrs) > 0:
146+
attrs = " " + attrs
147+
148+
if self._empty:
149+
return f"<{self._name.val}{attrs}/>"
150+
else:
151+
children = (x.xml(template) for x in self._children)
152+
return "<{}{}>{}</{}>".format(self._name.val, attrs, "".join(children), self._name.val)
153+
154+
class ValueSpec:
155+
def __init__(self, buf, offset, value_offset):
156+
self.length, self.type, value_eof = struct.unpack_from("<HBB", buf, offset)
157+
self.data = buf[value_offset:value_offset + self.length]
158+
159+
if self.type == 0x21:
160+
self.template = BinXML(buf, value_offset)
161+
162+
class TemplateInstance:
163+
def __init__(self, buf, offset):
164+
token, unknown0, guid, length, next_token = struct.unpack_from("<BB16sIB", buf, offset)
165+
if next_token == 0x0F:
166+
self._xml = BinXML(buf, offset + 0x16)
167+
eof, num_values = struct.unpack_from("<BI", buf, offset + 22 + self._xml.length)
168+
values_length = 0
169+
self.values = []
170+
for x in range(num_values):
171+
value = ValueSpec(buf, offset + 22 + self._xml.length + 5 + x * 4, offset + 22 + self._xml.length + 5 + num_values * 4 + values_length)
172+
self.values.append(value)
173+
values_length += value.length
174+
175+
self.length = 22 + self._xml.length + 5 + num_values * 4 + values_length
176+
else:
177+
print("Unknown template token", hex(next_token))
178+
179+
def xml(self, template=None):
180+
return self._xml.xml(self)
181+
182+
class BinXML:
183+
def __init__(self, buf, offset):
184+
header_token, major_version, minor_version, flags, next_token = struct.unpack_from("<BBBBB", buf, offset)
185+
186+
if next_token == 0x0C:
187+
self._element = TemplateInstance(buf, offset + 4)
188+
elif next_token == 0x01 or next_token == 0x41:
189+
self._element = Element(buf, offset + 4)
190+
else:
191+
print("Unknown binxml token", hex(next_token))
192+
193+
self.length = 4 + self._element.length
194+
195+
def xml(self, template=None):
196+
return self._element.xml(template)
197+
198+
class ResultSet:
199+
def __init__(self, buf):
200+
total_size, header_size, event_offset, bookmark_offset, binxml_size = struct.unpack_from("<IIIII", buf)
201+
self._xml = BinXML(buf, 0x14)
202+
203+
def xml(self):
204+
return self._xml.xml()

0 commit comments

Comments
 (0)