Package Evtx :: Module Nodes
[hide private]
[frames] | no frames]

Source Code for Module Evtx.Nodes

   1  #!/usr/bin/python 
   2  #    This file is part of python-evtx. 
   3  # 
   4  #   Copyright 2012, 2013 Willi Ballenthin william.ballenthin@mandiant.com> 
   5  #                    while at Mandiant <http://www.mandiant.com> 
   6  # 
   7  #   Licensed under the Apache License, Version 2.0 (the "License"); 
   8  #   you may not use this file except in compliance with the License. 
   9  #   You may obtain a copy of the License at 
  10  # 
  11  #       http://www.apache.org/licenses/LICENSE-2.0 
  12  # 
  13  #   Unless required by applicable law or agreed to in writing, software 
  14  #   distributed under the License is distributed on an "AS IS" BASIS, 
  15  #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  16  #   See the License for the specific language governing permissions and 
  17  #   limitations under the License. 
  18  # 
  19  #   Version v0.3.0 
  20  import re 
  21  import itertools 
  22  import base64 
  23   
  24  from BinaryParser import Block 
  25  from BinaryParser import hex_dump 
  26  from BinaryParser import ParseException 
  27  from BinaryParser import memoize 
28 29 30 -class SYSTEM_TOKENS:
31 EndOfStreamToken = 0x00 32 OpenStartElementToken = 0x01 33 CloseStartElementToken = 0x02 34 CloseEmptyElementToken = 0x03 35 CloseElementToken = 0x04 36 ValueToken = 0x05 37 AttributeToken = 0x06 38 CDataSectionToken = 0x07 39 EntityReferenceToken = 0x08 40 ProcessingInstructionTargetToken = 0x0A 41 ProcessingInstructionDataToken = 0x0B 42 TemplateInstanceToken = 0x0C 43 NormalSubstitutionToken = 0x0D 44 ConditionalSubstitutionToken = 0x0E 45 StartOfStreamToken = 0x0F
46 47 48 node_dispatch_table = [] # updated at end of file 49 node_readable_tokens = [] # updated at end of file
50 51 52 -class SuppressConditionalSubstitution(Exception):
53 """ 54 This exception is to be thrown to indicate that a conditional 55 substitution evaluated to NULL, and the parent element should 56 be suppressed. This exception should be caught at the first 57 opportunity, and must not propagate far up the call chain. 58 59 Strategy: 60 AttributeNode catches this, .xml() --> "" 61 StartOpenElementNode catches this for each child, ensures 62 there's at least one useful value. Or, .xml() --> "" 63 """
64 - def __init__(self, msg):
66
67 68 -class BXmlNode(Block):
69
70 - def __init__(self, buf, offset, chunk, parent):
71 super(BXmlNode, self).__init__(buf, offset) 72 self._chunk = chunk 73 self._parent = parent
74
75 - def __repr__(self):
76 return "BXmlNode(buf=%r, offset=%r, chunk=%r, parent=%r)" % \ 77 (self._buf, self.offset(), self._chunk, self._parent)
78
79 - def __str__(self):
80 return "BXmlNode(offset=%s)" % (hex(self.offset()))
81
82 - def dump(self):
83 return hex_dump(self._buf[self.offset():self.offset() + self.length()], 84 start_addr=self.offset())
85
86 - def tag_length(self):
87 """ 88 This method must be implemented and overridden for all BXmlNodes. 89 @return An integer specifying the length of this tag, not including 90 its children. 91 """ 92 raise NotImplementedError("tag_length not implemented for %r") % \ 93 (self)
94
95 - def _children(self, max_children=None, 96 end_tokens=[SYSTEM_TOKENS.EndOfStreamToken]):
97 """ 98 @return A list containing all of the children BXmlNodes. 99 """ 100 ret = [] 101 ofs = self.tag_length() 102 103 if max_children: 104 gen = xrange(max_children) 105 else: 106 gen = itertools.count() 107 108 for _ in gen: 109 # we lose error checking by masking off the higher nibble, 110 # but, some tokens like 0x01, make use of the flags nibble. 111 token = self.unpack_byte(ofs) & 0x0F 112 try: 113 HandlerNodeClass = node_dispatch_table[token] 114 child = HandlerNodeClass(self._buf, self.offset() + ofs, 115 self._chunk, self) 116 except IndexError: 117 raise ParseException("Unexpected token %02X at %s" % \ 118 (token, 119 self.absolute_offset(0x0) + ofs)) 120 ret.append(child) 121 ofs += child.length() 122 if token in end_tokens: 123 break 124 if child.find_end_of_stream(): 125 break 126 return ret
127 128 @memoize
129 - def children(self):
130 return self._children()
131 132 @memoize
133 - def length(self):
134 """ 135 @return An integer specifying the length of this tag and all 136 its children. 137 """ 138 ret = self.tag_length() 139 for child in self.children(): 140 ret += child.length() 141 return ret
142 143 @memoize
144 - def find_end_of_stream(self):
145 for child in self.children(): 146 if isinstance(child, EndOfStreamNode): 147 return child 148 ret = child.find_end_of_stream() 149 if ret: 150 return ret 151 return None
152
153 154 -class NameStringNode(BXmlNode):
155 - def __init__(self, buf, offset, chunk, parent):
156 super(NameStringNode, self).__init__(buf, offset, chunk, parent) 157 self.declare_field("dword", "next_offset", 0x0) 158 self.declare_field("word", "hash") 159 self.declare_field("word", "string_length") 160 self.declare_field("wstring", "string", length=self.string_length())
161
162 - def __repr__(self):
163 return "NameStringNode(buf=%r, offset=%r, chunk=%r)" % \ 164 (self._buf, self.offset(), self._chunk)
165
166 - def __str__(self):
167 return "NameStringNode(offset=%s, length=%s, end=%s)" % \ 168 (hex(self.offset()), hex(self.length()), 169 hex(self.offset() + self.length()))
170
171 - def string(self):
172 return str(self._string())
173
174 - def tag_length(self):
175 return (self.string_length() * 2) + 8
176
177 - def length(self):
178 # two bytes unaccounted for... 179 return self.tag_length() + 2
180
181 182 -class TemplateNode(BXmlNode):
183 - def __init__(self, buf, offset, chunk, parent):
184 super(TemplateNode, self).__init__(buf, offset, chunk, parent) 185 self.declare_field("dword", "next_offset", 0x0) 186 self.declare_field("dword", "template_id") 187 self.declare_field("guid", "guid", 0x04) # unsure why this overlaps 188 self.declare_field("dword", "data_length")
189
190 - def __repr__(self):
191 return "TemplateNode(buf=%r, offset=%r, chunk=%r, parent=%r)" % \ 192 (self._buf, self.offset(), self._chunk, self._parent)
193
194 - def __str__(self):
195 return "TemplateNode(offset=%s, guid=%s, length=%s)" % \ 196 (hex(self.offset()), self.guid(), hex(self.length()))
197
198 - def tag_length(self):
199 return 0x18
200
201 - def length(self):
202 return self.tag_length() + self.data_length()
203
204 205 -class EndOfStreamNode(BXmlNode):
206 """ 207 The binary XML node for the system token 0x00. 208 209 This is the "end of stream" token. It may never actually 210 be instantiated here. 211 """
212 - def __init__(self, buf, offset, chunk, parent):
213 super(EndOfStreamNode, self).__init__(buf, offset, chunk, parent)
214
215 - def __repr__(self):
216 return "EndOfStreamNode(buf=%r, offset=%r, chunk=%r, parent=%r)" % \ 217 (self._buf, self.offset(), self._chunk, self._parent)
218
219 - def __str__(self):
220 return "EndOfStreamNode(offset=%s, length=%s, token=%s)" % \ 221 (hex(self.offset()), hex(self.length()), 0x00)
222
223 - def flags(self):
224 return self.token() >> 4
225
226 - def tag_length(self):
227 return 1
228
229 - def length(self):
230 return 1
231
232 - def children(self):
233 return []
234
235 236 -class OpenStartElementNode(BXmlNode):
237 """ 238 The binary XML node for the system token 0x01. 239 240 This is the "open start element" token. 241 """
242 - def __init__(self, buf, offset, chunk, parent):
243 super(OpenStartElementNode, self).__init__(buf, offset, chunk, parent) 244 self.declare_field("byte", "token", 0x0) 245 self.declare_field("word", "unknown0") 246 # TODO(wb): use this size() field. 247 self.declare_field("dword", "size") 248 self.declare_field("dword", "string_offset") 249 self._tag_length = 11 250 self._element_type = 0 251 252 if self.flags() & 0x04: 253 self._tag_length += 4 254 255 if self.string_offset() > self.offset() - self._chunk._offset: 256 new_string = self._chunk.add_string(self.string_offset(), 257 parent=self) 258 self._tag_length += new_string.length()
259
260 - def __repr__(self):
261 return "OpenStartElementNode(buf=%r, offset=%r, chunk=%r)" % \ 262 (self._buf, self.offset(), self._chunk)
263
264 - def __str__(self):
265 return "OpenStartElementNode(offset=%s, name=%s, length=%s, token=%s, end=%s, taglength=%s, endtag=%s)" % \ 266 (hex(self.offset()), self.tag_name(), 267 hex(self.length()), hex(self.token()), 268 hex(self.offset() + self.length()), 269 hex(self.tag_length()), 270 hex(self.offset() + self.tag_length()))
271 272 @memoize
273 - def is_empty_node(self):
274 for child in self.children(): 275 if type(child) is CloseEmptyElementNode: 276 return True 277 return False
278
279 - def flags(self):
280 return self.token() >> 4
281 282 @memoize
283 - def tag_name(self):
284 return self._chunk.strings()[self.string_offset()].string()
285
286 - def tag_length(self):
287 return self._tag_length
288
289 - def verify(self):
290 return self.flags() & 0x0b == 0 and \ 291 self.opcode() & 0x0F == 0x01
292 293 @memoize
294 - def children(self):
297
298 299 -class CloseStartElementNode(BXmlNode):
300 """ 301 The binary XML node for the system token 0x02. 302 303 This is the "close start element" token. 304 """
305 - def __init__(self, buf, offset, chunk, parent):
306 super(CloseStartElementNode, self).__init__(buf, offset, chunk, parent) 307 self.declare_field("byte", "token", 0x0)
308
309 - def __repr__(self):
310 return "CloseStartElementNode(buf=%r, offset=%r, chunk=%r, parent=%r)" % \ 311 (self._buf, self.offset(), self._chunk, self._parent)
312
313 - def __str__(self):
314 return "CloseStartElementNode(offset=%s, length=%s, token=%s)" % \ 315 (hex(self.offset()), hex(self.length()), hex(self.token()))
316
317 - def flags(self):
318 return self.token() >> 4
319
320 - def tag_length(self):
321 return 1
322
323 - def length(self):
324 return 1
325
326 - def children(self):
327 return []
328
329 - def verify(self):
330 return self.flags() & 0x0F == 0 and \ 331 self.opcode() & 0x0F == 0x02
332
333 334 -class CloseEmptyElementNode(BXmlNode):
335 """ 336 The binary XML node for the system token 0x03. 337 """
338 - def __init__(self, buf, offset, chunk, parent):
339 super(CloseEmptyElementNode, self).__init__(buf, offset, chunk, parent) 340 self.declare_field("byte", "token", 0x0)
341
342 - def __repr__(self):
343 return "CloseEmptyElementNode(buf=%r, offset=%r, chunk=%r, parent=%r)" % \ 344 (self._buf, self.offset(), self._chunk, self._parent)
345
346 - def __str__(self):
347 return "CloseEmptyElementNode(offset=%s, length=%s, token=%s)" % \ 348 (hex(self.offset()), hex(self.length()), hex(0x03))
349
350 - def flags(self):
351 return self.token() >> 4
352
353 - def tag_length(self):
354 return 1
355
356 - def length(self):
357 return 1
358
359 - def children(self):
360 return []
361
362 363 -class CloseElementNode(BXmlNode):
364 """ 365 The binary XML node for the system token 0x04. 366 367 This is the "close element" token. 368 """
369 - def __init__(self, buf, offset, chunk, parent):
370 super(CloseElementNode, self).__init__(buf, offset, chunk, parent) 371 self.declare_field("byte", "token", 0x0)
372
373 - def __repr__(self):
374 return "CloseElementNode(buf=%r, offset=%r, chunk=%r, parent=%r)" % \ 375 (self._buf, self.offset(), self._chunk, self._parent)
376
377 - def __str__(self):
378 return "CloseElementNode(offset=%s, length=%s, token=%s)" % \ 379 (hex(self.offset()), hex(self.length()), hex(self.token()))
380
381 - def flags(self):
382 return self.token() >> 4
383
384 - def tag_length(self):
385 return 1
386
387 - def length(self):
388 return 1
389
390 - def children(self):
391 return []
392
393 - def verify(self):
394 return self.flags() & 0x0F == 0 and \ 395 self.opcode() & 0x0F == 0x04
396
397 398 -def get_variant_value(buf, offset, chunk, parent, type_, length=None):
399 """ 400 @return A VariantType subclass instance found in the given 401 buffer and offset. 402 """ 403 types = { 404 0x00: NullTypeNode, 405 0x01: WstringTypeNode, 406 0x02: StringTypeNode, 407 0x03: SignedByteTypeNode, 408 0x04: UnsignedByteTypeNode, 409 0x05: SignedWordTypeNode, 410 0x06: UnsignedWordTypeNode, 411 0x07: SignedDwordTypeNode, 412 0x08: UnsignedDwordTypeNode, 413 0x09: SignedQwordTypeNode, 414 0x0A: UnsignedQwordTypeNode, 415 0x0B: FloatTypeNode, 416 0x0C: DoubleTypeNode, 417 0x0D: BooleanTypeNode, 418 0x0E: BinaryTypeNode, 419 0x0F: GuidTypeNode, 420 0x10: SizeTypeNode, 421 0x11: FiletimeTypeNode, 422 0x12: SystemtimeTypeNode, 423 0x13: SIDTypeNode, 424 0x14: Hex32TypeNode, 425 0x15: Hex64TypeNode, 426 0x21: BXmlTypeNode, 427 0x81: WstringArrayTypeNode, 428 } 429 try: 430 TypeClass = types[type_] 431 except IndexError: 432 raise NotImplementedError("Type %s not implemented" % (type_)) 433 return TypeClass(buf, offset, chunk, parent, length=length)
434
435 436 -class ValueNode(BXmlNode):
437 """ 438 The binary XML node for the system token 0x05. 439 440 This is the "value" token. 441 """
442 - def __init__(self, buf, offset, chunk, parent):
443 super(ValueNode, self).__init__(buf, offset, chunk, parent) 444 self.declare_field("byte", "token", 0x0) 445 self.declare_field("byte", "type")
446
447 - def __repr__(self):
448 return "ValueNode(buf=%r, offset=%r, chunk=%r, parent=%r)" % \ 449 (self._buf, self.offset(), self._chunk, self._parent)
450
451 - def __str__(self):
452 return "ValueNode(offset=%s, length=%s, token=%s, value=%s)" % \ 453 (hex(self.offset()), hex(self.length()), 454 hex(self.token()), self.value().string())
455
456 - def flags(self):
457 return self.token() >> 4
458
459 - def value(self):
460 return self.children()[0]
461
462 - def tag_length(self):
463 return 2
464
465 - def children(self):
466 child = get_variant_value(self._buf, 467 self.offset() + self.tag_length(), 468 self._chunk, self, self.type()) 469 return [child]
470
471 - def verify(self):
472 return self.flags() & 0x0B == 0 and \ 473 self.token() & 0x0F == SYSTEM_TOKENS.ValueToken
474
475 476 -class AttributeNode(BXmlNode):
477 """ 478 The binary XML node for the system token 0x06. 479 480 This is the "attribute" token. 481 """
482 - def __init__(self, buf, offset, chunk, parent):
483 super(AttributeNode, self).__init__(buf, offset, chunk, parent) 484 self.declare_field("byte", "token", 0x0) 485 self.declare_field("dword", "string_offset") 486 487 self._name_string_length = 0 488 if self.string_offset() > self.offset() - self._chunk._offset: 489 new_string = self._chunk.add_string(self.string_offset(), 490 parent=self) 491 self._name_string_length += new_string.length()
492
493 - def __repr__(self):
494 return "AttributeNode(buf=%r, offset=%r, chunk=%r, parent=%r)" % \ 495 (self._buf, self.offset(), self._chunk, self._parent)
496
497 - def __str__(self):
498 return "AttributeNode(offset=%s, length=%s, token=%s, name=%s, value=%s)" % \ 499 (hex(self.offset()), hex(self.length()), hex(self.token()), 500 self.attribute_name(), self.attribute_value())
501
502 - def flags(self):
503 return self.token() >> 4
504
505 - def attribute_name(self):
506 """ 507 @return A NameNode instance that contains the attribute name. 508 """ 509 return self._chunk.strings()[self.string_offset()]
510
511 - def attribute_value(self):
512 """ 513 @return A BXmlNode instance that is one of (ValueNode, 514 ConditionalSubstitutionNode, NormalSubstitutionNode). 515 """ 516 return self.children()[0]
517
518 - def tag_length(self):
519 return 5 + self._name_string_length
520
521 - def verify(self):
522 return self.flags() & 0x0B == 0 and \ 523 self.opcode() & 0x0F == 0x06
524 525 @memoize
526 - def children(self):
527 return self._children(max_children=1)
528
529 530 -class CDataSectionNode(BXmlNode):
531 """ 532 The binary XML node for the system token 0x07. 533 534 This is the "CDATA section" system token. 535 """
536 - def __init__(self, buf, offset, chunk, parent):
537 super(CDataSectionNode, self).__init__(buf, offset, chunk, parent) 538 self.declare_field("byte", "token", 0x0) 539 self.declare_field("word", "string_length") 540 self.declare_field("wstring", "cdata", length=self.string_length() - 2)
541
542 - def __repr__(self):
543 return "CDataSectionNode(buf=%r, offset=%r, chunk=%r, parent=%r)" % \ 544 (self._buf, self.offset(), self._chunk, self._parent)
545
546 - def __str__(self):
547 return "CDataSectionNode(offset=%s, length=%s, token=%s)" % \ 548 (hex(self.offset()), hex(self.length()), 0x07)
549
550 - def flags(self):
551 return self.token() >> 4
552
553 - def tag_length(self):
554 return 0x3 + self.string_length()
555
556 - def length(self):
557 return self.tag_length()
558
559 - def children(self):
560 return []
561
562 - def verify(self):
563 return self.flags() == 0x0 and \ 564 self.token() & 0x0F == SYSTEM_TOKENS.CDataSectionToken
565
566 567 -class EntityReferenceNode(BXmlNode):
568 """ 569 The binary XML node for the system token 0x09. 570 571 This is an entity reference node. That is, something that represents 572 a non-XML character, eg. & --> &amp;. 573 574 TODO(wb): this is untested. 575 """
576 - def __init__(self, buf, offset, chunk, parent):
577 super(EntityReferenceNode, self).__init__(buf, offset, chunk, parent) 578 self.declare_field("byte", "token", 0x0) 579 self.declare_field("dword", "string_offset") 580 self._tag_length = 5 581 582 if self.string_offset() > self.offset() - self._chunk.offset(): 583 new_string = self._chunk.add_string(self.string_offset(), 584 parent=self) 585 self._tag_length += new_string.length()
586 587
588 - def __repr__(self):
589 return "EntityReferenceNode(buf=%r, offset=%r, chunk=%r, parent=%r)" % \ 590 (self._buf, self.offset(), self._chunk, self._parent)
591
592 - def __str__(self):
593 return "EntityReferenceNode(offset=%s, length=%s, token=%s)" % \ 594 (hex(self.offset()), hex(self.length()), hex(0x09))
595
596 - def entity_reference(self):
597 return "&%s;" % \ 598 (self._chunk.strings()[self.string_offset()].string())
599
600 - def flags(self):
601 return self.token() >> 4
602
603 - def tag_length(self):
604 return self._tag_length
605
606 - def children(self):
607 # TODO(wb): it may be possible for this element to have children. 608 return []
609
610 611 -class ProcessingInstructionTargetNode(BXmlNode):
612 """ 613 The binary XML node for the system token 0x0A. 614 615 TODO(wb): untested. 616 """
617 - def __init__(self, buf, offset, chunk, parent):
618 super(ProcessingInstructionTargetNode, self).__init__(buf, offset, chunk, parent) 619 self.declare_field("byte", "token", 0x0) 620 self.declare_field("dword", "string_offset") 621 self._tag_length = 5 622 623 if self.string_offset() > self.offset() - self._chunk.offset(): 624 new_string = self._chunk.add_string(self.string_offset(), 625 parent=self) 626 self._tag_length += new_string.length()
627
628 - def __repr__(self):
629 return "ProcessingInstructionTargetNode(buf=%r, offset=%r, chunk=%r, parent=%r)" % \ 630 (self._buf, self.offset(), self._chunk, self._parent)
631
632 - def __str__(self):
633 return "ProcessingInstructionTargetNode(offset=%s, length=%s, token=%s)" % \ 634 (hex(self.offset()), hex(self.length()), hex(0x0A))
635
637 return "<?%s" % \ 638 (self._chunk.strings()[self.string_offset()].string())
639
640 - def flags(self):
641 return self.token() >> 4
642
643 - def tag_length(self):
644 return self._tag_length
645
646 - def children(self):
647 # TODO(wb): it may be possible for this element to have children. 648 return []
649
650 651 -class ProcessingInstructionDataNode(BXmlNode):
652 """ 653 The binary XML node for the system token 0x0B. 654 655 TODO(wb): untested. 656 """
657 - def __init__(self, buf, offset, chunk, parent):
658 super(ProcessingInstructionDataNode, self).__init__(buf, offset, chunk, parent) 659 self.declare_field("byte", "token", 0x0) 660 self.declare_field("word", "string_length") 661 self._tag_length = 3 + (2 * self.string_length()) 662 663 if self.string_length() > 0: 664 self._string = self.unpack_wstring(0x3, self.string_length()) 665 else: 666 self._string = ""
667
668 - def __repr__(self):
669 return "ProcessingInstructionDataNode(buf=%r, offset=%r, chunk=%r, parent=%r)" % \ 670 (self._buf, self.offset(), self._chunk, self._parent)
671
672 - def __str__(self):
673 return "ProcessingInstructionDataNode(offset=%s, length=%s, token=%s)" % \ 674 (hex(self.offset()), hex(self.length()), hex(0x0B))
675
676 - def flags(self):
677 return self.token() >> 4
678
679 - def string(self):
680 if self.string_length() > 0: 681 return " %s?>" % (self._string) 682 else: 683 return "?>"
684
685 - def tag_length(self):
686 return self._tag_length
687
688 - def children(self):
689 # TODO(wb): it may be possible for this element to have children. 690 return []
691
692 693 -class TemplateInstanceNode(BXmlNode):
694 """ 695 The binary XML node for the system token 0x0C. 696 """
697 - def __init__(self, buf, offset, chunk, parent):
698 super(TemplateInstanceNode, self).__init__(buf, offset, chunk, parent) 699 self.declare_field("byte", "token", 0x0) 700 self.declare_field("byte", "unknown0") 701 self.declare_field("dword", "template_id") 702 self.declare_field("dword", "template_offset") 703 704 self._data_length = 0 705 706 if self.is_resident_template(): 707 new_template = self._chunk.add_template(self.template_offset(), 708 parent=self) 709 self._data_length += new_template.length()
710
711 - def __repr__(self):
712 return "TemplateInstanceNode(buf=%r, offset=%r, chunk=%r, parent=%r)" % \ 713 (self._buf, self.offset(), self._chunk, self._parent)
714
715 - def __str__(self):
716 return "TemplateInstanceNode(offset=%s, length=%s, token=%s)" % \ 717 (hex(self.offset()), hex(self.length()), hex(0x0C))
718
719 - def flags(self):
720 return self.token() >> 4
721
722 - def is_resident_template(self):
723 return self.template_offset() > self.offset() - self._chunk._offset
724
725 - def tag_length(self):
726 return 10
727
728 - def length(self):
729 return self.tag_length() + self._data_length
730
731 - def template(self):
732 return self._chunk.templates()[self.template_offset()]
733
734 - def children(self):
735 return []
736 737 @memoize
738 - def find_end_of_stream(self):
739 return self.template().find_end_of_stream()
740
741 742 -class NormalSubstitutionNode(BXmlNode):
743 """ 744 The binary XML node for the system token 0x0D. 745 746 This is a "normal substitution" token. 747 """
748 - def __init__(self, buf, offset, chunk, parent):
749 super(NormalSubstitutionNode, self).__init__(buf, offset, 750 chunk, parent) 751 self.declare_field("byte", "token", 0x0) 752 self.declare_field("word", "index") 753 self.declare_field("byte", "type")
754
755 - def __repr__(self):
756 return "NormalSubstitutionNode(buf=%r, offset=%r, chunk=%r, parent=%r)" % \ 757 (self._buf, self.offset(), self._chunk, self._parent)
758
759 - def __str__(self):
760 return "NormalSubstitutionNode(offset=%s, length=%s, token=%s, index=%d, type=%d)" % \ 761 (hex(self.offset()), hex(self.length()), hex(self.token()), 762 self.index(), self.type())
763
764 - def flags(self):
765 return self.token() >> 4
766
767 - def tag_length(self):
768 return 0x4
769
770 - def length(self):
771 return self.tag_length()
772
773 - def children(self):
774 return []
775
776 - def verify(self):
777 return self.flags() == 0 and \ 778 self.token() & 0x0F == SYSTEM_TOKENS.NormalSubstitutionToken
779
780 781 -class ConditionalSubstitutionNode(BXmlNode):
782 """ 783 The binary XML node for the system token 0x0E. 784 """
785 - def __init__(self, buf, offset, chunk, parent):
786 super(ConditionalSubstitutionNode, self).__init__(buf, offset, 787 chunk, parent) 788 self.declare_field("byte", "token", 0x0) 789 self.declare_field("word", "index") 790 self.declare_field("byte", "type")
791
792 - def __repr__(self):
793 return "ConditionalSubstitutionNode(buf=%r, offset=%r, chunk=%r, parent=%r)" % \ 794 (self._buf, self.offset(), self._chunk, self._parent)
795
796 - def __str__(self):
797 return "ConditionalSubstitutionNode(offset=%s, length=%s, token=%s)" % \ 798 (hex(self.offset()), hex(self.length()), hex(0x0E))
799
800 - def should_suppress(self, substitutions):
801 sub = substitutions[self.index()] 802 return type(sub) is NullTypeNode
803
804 - def flags(self):
805 return self.token() >> 4
806
807 - def tag_length(self):
808 return 0x4
809
810 - def length(self):
811 return self.tag_length()
812
813 - def children(self):
814 return []
815
816 - def verify(self):
817 return self.flags() == 0 and \ 818 self.token() & 0x0F == SYSTEM_TOKENS.ConditionalSubstitutionToken
819
820 821 -class StreamStartNode(BXmlNode):
822 """ 823 The binary XML node for the system token 0x0F. 824 825 This is the "start of stream" token. 826 """
827 - def __init__(self, buf, offset, chunk, parent):
828 super(StreamStartNode, self).__init__(buf, offset, chunk, parent) 829 self.declare_field("byte", "token", 0x0) 830 self.declare_field("byte", "unknown0") 831 self.declare_field("word", "unknown1")
832
833 - def __repr__(self):
834 return "StreamStartNode(buf=%r, offset=%r, chunk=%r, parent=%r)" % \ 835 (self._buf, self.offset(), self._chunk, self._parent)
836
837 - def __str__(self):
838 return "StreamStartNode(offset=%s, length=%s, token=%s)" % \ 839 (hex(self.offset()), hex(self.length()), hex(self.token()))
840
841 - def verify(self):
842 return self.flags() == 0x0 and \ 843 self.token() & 0x0F == SYSTEM_TOKENS.StartOfStreamToken and \ 844 self.unknown0() == 0x1 and \ 845 self.unknown1() == 0x1
846
847 - def flags(self):
848 return self.token() >> 4
849
850 - def tag_length(self):
851 return 4
852
853 - def length(self):
854 return self.tag_length() + 0
855
856 - def children(self):
857 return []
858
859 860 -class RootNode(BXmlNode):
861 """ 862 The binary XML node for the Root node. 863 """
864 - def __init__(self, buf, offset, chunk, parent):
865 super(RootNode, self).__init__(buf, offset, chunk, parent)
866
867 - def __repr__(self):
868 return "RootNode(buf=%r, offset=%r, chunk=%r, parent=%r)" % \ 869 (self._buf, self.offset(), self._chunk, self._parent)
870
871 - def __str__(self):
872 return "RootNode(offset=%s, length=%s)" % \ 873 (hex(self.offset()), hex(self.length()))
874
875 - def tag_length(self):
876 return 0
877 878 @memoize
879 - def children(self):
880 """ 881 @return The template instances which make up this node. 882 """ 883 return self._children(end_tokens=[SYSTEM_TOKENS.EndOfStreamToken])
884
885 - def tag_and_children_length(self):
886 """ 887 @return The length of the tag of this element, and the children. 888 This does not take into account the substitutions that may be 889 at the end of this element. 890 """ 891 children_length = 0 892 893 for child in self.children(): 894 children_length += child.length() 895 896 return self.tag_length() + children_length
897
898 - def fast_template_instance(self):
899 ofs = self.offset() 900 if self.unpack_byte(0x0) & 0x0F == 0xF: 901 ofs += 4 902 return TemplateInstanceNode(self._buf, ofs, self._chunk, self)
903 904 @memoize
905 - def fast_substitutions(self):
906 """ 907 Get the list of elements that are the 908 the substitutions for this root node. 909 Each element is one of: 910 str 911 int 912 float 913 RootNode 914 @rtype: list 915 """ 916 sub_decl = [] 917 sub_def = [] 918 ofs = self.tag_and_children_length() 919 sub_count = self.unpack_dword(ofs) 920 ofs += 4 921 for _ in xrange(sub_count): 922 size = self.unpack_word(ofs) 923 type_ = self.unpack_byte(ofs + 0x2) 924 sub_decl.append((size, type_)) 925 ofs += 4 926 for (size, type_) in sub_decl: 927 #[0] = parse_null_type_node, 928 if type_ == 0x0: 929 value = None 930 sub_def.append(value) 931 #[1] = parse_wstring_type_node, 932 elif type_ == 0x1: 933 s = self.unpack_wstring(ofs, size / 2).rstrip("\x00") 934 value = s.replace("<", "&gt;").replace(">", "&lt;") 935 sub_def.append(value) 936 #[2] = parse_string_type_node, 937 elif type_ == 0x2: 938 s = self.unpack_string(ofs, size) 939 value = s.decode("utf8").rstrip("\x00") 940 value = value.replace("<", "&gt;") 941 value = value.replace(">", "&lt;") 942 sub_def.append(value) 943 #[3] = parse_signed_byte_type_node, 944 elif type_ == 0x3: 945 sub_def.append(self.unpack_int8(ofs)) 946 #[4] = parse_unsigned_byte_type_node, 947 elif type_ == 0x4: 948 sub_def.append(self.unpack_byte(ofs)) 949 #[5] = parse_signed_word_type_node, 950 elif type_ == 0x5: 951 sub_def.append(self.unpack_int16(ofs)) 952 #[6] = parse_unsigned_word_type_node, 953 elif type_ == 0x6: 954 sub_def.append(self.unpack_word(ofs)) 955 #[7] = parse_signed_dword_type_node, 956 elif type_ == 0x7: 957 sub_def.append(self.unpack_int32(ofs)) 958 #[8] = parse_unsigned_dword_type_node, 959 elif type_ == 0x8: 960 sub_def.append(self.unpack_dword(ofs)) 961 #[9] = parse_signed_qword_type_node, 962 elif type_ == 0x9: 963 sub_def.append(self.unpack_int64(ofs)) 964 #[10] = parse_unsigned_qword_type_node, 965 elif type_ == 0xA: 966 sub_def.append(self.unpack_qword(ofs)) 967 #[11] = parse_float_type_node, 968 elif type_ == 0xB: 969 sub_def.append(self.unpack_float(ofs)) 970 #[12] = parse_double_type_node, 971 elif type_ == 0xC: 972 sub_def.append(self.unpack_double(ofs)) 973 #[13] = parse_boolean_type_node, 974 elif type_ == 0xD: 975 sub_def.append(str(self.unpack_word(ofs) > 1)) 976 #[14] = parse_binary_type_node, 977 elif type_ == 0xE: 978 sub_def.append(base64.b64encode(self.unpack_binary(ofs, size))) 979 #[15] = parse_guid_type_node, 980 elif type_ == 0xF: 981 sub_def.append(self.unpack_guid(ofs)) 982 #[16] = parse_size_type_node, 983 elif type_ == 0x10: 984 if size == 0x4: 985 sub_def.append(self.unpack_dword(ofs)) 986 elif size == 0x8: 987 sub_def.append(self.unpack_qword(ofs)) 988 else: 989 raise "Unexpected size for SizeTypeNode: %s" % hex(size) 990 #[17] = parse_filetime_type_node, 991 elif type_ == 0x11: 992 sub_def.append(self.unpack_filetime(ofs)) 993 #[18] = parse_systemtime_type_node, 994 elif type_ == 0x12: 995 sub_def.append(self.unpack_systemtime(ofs)) 996 #[19] = parse_sid_type_node, -- SIDTypeNode, 0x13 997 elif type_ == 0x13: 998 version = self.unpack_byte(ofs) 999 num_elements = self.unpack_byte(ofs + 1) 1000 id_high = self.unpack_dword_be(ofs) 1001 id_low = self.unpack_word_be(ofs) 1002 value = "S-%d-%d" % (version, (id_high << 16) ^ id_low) 1003 for i in xrange(num_elements): 1004 val = self.unpack_dword(ofs + 8 + (4 * i)) 1005 value += "-%d" % val 1006 sub_def.append(value) 1007 #[20] = parse_hex32_type_node, -- Hex32TypeNoe, 0x14 1008 elif type_ == 0x14: 1009 value = "0x" 1010 for c in self.unpack_binary(ofs, size)[::-1]: 1011 value += "%02x" % ord(c) 1012 sub_def.append(value) 1013 #[21] = parse_hex64_type_node, -- Hex64TypeNode, 0x15 1014 elif type_ == 0x15: 1015 value = "0x" 1016 for c in self.unpack_binary(ofs, size)[::-1]: 1017 value += "%02x" % ord(c) 1018 sub_def.append(value) 1019 #[33] = parse_bxml_type_node, -- BXmlTypeNode, 0x21 1020 elif type_ == 0x21: 1021 sub_def.append(RootNode(self._buf, self.offset() + ofs, 1022 self._chunk, self)) 1023 #[129] = TODO, -- WstringArrayTypeNode, 0x81 1024 elif type_ == 0x81: 1025 bin = self.unpack_binary(ofs, size) 1026 acc = [] 1027 while len(bin) > 0: 1028 match = re.search("((?:[^\x00].)+)", bin) 1029 if match: 1030 frag = match.group() 1031 acc.append("<string>") 1032 acc.append(frag.decode("utf16")) 1033 acc.append("</string>\n") 1034 bin = bin[len(frag) + 2:] 1035 if len(bin) == 0: 1036 break 1037 frag = re.search("(\x00*)", bin).group() 1038 if len(frag) % 2 == 0: 1039 for _ in xrange(len(frag) // 2): 1040 acc.append("<string></string>\n") 1041 else: 1042 raise "Error parsing uneven substring of NULLs" 1043 bin = bin[len(frag):] 1044 sub_def.append("".join(acc)) 1045 else: 1046 raise "Unexpected type encountered: %s" % hex(type_) 1047 ofs += size 1048 return sub_def
1049 1050 @memoize
1051 - def substitutions(self):
1052 """ 1053 @return A list of VariantTypeNode subclass instances that 1054 contain the substitutions for this root node. 1055 """ 1056 sub_decl = [] 1057 sub_def = [] 1058 ofs = self.tag_and_children_length() 1059 sub_count = self.unpack_dword(ofs) 1060 ofs += 4 1061 for _ in xrange(sub_count): 1062 size = self.unpack_word(ofs) 1063 type_ = self.unpack_byte(ofs + 0x2) 1064 sub_decl.append((size, type_)) 1065 ofs += 4 1066 for (size, type_) in sub_decl: 1067 val = get_variant_value(self._buf, self.offset() + ofs, 1068 self._chunk, self, type_, length=size) 1069 if abs(size - val.length()) > 4: 1070 # TODO(wb): This is a hack, so I'm sorry. 1071 # But, we are not passing around a 'length' field, 1072 # so we have to depend on the structure of each 1073 # variant type. It seems some BXmlTypeNode sizes 1074 # are not exact. Hopefully, this is just alignment. 1075 # So, that's what we compensate for here. 1076 raise ParseException("Invalid substitution value size") 1077 sub_def.append(val) 1078 ofs += size 1079 return sub_def
1080 1081 @memoize
1082 - def length(self):
1083 ofs = self.tag_and_children_length() 1084 sub_count = self.unpack_dword(ofs) 1085 ofs += 4 1086 ret = ofs 1087 for _ in xrange(sub_count): 1088 size = self.unpack_word(ofs) 1089 ret += size + 4 1090 ofs += 4 1091 return ret
1092
1093 1094 -class VariantTypeNode(BXmlNode):
1095 """ 1096 1097 """
1098 - def __init__(self, buf, offset, chunk, parent, length=None):
1099 super(VariantTypeNode, self).__init__(buf, offset, chunk, parent) 1100 self._length = length
1101
1102 - def __repr__(self):
1103 return "%s(buf=%r, offset=%s, chunk=%r)" % \ 1104 (self.__class__.__name__, self._buf, hex(self.offset()), 1105 self._chunk)
1106
1107 - def __str__(self):
1108 return "%s(offset=%s, length=%s, string=%s)" % \ 1109 (self.__class__.__name__, hex(self.offset()), 1110 hex(self.length()), self.string())
1111
1112 - def tag_length(self):
1113 raise NotImplementedError("tag_length not implemented for %r" % \ 1114 (self))
1115
1116 - def length(self):
1117 return self.tag_length()
1118
1119 - def children(self):
1120 return []
1121
1122 - def string(self):
1123 raise NotImplementedError("string not implemented for %r" % \ 1124 (self))
1125
1126 1127 -class NullTypeNode(object): # but satisfies the contract of VariantTypeNode, BXmlNode, but not Block
1128 """ 1129 Variant type 0x00. 1130 """
1131 - def __init__(self, buf, offset, chunk, parent, length=None):
1132 super(NullTypeNode, self).__init__() 1133 self._offset = offset 1134 self._length = length
1135
1136 - def __str__(self):
1137 return "NullTypeNode"
1138
1139 - def string(self):
1140 return ""
1141
1142 - def length(self):
1143 return self._length or 0
1144
1145 - def tag_length(self):
1146 return self._length or 0
1147
1148 - def children(self):
1149 return []
1150
1151 - def offset(self):
1152 return self._offset
1153
1154 1155 -class WstringTypeNode(VariantTypeNode):
1156 """ 1157 Variant ttype 0x01. 1158 """
1159 - def __init__(self, buf, offset, chunk, parent, length=None):
1160 super(WstringTypeNode, self).__init__(buf, offset, chunk, 1161 parent, length=length) 1162 if self._length is None: 1163 self.declare_field("word", "string_length", 0x0) 1164 self.declare_field("wstring", "_string", 1165 length=(self.string_length())) 1166 else: 1167 self.declare_field("wstring", "_string", 0x0, 1168 length=(self._length / 2))
1169
1170 - def tag_length(self):
1171 if self._length is None: 1172 return (2 + (self.string_length() * 2)) 1173 return self._length
1174
1175 - def string(self):
1176 return self._string().rstrip("\x00")
1177
1178 1179 -class StringTypeNode(VariantTypeNode):
1180 """ 1181 Variant type 0x02. 1182 """
1183 - def __init__(self, buf, offset, chunk, parent, length=None):
1184 super(StringTypeNode, self).__init__(buf, offset, chunk, 1185 parent, length=length) 1186 if self._length is None: 1187 self.declare_field("word", "string_length", 0x0) 1188 self.declare_field("string", "_string", 1189 length=(self.string_length())) 1190 else: 1191 self.declare_field("string", "_string", 0x0, length=self._length)
1192
1193 - def tag_length(self):
1194 if self._length is None: 1195 return (2 + (self.string_length())) 1196 return self._length
1197
1198 - def string(self):
1199 return self._string().rstrip("\x00")
1200
1201 1202 -class SignedByteTypeNode(VariantTypeNode):
1203 """ 1204 Variant type 0x03. 1205 """
1206 - def __init__(self, buf, offset, chunk, parent, length=None):
1207 super(SignedByteTypeNode, self).__init__(buf, offset, chunk, 1208 parent, length=length) 1209 self.declare_field("int8", "byte", 0x0)
1210
1211 - def tag_length(self):
1212 return 1
1213
1214 - def string(self):
1215 return str(self.byte())
1216
1217 1218 -class UnsignedByteTypeNode(VariantTypeNode):
1219 """ 1220 Variant type 0x04. 1221 """
1222 - def __init__(self, buf, offset, chunk, parent, length=None):
1223 super(UnsignedByteTypeNode, self).__init__(buf, offset, 1224 chunk, parent, 1225 length=length) 1226 self.declare_field("byte", "byte", 0x0)
1227
1228 - def tag_length(self):
1229 return 1
1230
1231 - def string(self):
1232 return str(self.byte())
1233
1234 1235 -class SignedWordTypeNode(VariantTypeNode):
1236 """ 1237 Variant type 0x05. 1238 """
1239 - def __init__(self, buf, offset, chunk, parent, length=None):
1240 super(SignedWordTypeNode, self).__init__(buf, offset, chunk, 1241 parent, length=length) 1242 self.declare_field("int16", "word", 0x0)
1243
1244 - def tag_length(self):
1245 return 2
1246
1247 - def string(self):
1248 return str(self.word())
1249
1250 1251 -class UnsignedWordTypeNode(VariantTypeNode):
1252 """ 1253 Variant type 0x06. 1254 """
1255 - def __init__(self, buf, offset, chunk, parent, length=None):
1256 super(UnsignedWordTypeNode, self).__init__(buf, offset, 1257 chunk, parent, 1258 length=length) 1259 self.declare_field("word", "word", 0x0)
1260
1261 - def tag_length(self):
1262 return 2
1263
1264 - def string(self):
1265 return str(self.word())
1266
1267 1268 -class SignedDwordTypeNode(VariantTypeNode):
1269 """ 1270 Variant type 0x07. 1271 """
1272 - def __init__(self, buf, offset, chunk, parent, length=None):
1273 super(SignedDwordTypeNode, self).__init__(buf, offset, chunk, 1274 parent, length=length) 1275 self.declare_field("int32", "dword", 0x0)
1276
1277 - def tag_length(self):
1278 return 4
1279
1280 - def string(self):
1281 return str(self.dword())
1282
1283 1284 -class UnsignedDwordTypeNode(VariantTypeNode):
1285 """ 1286 Variant type 0x08. 1287 """
1288 - def __init__(self, buf, offset, chunk, parent, length=None):
1289 super(UnsignedDwordTypeNode, self).__init__(buf, offset, 1290 chunk, parent, 1291 length=length) 1292 self.declare_field("dword", "dword", 0x0)
1293
1294 - def tag_length(self):
1295 return 4
1296
1297 - def string(self):
1298 return str(self.dword())
1299
1300 1301 -class SignedQwordTypeNode(VariantTypeNode):
1302 """ 1303 Variant type 0x09. 1304 """
1305 - def __init__(self, buf, offset, chunk, parent, length=None):
1306 super(SignedQwordTypeNode, self).__init__(buf, offset, chunk, 1307 parent, length=length) 1308 self.declare_field("int64", "qword", 0x0)
1309
1310 - def tag_length(self):
1311 return 8
1312
1313 - def string(self):
1314 return str(self.qword())
1315
1316 1317 -class UnsignedQwordTypeNode(VariantTypeNode):
1318 """ 1319 Variant type 0x0A. 1320 """
1321 - def __init__(self, buf, offset, chunk, parent, length=None):
1322 super(UnsignedQwordTypeNode, self).__init__(buf, offset, 1323 chunk, parent, 1324 length=length) 1325 self.declare_field("qword", "qword", 0x0)
1326
1327 - def tag_length(self):
1328 return 8
1329
1330 - def string(self):
1331 return str(self.qword())
1332
1333 1334 -class FloatTypeNode(VariantTypeNode):
1335 """ 1336 Variant type 0x0B. 1337 """
1338 - def __init__(self, buf, offset, chunk, parent, length=None):
1339 super(FloatTypeNode, self).__init__(buf, offset, chunk, 1340 parent, length=length) 1341 self.declare_field("float", "float", 0x0)
1342
1343 - def tag_length(self):
1344 return 4
1345
1346 - def string(self):
1347 return str(self.float())
1348
1349 1350 -class DoubleTypeNode(VariantTypeNode):
1351 """ 1352 Variant type 0x0C. 1353 """
1354 - def __init__(self, buf, offset, chunk, parent, length=None):
1355 super(DoubleTypeNode, self).__init__(buf, offset, chunk, 1356 parent, length=length) 1357 self.declare_field("double", "double", 0x0)
1358
1359 - def tag_length(self):
1360 return 8
1361
1362 - def string(self):
1363 return str(self.double())
1364
1365 1366 -class BooleanTypeNode(VariantTypeNode):
1367 """ 1368 Variant type 0x0D. 1369 """
1370 - def __init__(self, buf, offset, chunk, parent, length=None):
1371 super(BooleanTypeNode, self).__init__(buf, offset, chunk, 1372 parent, length=length) 1373 self.declare_field("int32", "int32", 0x0)
1374
1375 - def tag_length(self):
1376 return 4
1377
1378 - def string(self):
1379 if self.int32 > 0: 1380 return "True" 1381 return "False"
1382
1383 1384 -class BinaryTypeNode(VariantTypeNode):
1385 """ 1386 Variant type 0x0E. 1387 1388 String/XML representation is Base64 encoded. 1389 """
1390 - def __init__(self, buf, offset, chunk, parent, length=None):
1391 super(BinaryTypeNode, self).__init__(buf, offset, chunk, 1392 parent, length=length) 1393 if self._length is None: 1394 self.declare_field("dword", "size", 0x0) 1395 self.declare_field("binary", "binary", length=self.size()) 1396 else: 1397 self.declare_field("binary", "binary", 0x0, length=self._length)
1398
1399 - def tag_length(self):
1400 if self._length is None: 1401 return (4 + self.size()) 1402 return self._length
1403
1404 - def string(self):
1405 return base64.b64encode(self.binary())
1406
1407 1408 -class GuidTypeNode(VariantTypeNode):
1409 """ 1410 Variant type 0x0F. 1411 """
1412 - def __init__(self, buf, offset, chunk, parent, length=None):
1413 super(GuidTypeNode, self).__init__(buf, offset, chunk, 1414 parent, length=length) 1415 self.declare_field("guid", "guid", 0x0)
1416
1417 - def tag_length(self):
1418 return 16
1419
1420 - def string(self):
1421 return "{%s}" % (self.guid())
1422
1423 1424 -class SizeTypeNode(VariantTypeNode):
1425 """ 1426 Variant type 0x10. 1427 1428 Note: Assuming sizeof(size_t) == 0x8. 1429 """
1430 - def __init__(self, buf, offset, chunk, parent, length=None):
1431 super(SizeTypeNode, self).__init__(buf, offset, chunk, 1432 parent, length=length) 1433 if self._length == 0x4: 1434 self.declare_field("dword", "num", 0x0) 1435 elif self._length == 0x8: 1436 self.declare_field("qword", "num", 0x0) 1437 else: 1438 self.declare_field("qword", "num", 0x0)
1439
1440 - def tag_length(self):
1441 if self._length is None: 1442 return 8 1443 return self._length
1444
1445 - def string(self):
1446 return str(self.num())
1447
1448 1449 -class FiletimeTypeNode(VariantTypeNode):
1450 """ 1451 Variant type 0x11. 1452 """
1453 - def __init__(self, buf, offset, chunk, parent, length=None):
1454 super(FiletimeTypeNode, self).__init__(buf, offset, chunk, 1455 parent, length=length) 1456 self.declare_field("filetime", "filetime", 0x0)
1457
1458 - def string(self):
1459 return self.filetime().isoformat("T") + "Z"
1460
1461 - def tag_length(self):
1462 return 8
1463
1464 1465 -class SystemtimeTypeNode(VariantTypeNode):
1466 """ 1467 Variant type 0x12. 1468 """
1469 - def __init__(self, buf, offset, chunk, parent, length=None):
1470 super(SystemtimeTypeNode, self).__init__(buf, offset, chunk, 1471 parent, length=length) 1472 self.declare_field("systemtime", "systemtime", 0x0)
1473
1474 - def tag_length(self):
1475 return 16
1476
1477 - def string(self):
1478 return self.systemtime().isoformat("T") + "Z"
1479
1480 1481 -class SIDTypeNode(VariantTypeNode):
1482 """ 1483 Variant type 0x13. 1484 """
1485 - def __init__(self, buf, offset, chunk, parent, length=None):
1486 super(SIDTypeNode, self).__init__(buf, offset, chunk, 1487 parent, length=length) 1488 self.declare_field("byte", "version", 0x0) 1489 self.declare_field("byte", "num_elements") 1490 self.declare_field("dword_be", "id_high") 1491 self.declare_field("word_be", "id_low")
1492 1493 @memoize
1494 - def elements(self):
1495 ret = [] 1496 for i in xrange(self.num_elements()): 1497 ret.append(self.unpack_dword(self.current_field_offset() + 4 * i)) 1498 return ret
1499 1500 @memoize
1501 - def id(self):
1502 ret = "S-%d-%d" % \ 1503 (self.version(), (self.id_high() << 16) ^ self.id_low()) 1504 for elem in self.elements(): 1505 ret += "-%d" % (elem) 1506 return ret
1507
1508 - def tag_length(self):
1509 return 8 + 4 * self.num_elements()
1510
1511 - def string(self):
1512 return self.id()
1513
1514 1515 -class Hex32TypeNode(VariantTypeNode):
1516 """ 1517 Variant type 0x14. 1518 """
1519 - def __init__(self, buf, offset, chunk, parent, length=None):
1520 super(Hex32TypeNode, self).__init__(buf, offset, chunk, 1521 parent, length=length) 1522 self.declare_field("binary", "hex", 0x0, length=0x4)
1523
1524 - def tag_length(self):
1525 return 4
1526
1527 - def string(self):
1528 ret = "0x" 1529 for c in self.hex()[::-1]: 1530 ret += "%02x" % (ord(c)) 1531 return ret
1532
1533 1534 -class Hex64TypeNode(VariantTypeNode):
1535 """ 1536 Variant type 0x15. 1537 """
1538 - def __init__(self, buf, offset, chunk, parent, length=None):
1539 super(Hex64TypeNode, self).__init__(buf, offset, chunk, 1540 parent, length=length) 1541 self.declare_field("binary", "hex", 0x0, length=0x8)
1542
1543 - def tag_length(self):
1544 return 8
1545
1546 - def string(self):
1547 ret = "0x" 1548 for c in self.hex()[::-1]: 1549 ret += "%02x" % (ord(c)) 1550 return ret
1551
1552 1553 -class BXmlTypeNode(VariantTypeNode):
1554 """ 1555 Variant type 0x21. 1556 """
1557 - def __init__(self, buf, offset, chunk, parent, length=None):
1558 super(BXmlTypeNode, self).__init__(buf, offset, chunk, 1559 parent, length=length) 1560 self._root = RootNode(buf, offset, chunk, self)
1561
1562 - def tag_length(self):
1563 return self._length or self._root.length()
1564
1565 - def string(self):
1566 return str(self._root)
1567
1568 - def root(self):
1569 return self._root
1570
1571 1572 -class WstringArrayTypeNode(VariantTypeNode):
1573 """ 1574 Variant ttype 0x81. 1575 """
1576 - def __init__(self, buf, offset, chunk, parent, length=None):
1577 super(WstringArrayTypeNode, self).__init__(buf, offset, chunk, 1578 parent, length=length) 1579 if self._length is None: 1580 self.declare_field("word", "binary_length", 0x0) 1581 self.declare_field("binary", "binary", 1582 length=(self.binary_length())) 1583 else: 1584 self.declare_field("binary", "binary", 0x0, 1585 length=(self._length))
1586
1587 - def tag_length(self):
1588 if self._length is None: 1589 return (2 + self.binary_length()) 1590 return self._length
1591
1592 - def string(self):
1593 bin = self.binary() 1594 acc = [] 1595 while len(bin) > 0: 1596 match = re.search("((?:[^\x00].)+)", bin) 1597 if match: 1598 frag = match.group() 1599 acc.append("<string>") 1600 acc.append(frag.decode("utf16")) 1601 acc.append("</string>\n") 1602 bin = bin[len(frag) + 2:] 1603 if len(bin) == 0: 1604 break 1605 frag = re.search("(\x00*)", bin).group() 1606 if len(frag) % 2 == 0: 1607 for _ in xrange(len(frag) // 2): 1608 acc.append("<string></string>\n") 1609 else: 1610 raise "Error parsing uneven substring of NULLs" 1611 bin = bin[len(frag):] 1612 return "".join(acc)
1613 1614 1615 node_dispatch_table = [ 1616 EndOfStreamNode, 1617 OpenStartElementNode, 1618 CloseStartElementNode, 1619 CloseEmptyElementNode, 1620 CloseElementNode, 1621 ValueNode, 1622 AttributeNode, 1623 CDataSectionNode, 1624 None, 1625 EntityReferenceNode, 1626 ProcessingInstructionTargetNode, 1627 ProcessingInstructionDataNode, 1628 TemplateInstanceNode, 1629 NormalSubstitutionNode, 1630 ConditionalSubstitutionNode, 1631 StreamStartNode, 1632 ] 1633 1634 node_readable_tokens = [ 1635 "End of Stream", 1636 "Open Start Element", 1637 "Close Start Element", 1638 "Close Empty Element", 1639 "Close Element", 1640 "Value", 1641 "Attribute", 1642 "unknown", 1643 "unknown", 1644 "unknown", 1645 "unknown", 1646 "unknown", 1647 "TemplateInstanceNode", 1648 "Normal Substitution", 1649 "Conditional Substitution", 1650 "Start of Stream", 1651 ] 1652