atomicshop 2.13.2__py3-none-any.whl → 2.14.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of atomicshop might be problematic. Click here for more details.

atomicshop/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  """Atomic Basic functions and classes to make developer life easier"""
2
2
 
3
3
  __author__ = "Den Kras"
4
- __version__ = '2.13.2'
4
+ __version__ = '2.14.0'
atomicshop/etws/trace.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import queue
2
2
  import sys
3
3
  import time
4
+ from typing import Literal
4
5
 
5
6
  # Import FireEye Event Tracing library.
6
7
  import etw
@@ -26,7 +27,8 @@ class EventTrace(etw.ETW):
26
27
  session_name: str = None,
27
28
  close_existing_session_name: bool = True,
28
29
  enable_process_poller: bool = False,
29
- process_poller_etw_session_name: str = None
30
+ process_poller_etw_session_name: str = None,
31
+ process_poller_method: Literal['psutil', 'pywin32', 'process_dll', 'sysmon_etw'] = 'sysmon_etw'
30
32
  ):
31
33
  """
32
34
  :param providers: List of tuples with provider name and provider GUID.
@@ -41,6 +43,12 @@ class EventTrace(etw.ETW):
41
43
  Since the DNS events doesn't contain the process name and command line, only PID.
42
44
  Then DNS events will be enriched with the process name and command line from the process poller.
43
45
  :param process_poller_etw_session_name: The name of the ETW session for tracing process creation.
46
+ :param process_poller_method: The method to get the process information. For more information, see the
47
+ 'process_poller.ProcessPollerPool' class. Summary:
48
+ 'psutil': Uses 'psutil' library to get the process information.
49
+ 'pywin32': Uses 'pywin32' library to get the process information.
50
+ 'process_dll': Uses 'process' custom DLL to get the process information.
51
+ 'sysmon_etw': Uses 'sysmon_etw' uses sysmon and ETW to get the process information.
44
52
 
45
53
  ------------------------------------------
46
54
 
@@ -83,7 +91,7 @@ class EventTrace(etw.ETW):
83
91
 
84
92
  if self.enable_process_poller:
85
93
  self.process_poller = process_poller.ProcessPollerPool(
86
- operation='process', poller_method='sysmon_etw',
94
+ operation='process', poller_method=process_poller_method,
87
95
  sysmon_etw_session_name=process_poller_etw_session_name)
88
96
 
89
97
  super().__init__(
File without changes
File without changes
@@ -0,0 +1,149 @@
1
+ import win32evtlog
2
+ import xml.etree.ElementTree as Et
3
+ import time
4
+ import threading
5
+ import queue
6
+ from typing import Union
7
+
8
+
9
+ class EventLogSubscriber:
10
+ """
11
+ Class for subscribing to Windows Event Log events.
12
+
13
+ Usage:
14
+ from atomicshop.wrappers.pywin32w.win_event_log import subscribe
15
+
16
+ event_log_subscriber = subscribe.EventLogSubscriber('Security', 4688)
17
+ event_log_subscriber.start()
18
+
19
+ while True:
20
+ event = event_log_subscriber.emit()
21
+ print(event)
22
+ """
23
+ def __init__(self, log_channel: str, event_id: int):
24
+ """
25
+ :param log_channel: The name of the event log channel to subscribe to. Examples:
26
+ Security, System, Application, etc.
27
+ :param event_id: The ID of the event to subscribe to.
28
+ Example: 4688 for process creation events in "Security" channel.
29
+ """
30
+ self.log_channel: str = log_channel
31
+ self.event_id: str = str(event_id)
32
+
33
+ self._event_queue = queue.Queue()
34
+ self._subscription_thread = None
35
+
36
+ def start(self):
37
+ """Start the subscription process."""
38
+ self._subscription_thread = threading.Thread(
39
+ target=start_subscription, args=(self.log_channel, self.event_id, self._event_queue)
40
+ )
41
+ self._subscription_thread.daemon = True
42
+ self._subscription_thread.start()
43
+
44
+ def stop(self):
45
+ """Stop the subscription process."""
46
+ if self._subscription_thread:
47
+ self._subscription_thread.join()
48
+ self._subscription_thread = None
49
+
50
+ def emit(self, timeout: float = None) -> Union[dict, None]:
51
+ """
52
+ Get the next event from the event queue.
53
+
54
+ :param timeout: The maximum time (in seconds) to wait for an event.
55
+ If None, the function will block until an event is available.
56
+ :return: A dictionary containing the event data, or None if no event is available.
57
+ """
58
+ try:
59
+ return self._event_queue.get(timeout=timeout)
60
+ except queue.Empty:
61
+ return None
62
+
63
+
64
+ def _parse_event_xml(event_xml):
65
+ root = Et.fromstring(event_xml)
66
+ data = {}
67
+ for elem in root.iter():
68
+ if 'Name' in elem.attrib:
69
+ data[elem.attrib['Name']] = elem.text
70
+ return data
71
+
72
+
73
+ def _handle_event(event, event_queue):
74
+ event_xml = win32evtlog.EvtRender(event, win32evtlog.EvtRenderEventXml)
75
+ try:
76
+ data = _parse_event_xml(event_xml)
77
+ except Et.ParseError as e:
78
+ print(f"Error parsing event XML: {e}")
79
+ return
80
+
81
+ event_dict: dict = {
82
+ 'user_sid': data.get("SubjectUserSid", "Unknown"),
83
+ 'user_name': data.get("SubjectUserName", "Unknown"),
84
+ 'domain': data.get("SubjectDomainName", "Unknown"),
85
+ 'pid_hex': data.get("NewProcessId", "0"),
86
+ 'process_name': data.get("NewProcessName", "Unknown"),
87
+ 'command_line': data.get("CommandLine", None),
88
+ 'parent_pid_hex': data.get("ProcessId", "0"),
89
+ 'parent_process_name': data.get("ParentProcessName", "Unknown")
90
+ }
91
+
92
+ try:
93
+ process_id = int(event_dict['pid_hex'], 16)
94
+ except ValueError:
95
+ process_id = "Unknown"
96
+
97
+ try:
98
+ parent_pid = int(event_dict['parent_pid_hex'], 16)
99
+ except ValueError:
100
+ parent_pid = "Unknown"
101
+
102
+ event_dict['pid'] = process_id
103
+ event_dict['parent_pid'] = parent_pid
104
+
105
+ # if user_sid != "Unknown":
106
+ # try:
107
+ # user_name, domain, type = win32security.LookupAccountSid(None, user_sid)
108
+ # except Exception as e:
109
+ # print(f"Error looking up account SID: {e}")
110
+
111
+ event_queue.put(event_dict)
112
+
113
+
114
+ def _event_callback(action, context, event):
115
+ event_queue = context['event_queue']
116
+ if action == win32evtlog.EvtSubscribeActionDeliver:
117
+ _handle_event(event, event_queue)
118
+
119
+
120
+ def start_subscription(log_channel: str, event_id: int, event_queue):
121
+ """
122
+ Start listening for events in the specified log channel with the given event ID.
123
+
124
+ :param log_channel: The name of the event log channel to subscribe to. Examples:
125
+ Security, System, Application, etc.
126
+ :param event_id: The ID of the event to subscribe to.
127
+ Example: 4688 for process creation events in "Security" channel.
128
+ :param event_queue: A queue to store the received events
129
+ """
130
+ # This selects the System node within each event.
131
+ # The System node contains metadata about the event, such as the event ID, provider name, timestamp, and more.
132
+ query = f"*[System/EventID={str(event_id)}]"
133
+
134
+ subscription = win32evtlog.EvtSubscribe(
135
+ log_channel,
136
+ win32evtlog.EvtSubscribeToFutureEvents,
137
+ SignalEvent=None,
138
+ Query=query,
139
+ Callback=_event_callback,
140
+ Context={'event_queue': event_queue}
141
+ )
142
+
143
+ print("Listening for new process creation events...")
144
+
145
+ try:
146
+ while True:
147
+ time.sleep(1)
148
+ except KeyboardInterrupt:
149
+ print("Stopped listening for events.")
@@ -0,0 +1,145 @@
1
+ import subprocess
2
+ import winreg
3
+
4
+ from .. import subscribe
5
+ from .....print_api import print_api
6
+
7
+
8
+ AUDITING_REG_PATH: str = r"Software\Microsoft\Windows\CurrentVersion\Policies\System\Audit"
9
+ PROCESS_CREATION_INCLUDE_CMDLINE_VALUE: str = "ProcessCreationIncludeCmdLine_Enabled"
10
+
11
+
12
+ class ProcessCreateSubscriber(subscribe.EventLogSubscriber):
13
+ """
14
+ Class for subscribing to Windows Event Log events related to process creation.
15
+
16
+ Usage:
17
+ from atomicshop.wrappers.pywin32w.win_event_log.subscribes import subscribe_to_process_create
18
+
19
+ process_create_subscriber = subscribe_to_process_create.ProcessCreateSubscriber()
20
+ process_create_subscriber.start()
21
+
22
+ while True:
23
+ event = process_create_subscriber.emit()
24
+ print(event)
25
+ """
26
+ def __init__(self):
27
+ super().__init__('Security', 4688)
28
+
29
+ def start(self):
30
+ """Start the subscription process."""
31
+ enable_audit_process_creation()
32
+ enable_command_line_auditing()
33
+
34
+ super().start()
35
+
36
+ def stop(self):
37
+ """Stop the subscription process."""
38
+ super().stop()
39
+
40
+ def emit(self, timeout: float = None) -> dict:
41
+ """
42
+ Get the next event from the event queue.
43
+
44
+ :param timeout: The maximum time (in seconds) to wait for an event.
45
+ If None, the function will block until an event is available.
46
+ :return: A dictionary containing the event data.
47
+ """
48
+ return super().emit(timeout=timeout)
49
+
50
+
51
+ def enable_audit_process_creation(print_kwargs: dict = None):
52
+ """
53
+ Enable the 'Audit Process Creation' policy.
54
+
55
+ :param print_kwargs: Optional keyword arguments for the print function.
56
+ """
57
+ if is_audit_process_creation_enabled():
58
+ print_api("Audit Process Creation is already enabled.", color='yellow', **(print_kwargs or {}))
59
+ return
60
+
61
+ # Enable "Audit Process Creation" policy
62
+ audit_policy_command = [
63
+ "auditpol", "/set", "/subcategory:Process Creation", "/success:enable", "/failure:enable"
64
+ ]
65
+ try:
66
+ subprocess.run(audit_policy_command, check=True)
67
+ print_api("Successfully enabled 'Audit Process Creation'.", color='green', **(print_kwargs or {}))
68
+ except subprocess.CalledProcessError as e:
69
+ print_api(f"Failed to enable 'Audit Process Creation': {e}", error_type=True, color='red', **(print_kwargs or {}))
70
+ raise e
71
+
72
+
73
+ def is_audit_process_creation_enabled(print_kwargs: dict = None) -> bool:
74
+ """
75
+ Check if the 'Audit Process Creation' policy is enabled.
76
+
77
+ :param print_kwargs: Optional keyword arguments for the print function.
78
+ """
79
+ # Command to check the "Audit Process Creation" policy
80
+ audit_policy_check_command = [
81
+ "auditpol", "/get", "/subcategory:Process Creation"
82
+ ]
83
+ try:
84
+ result = subprocess.run(audit_policy_check_command, check=True, capture_output=True, text=True)
85
+ output = result.stdout
86
+ # print_api(output) # Print the output for inspection
87
+
88
+ if "Process Creation" in output and "Success and Failure" in output:
89
+ # print_api(
90
+ # "'Audit Process Creation' is enabled for both success and failure.",
91
+ # color='green', **(print_kwargs or {}))
92
+ return True
93
+ else:
94
+ print_api(output, **(print_kwargs or {}))
95
+ print_api(
96
+ "'Audit Process Creation' is not fully enabled. Check the output above for details.",
97
+ color='yellow', **(print_kwargs or {}))
98
+ return False
99
+ except subprocess.CalledProcessError as e:
100
+ print_api(f"Failed to check 'Audit Process Creation': {e}", color='red', error_type=True, **(print_kwargs or {}))
101
+ return False
102
+
103
+
104
+ def enable_command_line_auditing(print_kwargs: dict = None):
105
+ """
106
+ Enable the 'Include command line in process creation events' policy.
107
+
108
+ :param print_kwargs: Optional keyword arguments for the print function.
109
+ """
110
+
111
+ if is_command_line_auditing_enabled():
112
+ print_api(
113
+ "'Include command line in process creation events' is already enabled.", color='yellow',
114
+ **(print_kwargs or {}))
115
+ return
116
+
117
+ try:
118
+ # Open the registry key
119
+ with winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE, AUDITING_REG_PATH) as reg_key:
120
+ # Set the value
121
+ winreg.SetValueEx(reg_key, PROCESS_CREATION_INCLUDE_CMDLINE_VALUE, 0, winreg.REG_DWORD, 1)
122
+
123
+ print_api(
124
+ "Successfully enabled 'Include command line in process creation events'.",
125
+ color='green', **(print_kwargs or {}))
126
+ except WindowsError as e:
127
+ print_api(
128
+ f"Failed to enable 'Include command line in process creation events': {e}", error_type=True,
129
+ color='red', **(print_kwargs or {}))
130
+
131
+
132
+ def is_command_line_auditing_enabled():
133
+ try:
134
+ # Open the registry key
135
+ with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, AUDITING_REG_PATH, 0, winreg.KEY_READ) as reg_key:
136
+ # Query the value
137
+ value, reg_type = winreg.QueryValueEx(reg_key, PROCESS_CREATION_INCLUDE_CMDLINE_VALUE)
138
+ # Check if the value is 1 (enabled)
139
+ return value == 1
140
+ except FileNotFoundError:
141
+ # Key or value not found, assume it's not enabled
142
+ return False
143
+ except WindowsError as e:
144
+ print(f"Failed to read the 'Include command line in process creation events' setting: {e}")
145
+ return False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.13.2
3
+ Version: 2.14.0
4
4
  Summary: Atomic functions and classes to make developer life easier
5
5
  Author: Denis Kras
6
6
  License: MIT License
@@ -1,4 +1,4 @@
1
- atomicshop/__init__.py,sha256=e_cepUB_kyEwwtls5dudclY5653g8Bn7epJj7a_khw8,123
1
+ atomicshop/__init__.py,sha256=LlDA7S0dPFwG14ZFuGv5tyUVyow2__rgMRanlcYHT88,123
2
2
  atomicshop/_basics_temp.py,sha256=6cu2dd6r2dLrd1BRNcVDKTHlsHs_26Gpw8QS6v32lQ0,3699
3
3
  atomicshop/_create_pdf_demo.py,sha256=Yi-PGZuMg0RKvQmLqVeLIZYadqEZwUm-4A9JxBl_vYA,3713
4
4
  atomicshop/_patch_import.py,sha256=ENp55sKVJ0e6-4lBvZnpz9PQCt3Otbur7F6aXDlyje4,6334
@@ -106,7 +106,7 @@ atomicshop/etws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
106
106
  atomicshop/etws/const.py,sha256=v3x_IdCYeSKbCGywiZFOZln80ldpwKW5nuMDuUe51Jg,1257
107
107
  atomicshop/etws/providers.py,sha256=fVmWi-uGdtnsQTDpu_ty6dzx0GMhGokiST73LNBEJ38,129
108
108
  atomicshop/etws/sessions.py,sha256=k3miewU278xn829cqDbsuH_bmZHPQE9-Zn-hINbxUSE,1330
109
- atomicshop/etws/trace.py,sha256=ptdDyLuk8frKgmgOEug8KrH5niC6SfgWnOqw06tGPAw,7831
109
+ atomicshop/etws/trace.py,sha256=H0uDB6I86UoNyijE5HCukp_paJNHTjKL6eAzBRGSI50,8509
110
110
  atomicshop/etws/traces/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
111
111
  atomicshop/etws/traces/trace_dns.py,sha256=8Fl5UW4An3SE8tGXGTufTgOcWa574YZ6zQbU7x5DYrs,6270
112
112
  atomicshop/etws/traces/trace_sysmon_process_creation.py,sha256=WdlQiOfRZC-_PpuE6BkOw5zB0DLc3fhVrANyLrgfCac,4833
@@ -246,9 +246,14 @@ atomicshop/wrappers/psutilw/disks.py,sha256=3ZSVoommKH1TWo37j_83frB-NqXF4Nf5q5mB
246
246
  atomicshop/wrappers/psutilw/memories.py,sha256=_S0aL8iaoIHebd1vOFrY_T9aROM5Jx2D5CvDh_4j0Vc,528
247
247
  atomicshop/wrappers/psutilw/psutilw.py,sha256=q3EwgprqyrR4zLCjl4l5DHFOQoukEvQMIPjNB504oQ0,21262
248
248
  atomicshop/wrappers/psycopgw/psycopgw.py,sha256=XJvVf0oAUjCHkrYfKeFuGCpfn0Oxj3u4SbKMKA1508E,7118
249
+ atomicshop/wrappers/pywin32w/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
249
250
  atomicshop/wrappers/pywin32w/console.py,sha256=LstHajPLgXp9qQxFNR44QfH10nOnNp3bCJquxaTquns,1175
250
251
  atomicshop/wrappers/pywin32w/winshell.py,sha256=i2bKiMldPU7_azsD5xGQDdMwjaM7suKJd3k0Szmcs6c,723
251
252
  atomicshop/wrappers/pywin32w/wmi_win32process.py,sha256=qMzXtJ5hBZ5ydAyqpDbSx0nO2RJQL95HdmV5SzNKMhk,6826
253
+ atomicshop/wrappers/pywin32w/win_event_log/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
254
+ atomicshop/wrappers/pywin32w/win_event_log/subscribe.py,sha256=UztWltQPK_fQ3EWyY6tGfhAqwxDjK7RVIAZppu97rKI,5104
255
+ atomicshop/wrappers/pywin32w/win_event_log/subscribes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
256
+ atomicshop/wrappers/pywin32w/win_event_log/subscribes/subscribe_to_process_create.py,sha256=_rMCTaREi_PJxAPP4gAB0IW9F0XO-suUXLf97tboKSc,5594
252
257
  atomicshop/wrappers/socketw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
253
258
  atomicshop/wrappers/socketw/accepter.py,sha256=HQC1EyZmyUtVEfFbaBkHCE-VZp6RWyd9mEqAkgsE1fk,1749
254
259
  atomicshop/wrappers/socketw/base.py,sha256=1vvg8EhRGvnxdrRAm1VJSLCXkm2SZDHRjdpTuhkH3Mg,1844
@@ -265,8 +270,8 @@ atomicshop/wrappers/socketw/socket_server_tester.py,sha256=AhpurHJmP2kgzHaUbq5ey
265
270
  atomicshop/wrappers/socketw/socket_wrapper.py,sha256=aXBwlEIJhFT0-c4i8iNlFx2It9VpCEpsv--5Oqcpxao,11624
266
271
  atomicshop/wrappers/socketw/ssl_base.py,sha256=k4V3gwkbq10MvOH4btU4onLX2GNOsSfUAdcHmL1rpVE,2274
267
272
  atomicshop/wrappers/socketw/statistics_csv.py,sha256=t3dtDEfN47CfYVi0CW6Kc2QHTEeZVyYhc57IYYh5nmA,826
268
- atomicshop-2.13.2.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
269
- atomicshop-2.13.2.dist-info/METADATA,sha256=FwrMOVELwpnXQKf-LbaJhMr9B2mbEos5YA94BQbSuAk,10478
270
- atomicshop-2.13.2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
271
- atomicshop-2.13.2.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
272
- atomicshop-2.13.2.dist-info/RECORD,,
273
+ atomicshop-2.14.0.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
274
+ atomicshop-2.14.0.dist-info/METADATA,sha256=M4vV-yH5er5NVOQJMUtIPqdgh6IHzINAY1frKcRF9oU,10478
275
+ atomicshop-2.14.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
276
+ atomicshop-2.14.0.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
277
+ atomicshop-2.14.0.dist-info/RECORD,,