Skip to content

Commit 00355bd

Browse files
committed
be able to import massive files like sysmon config from olaf
1 parent d7d437c commit 00355bd

7 files changed

Lines changed: 110 additions & 4 deletions

File tree

data/sysmon_conditions.py

Whitespace-only changes.

data/sysmon_events.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@
3131
30: "File Blocked",
3232
}
3333

34+
3435
def get_event_xml_tag(event_id: int) -> str:
3536
name = SYS_MON_EVENTS.get(event_id, f"Event{event_id}")
36-
return name.replace(" ", "")
37+
return name.replace(" ", "")
38+
39+
40+
def get_event_id_from_xml_tag(xml_tag: str) -> int | None:
41+
normalized = xml_tag.replace(" ", "").lower()
42+
43+
for event_id in SYS_MON_EVENTS:
44+
if get_event_xml_tag(event_id).lower() == normalized:
45+
return event_id
46+
47+
return None

gui/event_panel.py

Whitespace-only changes.

gui/main_window.py

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from exporters.xml_exporter import export_config
2+
from importers.xml_importer import import_config
23
from gui.rule_editor import RuleEditor
34
from models.sysmon_config import SysmonConfig
45
from data.sysmon_events import SYS_MON_EVENTS
@@ -20,9 +21,7 @@ def __init__(self) -> None:
2021

2122
self.setWindowTitle("Sysmon Config Builder")
2223
self.setGeometry(100, 100, 1000, 600)
23-
2424
self.event_map = SYS_MON_EVENTS
25-
2625
self.config = SysmonConfig()
2726

2827
central_widget = QWidget()
@@ -45,16 +44,47 @@ def __init__(self) -> None:
4544
main_layout.addWidget(self.event_list, 1)
4645
main_layout.addWidget(self.rule_editor, 3)
4746

47+
button_layout = QHBoxLayout()
48+
49+
self.import_button = QPushButton("Import XML")
50+
self.import_button.clicked.connect(self.import_xml)
51+
4852
self.save_button = QPushButton("Save XML")
4953
self.save_button.clicked.connect(self.save_xml)
50-
outer_layout.addWidget(self.save_button)
54+
55+
button_layout.addWidget(self.import_button)
56+
button_layout.addWidget(self.save_button)
57+
58+
outer_layout.addLayout(button_layout)
5159

5260
self.event_list.setCurrentRow(0)
5361

5462
def on_event_selected(self, event_text: str) -> None:
5563
event_id_str, event_name = event_text.split(" - ", 1)
5664
self.rule_editor.set_event(int(event_id_str), event_name)
5765

66+
def import_xml(self) -> None:
67+
file_path, _ = QFileDialog.getOpenFileName(
68+
self,
69+
"Import Sysmon Config",
70+
"",
71+
"XML Files (*.xml)",
72+
)
73+
74+
if not file_path:
75+
return
76+
77+
try:
78+
imported_config = import_config(file_path)
79+
self.config.events = imported_config.events
80+
self.rule_editor.config = self.config
81+
self.rule_editor.refresh_rules()
82+
except Exception as exc:
83+
QMessageBox.critical(self, "Import Failed", f"Failed to import XML:\n{exc}")
84+
return
85+
86+
QMessageBox.information(self, "Success", f"Imported Sysmon config from:\n{file_path}")
87+
5888
def save_xml(self) -> None:
5989
file_path, _ = QFileDialog.getSaveFileName(
6090
self,

importers/xml_importer.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
from xml.etree import ElementTree as ET
2+
3+
from data.sysmon_events import SYS_MON_EVENTS, get_event_id_from_xml_tag
4+
from models.sysmon_config import RuleFilter, SysmonConfig
5+
6+
7+
def extract_rules_from_node(
8+
node: ET.Element,
9+
event_config,
10+
rule_type: str,
11+
) -> None:
12+
for child in node:
13+
if child.tag == "Rule":
14+
extract_rules_from_node(child, event_config, rule_type)
15+
continue
16+
17+
if len(child) > 0:
18+
extract_rules_from_node(child, event_config, rule_type)
19+
continue
20+
21+
field_name = child.tag
22+
condition = child.attrib.get("condition", "is")
23+
value = (child.text or "").strip()
24+
25+
if not value:
26+
continue
27+
28+
event_config.rules.append(
29+
RuleFilter(
30+
rule_type=rule_type,
31+
field_name=field_name,
32+
condition=condition,
33+
value=value,
34+
)
35+
)
36+
37+
38+
def import_config(input_path: str) -> SysmonConfig:
39+
tree = ET.parse(input_path)
40+
root = tree.getroot()
41+
42+
config = SysmonConfig()
43+
44+
event_filtering = root.find("EventFiltering")
45+
if event_filtering is None:
46+
return config
47+
48+
for rule_group in event_filtering:
49+
if rule_group.tag != "RuleGroup":
50+
continue
51+
52+
for event_element in rule_group:
53+
event_tag = event_element.tag
54+
event_id = get_event_id_from_xml_tag(event_tag)
55+
56+
if event_id is None:
57+
continue
58+
59+
event_name = SYS_MON_EVENTS.get(event_id, event_tag)
60+
rule_type = event_element.attrib.get("onmatch", "include")
61+
62+
event_config = config.get_or_create_event(event_id, event_name)
63+
extract_rules_from_node(event_element, event_config, rule_type)
64+
65+
return config

models/event_config.py

Whitespace-only changes.

models/rule_filter.py

Whitespace-only changes.

0 commit comments

Comments
 (0)