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.
- atomicshop/__init__.py +1 -1
- atomicshop/datetimes.py +3 -2
- atomicshop/etws/providers.py +18 -2
- atomicshop/etws/sessions.py +1 -1
- atomicshop/etws/trace.py +5 -22
- atomicshop/etws/traces/trace_dns.py +17 -14
- atomicshop/etws/traces/trace_sysmon_process_creation.py +34 -22
- atomicshop/file_io/csvs.py +1 -1
- atomicshop/get_process_list.py +133 -0
- atomicshop/mitm/statistic_analyzer.py +376 -3
- atomicshop/monitor/change_monitor.py +1 -0
- atomicshop/monitor/checks/dns.py +2 -1
- atomicshop/process.py +3 -3
- atomicshop/process_poller/__init__.py +0 -0
- atomicshop/process_poller/pollers/__init__.py +0 -0
- atomicshop/process_poller/pollers/psutil_pywin32wmi_dll.py +95 -0
- atomicshop/process_poller/process_pool.py +208 -0
- atomicshop/process_poller/simple_process_pool.py +112 -0
- atomicshop/process_poller/tracer_base.py +45 -0
- atomicshop/process_poller/tracers/__init__.py +0 -0
- atomicshop/process_poller/tracers/event_log.py +46 -0
- atomicshop/process_poller/tracers/sysmon_etw.py +68 -0
- atomicshop/wrappers/ctyping/etw_winapi/const.py +130 -20
- atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py +141 -5
- atomicshop/wrappers/loggingw/reading.py +20 -19
- atomicshop/wrappers/pywin32w/win_event_log/subscribe.py +0 -2
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +3 -24
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +103 -0
- {atomicshop-2.14.2.dist-info → atomicshop-2.14.4.dist-info}/METADATA +1 -1
- {atomicshop-2.14.2.dist-info → atomicshop-2.14.4.dist-info}/RECORD +34 -24
- atomicshop/process_poller.py +0 -345
- /atomicshop/{process_name_cmd.py → get_process_name_cmd_dll.py} +0 -0
- {atomicshop-2.14.2.dist-info → atomicshop-2.14.4.dist-info}/LICENSE.txt +0 -0
- {atomicshop-2.14.2.dist-info → atomicshop-2.14.4.dist-info}/WHEEL +0 -0
- {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(
|
|
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
|
-
:
|
|
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
|
-
|
|
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
|
|
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
|
|
@@ -50,29 +50,8 @@ class ProcessCreateSubscriber(subscribe.EventLogSubscriber):
|
|
|
50
50
|
|
|
51
51
|
data = super().emit(timeout=timeout)
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
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
|
|
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,4 +1,4 @@
|
|
|
1
|
-
atomicshop/__init__.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
108
|
-
atomicshop/etws/sessions.py,sha256=
|
|
109
|
-
atomicshop/etws/trace.py,sha256=
|
|
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
|
|
112
|
-
atomicshop/etws/traces/trace_sysmon_process_creation.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
179
|
-
atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
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.
|
|
275
|
-
atomicshop-2.14.
|
|
276
|
-
atomicshop-2.14.
|
|
277
|
-
atomicshop-2.14.
|
|
278
|
-
atomicshop-2.14.
|
|
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,,
|