Skip to content

Commit 720016f

Browse files
deduplicate etw aux modules (kevoreilly#2888)
* deduplicate etw aux modules * Update analyzer/windows/modules/auxiliary/wmi_etw.py Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * sync * Update etw_utils.py * Update dns_etw.py * sync * fixes and randomize --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent 9dfe366 commit 720016f

5 files changed

Lines changed: 365 additions & 469 deletions

File tree

analyzer/windows/analyzer.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,8 +527,19 @@ def configure_aux_from_data(instance):
527527
# Walk through the available auxiliary modules.
528528
aux_modules = []
529529

530-
for module in sorted(Auxiliary.__subclasses__(), key=lambda x: x.start_priority, reverse=True):
530+
def get_all_subclasses(cls):
531+
all_subclasses = []
532+
for subclass in cls.__subclasses__():
533+
all_subclasses.append(subclass)
534+
all_subclasses.extend(get_all_subclasses(subclass))
535+
return all_subclasses
536+
537+
for module in sorted(get_all_subclasses(Auxiliary), key=lambda x: x.start_priority, reverse=True):
531538
try:
539+
# this is not a real module, ignore it
540+
if module.__name__ == "ETWAuxiliaryWrapper":
541+
continue
542+
532543
aux = module(self.options, self.config)
533544
log.debug('Initialized auxiliary module "%s"', module.__name__)
534545
aux_modules.append(aux)
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import json
2+
import logging
3+
import pprint
4+
from collections.abc import Iterable, Mapping
5+
6+
from lib.common.abstracts import Auxiliary
7+
from lib.core.config import Config
8+
9+
log = logging.getLogger(__name__)
10+
11+
ETW = False
12+
HAVE_ETW = False
13+
try:
14+
from etw import ETW, ProviderInfo # noqa: F401
15+
from etw import evntrace as et # noqa: F401
16+
from etw.GUID import GUID # noqa: F401
17+
18+
HAVE_ETW = True
19+
except ImportError as e:
20+
ETW_IMPORT_ERROR = str(e)
21+
else:
22+
ETW_IMPORT_ERROR = None
23+
24+
25+
def encode(data, encoding="utf-8"):
26+
if isinstance(data, str):
27+
return data.encode(encoding, "ignore")
28+
elif isinstance(data, Mapping):
29+
return dict(map(lambda x: encode(x, encoding=encoding), data.items()))
30+
elif isinstance(data, Iterable):
31+
return type(data)(map(lambda x: encode(x, encoding=encoding), data))
32+
else:
33+
return data
34+
35+
36+
class ETWProviderWrapper(ETW if HAVE_ETW else object):
37+
def __init__(
38+
self,
39+
session_name,
40+
providers,
41+
event_id_filters=None,
42+
ring_buf_size=1024,
43+
max_str_len=1024,
44+
min_buffers=0,
45+
max_buffers=0,
46+
filters=None,
47+
event_callback=None,
48+
logfile=None,
49+
no_conout=False,
50+
):
51+
if not HAVE_ETW:
52+
return
53+
54+
self.logfile = logfile
55+
self.no_conout = no_conout
56+
self.event_callback = event_callback or self.on_event
57+
self.event_id_filters = event_id_filters or []
58+
59+
super().__init__(
60+
session_name=session_name,
61+
ring_buf_size=ring_buf_size,
62+
max_str_len=max_str_len,
63+
min_buffers=min_buffers,
64+
max_buffers=max_buffers,
65+
event_callback=self.event_callback,
66+
task_name_filters=filters,
67+
providers=providers,
68+
event_id_filters=self.event_id_filters,
69+
)
70+
71+
def on_event(self, event_tufo):
72+
event_id, event = event_tufo
73+
74+
if self.event_id_filters and event_id not in self.event_id_filters:
75+
return
76+
77+
if not self.no_conout:
78+
log.info("%d (%s)\n%s\n", event_id, event.get("Task Name", ""), pprint.pformat(encode(event)))
79+
80+
if self.logfile:
81+
self.write_to_log(self.logfile, event_id, event)
82+
83+
def write_to_log(self, file_handle, event_id, event):
84+
json.dump({"event_id": event_id, "event": event}, file_handle)
85+
file_handle.write("\n")
86+
87+
def start(self):
88+
if HAVE_ETW:
89+
self.do_capture_setup()
90+
super().start()
91+
92+
def stop(self):
93+
if HAVE_ETW:
94+
super().stop()
95+
self.do_capture_teardown()
96+
97+
def do_capture_setup(self):
98+
pass
99+
100+
def do_capture_teardown(self):
101+
pass
102+
103+
104+
class ETWAuxiliaryWrapper(Auxiliary):
105+
def __init__(self, options, config, enabled_attr):
106+
Auxiliary.__init__(self, options, config)
107+
self.config = Config(cfg="analysis.conf")
108+
self.enabled = getattr(self.config, enabled_attr, False)
109+
self.do_run = self.enabled
110+
self.capture = None
111+
112+
if not HAVE_ETW:
113+
log.debug(
114+
"Could not load auxiliary module %s due to '%s'\n"
115+
"In order to use ETW functionality, it is required to have pywintrace setup in python",
116+
self.__class__.__name__,
117+
ETW_IMPORT_ERROR,
118+
)
119+
120+
def start(self):
121+
if not self.enabled or not HAVE_ETW:
122+
return False
123+
try:
124+
log.debug("Starting %s", self.__class__.__name__)
125+
if self.capture:
126+
self.capture.start()
127+
except Exception as e:
128+
log.exception("Error starting %s: %s", self.__class__.__name__, e)
129+
return True
130+
131+
def stop(self):
132+
if not HAVE_ETW or not self.capture:
133+
return
134+
log.debug("Stopping %s...", self.__class__.__name__)
135+
self.capture.stop()
136+
self.upload_results()
137+
138+
def upload_results(self):
139+
pass

0 commit comments

Comments
 (0)