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.
Files changed (221) hide show
  1. atomicshop/__init__.py +1 -1
  2. atomicshop/{addons/mains → a_mains}/FACT/update_extract.py +3 -2
  3. atomicshop/a_mains/dns_gateway_setting.py +11 -0
  4. atomicshop/a_mains/get_local_tcp_ports.py +85 -0
  5. atomicshop/a_mains/github_wrapper.py +11 -0
  6. atomicshop/a_mains/install_ca_certificate.py +172 -0
  7. atomicshop/a_mains/process_from_port.py +119 -0
  8. atomicshop/a_mains/set_default_dns_gateway.py +90 -0
  9. atomicshop/a_mains/update_config_toml.py +38 -0
  10. atomicshop/basics/ansi_escape_codes.py +3 -1
  11. atomicshop/basics/argparse_template.py +2 -0
  12. atomicshop/basics/booleans.py +27 -30
  13. atomicshop/basics/bytes_arrays.py +43 -0
  14. atomicshop/basics/classes.py +149 -1
  15. atomicshop/basics/enums.py +2 -2
  16. atomicshop/basics/exceptions.py +5 -1
  17. atomicshop/basics/list_of_classes.py +29 -0
  18. atomicshop/basics/multiprocesses.py +374 -50
  19. atomicshop/basics/strings.py +72 -3
  20. atomicshop/basics/threads.py +14 -0
  21. atomicshop/basics/tracebacks.py +13 -3
  22. atomicshop/certificates.py +153 -52
  23. atomicshop/config_init.py +11 -6
  24. atomicshop/console_user_response.py +7 -14
  25. atomicshop/consoles.py +9 -0
  26. atomicshop/datetimes.py +1 -1
  27. atomicshop/diff_check.py +3 -3
  28. atomicshop/dns.py +128 -3
  29. atomicshop/etws/_pywintrace_fix.py +17 -0
  30. atomicshop/etws/trace.py +40 -42
  31. atomicshop/etws/traces/trace_dns.py +56 -44
  32. atomicshop/etws/traces/trace_tcp.py +130 -0
  33. atomicshop/file_io/csvs.py +27 -5
  34. atomicshop/file_io/docxs.py +34 -17
  35. atomicshop/file_io/file_io.py +31 -17
  36. atomicshop/file_io/jsons.py +49 -0
  37. atomicshop/file_io/tomls.py +139 -0
  38. atomicshop/filesystem.py +616 -291
  39. atomicshop/get_process_list.py +3 -3
  40. atomicshop/http_parse.py +149 -93
  41. atomicshop/ip_addresses.py +6 -1
  42. atomicshop/mitm/centered_settings.py +132 -0
  43. atomicshop/mitm/config_static.py +207 -0
  44. atomicshop/mitm/config_toml_editor.py +55 -0
  45. atomicshop/mitm/connection_thread_worker.py +875 -357
  46. atomicshop/mitm/engines/__parent/parser___parent.py +4 -17
  47. atomicshop/mitm/engines/__parent/recorder___parent.py +108 -51
  48. atomicshop/mitm/engines/__parent/requester___parent.py +116 -0
  49. atomicshop/mitm/engines/__parent/responder___parent.py +75 -114
  50. atomicshop/mitm/engines/__reference_general/parser___reference_general.py +10 -7
  51. atomicshop/mitm/engines/__reference_general/recorder___reference_general.py +5 -5
  52. atomicshop/mitm/engines/__reference_general/requester___reference_general.py +47 -0
  53. atomicshop/mitm/engines/__reference_general/responder___reference_general.py +95 -13
  54. atomicshop/mitm/engines/create_module_template.py +58 -14
  55. atomicshop/mitm/import_config.py +359 -139
  56. atomicshop/mitm/initialize_engines.py +160 -80
  57. atomicshop/mitm/message.py +64 -23
  58. atomicshop/mitm/mitm_main.py +892 -0
  59. atomicshop/mitm/recs_files.py +183 -0
  60. atomicshop/mitm/shared_functions.py +4 -10
  61. atomicshop/mitm/ssh_tester.py +82 -0
  62. atomicshop/mitm/statistic_analyzer.py +136 -40
  63. atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py +265 -83
  64. atomicshop/monitor/checks/dns.py +1 -1
  65. atomicshop/networks.py +671 -0
  66. atomicshop/on_exit.py +39 -9
  67. atomicshop/package_mains_processor.py +84 -0
  68. atomicshop/permissions/permissions.py +22 -0
  69. atomicshop/permissions/ubuntu_permissions.py +239 -0
  70. atomicshop/permissions/win_permissions.py +33 -0
  71. atomicshop/print_api.py +24 -42
  72. atomicshop/process.py +24 -6
  73. atomicshop/process_poller/process_pool.py +0 -1
  74. atomicshop/process_poller/simple_process_pool.py +204 -5
  75. atomicshop/python_file_patcher.py +1 -1
  76. atomicshop/python_functions.py +27 -75
  77. atomicshop/speech_recognize.py +8 -0
  78. atomicshop/ssh_remote.py +158 -172
  79. atomicshop/system_resource_monitor.py +61 -47
  80. atomicshop/system_resources.py +8 -8
  81. atomicshop/tempfiles.py +1 -2
  82. atomicshop/urls.py +6 -0
  83. atomicshop/venvs.py +28 -0
  84. atomicshop/versioning.py +27 -0
  85. atomicshop/web.py +98 -27
  86. atomicshop/web_apis/google_custom_search.py +44 -0
  87. atomicshop/web_apis/google_llm.py +188 -0
  88. atomicshop/websocket_parse.py +450 -0
  89. atomicshop/wrappers/certauthw/certauth.py +1 -0
  90. atomicshop/wrappers/cryptographyw.py +29 -8
  91. atomicshop/wrappers/ctyping/etw_winapi/const.py +97 -47
  92. atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py +178 -49
  93. atomicshop/wrappers/ctyping/file_details_winapi.py +67 -0
  94. atomicshop/wrappers/ctyping/msi_windows_installer/cabs.py +2 -1
  95. atomicshop/wrappers/ctyping/msi_windows_installer/extract_msi_main.py +2 -2
  96. atomicshop/wrappers/ctyping/setup_device.py +466 -0
  97. atomicshop/wrappers/ctyping/win_console.py +39 -0
  98. atomicshop/wrappers/dockerw/dockerw.py +113 -2
  99. atomicshop/wrappers/elasticsearchw/config_basic.py +0 -12
  100. atomicshop/wrappers/elasticsearchw/elastic_infra.py +75 -0
  101. atomicshop/wrappers/elasticsearchw/elasticsearchw.py +2 -20
  102. atomicshop/wrappers/factw/get_file_data.py +12 -5
  103. atomicshop/wrappers/factw/install/install_after_restart.py +89 -5
  104. atomicshop/wrappers/factw/install/pre_install_and_install_before_restart.py +20 -14
  105. atomicshop/wrappers/githubw.py +537 -54
  106. atomicshop/wrappers/loggingw/consts.py +1 -1
  107. atomicshop/wrappers/loggingw/filters.py +23 -0
  108. atomicshop/wrappers/loggingw/formatters.py +12 -0
  109. atomicshop/wrappers/loggingw/handlers.py +214 -107
  110. atomicshop/wrappers/loggingw/loggers.py +19 -0
  111. atomicshop/wrappers/loggingw/loggingw.py +860 -22
  112. atomicshop/wrappers/loggingw/reading.py +134 -112
  113. atomicshop/wrappers/mongodbw/mongo_infra.py +31 -0
  114. atomicshop/wrappers/mongodbw/mongodbw.py +1324 -36
  115. atomicshop/wrappers/netshw.py +271 -0
  116. atomicshop/wrappers/playwrightw/engine.py +34 -19
  117. atomicshop/wrappers/playwrightw/infra.py +5 -0
  118. atomicshop/wrappers/playwrightw/javascript.py +7 -3
  119. atomicshop/wrappers/playwrightw/keyboard.py +14 -0
  120. atomicshop/wrappers/playwrightw/scenarios.py +172 -5
  121. atomicshop/wrappers/playwrightw/waits.py +9 -7
  122. atomicshop/wrappers/powershell_networking.py +80 -0
  123. atomicshop/wrappers/psutilw/processes.py +37 -1
  124. atomicshop/wrappers/psutilw/psutil_networks.py +85 -0
  125. atomicshop/wrappers/pyopensslw.py +9 -2
  126. atomicshop/wrappers/pywin32w/cert_store.py +116 -0
  127. atomicshop/wrappers/pywin32w/win_event_log/fetch.py +174 -0
  128. atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +3 -105
  129. atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +3 -57
  130. atomicshop/wrappers/pywin32w/wmis/msft_netipaddress.py +113 -0
  131. atomicshop/wrappers/pywin32w/wmis/win32_networkadapterconfiguration.py +259 -0
  132. atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py +112 -0
  133. atomicshop/wrappers/pywin32w/wmis/wmi_helpers.py +236 -0
  134. atomicshop/wrappers/socketw/accepter.py +21 -7
  135. atomicshop/wrappers/socketw/certificator.py +216 -150
  136. atomicshop/wrappers/socketw/creator.py +190 -50
  137. atomicshop/wrappers/socketw/dns_server.py +491 -182
  138. atomicshop/wrappers/socketw/exception_wrapper.py +45 -52
  139. atomicshop/wrappers/socketw/process_getter.py +86 -0
  140. atomicshop/wrappers/socketw/receiver.py +144 -102
  141. atomicshop/wrappers/socketw/sender.py +65 -35
  142. atomicshop/wrappers/socketw/sni.py +334 -165
  143. atomicshop/wrappers/socketw/socket_base.py +134 -0
  144. atomicshop/wrappers/socketw/socket_client.py +137 -95
  145. atomicshop/wrappers/socketw/socket_server_tester.py +11 -7
  146. atomicshop/wrappers/socketw/socket_wrapper.py +717 -116
  147. atomicshop/wrappers/socketw/ssl_base.py +15 -14
  148. atomicshop/wrappers/socketw/statistics_csv.py +148 -17
  149. atomicshop/wrappers/sysmonw.py +1 -1
  150. atomicshop/wrappers/ubuntu_terminal.py +65 -26
  151. atomicshop/wrappers/win_auditw.py +189 -0
  152. atomicshop/wrappers/winregw/__init__.py +0 -0
  153. atomicshop/wrappers/winregw/winreg_installed_software.py +58 -0
  154. atomicshop/wrappers/winregw/winreg_network.py +232 -0
  155. {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/METADATA +31 -51
  156. atomicshop-3.10.5.dist-info/RECORD +306 -0
  157. {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/WHEEL +1 -1
  158. atomicshop/_basics_temp.py +0 -101
  159. atomicshop/a_installs/win/fibratus.py +0 -9
  160. atomicshop/a_installs/win/mongodb.py +0 -9
  161. atomicshop/a_installs/win/pycharm.py +0 -9
  162. atomicshop/addons/a_setup_scripts/install_psycopg2_ubuntu.sh +0 -3
  163. atomicshop/addons/a_setup_scripts/install_pywintrace_0.3.cmd +0 -2
  164. atomicshop/addons/mains/__pycache__/install_fibratus_windows.cpython-312.pyc +0 -0
  165. atomicshop/addons/mains/__pycache__/msi_unpacker.cpython-312.pyc +0 -0
  166. atomicshop/addons/mains/install_docker_rootless_ubuntu.py +0 -11
  167. atomicshop/addons/mains/install_docker_ubuntu_main_sudo.py +0 -11
  168. atomicshop/addons/mains/install_elastic_search_and_kibana_ubuntu.py +0 -10
  169. atomicshop/addons/mains/install_wsl_ubuntu_lts_admin.py +0 -9
  170. atomicshop/addons/package_setup/CreateWheel.cmd +0 -7
  171. atomicshop/addons/package_setup/Setup in Edit mode.cmd +0 -6
  172. atomicshop/addons/package_setup/Setup.cmd +0 -7
  173. atomicshop/archiver/_search_in_zip.py +0 -189
  174. atomicshop/archiver/archiver.py +0 -34
  175. atomicshop/archiver/search_in_archive.py +0 -250
  176. atomicshop/archiver/sevenz_app_w.py +0 -86
  177. atomicshop/archiver/sevenzs.py +0 -44
  178. atomicshop/archiver/zips.py +0 -293
  179. atomicshop/file_types.py +0 -24
  180. atomicshop/mitm/config_editor.py +0 -37
  181. atomicshop/mitm/engines/create_module_template_example.py +0 -13
  182. atomicshop/mitm/initialize_mitm_server.py +0 -268
  183. atomicshop/pbtkmultifile_argparse.py +0 -88
  184. atomicshop/permissions.py +0 -151
  185. atomicshop/script_as_string_processor.py +0 -38
  186. atomicshop/ssh_scripts/process_from_ipv4.py +0 -37
  187. atomicshop/ssh_scripts/process_from_port.py +0 -27
  188. atomicshop/wrappers/_process_wrapper_curl.py +0 -27
  189. atomicshop/wrappers/_process_wrapper_tar.py +0 -21
  190. atomicshop/wrappers/dockerw/install_docker.py +0 -209
  191. atomicshop/wrappers/elasticsearchw/infrastructure.py +0 -265
  192. atomicshop/wrappers/elasticsearchw/install_elastic.py +0 -232
  193. atomicshop/wrappers/ffmpegw.py +0 -125
  194. atomicshop/wrappers/fibratusw/install.py +0 -81
  195. atomicshop/wrappers/mongodbw/infrastructure.py +0 -53
  196. atomicshop/wrappers/mongodbw/install_mongodb.py +0 -190
  197. atomicshop/wrappers/msiw.py +0 -149
  198. atomicshop/wrappers/nodejsw/install_nodejs.py +0 -139
  199. atomicshop/wrappers/process_wrapper_pbtk.py +0 -16
  200. atomicshop/wrappers/psutilw/networks.py +0 -45
  201. atomicshop/wrappers/pycharmw.py +0 -81
  202. atomicshop/wrappers/socketw/base.py +0 -59
  203. atomicshop/wrappers/socketw/get_process.py +0 -107
  204. atomicshop/wrappers/wslw.py +0 -191
  205. atomicshop-2.15.11.dist-info/RECORD +0 -302
  206. /atomicshop/{addons/mains → a_mains}/FACT/factw_fact_extractor_docker_image_main_sudo.py +0 -0
  207. /atomicshop/{addons → a_mains/addons}/PlayWrightCodegen.cmd +0 -0
  208. /atomicshop/{addons → a_mains/addons}/ScriptExecution.cmd +0 -0
  209. /atomicshop/{addons → a_mains/addons}/inits/init_to_import_all_modules.py +0 -0
  210. /atomicshop/{addons → a_mains/addons}/process_list/ReadMe.txt +0 -0
  211. /atomicshop/{addons → a_mains/addons}/process_list/compile.cmd +0 -0
  212. /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.dll +0 -0
  213. /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.exp +0 -0
  214. /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.lib +0 -0
  215. /atomicshop/{addons → a_mains/addons}/process_list/process_list.cpp +0 -0
  216. /atomicshop/{archiver → permissions}/__init__.py +0 -0
  217. /atomicshop/{wrappers/fibratusw → web_apis}/__init__.py +0 -0
  218. /atomicshop/wrappers/{nodejsw → pywin32w/wmis}/__init__.py +0 -0
  219. /atomicshop/wrappers/pywin32w/{wmi_win32process.py → wmis/win32process.py} +0 -0
  220. {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info/licenses}/LICENSE.txt +0 -0
  221. {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
- ("EventHeader", EVENT_HEADER),
189
- ("BufferContext", wintypes.ULONG),
190
- ("ExtendedDataCount", wintypes.USHORT),
191
- ("UserDataLength", wintypes.USHORT),
192
- ("ExtendedData", wintypes.LPVOID),
193
- ("UserData", wintypes.LPVOID),
194
- ("UserContext", wintypes.LPVOID)
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
- # class EVENT_TRACE_LOGFILE(ctypes.Structure):
199
- # _fields_ = [
200
- # ("LogFileName", wintypes.LPWSTR),
201
- # ("LoggerName", wintypes.LPWSTR),
202
- # ("CurrentTime", wintypes.LARGE_INTEGER),
203
- # ("BuffersRead", wintypes.ULONG),
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
- ("LogFileName", wintypes.LPWSTR),
222
- ("LoggerName", wintypes.LPWSTR),
223
- ("CurrentTime", wintypes.LARGE_INTEGER),
224
- ("BuffersRead", wintypes.ULONG),
225
- ("ProcessTraceMode", wintypes.ULONG),
226
- ("CurrentEvent", EVENT_RECORD),
227
- ("LogfileHeader", TRACE_LOGFILE_HEADER),
228
- ("BufferCallback", wintypes.LPVOID),
229
- ("BufferSize", wintypes.ULONG),
230
- ("Filled", wintypes.ULONG),
231
- ("EventsLost", wintypes.ULONG),
232
- ("EventCallback", ctypes.c_void_p),
233
- ("IsKernelTrace", wintypes.ULONG),
234
- ("Context", wintypes.LPVOID)
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('advapi32')
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 = [ctypes.POINTER(wintypes.ULONG), wintypes.ULONG, wintypes.LARGE_INTEGER, wintypes.LARGE_INTEGER]
281
- ProcessTrace.restype = wintypes.ULONG
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
- from ctypes import wintypes
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
- 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
- )
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
- 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
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
- raise Exception(f"EnableTraceEx2 failed for provider {provider_guid} with error {status}")
127
-
128
- print("ETW session started successfully")
129
-
130
- return session_handle
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,8 +1,9 @@
1
1
  import os
2
2
  from pathlib import Path
3
3
 
4
+ from dkarchiver.arch_wrappers import sevenz_app_w
5
+
4
6
  from . import tables
5
- from ....archiver import sevenz_app_w
6
7
 
7
8
 
8
9
  def resolve_directory_path(directory_info, directory_key):
@@ -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.