atomicshop 2.12.24__py3-none-any.whl → 2.12.25__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.12.24'
4
+ __version__ = '2.12.25'
@@ -0,0 +1,5 @@
1
+ from ..wrappers.ctyping.etw_winapi import etw_functions
2
+
3
+
4
+ def get_providers():
5
+ return etw_functions.get_all_providers()
@@ -12,3 +12,32 @@ def stop_and_delete(session_name) -> tuple[bool, int]:
12
12
  """
13
13
 
14
14
  return etw_functions.stop_and_delete_etw_session(session_name)
15
+
16
+
17
+ def get_running_list() -> list[dict]:
18
+ """
19
+ List all running ETW sessions.
20
+
21
+ :return: A list of strings containing the names of all running ETW sessions.
22
+ """
23
+
24
+ return etw_functions.list_etw_sessions()
25
+
26
+
27
+ def is_session_running(session_name: str) -> bool:
28
+ """
29
+ Check if an ETW session is running.
30
+
31
+ :param session_name: The name of the session to check.
32
+ :return: A boolean indicating if the session is running.
33
+ """
34
+
35
+ # Get all running sessions.
36
+ running_sessions = get_running_list()
37
+
38
+ # Check if the session is in the list of running sessions.
39
+ for session in running_sessions:
40
+ if session['session_name'] == session_name:
41
+ return True
42
+
43
+ return False
atomicshop/etw/trace.py CHANGED
@@ -5,6 +5,7 @@ import sys
5
5
  import etw
6
6
 
7
7
  from ..print_api import print_api
8
+ from . import sessions
8
9
 
9
10
 
10
11
  class EventTrace(etw.ETW):
@@ -13,7 +14,8 @@ class EventTrace(etw.ETW):
13
14
  providers: list,
14
15
  event_callback=None,
15
16
  event_id_filters: list = None,
16
- session_name: str = None
17
+ session_name: str = None,
18
+ close_existing_session_name: bool = True
17
19
  ):
18
20
  """
19
21
  :param providers: List of tuples with provider name and provider GUID.
@@ -23,6 +25,7 @@ class EventTrace(etw.ETW):
23
25
  :param event_id_filters: List of event IDs that we want to filter. If not provided, all events will be returned.
24
26
  The default in the 'etw.ETW' method is 'None'.
25
27
  :param session_name: The name of the session to create. If not provided, a UUID will be generated.
28
+ :param close_existing_session_name: Boolean to close existing session names.
26
29
  ------------------------------------------
27
30
  You should stop the ETW tracing when you are done with it.
28
31
  'pywintrace' module starts a new session for ETW tracing, and it will not stop the session when the script
@@ -42,6 +45,7 @@ class EventTrace(etw.ETW):
42
45
  atexits.run_callable_on_exit_and_signals(EventTrace.stop)
43
46
  """
44
47
  self.event_queue = queue.Queue()
48
+ self.close_existing_session_name: bool = close_existing_session_name
45
49
 
46
50
  # If no callback function is provided, we will use the default one, which will put the event in the queue.
47
51
  if not event_callback:
@@ -61,6 +65,17 @@ class EventTrace(etw.ETW):
61
65
  )
62
66
 
63
67
  def start(self):
68
+ # Check if the session name already exists.
69
+ if sessions.is_session_running(self.session_name):
70
+ print_api(f'ETW Session already running: {self.session_name}', color='yellow')
71
+
72
+ # Close the existing session name.
73
+ if self.close_existing_session_name:
74
+ print_api(f'Closing existing session: {self.session_name}', color='blue')
75
+ sessions.stop_and_delete(self.session_name)
76
+ else:
77
+ print_api(f'Using existing session: {self.session_name}', color='yellow')
78
+
64
79
  try:
65
80
  super().start()
66
81
  except OSError as e:
@@ -7,7 +7,13 @@ from ..print_api import print_api
7
7
 
8
8
 
9
9
  class DnsTrace:
10
- def __init__(self, enable_process_poller: bool = False, attrs: list = None, session_name: str = None):
10
+ def __init__(
11
+ self,
12
+ enable_process_poller: bool = False,
13
+ attrs: list = None,
14
+ session_name: str = None,
15
+ close_existing_session_name: bool = True
16
+ ):
11
17
  """
12
18
  DnsTrace class use to trace DNS events from Windows Event Tracing for EventId 3008.
13
19
 
@@ -16,6 +22,14 @@ class DnsTrace:
16
22
  Then DNS events will be enriched with the process name and command line from the process poller.
17
23
  :param attrs: List of attributes to return. If None, all attributes will be returned.
18
24
  :param session_name: The name of the session to create. If not provided, a UUID will be generated.
25
+ :param close_existing_session_name: Boolean to close existing session names.
26
+ True: if ETW session with 'session_name' exists, you will be notified and the session will be closed.
27
+ Then the new session with this name will be created.
28
+ False: if ETW session with 'session_name' exists, you will be notified and the new session will not be
29
+ created. Instead, the existing session will be used. If there is a buffer from the previous session,
30
+ you will get the events from the buffer.
31
+
32
+ -------------------------------------------------
19
33
 
20
34
  Usage Example:
21
35
  from atomicshop.etw import dns_trace
@@ -36,7 +50,8 @@ class DnsTrace:
36
50
  providers=[(dns.ETW_DNS_INFO['provider_name'], dns.ETW_DNS_INFO['provider_guid'])],
37
51
  # lambda x: self.event_queue.put(x),
38
52
  event_id_filters=[dns.ETW_DNS_INFO['event_id']],
39
- session_name=session_name
53
+ session_name=session_name,
54
+ close_existing_session_name=close_existing_session_name
40
55
  )
41
56
 
42
57
  if self.enable_process_poller:
@@ -30,7 +30,7 @@ class DnsCheck:
30
30
  self.fetch_engine: DnsTrace = (
31
31
  DnsTrace(
32
32
  enable_process_poller=True, attrs=['name', 'cmdline', 'domain', 'query_type'],
33
- session_name=self.etw_session_name)
33
+ session_name=self.etw_session_name, close_existing_session_name=True)
34
34
  )
35
35
 
36
36
  if self.settings['alert_always'] and self.settings['alert_about_missing_entries_after_learning']:
@@ -1,14 +1,14 @@
1
1
  import ctypes
2
2
  from ctypes import wintypes
3
+ from ctypes.wintypes import ULONG
3
4
 
4
5
 
5
- # Load the necessary library
6
- advapi32 = ctypes.WinDLL('advapi32')
7
-
8
6
  # Constants
9
7
  EVENT_TRACE_CONTROL_STOP = 1
10
8
  WNODE_FLAG_TRACED_GUID = 0x00020000
11
9
 
10
+ MAXIMUM_LOGGERS = 64
11
+
12
12
 
13
13
  # Define GUID structure
14
14
  class GUID(ctypes.Structure):
@@ -53,5 +53,42 @@ class EVENT_TRACE_PROPERTIES(ctypes.Structure):
53
53
  ("RealTimeBuffersLost", wintypes.ULONG),
54
54
  ("LoggerThreadId", wintypes.HANDLE),
55
55
  ("LogFileNameOffset", wintypes.ULONG),
56
- ("LoggerNameOffset", wintypes.ULONG)
56
+ ("LoggerNameOffset", wintypes.ULONG),
57
+ # Allocate space for the names at the end of the structure
58
+ ("_LoggerName", wintypes.WCHAR * 1024),
59
+ ("_LogFileName", wintypes.WCHAR * 1024)
60
+ ]
61
+
62
+
63
+ class PROVIDER_ENUMERATION_INFO(ctypes.Structure):
64
+ _fields_ = [
65
+ ("NumberOfProviders", ULONG),
66
+ ("Reserved", ULONG),
57
67
  ]
68
+
69
+
70
+ class PROVIDER_INFORMATION(ctypes.Structure):
71
+ _fields_ = [
72
+ ("ProviderId", ctypes.c_byte * 16),
73
+ ("SchemaSource", ULONG),
74
+ ("ProviderNameOffset", ULONG),
75
+ ]
76
+
77
+
78
+ # Load the necessary library
79
+ advapi32 = ctypes.WinDLL('advapi32')
80
+ tdh = ctypes.windll.tdh
81
+
82
+ # Define necessary TDH functions
83
+ tdh.TdhEnumerateProviders.argtypes = [ctypes.POINTER(PROVIDER_ENUMERATION_INFO), ctypes.POINTER(ULONG)]
84
+ tdh.TdhEnumerateProviders.restype = ULONG
85
+
86
+
87
+ # Define the function prototype
88
+ QueryAllTraces = advapi32.QueryAllTracesW
89
+ QueryAllTraces.argtypes = [
90
+ ctypes.POINTER(ctypes.POINTER(EVENT_TRACE_PROPERTIES)),
91
+ wintypes.ULONG,
92
+ ctypes.POINTER(wintypes.ULONG)
93
+ ]
94
+ QueryAllTraces.restype = wintypes.ULONG
@@ -1,4 +1,7 @@
1
1
  import ctypes
2
+ from ctypes.wintypes import ULONG
3
+ import uuid
4
+
2
5
  from . import const
3
6
 
4
7
 
@@ -35,3 +38,91 @@ def stop_and_delete_etw_session(session_name) -> tuple[bool, int]:
35
38
  else:
36
39
  # print("ETW session stopped and deleted successfully.")
37
40
  return True, status
41
+
42
+
43
+ def get_all_providers() -> list[tuple[any, uuid.UUID]]:
44
+ """
45
+ Get all ETW providers available on the system.
46
+
47
+ :return: A list of tuples containing the provider name and GUID.
48
+ """
49
+
50
+ providers_info_size = ULONG(0)
51
+ status = const.tdh.TdhEnumerateProviders(None, ctypes.byref(providers_info_size))
52
+
53
+ # Initial allocation
54
+ buffer = (ctypes.c_byte * providers_info_size.value)()
55
+ providers_info = ctypes.cast(buffer, ctypes.POINTER(const.PROVIDER_ENUMERATION_INFO))
56
+
57
+ # Loop to handle resizing
58
+ while True:
59
+ status = const.tdh.TdhEnumerateProviders(providers_info, ctypes.byref(providers_info_size))
60
+
61
+ if status == 0:
62
+ break
63
+ elif status == 0x8007007A: # ERROR_INSUFFICIENT_BUFFER
64
+ buffer = (ctypes.c_byte * providers_info_size.value)()
65
+ providers_info = ctypes.cast(buffer, ctypes.POINTER(const.PROVIDER_ENUMERATION_INFO))
66
+ else:
67
+ raise ctypes.WinError(status)
68
+
69
+ provider_count = providers_info.contents.NumberOfProviders
70
+ provider_array = ctypes.cast(
71
+ ctypes.addressof(providers_info.contents) + ctypes.sizeof(const.PROVIDER_ENUMERATION_INFO),
72
+ ctypes.POINTER(const.PROVIDER_INFORMATION * provider_count))
73
+
74
+ providers = []
75
+ for i in range(provider_count):
76
+ provider = provider_array.contents[i]
77
+ provider_name_offset = provider.ProviderNameOffset
78
+ provider_name_ptr = ctypes.cast(
79
+ ctypes.addressof(providers_info.contents) + provider_name_offset, ctypes.c_wchar_p)
80
+ provider_name = provider_name_ptr.value
81
+ provider_guid = uuid.UUID(bytes_le=bytes(provider.ProviderId))
82
+ providers.append((provider_name, provider_guid))
83
+
84
+ return providers
85
+
86
+
87
+ def list_etw_sessions() -> list[dict]:
88
+ """
89
+ List all running ETW sessions.
90
+
91
+ :return: A list of dictionaries containing the names of all running ETW sessions and their log files.
92
+ """
93
+ # Create an array of EVENT_TRACE_PROPERTIES pointers
94
+ PropertiesArrayType = ctypes.POINTER(const.EVENT_TRACE_PROPERTIES) * const.MAXIMUM_LOGGERS
95
+ properties_array = PropertiesArrayType()
96
+ for i in range(const.MAXIMUM_LOGGERS):
97
+ properties = const.EVENT_TRACE_PROPERTIES()
98
+ properties.Wnode.BufferSize = ctypes.sizeof(const.EVENT_TRACE_PROPERTIES)
99
+ properties_array[i] = ctypes.pointer(properties)
100
+
101
+ # Define the number of loggers variable
102
+ logger_count = ULONG(const.MAXIMUM_LOGGERS)
103
+
104
+ # Call QueryAllTraces
105
+ status = const.QueryAllTraces(properties_array, const.MAXIMUM_LOGGERS, ctypes.byref(logger_count))
106
+ if status != 0:
107
+ raise Exception(f"QueryAllTraces failed, error code: {status}")
108
+
109
+ # Extract session names
110
+ session_list: list = []
111
+ for i in range(logger_count.value):
112
+ logger_name = None
113
+ logfile_path = None
114
+
115
+ properties = properties_array[i].contents
116
+ if properties.LoggerNameOffset != 0:
117
+ logger_name_address = ctypes.addressof(properties) + properties.LoggerNameOffset
118
+ logger_name = ctypes.wstring_at(logger_name_address)
119
+ if properties.LogFileNameOffset != 0:
120
+ logfile_name_address = ctypes.addressof(properties) + properties.LogFileNameOffset
121
+ logfile_path = ctypes.wstring_at(logfile_name_address)
122
+
123
+ session_list.append({
124
+ 'session_name': logger_name,
125
+ 'log_file': logfile_path
126
+ })
127
+
128
+ return session_list
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.12.24
3
+ Version: 2.12.25
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=IWq2-3sezAvBANma6AYzXzywVzgI9rJOyd2ZKFBLQ1E,124
1
+ atomicshop/__init__.py,sha256=i0XAOpCKxA2g_BNalWhe-R5FvF3ui38CZEoR2TgPwIg,124
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
@@ -102,9 +102,10 @@ atomicshop/basics/threads.py,sha256=xvgdDJdmgN0wmmARoZ-H7Kvl1GOcEbvgaeGL4M3Hcx8,
102
102
  atomicshop/basics/timeit_template.py,sha256=fYLrk-X_dhdVtnPU22tarrhhvlggeW6FdKCXM8zkX68,405
103
103
  atomicshop/basics/tracebacks.py,sha256=cNfh_oAwF55kSIdqtv3boHZQIoQI8TajxkTnwJwpweI,535
104
104
  atomicshop/etw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
105
- atomicshop/etw/sessions.py,sha256=7RzlqOEc2zlikKgaNayCnR0IB-51PUrdMyU7uyoBKn4,582
106
- atomicshop/etw/trace.py,sha256=7xZ-Kj4-hIdVsaqXhpVtP0i8F6dND9ZMe0ZJWq3qtMk,4529
107
- atomicshop/etw/trace_dns.py,sha256=08xiTGpAAJ3qxobx-9uG49z5pR7BBsys6a_vrMh6JgE,5920
105
+ atomicshop/etw/providers.py,sha256=fVmWi-uGdtnsQTDpu_ty6dzx0GMhGokiST73LNBEJ38,129
106
+ atomicshop/etw/sessions.py,sha256=k3miewU278xn829cqDbsuH_bmZHPQE9-Zn-hINbxUSE,1330
107
+ atomicshop/etw/trace.py,sha256=tjBvV4RxCSn8Aoxj8NVxmqHekdECne_y4Zv2lbh11ak,5341
108
+ atomicshop/etw/trace_dns.py,sha256=f4homrWp4qMrmjC9UrEWjr9p9MrUg7SwOVbE22_IYgw,6728
108
109
  atomicshop/file_io/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
109
110
  atomicshop/file_io/csvs.py,sha256=y8cJtnlN-NNxNupzJgSeGq9aQ4wNxYLFPX9vNNlUiIc,5830
110
111
  atomicshop/file_io/docxs.py,sha256=6tcYFGp0vRsHR47VwcRqwhdt2DQOwrAUYhrwN996n9U,5117
@@ -136,7 +137,7 @@ atomicshop/mitm/engines/__reference_general/responder___reference_general.py,sha
136
137
  atomicshop/monitor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
137
138
  atomicshop/monitor/change_monitor.py,sha256=dGhk5bJPxLCHa2FOVkort99E7vjVojra9GlvhpcKSqE,7551
138
139
  atomicshop/monitor/checks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
139
- atomicshop/monitor/checks/dns.py,sha256=edO03gtGYb3tn8eV-wAKPELIkdCJvimjkO8PPF-ho-k,7150
140
+ atomicshop/monitor/checks/dns.py,sha256=YLCFoolq35dnzdnBnfUA2ag-4HfvzcHfRdm3mzX8R8o,7184
140
141
  atomicshop/monitor/checks/file.py,sha256=2tIDSlX2KZNc_9i9ji1tcOqupbFTIOj7cKXLyBEDWMk,3263
141
142
  atomicshop/monitor/checks/network.py,sha256=CGZWl4WlQrxayZeVF9JspJXwYA-zWx8ECWTVGSlXc98,3825
142
143
  atomicshop/monitor/checks/process_running.py,sha256=x66wd6-l466r8sbRQaIli0yswyGt1dH2DVXkGDL6O0Q,1891
@@ -169,8 +170,8 @@ atomicshop/wrappers/certauthw/certauthw.py,sha256=4WvhjANI7Kzqrr_nKmtA8Kf7B6rute
169
170
  atomicshop/wrappers/ctyping/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
170
171
  atomicshop/wrappers/ctyping/process_winapi.py,sha256=QcXL-ETtlSSkoT8F7pYle97ubGWsjYp8cx8HxkVMgAc,2762
171
172
  atomicshop/wrappers/ctyping/etw_winapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
172
- atomicshop/wrappers/ctyping/etw_winapi/const.py,sha256=-wGLmM8FUPrVOGeyEWnizlumkdX60Ziv6v7ANQd9xgM,1712
173
- atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py,sha256=T5gyTHk3BLTYKSnUKO4PS4h5xIVRrNrHKPL30r_N3HQ,1732
173
+ atomicshop/wrappers/ctyping/etw_winapi/const.py,sha256=YrAyXBamAmHoQgha7oXwH9g_EqeLYXRGPderuu9FRI8,2765
174
+ atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py,sha256=3DLVXpTeOyTND35T_dKGzKnlLVQ0R3zt3AEcW2bNLNc,5304
174
175
  atomicshop/wrappers/ctyping/msi_windows_installer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
175
176
  atomicshop/wrappers/ctyping/msi_windows_installer/base.py,sha256=Uu9SlWLsQQ6mjE-ek-ptHcmgiI3Ruah9bdZus70EaVY,4884
176
177
  atomicshop/wrappers/ctyping/msi_windows_installer/cabs.py,sha256=htzwb2ROYI8yyc82xApStckPS2yCcoyaw32yC15KROs,3285
@@ -259,8 +260,8 @@ atomicshop/wrappers/socketw/socket_server_tester.py,sha256=AhpurHJmP2kgzHaUbq5ey
259
260
  atomicshop/wrappers/socketw/socket_wrapper.py,sha256=aXBwlEIJhFT0-c4i8iNlFx2It9VpCEpsv--5Oqcpxao,11624
260
261
  atomicshop/wrappers/socketw/ssl_base.py,sha256=k4V3gwkbq10MvOH4btU4onLX2GNOsSfUAdcHmL1rpVE,2274
261
262
  atomicshop/wrappers/socketw/statistics_csv.py,sha256=t3dtDEfN47CfYVi0CW6Kc2QHTEeZVyYhc57IYYh5nmA,826
262
- atomicshop-2.12.24.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
263
- atomicshop-2.12.24.dist-info/METADATA,sha256=wjuGBnA-AbgpeRB_uDgPYzt5XbLF6mIT5yj721N4vi4,10479
264
- atomicshop-2.12.24.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
265
- atomicshop-2.12.24.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
266
- atomicshop-2.12.24.dist-info/RECORD,,
263
+ atomicshop-2.12.25.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
264
+ atomicshop-2.12.25.dist-info/METADATA,sha256=9B-DBn3RCaFkRPibGwrKm8FOiWIRdqjSifbGjXpi9z4,10479
265
+ atomicshop-2.12.25.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
266
+ atomicshop-2.12.25.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
267
+ atomicshop-2.12.25.dist-info/RECORD,,