atomicshop 2.14.2__py3-none-any.whl → 2.14.4__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.

Files changed (35) hide show
  1. atomicshop/__init__.py +1 -1
  2. atomicshop/datetimes.py +3 -2
  3. atomicshop/etws/providers.py +18 -2
  4. atomicshop/etws/sessions.py +1 -1
  5. atomicshop/etws/trace.py +5 -22
  6. atomicshop/etws/traces/trace_dns.py +17 -14
  7. atomicshop/etws/traces/trace_sysmon_process_creation.py +34 -22
  8. atomicshop/file_io/csvs.py +1 -1
  9. atomicshop/get_process_list.py +133 -0
  10. atomicshop/mitm/statistic_analyzer.py +376 -3
  11. atomicshop/monitor/change_monitor.py +1 -0
  12. atomicshop/monitor/checks/dns.py +2 -1
  13. atomicshop/process.py +3 -3
  14. atomicshop/process_poller/__init__.py +0 -0
  15. atomicshop/process_poller/pollers/__init__.py +0 -0
  16. atomicshop/process_poller/pollers/psutil_pywin32wmi_dll.py +95 -0
  17. atomicshop/process_poller/process_pool.py +208 -0
  18. atomicshop/process_poller/simple_process_pool.py +112 -0
  19. atomicshop/process_poller/tracer_base.py +45 -0
  20. atomicshop/process_poller/tracers/__init__.py +0 -0
  21. atomicshop/process_poller/tracers/event_log.py +46 -0
  22. atomicshop/process_poller/tracers/sysmon_etw.py +68 -0
  23. atomicshop/wrappers/ctyping/etw_winapi/const.py +130 -20
  24. atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py +141 -5
  25. atomicshop/wrappers/loggingw/reading.py +20 -19
  26. atomicshop/wrappers/pywin32w/win_event_log/subscribe.py +0 -2
  27. atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +3 -24
  28. atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +103 -0
  29. {atomicshop-2.14.2.dist-info → atomicshop-2.14.4.dist-info}/METADATA +1 -1
  30. {atomicshop-2.14.2.dist-info → atomicshop-2.14.4.dist-info}/RECORD +34 -24
  31. atomicshop/process_poller.py +0 -345
  32. /atomicshop/{process_name_cmd.py → get_process_name_cmd_dll.py} +0 -0
  33. {atomicshop-2.14.2.dist-info → atomicshop-2.14.4.dist-info}/LICENSE.txt +0 -0
  34. {atomicshop-2.14.2.dist-info → atomicshop-2.14.4.dist-info}/WHEEL +0 -0
  35. {atomicshop-2.14.2.dist-info → atomicshop-2.14.4.dist-info}/top_level.txt +0 -0
@@ -1,12 +1,137 @@
1
1
  import ctypes
2
+ from ctypes import wintypes
2
3
  from ctypes.wintypes import ULONG
3
4
  import uuid
5
+ from typing import Literal
4
6
 
5
7
  from . import const
8
+ from ....etws import providers
9
+
10
+ class ETWSessionExists(Exception):
11
+ pass
12
+
13
+
14
+ # Convert the GUID string to a GUID structure
15
+ def _string_to_guid(guid_string):
16
+ guid_string = guid_string.strip('{}') # Remove curly braces
17
+ parts = guid_string.split('-')
18
+ return const.GUID(
19
+ Data1=int(parts[0], 16),
20
+ Data2=int(parts[1], 16),
21
+ Data3=int(parts[2], 16),
22
+ Data4=(ctypes.c_ubyte * 8)(*[
23
+ int(parts[3][i:i+2], 16) for i in range(0, 4, 2)
24
+ ] + [
25
+ int(parts[4][i:i+2], 16) for i in range(0, 12, 2)
26
+ ])
27
+ )
28
+
29
+
30
+ # Set up the ETW session
31
+ def start_etw_session(
32
+ session_name: str,
33
+ provider_guid_list: list = None,
34
+ provider_name_list: list = None,
35
+ verbosity_mode: int = 4,
36
+ maximum_buffers: int = 38
37
+ ):
38
+ """
39
+ Start an ETW session and enable the specified provider.
40
+
41
+ :param session_name: The name of the session to start.
42
+ :param provider_guid_list: The GUID list of the providers to enable.
43
+ :param provider_name_list: The name list of the providers to enable.
44
+ :param verbosity_mode: The verbosity level of the events to capture.
45
+ 0 - Always: Capture all events. This is typically used for critical events that should always be logged.
46
+ 1 - Critical: Capture critical events that indicate a severe problem.
47
+ 2 - Error: Capture error events that indicate a problem but are not critical.
48
+ 3 - Warning: Capture warning events that indicate a potential problem.
49
+ 4 - Information: Capture informational events that are not indicative of problems.
50
+ 5 - Verbose: Capture detailed trace events for diagnostic purposes.
51
+ :param maximum_buffers: The maximum number of buffers to use.
52
+ 0 or 16: The default value of ETW class. If you put 0, it will be converted to 16 by default by ETW itself.
53
+ 38: The maximum number of buffers that can be used.
54
+
55
+ Event Handling Capacity:
56
+ 16 Buffers: With fewer buffers, the session can handle a smaller volume of events before needing to flush
57
+ the buffers to the log file or before a real-time consumer needs to process them. If the buffers fill up
58
+ quickly and cannot be processed in time, events might be lost.
59
+ 38 Buffers: With more buffers, the session can handle a higher volume of events. This reduces the
60
+ likelihood of losing events in high-traffic scenarios because more events can be held in memory before
61
+ they need to be processed or written to a log file.
62
+ Performance Considerations:
63
+ 16 Buffers: Requires less memory, but may be prone to event loss under heavy load if the buffers fill up
64
+ faster than they can be processed.
65
+ 38 Buffers: Requires more memory, but can improve reliability in capturing all events under heavy load by
66
+ providing more buffer space. However, it can also increase the memory footprint of the application or
67
+ system running the ETW session.
68
+ """
69
+
70
+ if not provider_guid_list and not provider_name_list:
71
+ raise ValueError("Either 'provider_guid_list' or 'provider_name_list' must be provided")
72
+ elif provider_guid_list and provider_name_list:
73
+ raise ValueError("Only one of 'provider_guid_list' or 'provider_name_list' must be provided")
74
+
75
+ if provider_name_list:
76
+ provider_guid_list = []
77
+ for provider_name in provider_name_list:
78
+ provider_guid_list.append(providers.get_provider_guid_by_name(provider_name))
79
+
80
+ properties_size = ctypes.sizeof(const.EVENT_TRACE_PROPERTIES) + (2 * wintypes.MAX_PATH)
81
+ properties = (ctypes.c_byte * properties_size)()
82
+ properties_ptr = ctypes.cast(properties, ctypes.POINTER(const.EVENT_TRACE_PROPERTIES))
83
+
84
+ # Initialize the EVENT_TRACE_PROPERTIES structure
85
+ properties_ptr.contents.Wnode.BufferSize = properties_size
86
+ properties_ptr.contents.Wnode.Guid = const.GUID()
87
+ properties_ptr.contents.Wnode.Flags = const.WNODE_FLAG_TRACED_GUID
88
+ properties_ptr.contents.Wnode.ClientContext = 1 # QPC clock resolution
89
+ properties_ptr.contents.BufferSize = 1024
90
+ properties_ptr.contents.MinimumBuffers = 1
91
+ properties_ptr.contents.MaximumBuffers = maximum_buffers
92
+ properties_ptr.contents.MaximumFileSize = 0
93
+ properties_ptr.contents.LogFileMode = const.EVENT_TRACE_REAL_TIME_MODE
94
+ properties_ptr.contents.FlushTimer = 1
95
+ properties_ptr.contents.EnableFlags = 0
96
+
97
+ # Start the ETW session
98
+ session_handle = wintypes.HANDLE()
99
+ status = ctypes.windll.advapi32.StartTraceW(
100
+ ctypes.byref(session_handle),
101
+ ctypes.c_wchar_p(session_name),
102
+ properties_ptr
103
+ )
104
+
105
+ if status != 0:
106
+ if status == 183:
107
+ raise ETWSessionExists(f"ETW session [{session_name}] already exists")
108
+ else:
109
+ raise Exception(f"StartTraceW failed with error {status}")
110
+
111
+ # Enable each provider
112
+ for provider_guid in provider_guid_list:
113
+ provider_guid_struct = _string_to_guid(provider_guid)
114
+ status = ctypes.windll.advapi32.EnableTraceEx2(
115
+ session_handle,
116
+ ctypes.byref(provider_guid_struct),
117
+ const.EVENT_CONTROL_CODE_ENABLE_PROVIDER,
118
+ verbosity_mode,
119
+ 0,
120
+ 0,
121
+ 0,
122
+ None
123
+ )
124
+
125
+ if status != 0:
126
+ raise Exception(f"EnableTraceEx2 failed for provider {provider_guid} with error {status}")
127
+
128
+ print("ETW session started successfully")
129
+
130
+ return session_handle
6
131
 
7
132
 
8
133
  # Function to stop and delete ETW session
9
- def stop_and_delete_etw_session(session_name) -> tuple[bool, int]:
134
+ def stop_and_delete_etw_session(session_name: str) -> tuple[bool, int]:
10
135
  """
11
136
  Stop and delete ETW session.
12
137
 
@@ -40,13 +165,19 @@ def stop_and_delete_etw_session(session_name) -> tuple[bool, int]:
40
165
  return True, status
41
166
 
42
167
 
43
- def get_all_providers() -> list[tuple[any, uuid.UUID]]:
168
+ def get_all_providers(key_as: Literal['name', 'guid'] = 'name') -> dict:
44
169
  """
45
170
  Get all ETW providers available on the system.
46
171
 
47
- :return: A list of tuples containing the provider name and GUID.
172
+ :param key_as: The key to use in the dictionary, either 'name' or 'guid'.
173
+ 'name': The provider name is used as the key, the guid as the value.
174
+ 'guid': The provider guid is used as the key, the name as the value.
175
+ :return: dict containing the provider name and GUID.
48
176
  """
49
177
 
178
+ if key_as not in ['name', 'guid']:
179
+ raise ValueError("key_as must be either 'name' or 'guid'")
180
+
50
181
  providers_info_size = ULONG(0)
51
182
  status = const.tdh.TdhEnumerateProviders(None, ctypes.byref(providers_info_size))
52
183
 
@@ -71,7 +202,7 @@ def get_all_providers() -> list[tuple[any, uuid.UUID]]:
71
202
  ctypes.addressof(providers_info.contents) + ctypes.sizeof(const.PROVIDER_ENUMERATION_INFO),
72
203
  ctypes.POINTER(const.PROVIDER_INFORMATION * provider_count))
73
204
 
74
- providers = []
205
+ providers: dict = {}
75
206
  for i in range(provider_count):
76
207
  provider = provider_array.contents[i]
77
208
  provider_name_offset = provider.ProviderNameOffset
@@ -79,7 +210,12 @@ def get_all_providers() -> list[tuple[any, uuid.UUID]]:
79
210
  ctypes.addressof(providers_info.contents) + provider_name_offset, ctypes.c_wchar_p)
80
211
  provider_name = provider_name_ptr.value
81
212
  provider_guid = uuid.UUID(bytes_le=bytes(provider.ProviderId))
82
- providers.append((provider_name, provider_guid))
213
+ provider_guid_string = str(provider_guid)
214
+
215
+ if key_as == 'name':
216
+ providers[provider_name] = provider_guid_string
217
+ elif key_as == 'guid':
218
+ providers[provider_guid_string] = provider_name
83
219
 
84
220
  return providers
85
221
 
@@ -1,6 +1,7 @@
1
1
  import os
2
2
  from typing import Literal, Union
3
3
  from pathlib import Path
4
+ import datetime
4
5
 
5
6
  from ... import filesystem, datetimes
6
7
  from ...file_io import csvs
@@ -11,7 +12,6 @@ def get_logs_paths(
11
12
  log_file_path: str = None,
12
13
  file_name_pattern: str = '*.*',
13
14
  date_pattern: str = None,
14
- log_type: Literal['csv'] = 'csv',
15
15
  latest_only: bool = False,
16
16
  previous_day_only: bool = False
17
17
  ):
@@ -36,7 +36,6 @@ def get_logs_paths(
36
36
  :param date_pattern: Pattern to match the date in the log file name.
37
37
  If specified, the function will get the log file by the date pattern.
38
38
  If not specified, the function will get the file date by file last modified time.
39
- :param log_type: Type of log to get.
40
39
  :param latest_only: Boolean, if True, only the latest log file path will be returned.
41
40
  :param previous_day_only: Boolean, if True, only the log file path from the previous day will be returned.
42
41
  """
@@ -46,9 +45,6 @@ def get_logs_paths(
46
45
  elif log_files_directory_path and log_file_path:
47
46
  raise ValueError('Both "log_files_directory_path" and "log_file_path" cannot be specified at the same time.')
48
47
 
49
- if log_type != 'csv':
50
- raise ValueError('Only "csv" log type is supported.')
51
-
52
48
  if latest_only and previous_day_only:
53
49
  raise ValueError('Both "latest_only" and "previous_day_only" cannot be True at the same time.')
54
50
 
@@ -75,16 +71,22 @@ def get_logs_paths(
75
71
  for file_index, single_file in enumerate(logs_files):
76
72
  # Get file name from current loop file path.
77
73
  current_file_name: str = Path(single_file['file_path']).name
74
+ logs_files[file_index]['file_name'] = current_file_name
75
+
78
76
  # Get the datetime object from the file name by the date pattern.
79
77
  try:
80
- datetime_object = datetimes.get_datetime_from_complex_string_by_pattern(
78
+ datetime_object, date_string, timestamp_float = datetimes.get_datetime_from_complex_string_by_pattern(
81
79
  current_file_name, date_pattern)
82
- timestamp_float = datetime_object.timestamp()
83
80
  # ValueError will be raised if the date pattern does not match the file name.
84
81
  except ValueError:
85
82
  timestamp_float = 0
83
+ datetime_object = None
84
+ date_string = None
85
+
86
86
  # Update the last modified time to the dictionary.
87
87
  logs_files[file_index]['last_modified'] = timestamp_float
88
+ logs_files[file_index]['datetime'] = datetime_object
89
+ logs_files[file_index]['date_string'] = date_string
88
90
 
89
91
  if timestamp_float > latest_timestamp:
90
92
  latest_timestamp = timestamp_float
@@ -95,6 +97,8 @@ def get_logs_paths(
95
97
  if single_file['last_modified'] == 0:
96
98
  latest_timestamp += 86400
97
99
  logs_files[file_index]['last_modified'] = latest_timestamp
100
+ logs_files[file_index]['datetime'] = datetime.datetime.fromtimestamp(latest_timestamp)
101
+ logs_files[file_index]['date_string'] = logs_files[file_index]['datetime'].strftime(date_pattern)
98
102
  break
99
103
 
100
104
  # Sort the files by the last modified time.
@@ -117,7 +121,7 @@ def get_logs_paths(
117
121
  return logs_files
118
122
 
119
123
 
120
- def get_logs(
124
+ def get_all_log_files_into_list(
121
125
  log_files_directory_path: str = None,
122
126
  log_file_path: str = None,
123
127
  file_name_pattern: str = '*.*',
@@ -127,9 +131,10 @@ def get_logs(
127
131
  remove_logs: bool = False,
128
132
  move_to_path: str = None,
129
133
  print_kwargs: dict = None
130
- ):
134
+ ) -> list:
131
135
  """
132
- This function gets the logs from the log files. Supports rotating files to get the logs by time.
136
+ This function gets the logs contents from the log files. Supports rotating files to get the logs by time.
137
+ All the contents will be merged into one list.
133
138
 
134
139
  :param log_files_directory_path: Path to the log files. Check the 'get_logs_paths' function for more details.
135
140
  :param log_file_path: Path to the log file. Check the 'get_logs_paths' function for more details.
@@ -144,8 +149,9 @@ def get_logs(
144
149
  'all' - Each CSV file has a header. Get the header from each file.
145
150
  :param remove_logs: Boolean, if True, the logs will be removed after getting them.
146
151
  :param move_to_path: Path to move the logs to.
147
-
148
152
  :param print_kwargs: Keyword arguments dict for 'print_api' function.
153
+
154
+ :return: List of dictionaries with the logs content.
149
155
  """
150
156
 
151
157
  if not print_kwargs:
@@ -162,8 +168,7 @@ def get_logs(
162
168
  log_files_directory_path=log_files_directory_path,
163
169
  log_file_path=log_file_path,
164
170
  file_name_pattern=file_name_pattern,
165
- date_pattern=date_pattern,
166
- log_type=log_type)
171
+ date_pattern=date_pattern)
167
172
 
168
173
  # Read all the logs.
169
174
  logs_content: list = list()
@@ -294,8 +299,7 @@ class LogReader:
294
299
  # If the existing logs file count is 0, it means that this is the first check. We need to get the current count.
295
300
  if self._existing_logs_file_count == 0:
296
301
  self._existing_logs_file_count = len(get_logs_paths(
297
- log_file_path=self.log_file_path,
298
- log_type='csv'
302
+ log_file_path=self.log_file_path
299
303
  ))
300
304
 
301
305
  # If the count is still 0, then there are no logs to read.
@@ -311,7 +315,6 @@ class LogReader:
311
315
  latest_statistics_file_path_object = get_logs_paths(
312
316
  log_file_path=self.log_file_path,
313
317
  date_pattern=self.date_pattern,
314
- log_type='csv',
315
318
  latest_only=True
316
319
  )
317
320
 
@@ -327,7 +330,6 @@ class LogReader:
327
330
  previous_day_statistics_file_path = get_logs_paths(
328
331
  log_file_path=self.log_file_path,
329
332
  date_pattern=self.date_pattern,
330
- log_type='csv',
331
333
  previous_day_only=True
332
334
  )[0]['file_path']
333
335
  # If you get IndexError, it means that there are no previous day logs to read.
@@ -336,8 +338,7 @@ class LogReader:
336
338
 
337
339
  # Count all the rotated files.
338
340
  current_log_files_count: int = len(get_logs_paths(
339
- log_file_path=self.log_file_path,
340
- log_type='csv'
341
+ log_file_path=self.log_file_path
341
342
  ))
342
343
 
343
344
  # If the count of the log files is greater than the existing logs file count, it means that the rotation
@@ -205,8 +205,6 @@ def start_subscription(
205
205
  Context={'event_queue': event_queue}
206
206
  )
207
207
 
208
- print("Listening for new process creation events...")
209
-
210
208
  try:
211
209
  while True:
212
210
  time.sleep(1)
@@ -50,29 +50,8 @@ class ProcessCreateSubscriber(subscribe.EventLogSubscriber):
50
50
 
51
51
  data = super().emit(timeout=timeout)
52
52
 
53
- event_dict: dict = {
54
- 'user_sid': data.get("SubjectUserSid", "Unknown"),
55
- 'user_name': data.get("SubjectUserName", "Unknown"),
56
- 'domain': data.get("SubjectDomainName", "Unknown"),
57
- 'pid_hex': data.get("NewProcessId", "0"),
58
- 'process_name': data.get("NewProcessName", "Unknown"),
59
- 'command_line': data.get("CommandLine", None),
60
- 'parent_pid_hex': data.get("ProcessId", "0"),
61
- 'parent_process_name': data.get("ParentProcessName", "Unknown")
62
- }
63
-
64
- try:
65
- process_id = int(event_dict['pid_hex'], 16)
66
- except ValueError:
67
- process_id = "Unknown"
68
-
69
- try:
70
- parent_pid = int(event_dict['parent_pid_hex'], 16)
71
- except ValueError:
72
- parent_pid = "Unknown"
73
-
74
- event_dict['pid'] = process_id
75
- event_dict['parent_pid'] = parent_pid
53
+ data['NewProcessIdInt'] = int(data['NewProcessId'], 16)
54
+ data['ParentProcessIdInt'] = int(data['ProcessId'], 16)
76
55
 
77
56
  # if user_sid != "Unknown":
78
57
  # try:
@@ -80,7 +59,7 @@ class ProcessCreateSubscriber(subscribe.EventLogSubscriber):
80
59
  # except Exception as e:
81
60
  # print(f"Error looking up account SID: {e}")
82
61
 
83
- return event_dict
62
+ return data
84
63
 
85
64
 
86
65
  def enable_audit_process_creation(print_kwargs: dict = None):
@@ -0,0 +1,103 @@
1
+ import subprocess
2
+
3
+ from .. import subscribe
4
+ from .....print_api import print_api
5
+
6
+
7
+ LOG_CHANNEL: str = 'Security'
8
+ EVENT_ID: int = 4689
9
+
10
+
11
+ class ProcessTerminateSubscriber(subscribe.EventLogSubscriber):
12
+ """
13
+ Class for subscribing to Windows Event Log events related to process termination.
14
+
15
+ Usage:
16
+ from atomicshop.wrappers.pywin32w.win_event_log.subscribes import process_terminate
17
+
18
+ process_terminate_subscriber = process_terminate.ProcessTerminateSubscriber()
19
+ process_terminate_subscriber.start()
20
+
21
+ while True:
22
+ event = process_terminate_subscriber.emit()
23
+ print(event)
24
+ """
25
+ def __init__(self):
26
+ super().__init__(log_channel=LOG_CHANNEL, event_id=EVENT_ID)
27
+
28
+ def start(self):
29
+ """Start the subscription process."""
30
+ enable_audit_process_termination()
31
+
32
+ super().start()
33
+
34
+ def stop(self):
35
+ """Stop the subscription process."""
36
+ super().stop()
37
+
38
+ def emit(self, timeout: float = None) -> dict:
39
+ """
40
+ Get the next event from the event queue.
41
+
42
+ :param timeout: The maximum time (in seconds) to wait for an event.
43
+ If None, the function will block until an event is available.
44
+ :return: A dictionary containing the event data.
45
+ """
46
+
47
+ data = super().emit(timeout=timeout)
48
+
49
+ data['ProcessIdInt'] = int(data['ProcessId'], 16)
50
+
51
+ return data
52
+
53
+
54
+ def enable_audit_process_termination(print_kwargs: dict = None):
55
+ """
56
+ Enable the 'Audit Process Termination' policy.
57
+
58
+ :param print_kwargs: Optional keyword arguments for the print function.
59
+ """
60
+ if is_audit_process_termination_enabled():
61
+ print_api("Audit Process Termination is already enabled.", color='yellow', **(print_kwargs or {}))
62
+ return
63
+
64
+ audit_policy_command = [
65
+ "auditpol", "/set", "/subcategory:Process Termination", "/success:enable", "/failure:enable"
66
+ ]
67
+ try:
68
+ subprocess.run(audit_policy_command, check=True)
69
+ print_api("Successfully enabled 'Audit Process Termination'.", color='green', **(print_kwargs or {}))
70
+ except subprocess.CalledProcessError as e:
71
+ print_api(f"Failed to enable 'Audit Process Termination': {e}", error_type=True, color='red', **(print_kwargs or {}))
72
+ raise e
73
+
74
+
75
+ def is_audit_process_termination_enabled(print_kwargs: dict = None) -> bool:
76
+ """
77
+ Check if the 'Audit Process Termination' policy is enabled.
78
+
79
+ :param print_kwargs: Optional keyword arguments for the print function.
80
+ """
81
+ # Command to check the "Audit Process Creation" policy
82
+ audit_policy_check_command = [
83
+ "auditpol", "/get", "/subcategory:Process Termination"
84
+ ]
85
+ try:
86
+ result = subprocess.run(audit_policy_check_command, check=True, capture_output=True, text=True)
87
+ output = result.stdout
88
+ # print_api(output) # Print the output for inspection
89
+
90
+ if "Process Termination" in output and "Success and Failure" in output:
91
+ # print_api(
92
+ # "'Audit Process Termination' is enabled for both success and failure.",
93
+ # color='green', **(print_kwargs or {}))
94
+ return True
95
+ else:
96
+ # print_api(output, **(print_kwargs or {}))
97
+ # print_api(
98
+ # "'Audit Process Termination' is not fully enabled. Check the output above for details.",
99
+ # color='yellow', **(print_kwargs or {}))
100
+ return False
101
+ except subprocess.CalledProcessError as e:
102
+ print_api(f"Failed to check 'Audit Process Termination': {e}", color='red', error_type=True, **(print_kwargs or {}))
103
+ return False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.14.2
3
+ Version: 2.14.4
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=z4rThLLSu1i3Wlh2xQO9kTZiAnom3boVcidQ2m4F8V0,123
1
+ atomicshop/__init__.py,sha256=tunTjRW84u7Nao5t0Z6ZWFYrQDUW_zun_a86yEIubts,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
@@ -8,7 +8,7 @@ atomicshop/command_line_processing.py,sha256=u5yT9Ger_cu7ni5ID0VFlRbVD46ARHeNC9t
8
8
  atomicshop/config_init.py,sha256=z2RXD_mw9nQlAOpuGry1h9QT-2LhNscXgGAktN3dCVQ,2497
9
9
  atomicshop/console_output.py,sha256=AOSJjrRryE97PAGtgDL03IBtWSi02aNol8noDnW3k6M,4667
10
10
  atomicshop/console_user_response.py,sha256=31HIy9QGXa7f-GVR8MzJauQ79E_ZqAeagF3Ks4GGdDU,3234
11
- atomicshop/datetimes.py,sha256=olsL01S5tkXk4WPzucxujqgLOh198BLgJntDnGYukRU,15533
11
+ atomicshop/datetimes.py,sha256=wZ75JS6Aq5kTQrCSrjCwBrT-KPO7Xu9_BRWKrY8uU3c,15645
12
12
  atomicshop/diff_check.py,sha256=RJvzJhyYAZyRPKVDk1dS7UwZCx0kq__WDZ6N0rNfZUY,27110
13
13
  atomicshop/dns.py,sha256=h4uZKoz4wbBlLOOduL1GtRcTm-YpiPnGOEGxUm7hhOI,2140
14
14
  atomicshop/domains.py,sha256=Rxu6JhhMqFZRcoFs69IoEd1PtYca0lMCG6F1AomP7z4,3197
@@ -16,6 +16,8 @@ atomicshop/emails.py,sha256=I0KyODQpIMEsNRi9YWSOL8EUPBiWyon3HRdIuSj3AEU,1410
16
16
  atomicshop/file_types.py,sha256=-0jzQMRlmU1AP9DARjk-HJm1tVE22E6ngP2mRblyEjY,763
17
17
  atomicshop/filesystem.py,sha256=202ue2LkjI1KdaxvB_RHV-2eIczy2-caZGLO4PSePik,53887
18
18
  atomicshop/functions.py,sha256=pK8hoCE9z61PtWCxQJsda7YAphrLH1wxU5x-1QJP-sY,499
19
+ atomicshop/get_process_list.py,sha256=hi1NOG-i8S6EcyQ6LTfP4pdxqRfjEijz9SZ5nEbcM9Q,6076
20
+ atomicshop/get_process_name_cmd_dll.py,sha256=CtaSp3mgxxJKCCVW8BLx6BJNx4giCklU_T7USiCEwfc,5162
19
21
  atomicshop/hashing.py,sha256=Le8qGFyt3_wX-zGTeQShz7L2HL_b6nVv9PnawjglyHo,3474
20
22
  atomicshop/http_parse.py,sha256=nrf2rZcprLqtW8HVrV7TCZ1iTBcWRRy-mXIlAOzcaJs,9703
21
23
  atomicshop/inspect_wrapper.py,sha256=sGRVQhrJovNygHTydqJj0hxES-aB2Eg9KbIk3G31apw,11429
@@ -25,9 +27,7 @@ atomicshop/on_exit.py,sha256=Wf1iy2e0b0Zu7oRxrct3VkLdQ_x9B32-z_JerKTt9Z0,5493
25
27
  atomicshop/pbtkmultifile_argparse.py,sha256=aEk8nhvoQVu-xyfZosK3ma17CwIgOjzO1erXXdjwtS4,4574
26
28
  atomicshop/permissions.py,sha256=P6tiUKV-Gw-c3ePEVsst9bqWaHJbB4ZlJB4xbDYVpEs,4436
27
29
  atomicshop/print_api.py,sha256=DhbCQd0MWZZ5GYEk4oTu1opRFC-b31g1VWZgTGewG2Y,11568
28
- atomicshop/process.py,sha256=R1BtXWjG2g2Q3WlsyhbIlXZz0UkQeagY7fQyBOIX_DM,15951
29
- atomicshop/process_name_cmd.py,sha256=CtaSp3mgxxJKCCVW8BLx6BJNx4giCklU_T7USiCEwfc,5162
30
- atomicshop/process_poller.py,sha256=17sc332AcTfSVPorjYsgRwNm75rLCqvpOQsieMwLMKU,16105
30
+ atomicshop/process.py,sha256=U2gyRl0bw2138y-rOMABMVptRvAL81ZfX1JyfxJI_Oo,15973
31
31
  atomicshop/python_file_patcher.py,sha256=kd3rBWvTcosLEk-7TycNdfKW9fZbe161iVwmH4niUo0,5515
32
32
  atomicshop/python_functions.py,sha256=zJg4ogUwECxrDD7xdDN5JikIUctITM5lsyabr_ZNsRw,4435
33
33
  atomicshop/question_answer_engine.py,sha256=DuOn7QEgKKfqZu2cR8mVeFIfFgayfBHiW-jY2VPq_Fo,841
@@ -104,14 +104,14 @@ atomicshop/basics/timeit_template.py,sha256=fYLrk-X_dhdVtnPU22tarrhhvlggeW6FdKCX
104
104
  atomicshop/basics/tracebacks.py,sha256=cNfh_oAwF55kSIdqtv3boHZQIoQI8TajxkTnwJwpweI,535
105
105
  atomicshop/etws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
106
106
  atomicshop/etws/const.py,sha256=v3x_IdCYeSKbCGywiZFOZln80ldpwKW5nuMDuUe51Jg,1257
107
- atomicshop/etws/providers.py,sha256=fVmWi-uGdtnsQTDpu_ty6dzx0GMhGokiST73LNBEJ38,129
108
- atomicshop/etws/sessions.py,sha256=k3miewU278xn829cqDbsuH_bmZHPQE9-Zn-hINbxUSE,1330
109
- atomicshop/etws/trace.py,sha256=v2yA3FicR9WIg5n5KlZEuYbLAzTTjiDk7avWxcEjwp8,8439
107
+ atomicshop/etws/providers.py,sha256=CXNx8pYdjtpLIpA66IwrnE64XhY4U5ExnFBMLEb8Uzk,547
108
+ atomicshop/etws/sessions.py,sha256=b_KeiOvgOBJezJokN81TRlrvJiQNJlIWN4Z6UVjuxP0,1335
109
+ atomicshop/etws/trace.py,sha256=WMOjdazK97UcIdhVgcnjh98OCbuEJcnm1Z_yPp_nE2c,7258
110
110
  atomicshop/etws/traces/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
111
- atomicshop/etws/traces/trace_dns.py,sha256=-bw7JGDeAl2UtNGoSPeD_gh6ij4IGAbPdB8VWip8fXc,5960
112
- atomicshop/etws/traces/trace_sysmon_process_creation.py,sha256=WdlQiOfRZC-_PpuE6BkOw5zB0DLc3fhVrANyLrgfCac,4833
111
+ atomicshop/etws/traces/trace_dns.py,sha256=rWQ8bv8eMHBRRkA8oxO9caYqj0h4Emw4aZXmoI3Q6fg,6292
112
+ atomicshop/etws/traces/trace_sysmon_process_creation.py,sha256=OM-bkK38uYMwWLZKNOTDa0Xdk3sO6sqsxoMUIiPvm5g,4656
113
113
  atomicshop/file_io/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
114
- atomicshop/file_io/csvs.py,sha256=y8cJtnlN-NNxNupzJgSeGq9aQ4wNxYLFPX9vNNlUiIc,5830
114
+ atomicshop/file_io/csvs.py,sha256=eS2SSGwcC1MlRPPgoqyFyE-qqH2esUWQvv3wWLMiOuA,5876
115
115
  atomicshop/file_io/docxs.py,sha256=6tcYFGp0vRsHR47VwcRqwhdt2DQOwrAUYhrwN996n9U,5117
116
116
  atomicshop/file_io/file_io.py,sha256=FOZ6_PjOASxSDHESe4fwDv5miXYR10OHTxkxtEHoZYQ,6555
117
117
  atomicshop/file_io/jsons.py,sha256=q9ZU8slBKnHLrtn3TnbK1qxrRpj5ZvCm6AlsFzoANjo,5303
@@ -126,7 +126,7 @@ atomicshop/mitm/initialize_engines.py,sha256=UGdT5DKYNri3MNOxESP7oeSxYiUDrVilJ4j
126
126
  atomicshop/mitm/initialize_mitm_server.py,sha256=5JGkyvAvz1sJVeRGMJWSQiQ-VOdrU-NJn633oxQe0cw,13143
127
127
  atomicshop/mitm/message.py,sha256=u2U2f2SOHdBNU-6r1Ik2W14ai2EOwxUV4wVfGZA098k,1732
128
128
  atomicshop/mitm/shared_functions.py,sha256=PaK_sbnEA5zo9k2ktEOKLmvo-6wRUunxzSNRr41uXIQ,1924
129
- atomicshop/mitm/statistic_analyzer.py,sha256=WvTal-Aox-enM-5jYtFqiTplNquS4VMnmQYNEIXvZZA,23552
129
+ atomicshop/mitm/statistic_analyzer.py,sha256=ctsf-MBIUvG4-R0K4gFQyi_b42-VCq-5s7hgO9jMOes,38415
130
130
  atomicshop/mitm/engines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
131
131
  atomicshop/mitm/engines/create_module_template.py,sha256=tRjVSm1sD6FzML71Qbuwvita0qsusdFGm8NZLsZ-XMs,4853
132
132
  atomicshop/mitm/engines/create_module_template_example.py,sha256=X5xhvbV6-g9jU_bQVhf_crZmaH50LRWz3bS-faQ18ds,489
@@ -139,13 +139,22 @@ atomicshop/mitm/engines/__reference_general/parser___reference_general.py,sha256
139
139
  atomicshop/mitm/engines/__reference_general/recorder___reference_general.py,sha256=KENDVf9OwXD9gwSh4B1XxACCe7iHYjrvnW1t6F64wdE,695
140
140
  atomicshop/mitm/engines/__reference_general/responder___reference_general.py,sha256=1AM49UaFTKA0AHw-k3SV3uH3QbG-o6ux0c-GoWkKNU0,6993
141
141
  atomicshop/monitor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
142
- atomicshop/monitor/change_monitor.py,sha256=dGhk5bJPxLCHa2FOVkort99E7vjVojra9GlvhpcKSqE,7551
142
+ atomicshop/monitor/change_monitor.py,sha256=K5NlVp99XIDDPnQQMdru4BDmua_DtcDIhVAzkTOvD5s,7673
143
143
  atomicshop/monitor/checks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
144
- atomicshop/monitor/checks/dns.py,sha256=clslElMi2HZaO3G1nXt2t0O2Yj0vFsJd6CXRdIXCGJM,7038
144
+ atomicshop/monitor/checks/dns.py,sha256=GHBQ2GEPaU3hAmK6l2vM2PKTcBNzDDF9ThZixqnl9Qk,7108
145
145
  atomicshop/monitor/checks/file.py,sha256=2tIDSlX2KZNc_9i9ji1tcOqupbFTIOj7cKXLyBEDWMk,3263
146
146
  atomicshop/monitor/checks/network.py,sha256=CGZWl4WlQrxayZeVF9JspJXwYA-zWx8ECWTVGSlXc98,3825
147
147
  atomicshop/monitor/checks/process_running.py,sha256=x66wd6-l466r8sbRQaIli0yswyGt1dH2DVXkGDL6O0Q,1891
148
148
  atomicshop/monitor/checks/url.py,sha256=1PvKt_d7wFg7rDMFpUejAQhj0mqWsmlmrNfjNAV2G4g,4123
149
+ atomicshop/process_poller/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
150
+ atomicshop/process_poller/process_pool.py,sha256=1CaG6Cov-Pt_kZohfFeQFT42YBnEwNBA6ge55dxok_8,9600
151
+ atomicshop/process_poller/simple_process_pool.py,sha256=hJkrn-efetLjyC8CevAFcsiKwBBKS8onYbf2ygq2J18,4540
152
+ atomicshop/process_poller/tracer_base.py,sha256=IOiHcnmF-MccOSCErixN5mve9RifZ9cPnGVHCIRchrs,1091
153
+ atomicshop/process_poller/pollers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
154
+ atomicshop/process_poller/pollers/psutil_pywin32wmi_dll.py,sha256=XRRfOIy62iOYU8IKRcyECWiL0rqQ35DeYbPsv_SHDVM,4510
155
+ atomicshop/process_poller/tracers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
156
+ atomicshop/process_poller/tracers/event_log.py,sha256=Ob5v18VPZ__PN8TP6aJJjQZcDMwfGA2pIKwKjrl5j3k,1417
157
+ atomicshop/process_poller/tracers/sysmon_etw.py,sha256=zn5YGX0Uro_Om7Gp1O4r0nlP1cR7BX1nYQmELPLZc9I,2500
149
158
  atomicshop/ssh_scripts/process_from_ipv4.py,sha256=uDBKZ2Ds20614JW1xMLr4IPB-z1LzIwy6QH5-SJ4j0s,1681
150
159
  atomicshop/ssh_scripts/process_from_port.py,sha256=uDTkVh4zc3HOTTGv1Et3IxM3PonDJCPuFRL6rnZDQZ4,1389
151
160
  atomicshop/startup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -175,8 +184,8 @@ atomicshop/wrappers/certauthw/certauthw.py,sha256=4WvhjANI7Kzqrr_nKmtA8Kf7B6rute
175
184
  atomicshop/wrappers/ctyping/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
176
185
  atomicshop/wrappers/ctyping/process_winapi.py,sha256=QcXL-ETtlSSkoT8F7pYle97ubGWsjYp8cx8HxkVMgAc,2762
177
186
  atomicshop/wrappers/ctyping/etw_winapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
178
- atomicshop/wrappers/ctyping/etw_winapi/const.py,sha256=jq5nms2qu4FsuXuq3vaHjz9W4ILt9GY-C7CQ8VKcpyg,5764
179
- atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py,sha256=3DLVXpTeOyTND35T_dKGzKnlLVQ0R3zt3AEcW2bNLNc,5304
187
+ atomicshop/wrappers/ctyping/etw_winapi/const.py,sha256=stZHZ7tSiSAs04ikr7uH-Td_yBXxsF-bp2Q0F3K2fsM,9543
188
+ atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py,sha256=Iwd0wIuoxpjMaaOfZZtT1bPtDTsMO8jjItBE5bvkocM,11546
180
189
  atomicshop/wrappers/ctyping/msi_windows_installer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
181
190
  atomicshop/wrappers/ctyping/msi_windows_installer/base.py,sha256=Uu9SlWLsQQ6mjE-ek-ptHcmgiI3Ruah9bdZus70EaVY,4884
182
191
  atomicshop/wrappers/ctyping/msi_windows_installer/cabs.py,sha256=htzwb2ROYI8yyc82xApStckPS2yCcoyaw32yC15KROs,3285
@@ -228,7 +237,7 @@ atomicshop/wrappers/loggingw/formatters.py,sha256=mUtcJJfmhLNrwUVYShXTmdu40dBaJu
228
237
  atomicshop/wrappers/loggingw/handlers.py,sha256=2A_3Qy1B0RvVWZmQocAB6CmpqlXoKJ-yi6iBWG2jNLo,8274
229
238
  atomicshop/wrappers/loggingw/loggers.py,sha256=DHOOTAtqkwn1xgvLHSkOiBm6yFGNuQy1kvbhG-TDog8,2374
230
239
  atomicshop/wrappers/loggingw/loggingw.py,sha256=m6YySEedP3_4Ik1S_uGMxETSbmRkmMYmAZxhHBlXSlo,16616
231
- atomicshop/wrappers/loggingw/reading.py,sha256=bsSUM9_epMO2L-lHBEULFxeqdxXOHfICt-1BtQZn7lA,16712
240
+ atomicshop/wrappers/loggingw/reading.py,sha256=wse-38zUDHB3HUB28R8Ah_Ig3Wxt2tChapKtu-yyy2E,17036
232
241
  atomicshop/wrappers/nodejsw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
233
242
  atomicshop/wrappers/nodejsw/install_nodejs.py,sha256=QZg-R2iTQt7kFb8wNtnTmwraSGwvUs34JIasdbNa7ZU,5154
234
243
  atomicshop/wrappers/playwrightw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -251,9 +260,10 @@ atomicshop/wrappers/pywin32w/console.py,sha256=LstHajPLgXp9qQxFNR44QfH10nOnNp3bC
251
260
  atomicshop/wrappers/pywin32w/winshell.py,sha256=i2bKiMldPU7_azsD5xGQDdMwjaM7suKJd3k0Szmcs6c,723
252
261
  atomicshop/wrappers/pywin32w/wmi_win32process.py,sha256=qMzXtJ5hBZ5ydAyqpDbSx0nO2RJQL95HdmV5SzNKMhk,6826
253
262
  atomicshop/wrappers/pywin32w/win_event_log/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
254
- atomicshop/wrappers/pywin32w/win_event_log/subscribe.py,sha256=a0SqjtUfo-fVR5jlsoygFlDrjHelOKgCBvia3suyzW8,8217
263
+ atomicshop/wrappers/pywin32w/win_event_log/subscribe.py,sha256=FYo2X0Xm3lb3GIdIt_8usoj7JPSDWj0iwsIJ4OwZLQM,8156
255
264
  atomicshop/wrappers/pywin32w/win_event_log/subscribes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
256
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py,sha256=_no1MnXjhLgOi9Y7xc7HHgTe6sjZkHIIhcVCd5BKZgM,6865
265
+ atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py,sha256=1PrPiDiuiVfzfzN5BUuxMfUoCgGW7RGgH6HVrjpTnQc,6064
266
+ atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py,sha256=0k09fiAwKDJO404bjxUWSSSLOiNANl-VTJDD_YLq-I8,3763
257
267
  atomicshop/wrappers/pywin32w/win_event_log/subscribes/schannel_logging.py,sha256=8nxIcNcbeEuvoBwhujgh7-oIpL9A6J-gg1NM8hOGAVA,3442
258
268
  atomicshop/wrappers/socketw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
259
269
  atomicshop/wrappers/socketw/accepter.py,sha256=HQC1EyZmyUtVEfFbaBkHCE-VZp6RWyd9mEqAkgsE1fk,1749
@@ -271,8 +281,8 @@ atomicshop/wrappers/socketw/socket_server_tester.py,sha256=AhpurHJmP2kgzHaUbq5ey
271
281
  atomicshop/wrappers/socketw/socket_wrapper.py,sha256=aXBwlEIJhFT0-c4i8iNlFx2It9VpCEpsv--5Oqcpxao,11624
272
282
  atomicshop/wrappers/socketw/ssl_base.py,sha256=k4V3gwkbq10MvOH4btU4onLX2GNOsSfUAdcHmL1rpVE,2274
273
283
  atomicshop/wrappers/socketw/statistics_csv.py,sha256=t3dtDEfN47CfYVi0CW6Kc2QHTEeZVyYhc57IYYh5nmA,826
274
- atomicshop-2.14.2.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
275
- atomicshop-2.14.2.dist-info/METADATA,sha256=VIgp-Go_u3KNgCb_tRAE6XcD9IyNa2lHdn0C2WFmscY,10478
276
- atomicshop-2.14.2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
277
- atomicshop-2.14.2.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
278
- atomicshop-2.14.2.dist-info/RECORD,,
284
+ atomicshop-2.14.4.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
285
+ atomicshop-2.14.4.dist-info/METADATA,sha256=fjxtj_SzmyjVK6o_Z08jX-lLJoz7m_vYNPvn0fCoFYU,10478
286
+ atomicshop-2.14.4.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
287
+ atomicshop-2.14.4.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
288
+ atomicshop-2.14.4.dist-info/RECORD,,