atomicshop 2.12.23__py3-none-any.whl → 2.12.24__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/etw/sessions.py +14 -0
- atomicshop/etw/{etw.py → trace.py} +17 -14
- atomicshop/etw/{dns_trace.py → trace_dns.py} +2 -2
- atomicshop/monitor/checks/dns.py +1 -1
- atomicshop/on_exit.py +175 -0
- atomicshop/process_name_cmd.py +3 -4
- atomicshop/process_poller.py +1 -2
- atomicshop/wrappers/ctyping/etw_winapi/__init__.py +0 -0
- atomicshop/wrappers/ctyping/etw_winapi/const.py +57 -0
- atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py +37 -0
- atomicshop/wrappers/pywin32w/console.py +34 -0
- {atomicshop-2.12.23.dist-info → atomicshop-2.12.24.dist-info}/METADATA +1 -1
- {atomicshop-2.12.23.dist-info → atomicshop-2.12.24.dist-info}/RECORD +17 -13
- atomicshop/basics/atexits.py +0 -64
- atomicshop/monitor/checks/hash.py +0 -56
- {atomicshop-2.12.23.dist-info → atomicshop-2.12.24.dist-info}/LICENSE.txt +0 -0
- {atomicshop-2.12.23.dist-info → atomicshop-2.12.24.dist-info}/WHEEL +0 -0
- {atomicshop-2.12.23.dist-info → atomicshop-2.12.24.dist-info}/top_level.txt +0 -0
atomicshop/__init__.py
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from ..wrappers.ctyping.etw_winapi import etw_functions
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def stop_and_delete(session_name) -> tuple[bool, int]:
|
|
5
|
+
"""
|
|
6
|
+
Stop and delete ETW session.
|
|
7
|
+
|
|
8
|
+
:param session_name: The name of the session to stop and delete.
|
|
9
|
+
:return: A tuple containing a boolean indicating success and an integer status code.
|
|
10
|
+
True, 0: If the session was stopped and deleted successfully.
|
|
11
|
+
False, <status>: If the session could not be stopped and deleted and the status code, why it failed.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
return etw_functions.stop_and_delete_etw_session(session_name)
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import queue
|
|
2
|
+
import sys
|
|
2
3
|
|
|
3
4
|
# Import FireEye Event Tracing library.
|
|
4
5
|
import etw
|
|
5
6
|
|
|
6
|
-
from ..
|
|
7
|
+
from ..print_api import print_api
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
class EventTrace(etw.ETW):
|
|
@@ -12,9 +13,8 @@ class EventTrace(etw.ETW):
|
|
|
12
13
|
providers: list,
|
|
13
14
|
event_callback=None,
|
|
14
15
|
event_id_filters: list = None,
|
|
15
|
-
session_name: str = None
|
|
16
|
-
|
|
17
|
-
):
|
|
16
|
+
session_name: str = None
|
|
17
|
+
):
|
|
18
18
|
"""
|
|
19
19
|
:param providers: List of tuples with provider name and provider GUID.
|
|
20
20
|
tuple[0] = provider name
|
|
@@ -23,7 +23,8 @@ class EventTrace(etw.ETW):
|
|
|
23
23
|
:param event_id_filters: List of event IDs that we want to filter. If not provided, all events will be returned.
|
|
24
24
|
The default in the 'etw.ETW' method is 'None'.
|
|
25
25
|
:param session_name: The name of the session to create. If not provided, a UUID will be generated.
|
|
26
|
-
|
|
26
|
+
------------------------------------------
|
|
27
|
+
You should stop the ETW tracing when you are done with it.
|
|
27
28
|
'pywintrace' module starts a new session for ETW tracing, and it will not stop the session when the script
|
|
28
29
|
exits or exception is raised.
|
|
29
30
|
This can cause problems when you want to start the script again, and the session is already running.
|
|
@@ -32,11 +33,15 @@ class EventTrace(etw.ETW):
|
|
|
32
33
|
If you give different session name for new session, the previous session will still continue to run,
|
|
33
34
|
filling the buffer with events, until you will stop getting new events on all sessions or get an
|
|
34
35
|
exception that the buffer is full (WinError 1450).
|
|
36
|
+
|
|
37
|
+
Example to stop the ETW tracing at the end of the script:
|
|
38
|
+
from atomicshop.basics import atexits
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
event_tracing = EventTrace(<Your parameters>)
|
|
42
|
+
atexits.run_callable_on_exit_and_signals(EventTrace.stop)
|
|
35
43
|
"""
|
|
36
44
|
self.event_queue = queue.Queue()
|
|
37
|
-
self.stop_etw_tracing_on_exit: bool = stop_etw_tracing_on_exit
|
|
38
|
-
|
|
39
|
-
self._set_atexit_and_signals()
|
|
40
45
|
|
|
41
46
|
# If no callback function is provided, we will use the default one, which will put the event in the queue.
|
|
42
47
|
if not event_callback:
|
|
@@ -59,8 +64,10 @@ class EventTrace(etw.ETW):
|
|
|
59
64
|
try:
|
|
60
65
|
super().start()
|
|
61
66
|
except OSError as e:
|
|
62
|
-
|
|
63
|
-
|
|
67
|
+
message = f"PyWinTrace Error: {e}\n" \
|
|
68
|
+
f"PyWinTrace crashed, didn't find solution to this, RESTART computer."
|
|
69
|
+
print_api(message, error_type=True, logger_method='critical')
|
|
70
|
+
sys.exit(1)
|
|
64
71
|
|
|
65
72
|
def stop(self):
|
|
66
73
|
super().stop()
|
|
@@ -84,10 +91,6 @@ class EventTrace(etw.ETW):
|
|
|
84
91
|
|
|
85
92
|
return self.event_queue.get()
|
|
86
93
|
|
|
87
|
-
def _set_atexit_and_signals(self):
|
|
88
|
-
if self.stop_etw_tracing_on_exit:
|
|
89
|
-
atexits.run_callable_on_exit_and_signals(self.stop)
|
|
90
|
-
|
|
91
94
|
|
|
92
95
|
def find_sessions_by_provider(provider_name: str):
|
|
93
96
|
"""
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from . import
|
|
1
|
+
from . import trace
|
|
2
2
|
from .. import dns
|
|
3
3
|
from ..wrappers.psutilw import psutilw
|
|
4
4
|
from ..basics import dicts
|
|
@@ -32,7 +32,7 @@ class DnsTrace:
|
|
|
32
32
|
self.enable_process_poller = enable_process_poller
|
|
33
33
|
self.attrs = attrs
|
|
34
34
|
|
|
35
|
-
self.event_trace =
|
|
35
|
+
self.event_trace = trace.EventTrace(
|
|
36
36
|
providers=[(dns.ETW_DNS_INFO['provider_name'], dns.ETW_DNS_INFO['provider_guid'])],
|
|
37
37
|
# lambda x: self.event_queue.put(x),
|
|
38
38
|
event_id_filters=[dns.ETW_DNS_INFO['event_id']],
|
atomicshop/monitor/checks/dns.py
CHANGED
atomicshop/on_exit.py
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import atexit
|
|
2
|
+
import signal
|
|
3
|
+
import sys
|
|
4
|
+
import platform
|
|
5
|
+
|
|
6
|
+
import win32api
|
|
7
|
+
import win32con
|
|
8
|
+
|
|
9
|
+
from .print_api import print_api
|
|
10
|
+
from .wrappers.pywin32w import console
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
EXIT_HANDLER_INSTANCE = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ExitHandler:
|
|
17
|
+
"""
|
|
18
|
+
This class is used to handle exit events: Closing the console, pressing 'CTRL+C', Killing the process.
|
|
19
|
+
|
|
20
|
+
Example:
|
|
21
|
+
from atomicshop import on_exit
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def clean_up_function():
|
|
25
|
+
print("Cleaning up.")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
on_exit.ExitHandler(clean_up_function).register_handlers()
|
|
29
|
+
|
|
30
|
+
# OR
|
|
31
|
+
on_exit.register_exit_handler(clean_up_function)
|
|
32
|
+
"""
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
cleanup_action: callable,
|
|
36
|
+
args: tuple = None,
|
|
37
|
+
kwargs: dict = None
|
|
38
|
+
):
|
|
39
|
+
"""
|
|
40
|
+
:param cleanup_action: The action to run when one of exit types is triggered.
|
|
41
|
+
:param args: The arguments to pass to the cleanup action.
|
|
42
|
+
:param kwargs: The keyword arguments to pass to the cleanup action.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
if not callable(cleanup_action):
|
|
46
|
+
raise ValueError("The 'cleanup_action' must be a callable function.")
|
|
47
|
+
|
|
48
|
+
if args is None:
|
|
49
|
+
args = tuple()
|
|
50
|
+
|
|
51
|
+
if kwargs is None:
|
|
52
|
+
kwargs = dict()
|
|
53
|
+
|
|
54
|
+
self.cleanup_action: callable = cleanup_action
|
|
55
|
+
self.args: tuple = args
|
|
56
|
+
self.kwargs: dict = kwargs
|
|
57
|
+
|
|
58
|
+
self._called: bool = False
|
|
59
|
+
self._handler_hit: bool = False
|
|
60
|
+
|
|
61
|
+
def _run_cleanup(self):
|
|
62
|
+
if not self._called:
|
|
63
|
+
self._called = True
|
|
64
|
+
self.cleanup_action(*self.args, **self.kwargs)
|
|
65
|
+
|
|
66
|
+
def console_handler(self, event):
|
|
67
|
+
if event == win32con.CTRL_CLOSE_EVENT:
|
|
68
|
+
|
|
69
|
+
if not self._handler_hit:
|
|
70
|
+
self._handler_hit = True
|
|
71
|
+
|
|
72
|
+
print("Console close event.")
|
|
73
|
+
self._run_cleanup()
|
|
74
|
+
|
|
75
|
+
return True
|
|
76
|
+
return False
|
|
77
|
+
|
|
78
|
+
def atexit_handler(self):
|
|
79
|
+
if not self._handler_hit:
|
|
80
|
+
self._handler_hit = True
|
|
81
|
+
|
|
82
|
+
print("atexit_handler")
|
|
83
|
+
self._run_cleanup()
|
|
84
|
+
|
|
85
|
+
def signal_handler(self, signum, frame):
|
|
86
|
+
if not self._handler_hit:
|
|
87
|
+
self._handler_hit = True
|
|
88
|
+
|
|
89
|
+
print_api(f"Signal {signum}")
|
|
90
|
+
self._run_cleanup()
|
|
91
|
+
# Exit the process gracefully
|
|
92
|
+
raise SystemExit(0)
|
|
93
|
+
|
|
94
|
+
def register_handlers(self):
|
|
95
|
+
win32api.SetConsoleCtrlHandler(self.console_handler, True)
|
|
96
|
+
atexit.register(self.atexit_handler)
|
|
97
|
+
signal.signal(signal.SIGINT, self.signal_handler)
|
|
98
|
+
signal.signal(signal.SIGTERM, self.signal_handler)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def register_exit_handler(clean_up_function, *args, **kwargs):
|
|
102
|
+
"""
|
|
103
|
+
This function will register the exit handler to handle exit events: Closing the console, pressing 'CTRL+C',
|
|
104
|
+
Killing the process.
|
|
105
|
+
|
|
106
|
+
:param clean_up_function: The action to run when one of exit types is triggered.
|
|
107
|
+
:param args: The arguments to pass to the cleanup action.
|
|
108
|
+
:param kwargs: The keyword arguments to pass to the cleanup action.
|
|
109
|
+
"""
|
|
110
|
+
global EXIT_HANDLER_INSTANCE
|
|
111
|
+
EXIT_HANDLER_INSTANCE = ExitHandler(clean_up_function, args, kwargs)
|
|
112
|
+
EXIT_HANDLER_INSTANCE.register_handlers()
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def restart_function(callable_function, *args, **kwargs):
|
|
116
|
+
"""
|
|
117
|
+
This function will run the callable function with the given arguments and keyword arguments.
|
|
118
|
+
If the function raises an exception, the function will be restarted.
|
|
119
|
+
|
|
120
|
+
:param callable_function: The function to run.
|
|
121
|
+
:param args: The arguments to pass to the function.
|
|
122
|
+
:param kwargs: The keyword arguments to pass to the function.
|
|
123
|
+
:return: The return value of the function.
|
|
124
|
+
"""
|
|
125
|
+
while True:
|
|
126
|
+
try:
|
|
127
|
+
return callable_function(*args, **kwargs)
|
|
128
|
+
except Exception as e:
|
|
129
|
+
print(f"ERROR: {e}")
|
|
130
|
+
continue
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _ref_run_callable_on_exit_and_signals(
|
|
134
|
+
callable_function,
|
|
135
|
+
print_kwargs: dict = None,
|
|
136
|
+
*args,
|
|
137
|
+
**kwargs
|
|
138
|
+
):
|
|
139
|
+
"""
|
|
140
|
+
THIS IS FOR REFERENCE ONLY.
|
|
141
|
+
|
|
142
|
+
This function will run the callable function with the given arguments and keyword arguments.
|
|
143
|
+
If the function raises an exception, the function will be restarted.
|
|
144
|
+
|
|
145
|
+
:param callable_function: The function to run.
|
|
146
|
+
:param print_kwargs: print_api kwargs.
|
|
147
|
+
:param args: The arguments to pass to the function.
|
|
148
|
+
:param kwargs: The keyword arguments to pass to the function.
|
|
149
|
+
:return: The return value of the function.
|
|
150
|
+
"""
|
|
151
|
+
def signal_handler(signum, frame):
|
|
152
|
+
print_api(f"Signal {signum} received, exiting.", **(print_kwargs or {}))
|
|
153
|
+
callable_function(*args, **kwargs)
|
|
154
|
+
sys.exit(0)
|
|
155
|
+
|
|
156
|
+
def exit_handler():
|
|
157
|
+
print_api("Exiting.", **(print_kwargs or {}))
|
|
158
|
+
callable_function(*args, **kwargs)
|
|
159
|
+
sys.exit(0)
|
|
160
|
+
|
|
161
|
+
signals = [signal.SIGINT, signal.SIGTERM]
|
|
162
|
+
if platform.system() != 'Windows':
|
|
163
|
+
signals.append(signal.SIGQUIT)
|
|
164
|
+
signals.append(signal.SIGHUP)
|
|
165
|
+
for sig in signals:
|
|
166
|
+
signal.signal(sig, signal_handler)
|
|
167
|
+
|
|
168
|
+
# signal.signal(signal.SIGINT, signal_handler)
|
|
169
|
+
# signal.signal(signal.SIGTERM, signal_handler)
|
|
170
|
+
atexit.register(exit_handler)
|
|
171
|
+
|
|
172
|
+
# Register console handler for Windows.
|
|
173
|
+
if platform.system() == 'Windows':
|
|
174
|
+
console_handler = console.ConsoleHandler(exit_handler, args, kwargs)
|
|
175
|
+
console_handler.register_handler()
|
atomicshop/process_name_cmd.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from importlib import
|
|
1
|
+
from importlib.resources import files
|
|
2
2
|
import ctypes
|
|
3
3
|
from ctypes import wintypes
|
|
4
4
|
from typing import Literal
|
|
@@ -8,20 +8,19 @@ from .basics import list_of_dicts
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
PACKAGE_DLL_PATH = 'addons/process_list/compiled/Win10x64/process_list.dll'
|
|
11
|
+
FULL_DLL_PATH = str(files(__package__).joinpath(PACKAGE_DLL_PATH))
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class ProcessNameCmdline:
|
|
14
15
|
def __init__(self, load_dll: bool = False):
|
|
15
16
|
self.load_dll: bool = load_dll
|
|
17
|
+
self.dll_path = FULL_DLL_PATH
|
|
16
18
|
|
|
17
19
|
self.dll = None
|
|
18
20
|
self.callback_output = None
|
|
19
21
|
self.CALLBACKFUNC = None
|
|
20
22
|
self.CALLBACKFUNC_ref = None
|
|
21
23
|
|
|
22
|
-
with resources.path(__package__, PACKAGE_DLL_PATH) as dll_path:
|
|
23
|
-
self.dll_path = str(dll_path)
|
|
24
|
-
|
|
25
24
|
if self.load_dll:
|
|
26
25
|
self.load()
|
|
27
26
|
|
atomicshop/process_poller.py
CHANGED
|
@@ -207,8 +207,7 @@ class ProcessPollerPool:
|
|
|
207
207
|
|
|
208
208
|
def _start_process(self):
|
|
209
209
|
self.running = True
|
|
210
|
-
|
|
211
|
-
multiprocessing.Process(target=self._worker, args=(stopping_queue,)).start()
|
|
210
|
+
multiprocessing.Process(target=self._worker).start()
|
|
212
211
|
|
|
213
212
|
thread = threading.Thread(target=self._thread_get_queue)
|
|
214
213
|
thread.daemon = True
|
|
File without changes
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import ctypes
|
|
2
|
+
from ctypes import wintypes
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
# Load the necessary library
|
|
6
|
+
advapi32 = ctypes.WinDLL('advapi32')
|
|
7
|
+
|
|
8
|
+
# Constants
|
|
9
|
+
EVENT_TRACE_CONTROL_STOP = 1
|
|
10
|
+
WNODE_FLAG_TRACED_GUID = 0x00020000
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# Define GUID structure
|
|
14
|
+
class GUID(ctypes.Structure):
|
|
15
|
+
_fields_ = [
|
|
16
|
+
("Data1", wintypes.DWORD),
|
|
17
|
+
("Data2", wintypes.WORD),
|
|
18
|
+
("Data3", wintypes.WORD),
|
|
19
|
+
("Data4", wintypes.BYTE * 8)
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Define WNODE_HEADER
|
|
24
|
+
class WNODE_HEADER(ctypes.Structure):
|
|
25
|
+
_fields_ = [
|
|
26
|
+
("BufferSize", wintypes.ULONG),
|
|
27
|
+
("ProviderId", wintypes.ULONG),
|
|
28
|
+
("HistoricalContext", wintypes.LARGE_INTEGER),
|
|
29
|
+
("TimeStamp", wintypes.LARGE_INTEGER),
|
|
30
|
+
("Guid", GUID),
|
|
31
|
+
("ClientContext", wintypes.ULONG),
|
|
32
|
+
("Flags", wintypes.ULONG)
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# Define EVENT_TRACE_PROPERTIES structure
|
|
37
|
+
class EVENT_TRACE_PROPERTIES(ctypes.Structure):
|
|
38
|
+
_fields_ = [
|
|
39
|
+
("Wnode", WNODE_HEADER),
|
|
40
|
+
("BufferSize", wintypes.ULONG),
|
|
41
|
+
("MinimumBuffers", wintypes.ULONG),
|
|
42
|
+
("MaximumBuffers", wintypes.ULONG),
|
|
43
|
+
("MaximumFileSize", wintypes.ULONG),
|
|
44
|
+
("LogFileMode", wintypes.ULONG),
|
|
45
|
+
("FlushTimer", wintypes.ULONG),
|
|
46
|
+
("EnableFlags", wintypes.ULONG),
|
|
47
|
+
("AgeLimit", wintypes.LONG),
|
|
48
|
+
("NumberOfBuffers", wintypes.ULONG),
|
|
49
|
+
("FreeBuffers", wintypes.ULONG),
|
|
50
|
+
("EventsLost", wintypes.ULONG),
|
|
51
|
+
("BuffersWritten", wintypes.ULONG),
|
|
52
|
+
("LogBuffersLost", wintypes.ULONG),
|
|
53
|
+
("RealTimeBuffersLost", wintypes.ULONG),
|
|
54
|
+
("LoggerThreadId", wintypes.HANDLE),
|
|
55
|
+
("LogFileNameOffset", wintypes.ULONG),
|
|
56
|
+
("LoggerNameOffset", wintypes.ULONG)
|
|
57
|
+
]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import ctypes
|
|
2
|
+
from . import const
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
# Function to stop and delete ETW session
|
|
6
|
+
def stop_and_delete_etw_session(session_name) -> tuple[bool, int]:
|
|
7
|
+
"""
|
|
8
|
+
Stop and delete ETW session.
|
|
9
|
+
|
|
10
|
+
:param session_name: The name of the session to stop and delete.
|
|
11
|
+
:return: A tuple containing a boolean indicating success and an integer status code.
|
|
12
|
+
True, 0: If the session was stopped and deleted successfully.
|
|
13
|
+
False, <status>: If the session could not be stopped and deleted and the status code, why it failed.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
session_name_unicode = ctypes.create_unicode_buffer(session_name)
|
|
17
|
+
properties_size = ctypes.sizeof(const.EVENT_TRACE_PROPERTIES) + 1024 # Adjust buffer size if needed
|
|
18
|
+
properties = ctypes.create_string_buffer(properties_size)
|
|
19
|
+
|
|
20
|
+
trace_properties = ctypes.cast(properties, ctypes.POINTER(const.EVENT_TRACE_PROPERTIES)).contents
|
|
21
|
+
trace_properties.Wnode.BufferSize = properties_size
|
|
22
|
+
trace_properties.Wnode.Flags = const.WNODE_FLAG_TRACED_GUID
|
|
23
|
+
trace_properties.Wnode.Guid = const.GUID() # Ensure a GUID is provided if necessary
|
|
24
|
+
trace_properties.LoggerNameOffset = ctypes.sizeof(const.EVENT_TRACE_PROPERTIES)
|
|
25
|
+
|
|
26
|
+
ctypes.memmove(ctypes.addressof(properties) + trace_properties.LoggerNameOffset,
|
|
27
|
+
session_name_unicode, ctypes.sizeof(session_name_unicode))
|
|
28
|
+
|
|
29
|
+
status = const.advapi32.ControlTraceW(
|
|
30
|
+
None, session_name_unicode, ctypes.byref(trace_properties), const.EVENT_TRACE_CONTROL_STOP)
|
|
31
|
+
|
|
32
|
+
if status != 0:
|
|
33
|
+
# print(f"Failed to stop and delete ETW session: {status}")
|
|
34
|
+
return False, status
|
|
35
|
+
else:
|
|
36
|
+
# print("ETW session stopped and deleted successfully.")
|
|
37
|
+
return True, status
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import win32api
|
|
2
|
+
import win32con
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ConsoleHandler:
|
|
6
|
+
"""
|
|
7
|
+
This class is used to handle console events.
|
|
8
|
+
Currently used to handle the 'CTRL_CLOSE_EVENT' event - Meaning what to do when the user closes the console by
|
|
9
|
+
clicking on X in the top right corner.
|
|
10
|
+
"""
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
cleanup_action: callable = None,
|
|
14
|
+
args: tuple = None,
|
|
15
|
+
kwargs: dict = None
|
|
16
|
+
):
|
|
17
|
+
"""
|
|
18
|
+
:param cleanup_action: The action to run when user closes the console.
|
|
19
|
+
:param args: The arguments to pass to the cleanup action.
|
|
20
|
+
:param kwargs: The keyword arguments to pass to the cleanup action.
|
|
21
|
+
"""
|
|
22
|
+
self.cleanup_action = cleanup_action
|
|
23
|
+
self.args = args
|
|
24
|
+
self.kwargs = kwargs
|
|
25
|
+
|
|
26
|
+
def _console_handler(self, event):
|
|
27
|
+
if event == win32con.CTRL_CLOSE_EVENT:
|
|
28
|
+
if self.cleanup_action and callable(self.cleanup_action):
|
|
29
|
+
self.cleanup_action(*self.args, **self.kwargs)
|
|
30
|
+
return True
|
|
31
|
+
return False
|
|
32
|
+
|
|
33
|
+
def register_handler(self):
|
|
34
|
+
win32api.SetConsoleCtrlHandler(self._console_handler, True)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
atomicshop/__init__.py,sha256=
|
|
1
|
+
atomicshop/__init__.py,sha256=IWq2-3sezAvBANma6AYzXzywVzgI9rJOyd2ZKFBLQ1E,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
|
|
@@ -21,12 +21,13 @@ atomicshop/http_parse.py,sha256=nrf2rZcprLqtW8HVrV7TCZ1iTBcWRRy-mXIlAOzcaJs,9703
|
|
|
21
21
|
atomicshop/inspect_wrapper.py,sha256=sGRVQhrJovNygHTydqJj0hxES-aB2Eg9KbIk3G31apw,11429
|
|
22
22
|
atomicshop/ip_addresses.py,sha256=Hvi4TumEFoTEpKWaq5WNF-YzcRzt24IxmNgv-Mgax1s,1190
|
|
23
23
|
atomicshop/keyboard_press.py,sha256=1W5kRtOB75fulVx-uF2yarBhW0_IzdI1k73AnvXstk0,452
|
|
24
|
+
atomicshop/on_exit.py,sha256=Wf1iy2e0b0Zu7oRxrct3VkLdQ_x9B32-z_JerKTt9Z0,5493
|
|
24
25
|
atomicshop/pbtkmultifile_argparse.py,sha256=aEk8nhvoQVu-xyfZosK3ma17CwIgOjzO1erXXdjwtS4,4574
|
|
25
26
|
atomicshop/permissions.py,sha256=P6tiUKV-Gw-c3ePEVsst9bqWaHJbB4ZlJB4xbDYVpEs,4436
|
|
26
27
|
atomicshop/print_api.py,sha256=DhbCQd0MWZZ5GYEk4oTu1opRFC-b31g1VWZgTGewG2Y,11568
|
|
27
28
|
atomicshop/process.py,sha256=Zgb4CUjy9gIBaawvtCOEcxGUCqvqPyARk0lpBjRzxWE,15950
|
|
28
|
-
atomicshop/process_name_cmd.py,sha256=
|
|
29
|
-
atomicshop/process_poller.py,sha256=
|
|
29
|
+
atomicshop/process_name_cmd.py,sha256=CtaSp3mgxxJKCCVW8BLx6BJNx4giCklU_T7USiCEwfc,5162
|
|
30
|
+
atomicshop/process_poller.py,sha256=naqoq-gJN1kkaOm_MfoM7teIkh5OniXromVR4pb0pjY,11680
|
|
30
31
|
atomicshop/python_file_patcher.py,sha256=kd3rBWvTcosLEk-7TycNdfKW9fZbe161iVwmH4niUo0,5515
|
|
31
32
|
atomicshop/python_functions.py,sha256=zJg4ogUwECxrDD7xdDN5JikIUctITM5lsyabr_ZNsRw,4435
|
|
32
33
|
atomicshop/question_answer_engine.py,sha256=DuOn7QEgKKfqZu2cR8mVeFIfFgayfBHiW-jY2VPq_Fo,841
|
|
@@ -79,7 +80,6 @@ atomicshop/archiver/zips.py,sha256=k742K1bEDtc_4N44j_Waebi-uOkxxavqltvV6q-BLW4,1
|
|
|
79
80
|
atomicshop/basics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
80
81
|
atomicshop/basics/ansi_escape_codes.py,sha256=WtIkm-BjSZS5J5irDUdAMBNvdX-qXFZcTX98jcBMpJE,3140
|
|
81
82
|
atomicshop/basics/argparse_template.py,sha256=horwgSf3MX1ZgRnYxtmmQuz9OU_vKrKggF65gmjlmfg,5836
|
|
82
|
-
atomicshop/basics/atexits.py,sha256=w7ge8sjuqK2_jdkdP4F4OCltkenQud8AhVEzxhFDiao,2145
|
|
83
83
|
atomicshop/basics/booleans.py,sha256=va3LYIaSOhjdifW4ZEesnIQxBICNHyQjUAkYelzchhE,2047
|
|
84
84
|
atomicshop/basics/bytes_arrays.py,sha256=WvSRDhIGt1ywF95t-yNgpxLm1nlZUbM1Dz6QckcyE8Y,5915
|
|
85
85
|
atomicshop/basics/classes.py,sha256=EijW_g4EhdNBnKPMG3nT3HjFspTchtM7to6zm9Ad_Mk,9771
|
|
@@ -102,8 +102,9 @@ 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/
|
|
106
|
-
atomicshop/etw/
|
|
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
|
|
107
108
|
atomicshop/file_io/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
108
109
|
atomicshop/file_io/csvs.py,sha256=y8cJtnlN-NNxNupzJgSeGq9aQ4wNxYLFPX9vNNlUiIc,5830
|
|
109
110
|
atomicshop/file_io/docxs.py,sha256=6tcYFGp0vRsHR47VwcRqwhdt2DQOwrAUYhrwN996n9U,5117
|
|
@@ -135,9 +136,8 @@ atomicshop/mitm/engines/__reference_general/responder___reference_general.py,sha
|
|
|
135
136
|
atomicshop/monitor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
136
137
|
atomicshop/monitor/change_monitor.py,sha256=dGhk5bJPxLCHa2FOVkort99E7vjVojra9GlvhpcKSqE,7551
|
|
137
138
|
atomicshop/monitor/checks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
138
|
-
atomicshop/monitor/checks/dns.py,sha256=
|
|
139
|
+
atomicshop/monitor/checks/dns.py,sha256=edO03gtGYb3tn8eV-wAKPELIkdCJvimjkO8PPF-ho-k,7150
|
|
139
140
|
atomicshop/monitor/checks/file.py,sha256=2tIDSlX2KZNc_9i9ji1tcOqupbFTIOj7cKXLyBEDWMk,3263
|
|
140
|
-
atomicshop/monitor/checks/hash.py,sha256=r4mDOdjItN3eyaJk8TVz03f4bQ_uKZ4MDTXagjseazs,2011
|
|
141
141
|
atomicshop/monitor/checks/network.py,sha256=CGZWl4WlQrxayZeVF9JspJXwYA-zWx8ECWTVGSlXc98,3825
|
|
142
142
|
atomicshop/monitor/checks/process_running.py,sha256=x66wd6-l466r8sbRQaIli0yswyGt1dH2DVXkGDL6O0Q,1891
|
|
143
143
|
atomicshop/monitor/checks/url.py,sha256=1PvKt_d7wFg7rDMFpUejAQhj0mqWsmlmrNfjNAV2G4g,4123
|
|
@@ -168,6 +168,9 @@ atomicshop/wrappers/certauthw/certauth.py,sha256=hKedW0DOWlEigSNm8wu4SqHkCQsGJ1t
|
|
|
168
168
|
atomicshop/wrappers/certauthw/certauthw.py,sha256=4WvhjANI7Kzqrr_nKmtA8Kf7B6rute_5wfP65gwQrjw,8082
|
|
169
169
|
atomicshop/wrappers/ctyping/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
170
170
|
atomicshop/wrappers/ctyping/process_winapi.py,sha256=QcXL-ETtlSSkoT8F7pYle97ubGWsjYp8cx8HxkVMgAc,2762
|
|
171
|
+
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
|
|
171
174
|
atomicshop/wrappers/ctyping/msi_windows_installer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
172
175
|
atomicshop/wrappers/ctyping/msi_windows_installer/base.py,sha256=Uu9SlWLsQQ6mjE-ek-ptHcmgiI3Ruah9bdZus70EaVY,4884
|
|
173
176
|
atomicshop/wrappers/ctyping/msi_windows_installer/cabs.py,sha256=htzwb2ROYI8yyc82xApStckPS2yCcoyaw32yC15KROs,3285
|
|
@@ -237,6 +240,7 @@ atomicshop/wrappers/psutilw/disks.py,sha256=3ZSVoommKH1TWo37j_83frB-NqXF4Nf5q5mB
|
|
|
237
240
|
atomicshop/wrappers/psutilw/memories.py,sha256=_S0aL8iaoIHebd1vOFrY_T9aROM5Jx2D5CvDh_4j0Vc,528
|
|
238
241
|
atomicshop/wrappers/psutilw/psutilw.py,sha256=G22ZQfGnqX15-feD8KUXfEZO4pFkIEnB8zgPzJ2jc7M,20868
|
|
239
242
|
atomicshop/wrappers/psycopgw/psycopgw.py,sha256=XJvVf0oAUjCHkrYfKeFuGCpfn0Oxj3u4SbKMKA1508E,7118
|
|
243
|
+
atomicshop/wrappers/pywin32w/console.py,sha256=LstHajPLgXp9qQxFNR44QfH10nOnNp3bCJquxaTquns,1175
|
|
240
244
|
atomicshop/wrappers/pywin32w/winshell.py,sha256=i2bKiMldPU7_azsD5xGQDdMwjaM7suKJd3k0Szmcs6c,723
|
|
241
245
|
atomicshop/wrappers/pywin32w/wmi_win32process.py,sha256=qMzXtJ5hBZ5ydAyqpDbSx0nO2RJQL95HdmV5SzNKMhk,6826
|
|
242
246
|
atomicshop/wrappers/socketw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -255,8 +259,8 @@ atomicshop/wrappers/socketw/socket_server_tester.py,sha256=AhpurHJmP2kgzHaUbq5ey
|
|
|
255
259
|
atomicshop/wrappers/socketw/socket_wrapper.py,sha256=aXBwlEIJhFT0-c4i8iNlFx2It9VpCEpsv--5Oqcpxao,11624
|
|
256
260
|
atomicshop/wrappers/socketw/ssl_base.py,sha256=k4V3gwkbq10MvOH4btU4onLX2GNOsSfUAdcHmL1rpVE,2274
|
|
257
261
|
atomicshop/wrappers/socketw/statistics_csv.py,sha256=t3dtDEfN47CfYVi0CW6Kc2QHTEeZVyYhc57IYYh5nmA,826
|
|
258
|
-
atomicshop-2.12.
|
|
259
|
-
atomicshop-2.12.
|
|
260
|
-
atomicshop-2.12.
|
|
261
|
-
atomicshop-2.12.
|
|
262
|
-
atomicshop-2.12.
|
|
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,,
|
atomicshop/basics/atexits.py
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import atexit
|
|
2
|
-
import signal
|
|
3
|
-
import sys
|
|
4
|
-
import platform
|
|
5
|
-
|
|
6
|
-
from ..print_api import print_api
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def restart_function(callable_function, *args, **kwargs):
|
|
10
|
-
"""
|
|
11
|
-
This function will run the callable function with the given arguments and keyword arguments.
|
|
12
|
-
If the function raises an exception, the function will be restarted.
|
|
13
|
-
|
|
14
|
-
:param callable_function: The function to run.
|
|
15
|
-
:param args: The arguments to pass to the function.
|
|
16
|
-
:param kwargs: The keyword arguments to pass to the function.
|
|
17
|
-
:return: The return value of the function.
|
|
18
|
-
"""
|
|
19
|
-
while True:
|
|
20
|
-
try:
|
|
21
|
-
return callable_function(*args, **kwargs)
|
|
22
|
-
except Exception as e:
|
|
23
|
-
print(f"ERROR: {e}")
|
|
24
|
-
continue
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def run_callable_on_exit_and_signals(
|
|
28
|
-
callable_function,
|
|
29
|
-
print_kwargs: dict = None,
|
|
30
|
-
*args,
|
|
31
|
-
**kwargs
|
|
32
|
-
):
|
|
33
|
-
"""
|
|
34
|
-
This function will run the callable function with the given arguments and keyword arguments.
|
|
35
|
-
If the function raises an exception, the function will be restarted.
|
|
36
|
-
|
|
37
|
-
:param callable_function: The function to run.
|
|
38
|
-
:param print_kwargs: print_api kwargs.
|
|
39
|
-
:param args: The arguments to pass to the function.
|
|
40
|
-
:param kwargs: The keyword arguments to pass to the function.
|
|
41
|
-
:return: The return value of the function.
|
|
42
|
-
"""
|
|
43
|
-
def signal_handler(signum, frame):
|
|
44
|
-
print_api(f"Signal {signum} received, exiting.", **(print_kwargs or {}))
|
|
45
|
-
callable_function(*args, **kwargs)
|
|
46
|
-
input("Press Enter to exit.")
|
|
47
|
-
sys.exit(0)
|
|
48
|
-
|
|
49
|
-
def exit_handler():
|
|
50
|
-
print_api("Exiting.", **(print_kwargs or {}))
|
|
51
|
-
callable_function(*args, **kwargs)
|
|
52
|
-
input("Press Enter to exit.")
|
|
53
|
-
sys.exit(0)
|
|
54
|
-
|
|
55
|
-
signals = [signal.SIGINT, signal.SIGTERM]
|
|
56
|
-
if platform.system() != 'Windows':
|
|
57
|
-
signals.append(signal.SIGQUIT)
|
|
58
|
-
signals.append(signal.SIGHUP)
|
|
59
|
-
for sig in signals:
|
|
60
|
-
signal.signal(sig, signal_handler)
|
|
61
|
-
|
|
62
|
-
# signal.signal(signal.SIGINT, signal_handler)
|
|
63
|
-
# signal.signal(signal.SIGTERM, signal_handler)
|
|
64
|
-
atexit.register(exit_handler)
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
from ... import diff_check
|
|
2
|
-
from ...print_api import print_api
|
|
3
|
-
from .hash_checks import file, url
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
DIFF_CHECKER = diff_check.DiffChecker(
|
|
7
|
-
return_first_cycle=False,
|
|
8
|
-
operation_type='single_object'
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def setup_check(change_monitor_instance):
|
|
13
|
-
change_monitor_instance.set_input_file_path()
|
|
14
|
-
|
|
15
|
-
if change_monitor_instance.object_type == 'file':
|
|
16
|
-
file.setup_check(change_monitor_instance, change_monitor_instance.check_object)
|
|
17
|
-
elif 'url_' in change_monitor_instance.object_type:
|
|
18
|
-
url.setup_check(change_monitor_instance, change_monitor_instance.check_object)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def execute_cycle(change_monitor_instance, print_kwargs: dict = None):
|
|
22
|
-
"""
|
|
23
|
-
This function executes the cycle of the change monitor: hash.
|
|
24
|
-
|
|
25
|
-
:param change_monitor_instance: Instance of the ChangeMonitor class.
|
|
26
|
-
:param print_kwargs: print_api kwargs.
|
|
27
|
-
|
|
28
|
-
:return: List of dictionaries with the results of the cycle.
|
|
29
|
-
"""
|
|
30
|
-
|
|
31
|
-
if print_kwargs is None:
|
|
32
|
-
print_kwargs = dict()
|
|
33
|
-
|
|
34
|
-
return_list = list()
|
|
35
|
-
|
|
36
|
-
if change_monitor_instance.object_type == 'file':
|
|
37
|
-
# Get the hash of the object.
|
|
38
|
-
file.get_hash(change_monitor_instance, change_monitor_instance.check_object, print_kwargs=print_kwargs)
|
|
39
|
-
elif 'url_' in change_monitor_instance.object_type:
|
|
40
|
-
# Get the hash of the object.
|
|
41
|
-
url.get_hash(change_monitor_instance, change_monitor_instance.check_object, print_kwargs=print_kwargs)
|
|
42
|
-
|
|
43
|
-
# Check if the object was updated.
|
|
44
|
-
result, message = change_monitor_instance.diff_checker.check_string(
|
|
45
|
-
print_kwargs=print_kwargs)
|
|
46
|
-
|
|
47
|
-
# If the object was updated, print the message in yellow color, otherwise print in green color.
|
|
48
|
-
if result:
|
|
49
|
-
print_api(message, color='yellow', **print_kwargs)
|
|
50
|
-
# create_message_file(message, self.__class__.__name__, logger=self.logger)
|
|
51
|
-
|
|
52
|
-
return_list.append(message)
|
|
53
|
-
else:
|
|
54
|
-
print_api(message, color='green', **print_kwargs)
|
|
55
|
-
|
|
56
|
-
return return_list
|
|
File without changes
|
|
File without changes
|
|
File without changes
|