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

Source Code for Module Evtx.Views

  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 v.0.3.0 
 20  from Nodes import RootNode 
 21  from Nodes import TemplateNode 
 22  from Nodes import EndOfStreamNode 
 23  from Nodes import OpenStartElementNode 
 24  from Nodes import CloseStartElementNode 
 25  from Nodes import CloseEmptyElementNode 
 26  from Nodes import CloseElementNode 
 27  from Nodes import ValueNode 
 28  from Nodes import AttributeNode 
 29  from Nodes import CDataSectionNode 
 30  from Nodes import EntityReferenceNode 
 31  from Nodes import ProcessingInstructionTargetNode 
 32  from Nodes import ProcessingInstructionDataNode 
 33  from Nodes import TemplateInstanceNode 
 34  from Nodes import NormalSubstitutionNode 
 35  from Nodes import ConditionalSubstitutionNode 
 36  from Nodes import StreamStartNode 
 37   
 38   
39 -class UnexpectedElementException(Exception):
40 - def __init__(self, msg):
41 super(UnexpectedElementException, self).__init__(msg)
42 43
44 -def _make_template_xml_view(root_node, cache=None):
45 """ 46 Given a RootNode, parse only the template/children 47 and not the substitutions. 48 49 Note, the cache should be local to the Evtx.Chunk. 50 Do not share caches across Chunks. 51 52 @type root_node: Nodes.RootNode 53 @type cache: dict of {int: TemplateNode} 54 @rtype: str 55 """ 56 if cache is None: 57 cache = {} 58 59 def escape_format_chars(s): 60 return s.replace("{", "{{").replace("}", "}}")
61 62 def rec(node, acc): 63 if isinstance(node, EndOfStreamNode): 64 pass # intended 65 elif isinstance(node, OpenStartElementNode): 66 acc.append("<") 67 acc.append(node.tag_name()) 68 for child in node.children(): 69 if isinstance(child, AttributeNode): 70 acc.append(" ") 71 acc.append(child.attribute_name().string()) 72 acc.append("=\"") 73 rec(child.attribute_value(), acc) 74 acc.append("\"") 75 acc.append(">") 76 for child in node.children(): 77 rec(child, acc) 78 acc.append("</") 79 acc.append(node.tag_name()) 80 acc.append(">\n") 81 elif isinstance(node, CloseStartElementNode): 82 pass # intended 83 elif isinstance(node, CloseEmptyElementNode): 84 pass # intended 85 elif isinstance(node, CloseElementNode): 86 pass # intended 87 elif isinstance(node, ValueNode): 88 acc.append(escape_format_chars(node.children()[0].string())) 89 elif isinstance(node, AttributeNode): 90 pass # intended 91 elif isinstance(node, CDataSectionNode): 92 acc.append("<![CDATA[") 93 acc.append(node.cdata()) 94 acc.append("]]>") 95 elif isinstance(node, EntityReferenceNode): 96 acc.append(node.entity_reference()) 97 elif isinstance(node, ProcessingInstructionTargetNode): 98 acc.append(node.processing_instruction_target()) 99 elif isinstance(node, ProcessingInstructionDataNode): 100 acc.append(node.string()) 101 elif isinstance(node, TemplateInstanceNode): 102 raise UnexpectedElementException("TemplateInstanceNode") 103 elif isinstance(node, NormalSubstitutionNode): 104 acc.append("{") 105 acc.append("%d" % (node.index())) 106 acc.append("}") 107 elif isinstance(node, ConditionalSubstitutionNode): 108 acc.append("{") 109 acc.append("%d" % (node.index())) 110 acc.append("}") 111 elif isinstance(node, StreamStartNode): 112 pass # intended 113 114 acc = [] 115 template_instance = root_node.fast_template_instance() 116 templ_off = template_instance.template_offset() + \ 117 template_instance._chunk.offset() 118 if templ_off in cache: 119 acc.append(cache[templ_off]) 120 else: 121 node = TemplateNode(template_instance._buf, templ_off, 122 template_instance._chunk, template_instance) 123 sub_acc = [] 124 for c in node.children(): 125 rec(c, sub_acc) 126 sub_templ = "".join(sub_acc) 127 cache[templ_off] = sub_templ 128 acc.append(sub_templ) 129 return "".join(acc) 130 131
132 -def _build_record_xml(record, cache=None):
133 """ 134 Note, the cache should be local to the Evtx.Chunk. 135 Do not share caches across Chunks. 136 137 @type record: Evtx.Record 138 @type cache: dict of {int: TemplateNode} 139 @rtype: str 140 """ 141 if cache is None: 142 cache = {} 143 144 def rec(root_node): 145 f = _make_template_xml_view(root_node, cache=cache) 146 subs_strs = [] 147 for sub in root_node.fast_substitutions(): 148 if isinstance(sub, basestring): 149 subs_strs.append(sub.encode("ascii", "xmlcharrefreplace")) 150 elif isinstance(sub, RootNode): 151 subs_strs.append(rec(sub)) 152 elif sub is None: 153 subs_strs.append("") 154 else: 155 subs_strs.append(str(sub)) 156 return f.format(*subs_strs)
157 xml = rec(record.root()) 158 xml = xml.replace("&", "&amp;") 159 return xml 160 161
162 -def evtx_record_xml_view(record, cache=None):
163 """ 164 Generate an UTF-8 XML representation of an EVTX record. 165 166 Note, the cache should be local to the Evtx.Chunk. 167 Do not share caches across Chunks. 168 169 @type record: Evtx.Record 170 @type cache: dict of {int: TemplateNode} 171 @rtype: str 172 """ 173 if cache is None: 174 cache = {} 175 return _build_record_xml(record, cache=cache).encode("utf8", "xmlcharrefreplace")
176 177
178 -def evtx_chunk_xml_view(chunk):
179 """ 180 Generate UTF-8 XML representations of the records in an EVTX chunk. 181 182 Does not include the XML <?xml... header. 183 Records are ordered by chunk.records() 184 185 @type chunk: Evtx.Chunk 186 @rtype: generator of str, Evtx.Record 187 """ 188 cache = {} 189 for record in chunk.records(): 190 record_str = _build_record_xml(record, cache=cache) 191 yield record_str.encode("utf8", "xmlcharrefreplace"), record
192 193
194 -def evtx_file_xml_view(file_header):
195 """ 196 Generate UTF-8 XML representations of the records in an EVTX file. 197 198 Does not include the XML <?xml... header. 199 Records are ordered by file_header.chunks(), and then by chunk.records() 200 201 @type file_header: Evtx.FileHeader 202 @rtype: generator of str, Evtx.Record 203 """ 204 for chunk in file_header.chunks(): 205 cache = {} 206 for record in chunk.records(): 207 record_str = _build_record_xml(record, cache=cache) 208 yield record_str.encode("utf8", "xmlcharrefreplace"), record
209 210
211 -def evtx_template_readable_view(template_node):
212 """ 213 """ 214 def rec(node, acc): 215 if isinstance(node, EndOfStreamNode): 216 pass # intended 217 elif isinstance(node, OpenStartElementNode): 218 acc.append("<") 219 acc.append(node.tag_name()) 220 for child in node.children(): 221 if isinstance(child, AttributeNode): 222 acc.append(" ") 223 acc.append(child.attribute_name().string()) 224 acc.append("=\"") 225 rec(child.attribute_value(), acc) 226 acc.append("\"") 227 acc.append(">") 228 for child in node.children(): 229 rec(child, acc) 230 acc.append("</") 231 acc.append(node.tag_name()) 232 acc.append(">\n") 233 elif isinstance(node, CloseStartElementNode): 234 pass # intended 235 elif isinstance(node, CloseEmptyElementNode): 236 pass # intended 237 elif isinstance(node, CloseElementNode): 238 pass # intended 239 elif isinstance(node, ValueNode): 240 acc.append(node.children()[0].string()) 241 elif isinstance(node, AttributeNode): 242 pass # intended 243 elif isinstance(node, CDataSectionNode): 244 acc.append("<![CDATA[") 245 acc.append(node.cdata()) 246 acc.append("]]>") 247 elif isinstance(node, EntityReferenceNode): 248 acc.append(node.entity_reference()) 249 elif isinstance(node, ProcessingInstructionTargetNode): 250 acc.append(node.processing_instruction_target()) 251 elif isinstance(node, ProcessingInstructionDataNode): 252 acc.append(node.string()) 253 elif isinstance(node, TemplateInstanceNode): 254 raise UnexpectedElementException("TemplateInstanceNode") 255 elif isinstance(node, NormalSubstitutionNode): 256 acc.append("[Normal Substitution(index=%d, type=%d)]" % \ 257 (node.index(), node.type())) 258 elif isinstance(node, ConditionalSubstitutionNode): 259 acc.append("[Condititional Substitution(index=%d, type=%d)]" % \ 260 (node.index(), node.type())) 261 elif isinstance(node, StreamStartNode): 262 pass # intended
263 264 sub_acc = [] 265 for c in template_node.children(): 266 rec(c, sub_acc) 267 return "".join(sub_acc) 268