Evtx.Nodes

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):
      65          super(SuppressConditionalSubstitution, self).__init__(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):
     295          return self._children(end_tokens=[SYSTEM_TOKENS.CloseElementToken,
     296                                            SYSTEM_TOKENS.CloseEmptyElementToken])
     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
     636 -    def processing_instruction_target(self):
     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