atomicshop 2.15.11__py3-none-any.whl → 3.10.5__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.
- atomicshop/__init__.py +1 -1
- atomicshop/{addons/mains → a_mains}/FACT/update_extract.py +3 -2
- atomicshop/a_mains/dns_gateway_setting.py +11 -0
- atomicshop/a_mains/get_local_tcp_ports.py +85 -0
- atomicshop/a_mains/github_wrapper.py +11 -0
- atomicshop/a_mains/install_ca_certificate.py +172 -0
- atomicshop/a_mains/process_from_port.py +119 -0
- atomicshop/a_mains/set_default_dns_gateway.py +90 -0
- atomicshop/a_mains/update_config_toml.py +38 -0
- atomicshop/basics/ansi_escape_codes.py +3 -1
- atomicshop/basics/argparse_template.py +2 -0
- atomicshop/basics/booleans.py +27 -30
- atomicshop/basics/bytes_arrays.py +43 -0
- atomicshop/basics/classes.py +149 -1
- atomicshop/basics/enums.py +2 -2
- atomicshop/basics/exceptions.py +5 -1
- atomicshop/basics/list_of_classes.py +29 -0
- atomicshop/basics/multiprocesses.py +374 -50
- atomicshop/basics/strings.py +72 -3
- atomicshop/basics/threads.py +14 -0
- atomicshop/basics/tracebacks.py +13 -3
- atomicshop/certificates.py +153 -52
- atomicshop/config_init.py +11 -6
- atomicshop/console_user_response.py +7 -14
- atomicshop/consoles.py +9 -0
- atomicshop/datetimes.py +1 -1
- atomicshop/diff_check.py +3 -3
- atomicshop/dns.py +128 -3
- atomicshop/etws/_pywintrace_fix.py +17 -0
- atomicshop/etws/trace.py +40 -42
- atomicshop/etws/traces/trace_dns.py +56 -44
- atomicshop/etws/traces/trace_tcp.py +130 -0
- atomicshop/file_io/csvs.py +27 -5
- atomicshop/file_io/docxs.py +34 -17
- atomicshop/file_io/file_io.py +31 -17
- atomicshop/file_io/jsons.py +49 -0
- atomicshop/file_io/tomls.py +139 -0
- atomicshop/filesystem.py +616 -291
- atomicshop/get_process_list.py +3 -3
- atomicshop/http_parse.py +149 -93
- atomicshop/ip_addresses.py +6 -1
- atomicshop/mitm/centered_settings.py +132 -0
- atomicshop/mitm/config_static.py +207 -0
- atomicshop/mitm/config_toml_editor.py +55 -0
- atomicshop/mitm/connection_thread_worker.py +875 -357
- atomicshop/mitm/engines/__parent/parser___parent.py +4 -17
- atomicshop/mitm/engines/__parent/recorder___parent.py +108 -51
- atomicshop/mitm/engines/__parent/requester___parent.py +116 -0
- atomicshop/mitm/engines/__parent/responder___parent.py +75 -114
- atomicshop/mitm/engines/__reference_general/parser___reference_general.py +10 -7
- atomicshop/mitm/engines/__reference_general/recorder___reference_general.py +5 -5
- atomicshop/mitm/engines/__reference_general/requester___reference_general.py +47 -0
- atomicshop/mitm/engines/__reference_general/responder___reference_general.py +95 -13
- atomicshop/mitm/engines/create_module_template.py +58 -14
- atomicshop/mitm/import_config.py +359 -139
- atomicshop/mitm/initialize_engines.py +160 -80
- atomicshop/mitm/message.py +64 -23
- atomicshop/mitm/mitm_main.py +892 -0
- atomicshop/mitm/recs_files.py +183 -0
- atomicshop/mitm/shared_functions.py +4 -10
- atomicshop/mitm/ssh_tester.py +82 -0
- atomicshop/mitm/statistic_analyzer.py +136 -40
- atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py +265 -83
- atomicshop/monitor/checks/dns.py +1 -1
- atomicshop/networks.py +671 -0
- atomicshop/on_exit.py +39 -9
- atomicshop/package_mains_processor.py +84 -0
- atomicshop/permissions/permissions.py +22 -0
- atomicshop/permissions/ubuntu_permissions.py +239 -0
- atomicshop/permissions/win_permissions.py +33 -0
- atomicshop/print_api.py +24 -42
- atomicshop/process.py +24 -6
- atomicshop/process_poller/process_pool.py +0 -1
- atomicshop/process_poller/simple_process_pool.py +204 -5
- atomicshop/python_file_patcher.py +1 -1
- atomicshop/python_functions.py +27 -75
- atomicshop/speech_recognize.py +8 -0
- atomicshop/ssh_remote.py +158 -172
- atomicshop/system_resource_monitor.py +61 -47
- atomicshop/system_resources.py +8 -8
- atomicshop/tempfiles.py +1 -2
- atomicshop/urls.py +6 -0
- atomicshop/venvs.py +28 -0
- atomicshop/versioning.py +27 -0
- atomicshop/web.py +98 -27
- atomicshop/web_apis/google_custom_search.py +44 -0
- atomicshop/web_apis/google_llm.py +188 -0
- atomicshop/websocket_parse.py +450 -0
- atomicshop/wrappers/certauthw/certauth.py +1 -0
- atomicshop/wrappers/cryptographyw.py +29 -8
- atomicshop/wrappers/ctyping/etw_winapi/const.py +97 -47
- atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py +178 -49
- atomicshop/wrappers/ctyping/file_details_winapi.py +67 -0
- atomicshop/wrappers/ctyping/msi_windows_installer/cabs.py +2 -1
- atomicshop/wrappers/ctyping/msi_windows_installer/extract_msi_main.py +2 -2
- atomicshop/wrappers/ctyping/setup_device.py +466 -0
- atomicshop/wrappers/ctyping/win_console.py +39 -0
- atomicshop/wrappers/dockerw/dockerw.py +113 -2
- atomicshop/wrappers/elasticsearchw/config_basic.py +0 -12
- atomicshop/wrappers/elasticsearchw/elastic_infra.py +75 -0
- atomicshop/wrappers/elasticsearchw/elasticsearchw.py +2 -20
- atomicshop/wrappers/factw/get_file_data.py +12 -5
- atomicshop/wrappers/factw/install/install_after_restart.py +89 -5
- atomicshop/wrappers/factw/install/pre_install_and_install_before_restart.py +20 -14
- atomicshop/wrappers/githubw.py +537 -54
- atomicshop/wrappers/loggingw/consts.py +1 -1
- atomicshop/wrappers/loggingw/filters.py +23 -0
- atomicshop/wrappers/loggingw/formatters.py +12 -0
- atomicshop/wrappers/loggingw/handlers.py +214 -107
- atomicshop/wrappers/loggingw/loggers.py +19 -0
- atomicshop/wrappers/loggingw/loggingw.py +860 -22
- atomicshop/wrappers/loggingw/reading.py +134 -112
- atomicshop/wrappers/mongodbw/mongo_infra.py +31 -0
- atomicshop/wrappers/mongodbw/mongodbw.py +1324 -36
- atomicshop/wrappers/netshw.py +271 -0
- atomicshop/wrappers/playwrightw/engine.py +34 -19
- atomicshop/wrappers/playwrightw/infra.py +5 -0
- atomicshop/wrappers/playwrightw/javascript.py +7 -3
- atomicshop/wrappers/playwrightw/keyboard.py +14 -0
- atomicshop/wrappers/playwrightw/scenarios.py +172 -5
- atomicshop/wrappers/playwrightw/waits.py +9 -7
- atomicshop/wrappers/powershell_networking.py +80 -0
- atomicshop/wrappers/psutilw/processes.py +37 -1
- atomicshop/wrappers/psutilw/psutil_networks.py +85 -0
- atomicshop/wrappers/pyopensslw.py +9 -2
- atomicshop/wrappers/pywin32w/cert_store.py +116 -0
- atomicshop/wrappers/pywin32w/win_event_log/fetch.py +174 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +3 -105
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +3 -57
- atomicshop/wrappers/pywin32w/wmis/msft_netipaddress.py +113 -0
- atomicshop/wrappers/pywin32w/wmis/win32_networkadapterconfiguration.py +259 -0
- atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py +112 -0
- atomicshop/wrappers/pywin32w/wmis/wmi_helpers.py +236 -0
- atomicshop/wrappers/socketw/accepter.py +21 -7
- atomicshop/wrappers/socketw/certificator.py +216 -150
- atomicshop/wrappers/socketw/creator.py +190 -50
- atomicshop/wrappers/socketw/dns_server.py +491 -182
- atomicshop/wrappers/socketw/exception_wrapper.py +45 -52
- atomicshop/wrappers/socketw/process_getter.py +86 -0
- atomicshop/wrappers/socketw/receiver.py +144 -102
- atomicshop/wrappers/socketw/sender.py +65 -35
- atomicshop/wrappers/socketw/sni.py +334 -165
- atomicshop/wrappers/socketw/socket_base.py +134 -0
- atomicshop/wrappers/socketw/socket_client.py +137 -95
- atomicshop/wrappers/socketw/socket_server_tester.py +11 -7
- atomicshop/wrappers/socketw/socket_wrapper.py +717 -116
- atomicshop/wrappers/socketw/ssl_base.py +15 -14
- atomicshop/wrappers/socketw/statistics_csv.py +148 -17
- atomicshop/wrappers/sysmonw.py +1 -1
- atomicshop/wrappers/ubuntu_terminal.py +65 -26
- atomicshop/wrappers/win_auditw.py +189 -0
- atomicshop/wrappers/winregw/__init__.py +0 -0
- atomicshop/wrappers/winregw/winreg_installed_software.py +58 -0
- atomicshop/wrappers/winregw/winreg_network.py +232 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/METADATA +31 -51
- atomicshop-3.10.5.dist-info/RECORD +306 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/WHEEL +1 -1
- atomicshop/_basics_temp.py +0 -101
- atomicshop/a_installs/win/fibratus.py +0 -9
- atomicshop/a_installs/win/mongodb.py +0 -9
- atomicshop/a_installs/win/pycharm.py +0 -9
- atomicshop/addons/a_setup_scripts/install_psycopg2_ubuntu.sh +0 -3
- atomicshop/addons/a_setup_scripts/install_pywintrace_0.3.cmd +0 -2
- atomicshop/addons/mains/__pycache__/install_fibratus_windows.cpython-312.pyc +0 -0
- atomicshop/addons/mains/__pycache__/msi_unpacker.cpython-312.pyc +0 -0
- atomicshop/addons/mains/install_docker_rootless_ubuntu.py +0 -11
- atomicshop/addons/mains/install_docker_ubuntu_main_sudo.py +0 -11
- atomicshop/addons/mains/install_elastic_search_and_kibana_ubuntu.py +0 -10
- atomicshop/addons/mains/install_wsl_ubuntu_lts_admin.py +0 -9
- atomicshop/addons/package_setup/CreateWheel.cmd +0 -7
- atomicshop/addons/package_setup/Setup in Edit mode.cmd +0 -6
- atomicshop/addons/package_setup/Setup.cmd +0 -7
- atomicshop/archiver/_search_in_zip.py +0 -189
- atomicshop/archiver/archiver.py +0 -34
- atomicshop/archiver/search_in_archive.py +0 -250
- atomicshop/archiver/sevenz_app_w.py +0 -86
- atomicshop/archiver/sevenzs.py +0 -44
- atomicshop/archiver/zips.py +0 -293
- atomicshop/file_types.py +0 -24
- atomicshop/mitm/config_editor.py +0 -37
- atomicshop/mitm/engines/create_module_template_example.py +0 -13
- atomicshop/mitm/initialize_mitm_server.py +0 -268
- atomicshop/pbtkmultifile_argparse.py +0 -88
- atomicshop/permissions.py +0 -151
- atomicshop/script_as_string_processor.py +0 -38
- atomicshop/ssh_scripts/process_from_ipv4.py +0 -37
- atomicshop/ssh_scripts/process_from_port.py +0 -27
- atomicshop/wrappers/_process_wrapper_curl.py +0 -27
- atomicshop/wrappers/_process_wrapper_tar.py +0 -21
- atomicshop/wrappers/dockerw/install_docker.py +0 -209
- atomicshop/wrappers/elasticsearchw/infrastructure.py +0 -265
- atomicshop/wrappers/elasticsearchw/install_elastic.py +0 -232
- atomicshop/wrappers/ffmpegw.py +0 -125
- atomicshop/wrappers/fibratusw/install.py +0 -81
- atomicshop/wrappers/mongodbw/infrastructure.py +0 -53
- atomicshop/wrappers/mongodbw/install_mongodb.py +0 -190
- atomicshop/wrappers/msiw.py +0 -149
- atomicshop/wrappers/nodejsw/install_nodejs.py +0 -139
- atomicshop/wrappers/process_wrapper_pbtk.py +0 -16
- atomicshop/wrappers/psutilw/networks.py +0 -45
- atomicshop/wrappers/pycharmw.py +0 -81
- atomicshop/wrappers/socketw/base.py +0 -59
- atomicshop/wrappers/socketw/get_process.py +0 -107
- atomicshop/wrappers/wslw.py +0 -191
- atomicshop-2.15.11.dist-info/RECORD +0 -302
- /atomicshop/{addons/mains → a_mains}/FACT/factw_fact_extractor_docker_image_main_sudo.py +0 -0
- /atomicshop/{addons → a_mains/addons}/PlayWrightCodegen.cmd +0 -0
- /atomicshop/{addons → a_mains/addons}/ScriptExecution.cmd +0 -0
- /atomicshop/{addons → a_mains/addons}/inits/init_to_import_all_modules.py +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/ReadMe.txt +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compile.cmd +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.dll +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.exp +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.lib +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/process_list.cpp +0 -0
- /atomicshop/{archiver → permissions}/__init__.py +0 -0
- /atomicshop/{wrappers/fibratusw → web_apis}/__init__.py +0 -0
- /atomicshop/wrappers/{nodejsw → pywin32w/wmis}/__init__.py +0 -0
- /atomicshop/wrappers/pywin32w/{wmi_win32process.py → wmis/win32process.py} +0 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info/licenses}/LICENSE.txt +0 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/top_level.txt +0 -0
|
@@ -11,10 +11,14 @@ EVENT_CONTROL_CODE_ENABLE_PROVIDER = 1
|
|
|
11
11
|
|
|
12
12
|
MAXIMUM_LOGGERS = 64
|
|
13
13
|
ULONG64 = ctypes.c_uint64
|
|
14
|
+
UCHAR = ctypes.c_ubyte
|
|
14
15
|
|
|
15
16
|
INVALID_HANDLE_VALUE = ctypes.c_void_p(-1).value
|
|
16
17
|
TRACEHANDLE = ULONG64
|
|
17
18
|
|
|
19
|
+
PROCESS_TRACE_MODE_EVENT_RECORD = 0x10000000 # new event-record callback
|
|
20
|
+
PROCESS_TRACE_MODE_REAL_TIME = 0x00000100
|
|
21
|
+
INVALID_PROCESSTRACE_HANDLE = 0xFFFFFFFFFFFFFFFF # Often -1 in 64-bit
|
|
18
22
|
|
|
19
23
|
|
|
20
24
|
"""
|
|
@@ -69,10 +73,7 @@ class EVENT_TRACE_PROPERTIES(ctypes.Structure):
|
|
|
69
73
|
("RealTimeBuffersLost", wintypes.ULONG),
|
|
70
74
|
("LoggerThreadId", wintypes.HANDLE),
|
|
71
75
|
("LogFileNameOffset", wintypes.ULONG),
|
|
72
|
-
("LoggerNameOffset", wintypes.ULONG)
|
|
73
|
-
# Allocate space for the names at the end of the structure
|
|
74
|
-
("_LoggerName", wintypes.WCHAR * 1024),
|
|
75
|
-
("_LogFileName", wintypes.WCHAR * 1024)
|
|
76
|
+
("LoggerNameOffset", wintypes.ULONG)
|
|
76
77
|
]
|
|
77
78
|
|
|
78
79
|
|
|
@@ -183,55 +184,59 @@ class EVENT_HEADER(ctypes.Structure):
|
|
|
183
184
|
("RelatedActivityId", GUID),
|
|
184
185
|
]
|
|
185
186
|
|
|
187
|
+
|
|
188
|
+
class ETW_BUFFER_CONTEXT(ctypes.Structure):
|
|
189
|
+
_fields_ = [('ProcessorNumber', ctypes.c_ubyte),
|
|
190
|
+
('Alignment', ctypes.c_ubyte),
|
|
191
|
+
('LoggerId', ctypes.c_ushort)]
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class EVENT_HEADER_EXTENDED_DATA_ITEM(ctypes.Structure):
|
|
195
|
+
_fields_ = [
|
|
196
|
+
('Reserved1', ctypes.c_ushort),
|
|
197
|
+
('ExtType', ctypes.c_ushort),
|
|
198
|
+
('Linkage', ctypes.c_ushort), # struct{USHORT :1, USHORT :15}
|
|
199
|
+
('DataSize', ctypes.c_ushort),
|
|
200
|
+
('DataPtr', ctypes.c_ulonglong)
|
|
201
|
+
]
|
|
202
|
+
|
|
203
|
+
|
|
186
204
|
class EVENT_RECORD(ctypes.Structure):
|
|
187
205
|
_fields_ = [
|
|
188
|
-
(
|
|
189
|
-
(
|
|
190
|
-
(
|
|
191
|
-
(
|
|
192
|
-
(
|
|
193
|
-
(
|
|
194
|
-
(
|
|
206
|
+
('EventHeader', EVENT_HEADER),
|
|
207
|
+
('BufferContext', ETW_BUFFER_CONTEXT),
|
|
208
|
+
('ExtendedDataCount', ctypes.c_ushort),
|
|
209
|
+
('UserDataLength', ctypes.c_ushort),
|
|
210
|
+
('ExtendedData', ctypes.POINTER(EVENT_HEADER_EXTENDED_DATA_ITEM)),
|
|
211
|
+
('UserData', ctypes.c_void_p),
|
|
212
|
+
('UserContext', ctypes.c_void_p)
|
|
195
213
|
]
|
|
196
214
|
|
|
197
215
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
# ("ProcessTraceMode", wintypes.ULONG),
|
|
205
|
-
# ("EventRecordCallback", wintypes.LPVOID),
|
|
206
|
-
# ("BufferSize", wintypes.ULONG),
|
|
207
|
-
# ("Filled", wintypes.ULONG),
|
|
208
|
-
# ("EventsLost", wintypes.ULONG),
|
|
209
|
-
# ("BuffersLost", wintypes.ULONG),
|
|
210
|
-
# ("RealTimeBuffersLost", wintypes.ULONG),
|
|
211
|
-
# ("LogBuffersLost", wintypes.ULONG),
|
|
212
|
-
# ("BuffersWritten", wintypes.ULONG),
|
|
213
|
-
# ("LogFileMode", wintypes.ULONG),
|
|
214
|
-
# ("IsKernelTrace", wintypes.ULONG),
|
|
215
|
-
# ("Context", wintypes.ULONG) # Placeholder for context pointer
|
|
216
|
-
# ]
|
|
216
|
+
class EVENT_TRACE_LOGFILE(ctypes.Structure):
|
|
217
|
+
pass
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
EVENT_RECORD_CALLBACK = ctypes.WINFUNCTYPE(None, ctypes.POINTER(EVENT_RECORD))
|
|
221
|
+
EVENT_TRACE_BUFFER_CALLBACK = ctypes.WINFUNCTYPE(ctypes.c_ulong, ctypes.POINTER(EVENT_TRACE_LOGFILE))
|
|
217
222
|
|
|
218
223
|
|
|
219
224
|
class EVENT_TRACE_LOGFILE(ctypes.Structure):
|
|
220
225
|
_fields_ = [
|
|
221
|
-
(
|
|
222
|
-
(
|
|
223
|
-
(
|
|
224
|
-
(
|
|
225
|
-
(
|
|
226
|
-
(
|
|
227
|
-
(
|
|
228
|
-
(
|
|
229
|
-
(
|
|
230
|
-
(
|
|
231
|
-
(
|
|
232
|
-
(
|
|
233
|
-
(
|
|
234
|
-
(
|
|
226
|
+
('LogFileName', ctypes.c_wchar_p),
|
|
227
|
+
('LoggerName', ctypes.c_wchar_p),
|
|
228
|
+
('CurrentTime', ctypes.c_longlong),
|
|
229
|
+
('BuffersRead', ctypes.c_ulong),
|
|
230
|
+
('ProcessTraceMode', ctypes.c_ulong),
|
|
231
|
+
('CurrentEvent', EVENT_TRACE),
|
|
232
|
+
('LogfileHeader', TRACE_LOGFILE_HEADER),
|
|
233
|
+
('BufferCallback', EVENT_TRACE_BUFFER_CALLBACK),
|
|
234
|
+
('BufferSize', ctypes.c_ulong),
|
|
235
|
+
('Filled', ctypes.c_ulong),
|
|
236
|
+
('EventsLost', ctypes.c_ulong),
|
|
237
|
+
('EventRecordCallback', EVENT_RECORD_CALLBACK),
|
|
238
|
+
('IsKernelTrace', ctypes.c_ulong),
|
|
239
|
+
('Context', ctypes.c_void_p)
|
|
235
240
|
]
|
|
236
241
|
|
|
237
242
|
|
|
@@ -255,7 +260,7 @@ class PROVIDER_INFORMATION(ctypes.Structure):
|
|
|
255
260
|
|
|
256
261
|
|
|
257
262
|
# Load the necessary library
|
|
258
|
-
advapi32 = ctypes.WinDLL(
|
|
263
|
+
advapi32 = ctypes.WinDLL("advapi32", use_last_error=True)
|
|
259
264
|
tdh = ctypes.windll.tdh
|
|
260
265
|
|
|
261
266
|
# Define necessary TDH functions
|
|
@@ -263,6 +268,46 @@ tdh.TdhEnumerateProviders.argtypes = [ctypes.POINTER(PROVIDER_ENUMERATION_INFO),
|
|
|
263
268
|
tdh.TdhEnumerateProviders.restype = ULONG
|
|
264
269
|
|
|
265
270
|
|
|
271
|
+
# Make sure StartTraceW has proper argtypes (if not set in consts)
|
|
272
|
+
StartTrace = advapi32.StartTraceW
|
|
273
|
+
StartTrace.argtypes = [
|
|
274
|
+
ctypes.POINTER(TRACEHANDLE),
|
|
275
|
+
wintypes.LPCWSTR,
|
|
276
|
+
ctypes.POINTER(EVENT_TRACE_PROPERTIES)
|
|
277
|
+
]
|
|
278
|
+
StartTrace.restype = wintypes.ULONG
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
class EVENT_FILTER_DESCRIPTOR(ctypes.Structure):
|
|
282
|
+
_fields_ = [('Ptr', ctypes.c_ulonglong),
|
|
283
|
+
('Size', ctypes.c_ulong),
|
|
284
|
+
('Type', ctypes.c_ulong)]
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
class ENABLE_TRACE_PARAMETERS(ctypes.Structure):
|
|
288
|
+
_fields_ = [
|
|
289
|
+
('Version', ctypes.c_ulong),
|
|
290
|
+
('EnableProperty', ctypes.c_ulong),
|
|
291
|
+
('ControlFlags', ctypes.c_ulong),
|
|
292
|
+
('SourceId', GUID),
|
|
293
|
+
('EnableFilterDesc', ctypes.POINTER(EVENT_FILTER_DESCRIPTOR)),
|
|
294
|
+
('FilterDescCount', ctypes.c_ulong)
|
|
295
|
+
]
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
EnableTraceEx2 = advapi32.EnableTraceEx2
|
|
299
|
+
EnableTraceEx2.argtypes = [
|
|
300
|
+
TRACEHANDLE, # TraceHandle (c_uint64)
|
|
301
|
+
ctypes.POINTER(GUID), # ProviderId
|
|
302
|
+
ctypes.c_ulong, # ControlCode
|
|
303
|
+
ctypes.c_char, # Level
|
|
304
|
+
ctypes.c_ulonglong, # MatchAnyKeyword
|
|
305
|
+
ctypes.c_ulonglong, # MatchAllKeyword
|
|
306
|
+
ctypes.c_ulong, # Timeout
|
|
307
|
+
ctypes.POINTER(ENABLE_TRACE_PARAMETERS)] # PENABLE_TRACE_PARAMETERS (optional) -> None or pointer
|
|
308
|
+
EnableTraceEx2.restype = ctypes.c_ulong
|
|
309
|
+
|
|
310
|
+
|
|
266
311
|
# Define the function prototype
|
|
267
312
|
QueryAllTraces = advapi32.QueryAllTracesW
|
|
268
313
|
QueryAllTraces.argtypes = [
|
|
@@ -277,8 +322,13 @@ OpenTrace.argtypes = [ctypes.POINTER(EVENT_TRACE_LOGFILE)]
|
|
|
277
322
|
OpenTrace.restype = wintypes.ULONG
|
|
278
323
|
|
|
279
324
|
ProcessTrace = advapi32.ProcessTrace
|
|
280
|
-
ProcessTrace.argtypes = [
|
|
281
|
-
|
|
325
|
+
ProcessTrace.argtypes = [
|
|
326
|
+
ctypes.POINTER(ctypes.c_uint64), # pointer to array of 64-bit handles
|
|
327
|
+
wintypes.ULONG, # handle count
|
|
328
|
+
ctypes.c_void_p, # LPFILETIME (start)
|
|
329
|
+
ctypes.c_void_p # LPFILETIME (end)
|
|
330
|
+
]
|
|
331
|
+
ProcessTrace.restype = wintypes.ULONG
|
|
282
332
|
|
|
283
333
|
CloseTrace = advapi32.CloseTrace
|
|
284
334
|
CloseTrace.argtypes = [wintypes.ULONG]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import ctypes
|
|
2
|
-
|
|
2
|
+
import queue
|
|
3
3
|
from ctypes.wintypes import ULONG
|
|
4
4
|
import uuid
|
|
5
5
|
from typing import Literal
|
|
@@ -34,7 +34,7 @@ def start_etw_session(
|
|
|
34
34
|
provider_name_list: list = None,
|
|
35
35
|
verbosity_mode: int = 4,
|
|
36
36
|
maximum_buffers: int = 38
|
|
37
|
-
):
|
|
37
|
+
) -> const.TRACEHANDLE:
|
|
38
38
|
"""
|
|
39
39
|
Start an ETW session and enable the specified provider.
|
|
40
40
|
|
|
@@ -77,57 +77,89 @@ def start_etw_session(
|
|
|
77
77
|
for provider_name in provider_name_list:
|
|
78
78
|
provider_guid_list.append(providers.get_provider_guid_by_name(provider_name))
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
80
|
+
# (1) Allocate a buffer large enough for EVENT_TRACE_PROPERTIES + space for 2 strings
|
|
81
|
+
# The typical approach is to allow enough space for:
|
|
82
|
+
# - The structure
|
|
83
|
+
# - The "LoggerName" string
|
|
84
|
+
# - The "LogFileName" string (even if we don't use it, we must leave offset space)
|
|
85
|
+
#
|
|
86
|
+
props_size = ctypes.sizeof(const.EVENT_TRACE_PROPERTIES)
|
|
87
|
+
# Add space for 2 x 1024 wide-chars (one for LoggerName, one for LogFileName)
|
|
88
|
+
# Each wide char = ctypes.sizeof(ctypes.c_wchar).
|
|
89
|
+
props_size += (2 * 1024 * ctypes.sizeof(ctypes.c_wchar)) # for logger name
|
|
90
|
+
props_size += (2 * 1024 * ctypes.sizeof(ctypes.c_wchar)) # for log file name
|
|
91
|
+
|
|
92
|
+
properties_buffer = ctypes.create_string_buffer(props_size)
|
|
93
|
+
properties_ptr = ctypes.cast(properties_buffer, ctypes.POINTER(const.EVENT_TRACE_PROPERTIES))
|
|
94
|
+
props = properties_ptr.contents
|
|
95
|
+
|
|
96
|
+
# (2) Fill in basic fields
|
|
97
|
+
props.Wnode.BufferSize = props_size
|
|
98
|
+
props.Wnode.Flags = const.WNODE_FLAG_TRACED_GUID # 0x00020000
|
|
99
|
+
props.Wnode.ClientContext = 1 # QPC clock
|
|
100
|
+
props.BufferSize = 1024
|
|
101
|
+
props.MinimumBuffers = 1
|
|
102
|
+
props.MaximumBuffers = maximum_buffers
|
|
103
|
+
props.MaximumFileSize = 0
|
|
104
|
+
props.LogFileMode = const.EVENT_TRACE_REAL_TIME_MODE # real-time
|
|
105
|
+
props.FlushTimer = 1
|
|
106
|
+
props.EnableFlags = 0
|
|
107
|
+
|
|
108
|
+
# (3) Indicate where in this allocated buffer the strings should go
|
|
109
|
+
struct_size = ctypes.sizeof(const.EVENT_TRACE_PROPERTIES)
|
|
110
|
+
props.LoggerNameOffset = struct_size
|
|
111
|
+
props.LogFileNameOffset = struct_size + (2 * 1024 * ctypes.sizeof(ctypes.c_wchar))
|
|
112
|
+
|
|
113
|
+
# (4) Copy the session name into the LoggerName space
|
|
114
|
+
logger_name_address = ctypes.addressof(properties_buffer) + props.LoggerNameOffset
|
|
115
|
+
session_name_wchar = ctypes.create_unicode_buffer(session_name)
|
|
116
|
+
ctypes.memmove(
|
|
117
|
+
logger_name_address,
|
|
118
|
+
session_name_wchar,
|
|
119
|
+
len(session_name) * ctypes.sizeof(ctypes.c_wchar)
|
|
120
|
+
)
|
|
104
121
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
|
122
|
+
# (5) Start the session
|
|
123
|
+
session_handle = const.TRACEHANDLE(0)
|
|
124
|
+
status = const.StartTrace(
|
|
125
|
+
ctypes.byref(session_handle),
|
|
126
|
+
session_name, # The session name as an LPCWSTR
|
|
127
|
+
properties_ptr # pointer to EVENT_TRACE_PROPERTIES
|
|
123
128
|
)
|
|
124
129
|
|
|
125
130
|
if status != 0:
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
+
# 183 => ERROR_ALREADY_EXISTS
|
|
132
|
+
if status == 183:
|
|
133
|
+
raise ETWSessionExists(f"ETW session [{session_name}] already exists")
|
|
134
|
+
else:
|
|
135
|
+
raise Exception(f"StartTraceW failed with error code {status}")
|
|
136
|
+
|
|
137
|
+
# (6) If we have providers to enable, enable each
|
|
138
|
+
if provider_guid_list:
|
|
139
|
+
for guid_str in provider_guid_list:
|
|
140
|
+
guid_struct = _string_to_guid(guid_str)
|
|
141
|
+
|
|
142
|
+
# Typically you'd do something like:
|
|
143
|
+
# advapi32.EnableTraceEx2(TRACEHANDLE, PGUID, CONTROL_CODE, LEVEL, KW, KW, TIMEOUT, FILTER)
|
|
144
|
+
|
|
145
|
+
enable_status = const.EnableTraceEx2(
|
|
146
|
+
session_handle, # The session handle
|
|
147
|
+
ctypes.byref(guid_struct), # The provider GUID
|
|
148
|
+
const.EVENT_CONTROL_CODE_ENABLE_PROVIDER, # 1 => enable
|
|
149
|
+
verbosity_mode, # level
|
|
150
|
+
0xFFFFFFFFFFFFFFFF, # matchAnyKeyword
|
|
151
|
+
0, # matchAllKeyword
|
|
152
|
+
0, # timeout
|
|
153
|
+
None # enableParameters (optional)
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
if enable_status != 0:
|
|
157
|
+
raise Exception(
|
|
158
|
+
f"EnableTraceEx2 failed for provider {guid_str} (error={enable_status})"
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
print(f"ETW session '{session_name}' started successfully.")
|
|
162
|
+
return session_handle
|
|
131
163
|
|
|
132
164
|
|
|
133
165
|
# Function to stop and delete ETW session
|
|
@@ -165,6 +197,103 @@ def stop_and_delete_etw_session(session_name: str) -> tuple[bool, int]:
|
|
|
165
197
|
return True, status
|
|
166
198
|
|
|
167
199
|
|
|
200
|
+
@const.EVENT_CALLBACK_TYPE
|
|
201
|
+
def _default_callback(
|
|
202
|
+
event_record_ptr
|
|
203
|
+
):
|
|
204
|
+
"""
|
|
205
|
+
This function will be called by Windows for every incoming ETW event.
|
|
206
|
+
'event_record_ptr' is a pointer to an EVENT_RECORD structure.
|
|
207
|
+
"""
|
|
208
|
+
# Convert pointer to a Python EVENT_RECORD object
|
|
209
|
+
event_record = event_record_ptr.contents
|
|
210
|
+
|
|
211
|
+
# Do something with event_record (e.g., parse via TDH)
|
|
212
|
+
print("Received an ETW event!", event_record.EventHeader.ProviderId)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def start_etw_consumer(
|
|
216
|
+
session_name: str,
|
|
217
|
+
record_queue: queue.Queue
|
|
218
|
+
):
|
|
219
|
+
"""
|
|
220
|
+
Attach to an existing real-time ETW session by 'session_name'
|
|
221
|
+
using the "new" EVENT_RECORD callback approach.
|
|
222
|
+
This call blocks until the ETW session is stopped or an error occurs.
|
|
223
|
+
"""
|
|
224
|
+
# 1) Create a closure callback that references the queue
|
|
225
|
+
# We define an inner function that sees 'record_queue' from outer scope.
|
|
226
|
+
# Then we wrap that in EVENT_CALLBACK_TYPE.
|
|
227
|
+
if record_queue is not None:
|
|
228
|
+
@const.EVENT_CALLBACK_TYPE
|
|
229
|
+
def _queue_callback(event_record_ptr):
|
|
230
|
+
event_record = event_record_ptr.contents
|
|
231
|
+
# # Example: put a simple dict with the provider ID & possibly more info
|
|
232
|
+
# record_queue.put({
|
|
233
|
+
# "provider_id": str(event_record.EventHeader.ProviderId),
|
|
234
|
+
# "process_id": event_record.EventHeader.ProcessId,
|
|
235
|
+
# "thread_id": event_record.EventHeader.ThreadId,
|
|
236
|
+
# # ... more fields or parse them with TdhGetEventInformation, etc.
|
|
237
|
+
# })
|
|
238
|
+
print("Received an ETW event!", event_record.EventHeader.ProviderId)
|
|
239
|
+
record_queue.put(event_record)
|
|
240
|
+
else:
|
|
241
|
+
_queue_callback = _default_callback
|
|
242
|
+
|
|
243
|
+
# Keep a reference to the callback so Python doesn't GC it.
|
|
244
|
+
start_etw_consumer._callback_ref = _queue_callback
|
|
245
|
+
|
|
246
|
+
# Prepare the EVENT_TRACE_LOGFILE structure
|
|
247
|
+
logfile = const.EVENT_TRACE_LOGFILE()
|
|
248
|
+
# You can also do: logfile.LoggerName = session_name
|
|
249
|
+
# If you assign session_name (a Python str), ctypes automatically converts it to a temporary c_wchar_p under the hood.
|
|
250
|
+
# logfile.LoggerName = ctypes.c_wchar_p(session_name)
|
|
251
|
+
logfile.LoggerName = session_name
|
|
252
|
+
logfile.LogFileName = None # Real-time, not from a file
|
|
253
|
+
logfile.ProcessTraceMode = (const.PROCESS_TRACE_MODE_REAL_TIME | const.PROCESS_TRACE_MODE_EVENT_RECORD)
|
|
254
|
+
|
|
255
|
+
# Point to our Python callback
|
|
256
|
+
logfile.EventRecordCallback = const.EVENT_RECORD_CALLBACK(_default_callback)
|
|
257
|
+
|
|
258
|
+
# Open the trace
|
|
259
|
+
trace_handle = const.OpenTrace(ctypes.byref(logfile))
|
|
260
|
+
if trace_handle == const.INVALID_PROCESSTRACE_HANDLE:
|
|
261
|
+
error_code = ctypes.get_last_error()
|
|
262
|
+
raise OSError(f"OpenTrace failed with error code: {error_code}")
|
|
263
|
+
|
|
264
|
+
# trace_handle is actually an unsigned long, but in 64-bit it's a 64-bit handle.
|
|
265
|
+
# We'll create an array of one handle for ProcessTrace:
|
|
266
|
+
trace_handle_array = (ctypes.c_uint64 * 1)(trace_handle)
|
|
267
|
+
|
|
268
|
+
# Blocking call - will not return until the session is stopped (or error).
|
|
269
|
+
status = const.ProcessTrace(
|
|
270
|
+
trace_handle_array,
|
|
271
|
+
1, # HandleCount = 1
|
|
272
|
+
None, # StartTime = None
|
|
273
|
+
None # EndTime = None
|
|
274
|
+
)
|
|
275
|
+
if status != 0:
|
|
276
|
+
raise OSError(f"ProcessTrace failed with error code: {status}")
|
|
277
|
+
|
|
278
|
+
print("ProcessTrace returned. ETW consumer finished.")
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def start_etw_consumer_in_thread(
|
|
282
|
+
session_name: str,
|
|
283
|
+
record_queue: queue.Queue
|
|
284
|
+
):
|
|
285
|
+
"""
|
|
286
|
+
Start an ETW consumer in a separate thread.
|
|
287
|
+
"""
|
|
288
|
+
import threading
|
|
289
|
+
|
|
290
|
+
def _start_etw_consumer():
|
|
291
|
+
start_etw_consumer(session_name, record_queue)
|
|
292
|
+
|
|
293
|
+
thread = threading.Thread(target=_start_etw_consumer)
|
|
294
|
+
thread.start()
|
|
295
|
+
|
|
296
|
+
|
|
168
297
|
def get_all_providers(key_as: Literal['name', 'guid'] = 'name') -> dict:
|
|
169
298
|
"""
|
|
170
299
|
Get all ETW providers available on the system.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import ctypes
|
|
3
|
+
import pefile
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def get_file_properties(file_path: str) -> dict:
|
|
7
|
+
"""
|
|
8
|
+
Retrieve file version properties using ctypes.
|
|
9
|
+
|
|
10
|
+
:param file_path: Full path to the file.
|
|
11
|
+
:return: Dictionary with file properties.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def query_value(name):
|
|
15
|
+
r = ctypes.c_void_p()
|
|
16
|
+
l = ctypes.c_uint()
|
|
17
|
+
ctypes.windll.version.VerQueryValueW(
|
|
18
|
+
res, f"\\StringFileInfo\\040904b0\\{name}", ctypes.byref(r), ctypes.byref(l))
|
|
19
|
+
return ctypes.wstring_at(r) if r.value else "N/A"
|
|
20
|
+
|
|
21
|
+
properties = {
|
|
22
|
+
"FileDescription": "N/A",
|
|
23
|
+
"FileVersion": "N/A",
|
|
24
|
+
"ProductName": "N/A",
|
|
25
|
+
"ProductVersion": "N/A",
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if not os.path.isfile(file_path):
|
|
29
|
+
return properties
|
|
30
|
+
|
|
31
|
+
# Load version information
|
|
32
|
+
size = ctypes.windll.version.GetFileVersionInfoSizeW(file_path, None)
|
|
33
|
+
if size == 0:
|
|
34
|
+
return properties
|
|
35
|
+
|
|
36
|
+
res = ctypes.create_string_buffer(size)
|
|
37
|
+
ctypes.windll.version.GetFileVersionInfoW(file_path, None, size, res)
|
|
38
|
+
|
|
39
|
+
properties["FileDescription"] = query_value("FileDescription")
|
|
40
|
+
properties["FileVersion"] = query_value("FileVersion")
|
|
41
|
+
properties["ProductName"] = query_value("ProductName")
|
|
42
|
+
properties["ProductVersion"] = query_value("ProductVersion")
|
|
43
|
+
|
|
44
|
+
# Fallback to pefile if ctypes fails or returns, pefile is much slower but more reliable, so we only use it as a fallback.
|
|
45
|
+
if properties["FileDescription"] == "N/A" or properties["FileVersion"] == "N/A":
|
|
46
|
+
pe = pefile.PE(file_path)
|
|
47
|
+
version_info = pe.VS_FIXEDFILEINFO
|
|
48
|
+
if version_info:
|
|
49
|
+
# If version_info is a list, take the first valid entry
|
|
50
|
+
if isinstance(version_info, list):
|
|
51
|
+
version_info = version_info[0]
|
|
52
|
+
|
|
53
|
+
properties["FileVersion"] = f"{version_info.FileVersionMS >> 16}.{version_info.FileVersionMS & 0xFFFF}.{version_info.FileVersionLS >> 16}.{version_info.FileVersionLS & 0xFFFF}"
|
|
54
|
+
# Attempt to get additional metadata
|
|
55
|
+
for entry in pe.FileInfo or []:
|
|
56
|
+
for structure in entry:
|
|
57
|
+
if hasattr(structure, "StringTable"):
|
|
58
|
+
for string_table in structure.StringTable:
|
|
59
|
+
for key, value in string_table.entries.items():
|
|
60
|
+
if key == b"FileDescription":
|
|
61
|
+
properties["FileDescription"] = value.decode("utf-8", errors="ignore")
|
|
62
|
+
elif key == b"ProductName":
|
|
63
|
+
properties["ProductName"] = value.decode("utf-8", errors="ignore")
|
|
64
|
+
elif key == b"ProductVersion":
|
|
65
|
+
properties["ProductVersion"] = value.decode("utf-8", errors="ignore")
|
|
66
|
+
|
|
67
|
+
return properties
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import os
|
|
2
|
-
import sys
|
|
3
2
|
import argparse
|
|
4
3
|
|
|
4
|
+
from dkarchiver.arch_wrappers import sevenz_app_w
|
|
5
|
+
|
|
5
6
|
from .base import msi
|
|
6
7
|
from . import base, tables, cabs
|
|
7
8
|
from ... import olefilew
|
|
8
9
|
from ....print_api import print_api
|
|
9
|
-
from ....archiver import sevenz_app_w
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
# Directory names.
|