-
Notifications
You must be signed in to change notification settings - Fork 8
/
build_resolver.py
121 lines (89 loc) · 4.03 KB
/
build_resolver.py
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# -*- coding: utf-8 -*-
# !/usr/bin/env python
"""
Prepare resolver json file for evtx2splunk
Based on Blardy work (https://github.com/blardy/evtx2elk)
"""
import logging as log
import argparse
import sqlite3
import re
import json
class Resolver(object):
def __init__(self, database):
self.database = database
self.filename = database.split('/')[-1]
self.basename = './'
if len(database.split('/')[-1]) > 1:
self.basename = '/'.join(database.split('/')[:-1])
self.basename += '/'
self.database_conn = sqlite3.connect(database)
self.database_cache_connectors = {
database: self.database_conn
}
self.cache = {}
def __del__(self):
for database, database_conn in self.database_cache_connectors.items():
database_conn.close()
def open_db(self, database):
""" Get a connection to the db from cache, open it otherwise.
"""
conn = self.database_cache_connectors.get(database, False)
if not conn:
conn = sqlite3.connect(database)
self.database_cache_connectors[database] = conn
return conn
def get_message_string(self, lcid=0x409):
try:
main_db = self.open_db(self.database)
QUERY_PROVIDER_DB = """
SELECT database_filename, log_source FROM event_log_providers
INNER JOIN message_file_per_event_log_provider ON
message_file_per_event_log_provider.event_log_provider_key = event_log_providers.event_log_provider_key
INNER JOIN message_files ON
message_files.message_file_key = message_file_per_event_log_provider.message_file_key
"""
database_filenames = main_db.execute(QUERY_PROVIDER_DB).fetchall()
evtx_bind = {}
for dfne in database_filenames:
log_source = dfne[1]
if log_source not in evtx_bind:
evtx_bind[log_source] = {}
database_filename = self.basename + dfne[0]
provider_db = self.open_db(database_filename)
cursor = provider_db.cursor()
cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
tables = [table[0] for table in cursor.fetchall() if 'message_table_0x' in table[0]]
for table in tables:
if not table.startswith('message_table_0x{:08x}'.format(lcid)):
continue
query_event_mess = "SELECT message_identifier,message_string FROM {}".format(table)
message = provider_db.execute(query_event_mess).fetchall()
for mess in message:
str_mess = mess[1]
str_eventid = mess[0]
me = str_mess.replace('\n', '').replace('%n', '. ').replace('%t', ' ').encode("utf-8").decode(
"utf-8").replace('\r', ' ').replace('\t', ' ').rstrip()
me = re.sub(r'%(\d+)', r'{\1}', me)
eventid = int(str_eventid, 0) & 0xFFFF
if eventid in evtx_bind.get(log_source):
if me != evtx_bind[log_source][eventid]:
evtx_bind[log_source][eventid] = evtx_bind[log_source][eventid] + me
else:
evtx_bind[log_source][eventid] = me
with open('evtx_data.json', 'w', encoding='utf-8') as f:
json.dump(evtx_bind, f, ensure_ascii=False, indent=4)
except Exception as e:
print(e)
return ''
def run():
# Handle arguments
argparser = argparse.ArgumentParser()
argparser.add_argument('-d', '--database', required=True, help='Main winevt-kb database')
args = argparser.parse_args()
# configure logging
resolver = Resolver(args.database)
resolver.get_message_string()
print("Done")
if __name__ == '__main__':
run()