File: record_structure.py

package info (click to toggle)
python-evtx 0.5.3b-3%2Bdeb9u1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 784 kB
  • sloc: python: 2,594; makefile: 5
file content (96 lines) | stat: -rw-r--r-- 3,491 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import hexdump

from Evtx.Evtx import Evtx
from Evtx.Nodes import RootNode
from Evtx.Nodes import BXmlTypeNode
from Evtx.Nodes import TemplateInstanceNode
from Evtx.Nodes import VariantTypeNode
from Evtx.Views import evtx_record_xml_view


def describe_root(record, root, indent=0, suppress_values=False):
    """
    @type record: Record
    @type indent: int
    @rtype: None
    """
    def format_node(n, extra=None, indent=0):
        """
        Depends on closure over `record` and `suppress_values`.
        @type n: BXmlNode
        @type extra: str
        @rtype: str
        """
        ret = ""
        if extra is not None:
            ret = "%s%s(offset=%s, %s)" % \
                   ("  " * indent, n.__class__.__name__, hex(n.offset() - record.offset()), extra)
        else:
            ret = "%s%s(offset=%s)" % \
                   ("  " * indent, n.__class__.__name__, hex(n.offset() - record.offset()))

        if not suppress_values and isinstance(n, VariantTypeNode):
            ret += " --> %s" % (n.string())
            if isinstance(n, BXmlTypeNode):
                ret += "\n"
                ret += describe_root(record, n._root, indent=indent + 1)

        return ret

    def rec(node, indent=0):
        """
        @type node: BXmlNode
        @type indent: int
        @rtype: str
        """
        ret = ""
        if isinstance(node, TemplateInstanceNode):
            if node.is_resident_template():
                ret += "%s\n" % (format_node(node, extra="resident=True, length=%s" % (hex(node.template().data_length())), indent=indent))
                ret += rec(node.template(), indent=indent + 1)
            else:
                ret += "%s\n" % (format_node(node, extra="resident=False", indent=indent))
        else:
            ret += "%s\n" % (format_node(node, indent=indent))

        for child in node.children():
            ret += rec(child, indent=indent + 1)
        if isinstance(node, RootNode):
            ofs = node.tag_and_children_length()
            ret += "%sSubstitutions(offset=%s)\n" % ("  " * (indent + 1),
                                                     hex(node.offset() - record.offset() + ofs))
            for sub in node.substitutions():
                ret += "%s\n" % (format_node(sub, indent=indent + 2))
        return ret

    ret = ""
    ret += rec(root, indent=indent)
    return ret


def main():
    import argparse

    parser = argparse.ArgumentParser(
        description="Pretty print the binary structure of an EVTX record.")
    parser.add_argument("evtx", type=str,
                        help="Path to the Windows EVTX file")
    parser.add_argument("record", type=int,
                        help="Record number")
    parser.add_argument("--suppress_values", action="store_true",
                        help="Do not print the values of substitutions.")
    args = parser.parse_args()

    with Evtx(args.evtx) as evtx:
        hexdump.hexdump(evtx.get_record(args.record).data())

        print(("record(absolute_offset=%s)" % \
                  (evtx.get_record(args.record).offset())))
        print(describe_root(evtx.get_record(args.record),
                            evtx.get_record(args.record).root(),
                            suppress_values=args.suppress_values))
        print(evtx_record_xml_view(evtx.get_record(args.record)))


if __name__ == "__main__":
    main()