atomicshop 2.11.47__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 (268) hide show
  1. atomicshop/__init__.py +1 -1
  2. atomicshop/{addons/mains → a_mains}/FACT/update_extract.py +3 -2
  3. atomicshop/a_mains/addons/process_list/compile.cmd +7 -0
  4. atomicshop/a_mains/addons/process_list/compiled/Win10x64/process_list.dll +0 -0
  5. atomicshop/a_mains/addons/process_list/compiled/Win10x64/process_list.exp +0 -0
  6. atomicshop/a_mains/addons/process_list/compiled/Win10x64/process_list.lib +0 -0
  7. atomicshop/{addons → a_mains/addons}/process_list/process_list.cpp +8 -1
  8. atomicshop/a_mains/dns_gateway_setting.py +11 -0
  9. atomicshop/a_mains/get_local_tcp_ports.py +85 -0
  10. atomicshop/a_mains/github_wrapper.py +11 -0
  11. atomicshop/a_mains/install_ca_certificate.py +172 -0
  12. atomicshop/{addons/mains → a_mains}/msi_unpacker.py +3 -1
  13. atomicshop/a_mains/process_from_port.py +119 -0
  14. atomicshop/a_mains/set_default_dns_gateway.py +90 -0
  15. atomicshop/a_mains/update_config_toml.py +38 -0
  16. atomicshop/appointment_management.py +5 -3
  17. atomicshop/basics/ansi_escape_codes.py +3 -1
  18. atomicshop/basics/argparse_template.py +2 -0
  19. atomicshop/basics/booleans.py +27 -30
  20. atomicshop/basics/bytes_arrays.py +43 -0
  21. atomicshop/basics/classes.py +149 -1
  22. atomicshop/basics/dicts.py +12 -0
  23. atomicshop/basics/enums.py +2 -2
  24. atomicshop/basics/exceptions.py +5 -1
  25. atomicshop/basics/list_of_classes.py +29 -0
  26. atomicshop/basics/list_of_dicts.py +69 -5
  27. atomicshop/basics/lists.py +14 -0
  28. atomicshop/basics/multiprocesses.py +374 -50
  29. atomicshop/basics/package_module.py +10 -0
  30. atomicshop/basics/strings.py +160 -7
  31. atomicshop/basics/threads.py +14 -0
  32. atomicshop/basics/tracebacks.py +13 -4
  33. atomicshop/certificates.py +153 -52
  34. atomicshop/config_init.py +12 -7
  35. atomicshop/console_user_response.py +7 -14
  36. atomicshop/consoles.py +9 -0
  37. atomicshop/datetimes.py +98 -0
  38. atomicshop/diff_check.py +340 -40
  39. atomicshop/dns.py +128 -12
  40. atomicshop/etws/_pywintrace_fix.py +17 -0
  41. atomicshop/etws/const.py +38 -0
  42. atomicshop/etws/providers.py +21 -0
  43. atomicshop/etws/sessions.py +43 -0
  44. atomicshop/etws/trace.py +168 -0
  45. atomicshop/etws/traces/trace_dns.py +162 -0
  46. atomicshop/etws/traces/trace_sysmon_process_creation.py +126 -0
  47. atomicshop/etws/traces/trace_tcp.py +130 -0
  48. atomicshop/file_io/csvs.py +222 -24
  49. atomicshop/file_io/docxs.py +35 -18
  50. atomicshop/file_io/file_io.py +35 -19
  51. atomicshop/file_io/jsons.py +49 -0
  52. atomicshop/file_io/tomls.py +139 -0
  53. atomicshop/filesystem.py +864 -293
  54. atomicshop/get_process_list.py +133 -0
  55. atomicshop/{process_name_cmd.py → get_process_name_cmd_dll.py} +52 -19
  56. atomicshop/http_parse.py +149 -93
  57. atomicshop/ip_addresses.py +6 -1
  58. atomicshop/mitm/centered_settings.py +132 -0
  59. atomicshop/mitm/config_static.py +207 -0
  60. atomicshop/mitm/config_toml_editor.py +55 -0
  61. atomicshop/mitm/connection_thread_worker.py +875 -357
  62. atomicshop/mitm/engines/__parent/parser___parent.py +4 -17
  63. atomicshop/mitm/engines/__parent/recorder___parent.py +108 -51
  64. atomicshop/mitm/engines/__parent/requester___parent.py +116 -0
  65. atomicshop/mitm/engines/__parent/responder___parent.py +75 -114
  66. atomicshop/mitm/engines/__reference_general/parser___reference_general.py +10 -7
  67. atomicshop/mitm/engines/__reference_general/recorder___reference_general.py +5 -5
  68. atomicshop/mitm/engines/__reference_general/requester___reference_general.py +47 -0
  69. atomicshop/mitm/engines/__reference_general/responder___reference_general.py +95 -13
  70. atomicshop/mitm/engines/create_module_template.py +58 -14
  71. atomicshop/mitm/import_config.py +359 -139
  72. atomicshop/mitm/initialize_engines.py +160 -74
  73. atomicshop/mitm/message.py +64 -23
  74. atomicshop/mitm/mitm_main.py +892 -0
  75. atomicshop/mitm/recs_files.py +183 -0
  76. atomicshop/mitm/shared_functions.py +4 -10
  77. atomicshop/mitm/ssh_tester.py +82 -0
  78. atomicshop/mitm/statistic_analyzer.py +257 -166
  79. atomicshop/mitm/statistic_analyzer_helper/analyzer_helper.py +136 -0
  80. atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py +525 -0
  81. atomicshop/monitor/change_monitor.py +96 -120
  82. atomicshop/monitor/checks/dns.py +139 -70
  83. atomicshop/monitor/checks/file.py +77 -0
  84. atomicshop/monitor/checks/network.py +81 -77
  85. atomicshop/monitor/checks/process_running.py +33 -34
  86. atomicshop/monitor/checks/url.py +94 -0
  87. atomicshop/networks.py +671 -0
  88. atomicshop/on_exit.py +205 -0
  89. atomicshop/package_mains_processor.py +84 -0
  90. atomicshop/permissions/permissions.py +22 -0
  91. atomicshop/permissions/ubuntu_permissions.py +239 -0
  92. atomicshop/permissions/win_permissions.py +33 -0
  93. atomicshop/print_api.py +24 -41
  94. atomicshop/process.py +63 -17
  95. atomicshop/process_poller/__init__.py +0 -0
  96. atomicshop/process_poller/pollers/__init__.py +0 -0
  97. atomicshop/process_poller/pollers/psutil_pywin32wmi_dll.py +95 -0
  98. atomicshop/process_poller/process_pool.py +207 -0
  99. atomicshop/process_poller/simple_process_pool.py +311 -0
  100. atomicshop/process_poller/tracer_base.py +45 -0
  101. atomicshop/process_poller/tracers/__init__.py +0 -0
  102. atomicshop/process_poller/tracers/event_log.py +46 -0
  103. atomicshop/process_poller/tracers/sysmon_etw.py +68 -0
  104. atomicshop/python_file_patcher.py +1 -1
  105. atomicshop/python_functions.py +27 -75
  106. atomicshop/question_answer_engine.py +2 -2
  107. atomicshop/scheduling.py +24 -5
  108. atomicshop/sound.py +4 -2
  109. atomicshop/speech_recognize.py +8 -0
  110. atomicshop/ssh_remote.py +158 -172
  111. atomicshop/startup/__init__.py +0 -0
  112. atomicshop/startup/win/__init__.py +0 -0
  113. atomicshop/startup/win/startup_folder.py +53 -0
  114. atomicshop/startup/win/task_scheduler.py +119 -0
  115. atomicshop/system_resource_monitor.py +61 -46
  116. atomicshop/system_resources.py +8 -8
  117. atomicshop/tempfiles.py +1 -2
  118. atomicshop/timer.py +30 -11
  119. atomicshop/urls.py +41 -0
  120. atomicshop/venvs.py +28 -0
  121. atomicshop/versioning.py +27 -0
  122. atomicshop/web.py +110 -25
  123. atomicshop/web_apis/__init__.py +0 -0
  124. atomicshop/web_apis/google_custom_search.py +44 -0
  125. atomicshop/web_apis/google_llm.py +188 -0
  126. atomicshop/websocket_parse.py +450 -0
  127. atomicshop/wrappers/certauthw/certauth.py +1 -0
  128. atomicshop/wrappers/cryptographyw.py +29 -8
  129. atomicshop/wrappers/ctyping/etw_winapi/__init__.py +0 -0
  130. atomicshop/wrappers/ctyping/etw_winapi/const.py +335 -0
  131. atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py +393 -0
  132. atomicshop/wrappers/ctyping/file_details_winapi.py +67 -0
  133. atomicshop/wrappers/ctyping/msi_windows_installer/cabs.py +2 -1
  134. atomicshop/wrappers/ctyping/msi_windows_installer/extract_msi_main.py +13 -9
  135. atomicshop/wrappers/ctyping/msi_windows_installer/tables.py +35 -0
  136. atomicshop/wrappers/ctyping/setup_device.py +466 -0
  137. atomicshop/wrappers/ctyping/win_console.py +39 -0
  138. atomicshop/wrappers/dockerw/dockerw.py +113 -2
  139. atomicshop/wrappers/elasticsearchw/config_basic.py +0 -12
  140. atomicshop/wrappers/elasticsearchw/elastic_infra.py +75 -0
  141. atomicshop/wrappers/elasticsearchw/elasticsearchw.py +2 -20
  142. atomicshop/wrappers/factw/get_file_data.py +12 -5
  143. atomicshop/wrappers/factw/install/install_after_restart.py +89 -5
  144. atomicshop/wrappers/factw/install/pre_install_and_install_before_restart.py +20 -14
  145. atomicshop/wrappers/factw/postgresql/firmware.py +4 -6
  146. atomicshop/wrappers/githubw.py +583 -51
  147. atomicshop/wrappers/loggingw/consts.py +49 -0
  148. atomicshop/wrappers/loggingw/filters.py +102 -0
  149. atomicshop/wrappers/loggingw/formatters.py +58 -71
  150. atomicshop/wrappers/loggingw/handlers.py +459 -40
  151. atomicshop/wrappers/loggingw/loggers.py +19 -0
  152. atomicshop/wrappers/loggingw/loggingw.py +1010 -178
  153. atomicshop/wrappers/loggingw/reading.py +344 -19
  154. atomicshop/wrappers/mongodbw/__init__.py +0 -0
  155. atomicshop/wrappers/mongodbw/mongo_infra.py +31 -0
  156. atomicshop/wrappers/mongodbw/mongodbw.py +1432 -0
  157. atomicshop/wrappers/netshw.py +271 -0
  158. atomicshop/wrappers/playwrightw/engine.py +34 -19
  159. atomicshop/wrappers/playwrightw/infra.py +5 -0
  160. atomicshop/wrappers/playwrightw/javascript.py +7 -3
  161. atomicshop/wrappers/playwrightw/keyboard.py +14 -0
  162. atomicshop/wrappers/playwrightw/scenarios.py +172 -5
  163. atomicshop/wrappers/playwrightw/waits.py +9 -7
  164. atomicshop/wrappers/powershell_networking.py +80 -0
  165. atomicshop/wrappers/psutilw/processes.py +81 -0
  166. atomicshop/wrappers/psutilw/psutil_networks.py +85 -0
  167. atomicshop/wrappers/psutilw/psutilw.py +9 -0
  168. atomicshop/wrappers/pyopensslw.py +9 -2
  169. atomicshop/wrappers/pywin32w/__init__.py +0 -0
  170. atomicshop/wrappers/pywin32w/cert_store.py +116 -0
  171. atomicshop/wrappers/pywin32w/console.py +34 -0
  172. atomicshop/wrappers/pywin32w/win_event_log/__init__.py +0 -0
  173. atomicshop/wrappers/pywin32w/win_event_log/fetch.py +174 -0
  174. atomicshop/wrappers/pywin32w/win_event_log/subscribe.py +212 -0
  175. atomicshop/wrappers/pywin32w/win_event_log/subscribes/__init__.py +0 -0
  176. atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +57 -0
  177. atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +49 -0
  178. atomicshop/wrappers/pywin32w/win_event_log/subscribes/schannel_logging.py +97 -0
  179. atomicshop/wrappers/pywin32w/winshell.py +19 -0
  180. atomicshop/wrappers/pywin32w/wmis/__init__.py +0 -0
  181. atomicshop/wrappers/pywin32w/wmis/msft_netipaddress.py +113 -0
  182. atomicshop/wrappers/pywin32w/wmis/win32_networkadapterconfiguration.py +259 -0
  183. atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py +112 -0
  184. atomicshop/wrappers/pywin32w/wmis/wmi_helpers.py +236 -0
  185. atomicshop/wrappers/socketw/accepter.py +21 -7
  186. atomicshop/wrappers/socketw/certificator.py +216 -150
  187. atomicshop/wrappers/socketw/creator.py +190 -50
  188. atomicshop/wrappers/socketw/dns_server.py +500 -173
  189. atomicshop/wrappers/socketw/exception_wrapper.py +45 -52
  190. atomicshop/wrappers/socketw/process_getter.py +86 -0
  191. atomicshop/wrappers/socketw/receiver.py +144 -102
  192. atomicshop/wrappers/socketw/sender.py +65 -35
  193. atomicshop/wrappers/socketw/sni.py +334 -165
  194. atomicshop/wrappers/socketw/socket_base.py +134 -0
  195. atomicshop/wrappers/socketw/socket_client.py +137 -95
  196. atomicshop/wrappers/socketw/socket_server_tester.py +14 -9
  197. atomicshop/wrappers/socketw/socket_wrapper.py +717 -116
  198. atomicshop/wrappers/socketw/ssl_base.py +15 -14
  199. atomicshop/wrappers/socketw/statistics_csv.py +148 -17
  200. atomicshop/wrappers/sysmonw.py +157 -0
  201. atomicshop/wrappers/ubuntu_terminal.py +65 -26
  202. atomicshop/wrappers/win_auditw.py +189 -0
  203. atomicshop/wrappers/winregw/__init__.py +0 -0
  204. atomicshop/wrappers/winregw/winreg_installed_software.py +58 -0
  205. atomicshop/wrappers/winregw/winreg_network.py +232 -0
  206. {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info}/METADATA +31 -49
  207. atomicshop-3.10.5.dist-info/RECORD +306 -0
  208. {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info}/WHEEL +1 -1
  209. atomicshop/_basics_temp.py +0 -101
  210. atomicshop/addons/a_setup_scripts/install_psycopg2_ubuntu.sh +0 -3
  211. atomicshop/addons/a_setup_scripts/install_pywintrace_0.3.cmd +0 -2
  212. atomicshop/addons/mains/install_docker_rootless_ubuntu.py +0 -11
  213. atomicshop/addons/mains/install_docker_ubuntu_main_sudo.py +0 -11
  214. atomicshop/addons/mains/install_elastic_search_and_kibana_ubuntu.py +0 -10
  215. atomicshop/addons/mains/install_wsl_ubuntu_lts_admin.py +0 -9
  216. atomicshop/addons/package_setup/CreateWheel.cmd +0 -7
  217. atomicshop/addons/package_setup/Setup in Edit mode.cmd +0 -6
  218. atomicshop/addons/package_setup/Setup.cmd +0 -7
  219. atomicshop/addons/process_list/compile.cmd +0 -2
  220. atomicshop/addons/process_list/compiled/Win10x64/process_list.dll +0 -0
  221. atomicshop/addons/process_list/compiled/Win10x64/process_list.exp +0 -0
  222. atomicshop/addons/process_list/compiled/Win10x64/process_list.lib +0 -0
  223. atomicshop/archiver/_search_in_zip.py +0 -189
  224. atomicshop/archiver/archiver.py +0 -34
  225. atomicshop/archiver/search_in_archive.py +0 -250
  226. atomicshop/archiver/sevenz_app_w.py +0 -86
  227. atomicshop/archiver/sevenzs.py +0 -44
  228. atomicshop/archiver/zips.py +0 -293
  229. atomicshop/etw/dns_trace.py +0 -118
  230. atomicshop/etw/etw.py +0 -61
  231. atomicshop/file_types.py +0 -24
  232. atomicshop/mitm/engines/create_module_template_example.py +0 -13
  233. atomicshop/mitm/initialize_mitm_server.py +0 -240
  234. atomicshop/monitor/checks/hash.py +0 -44
  235. atomicshop/monitor/checks/hash_checks/file.py +0 -55
  236. atomicshop/monitor/checks/hash_checks/url.py +0 -62
  237. atomicshop/pbtkmultifile_argparse.py +0 -88
  238. atomicshop/permissions.py +0 -110
  239. atomicshop/process_poller.py +0 -237
  240. atomicshop/script_as_string_processor.py +0 -38
  241. atomicshop/ssh_scripts/process_from_ipv4.py +0 -37
  242. atomicshop/ssh_scripts/process_from_port.py +0 -27
  243. atomicshop/wrappers/_process_wrapper_curl.py +0 -27
  244. atomicshop/wrappers/_process_wrapper_tar.py +0 -21
  245. atomicshop/wrappers/dockerw/install_docker.py +0 -209
  246. atomicshop/wrappers/elasticsearchw/infrastructure.py +0 -265
  247. atomicshop/wrappers/elasticsearchw/install_elastic.py +0 -232
  248. atomicshop/wrappers/ffmpegw.py +0 -125
  249. atomicshop/wrappers/loggingw/checks.py +0 -20
  250. atomicshop/wrappers/nodejsw/install_nodejs.py +0 -139
  251. atomicshop/wrappers/process_wrapper_pbtk.py +0 -16
  252. atomicshop/wrappers/socketw/base.py +0 -59
  253. atomicshop/wrappers/socketw/get_process.py +0 -107
  254. atomicshop/wrappers/wslw.py +0 -191
  255. atomicshop-2.11.47.dist-info/RECORD +0 -251
  256. /atomicshop/{addons/mains → a_mains}/FACT/factw_fact_extractor_docker_image_main_sudo.py +0 -0
  257. /atomicshop/{addons → a_mains/addons}/PlayWrightCodegen.cmd +0 -0
  258. /atomicshop/{addons → a_mains/addons}/ScriptExecution.cmd +0 -0
  259. /atomicshop/{addons/mains → a_mains/addons}/inits/init_to_import_all_modules.py +0 -0
  260. /atomicshop/{addons → a_mains/addons}/process_list/ReadMe.txt +0 -0
  261. /atomicshop/{addons/mains → a_mains}/search_for_hyperlinks_in_docx.py +0 -0
  262. /atomicshop/{archiver → etws}/__init__.py +0 -0
  263. /atomicshop/{etw → etws/traces}/__init__.py +0 -0
  264. /atomicshop/{monitor/checks/hash_checks → mitm/statistic_analyzer_helper}/__init__.py +0 -0
  265. /atomicshop/{wrappers/nodejsw → permissions}/__init__.py +0 -0
  266. /atomicshop/wrappers/pywin32w/{wmi_win32process.py → wmis/win32process.py} +0 -0
  267. {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info/licenses}/LICENSE.txt +0 -0
  268. {atomicshop-2.11.47.dist-info → atomicshop-3.10.5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,212 @@
1
+ import win32evtlog
2
+ import xml.etree.ElementTree as Et
3
+ import time
4
+ import threading
5
+ import queue
6
+ from typing import Union
7
+ import binascii
8
+
9
+
10
+ class EventLogSubscriber:
11
+ """
12
+ Class for subscribing to Windows Event Log events.
13
+
14
+ Usage:
15
+ from atomicshop.wrappers.pywin32w.win_event_log import subscribe
16
+
17
+ event_log_subscriber = subscribe.EventLogSubscriber('Security', 4688)
18
+ event_log_subscriber.start()
19
+
20
+ while True:
21
+ event = event_log_subscriber.emit()
22
+ print(event)
23
+ """
24
+ def __init__(self, log_channel: str, event_id: int = None, provider: str = None):
25
+ """
26
+ :param log_channel: The name of the event log channel to subscribe to. Examples:
27
+ Security, System, Application, etc.
28
+ :param event_id: The ID of the event to subscribe to.
29
+ Example: 4688 for process creation events in "Security" channel.
30
+ You can only subscribe by event ID or provider, not both.
31
+ :param provider: The name of the provider to subscribe to.
32
+ You can only subscribe by event ID or provider, not both.
33
+ """
34
+
35
+ if event_id is None and provider is None:
36
+ raise ValueError("You must specify either an event ID or provider name to subscribe to.")
37
+ elif event_id and provider:
38
+ raise ValueError("You can only subscribe by event ID or provider, not both.")
39
+
40
+ self.log_channel: str = log_channel
41
+ self.provider: str = provider
42
+
43
+ if event_id:
44
+ self.event_id: str = str(event_id)
45
+ else:
46
+ self.event_id = event_id
47
+
48
+ self._event_queue = queue.Queue()
49
+ self._subscription_thread = None
50
+
51
+ def start(self):
52
+ """Start the subscription process."""
53
+ self._subscription_thread = threading.Thread(
54
+ target=start_subscription, args=(self.log_channel, self._event_queue, self.event_id, self.provider)
55
+ )
56
+ self._subscription_thread.daemon = True
57
+ self._subscription_thread.start()
58
+
59
+ def stop(self):
60
+ """Stop the subscription process."""
61
+ if self._subscription_thread:
62
+ self._subscription_thread.join()
63
+ self._subscription_thread = None
64
+
65
+ def emit(self, timeout: float = None) -> Union[dict, None]:
66
+ """
67
+ Get the next event from the event queue.
68
+
69
+ :param timeout: The maximum time (in seconds) to wait for an event.
70
+ If None, the function will block until an event is available.
71
+ :return: A dictionary containing the event data, or None if no event is available.
72
+ """
73
+ try:
74
+ return self._event_queue.get(timeout=timeout)
75
+ except queue.Empty:
76
+ return None
77
+
78
+
79
+ def _parse_event_xml(event_xml):
80
+ root = Et.fromstring(event_xml)
81
+ data = {}
82
+
83
+ # Helper function to strip namespace
84
+ def strip_namespace(tag):
85
+ return tag.split('}')[-1] # Remove namespace
86
+
87
+ # Iterate over all elements
88
+ for elem in root.iter():
89
+ # Extract elements with text content
90
+ if elem.text and elem.text.strip():
91
+ tag = elem.tag.split('}')[-1] # Remove namespace
92
+ data[tag] = elem.text.strip()
93
+
94
+ # Extract elements with attributes
95
+ for attr_name, attr_value in elem.attrib.items():
96
+ tag = elem.tag.split('}')[-1] # Remove namespace
97
+ data[f"{tag}_{attr_name}"] = attr_value
98
+
99
+ # Handle Binary data
100
+ if elem.tag.split('}')[-1] == 'Binary':
101
+ try:
102
+ data['BinaryReadable'] = binascii.unhexlify(elem.text.strip())
103
+ except (TypeError, binascii.Error) as e:
104
+ print(f"Error decoding binary data: {e}")
105
+ data['BinaryReadable'] = elem.text.strip()
106
+
107
+ # Extract system-specific data
108
+ system_data = root.find(".//{http://schemas.microsoft.com/win/2004/08/events/event}System")
109
+ if system_data is not None:
110
+ for system_elem in system_data:
111
+ tag = strip_namespace(system_elem.tag)
112
+ if system_elem.attrib:
113
+ for attr_name, attr_value in system_elem.attrib.items():
114
+ data[f"{tag}_{attr_name}"] = attr_value
115
+ if system_elem.text and system_elem.text.strip():
116
+ data[tag] = system_elem.text.strip()
117
+
118
+ # Extract event-specific data
119
+ event_data = root.find(".//{http://schemas.microsoft.com/win/2004/08/events/event}EventData")
120
+ if event_data is not None:
121
+ for data_elem in event_data:
122
+ if strip_namespace(data_elem.tag) == 'Data' and 'Name' in data_elem.attrib:
123
+ data[data_elem.attrib['Name']] = data_elem.text.strip()
124
+
125
+ # Extract user data if available
126
+ user_data = root.find(".//{http://schemas.microsoft.com/win/2004/08/events/event}UserData")
127
+ if user_data is not None:
128
+ for user_elem in user_data:
129
+ tag = strip_namespace(user_elem.tag)
130
+ if user_elem.attrib:
131
+ for attr_name, attr_value in user_elem.attrib.items():
132
+ data[f"{tag}_{attr_name}"] = attr_value
133
+ if user_elem.text and user_elem.text.strip():
134
+ data[tag] = user_elem.text.strip()
135
+
136
+ # Extract rendering info (additional details like the message)
137
+ rendering_info = root.find(".//{http://schemas.microsoft.com/win/2004/08/events/event}RenderingInfo")
138
+ if rendering_info is not None:
139
+ for info_elem in rendering_info:
140
+ tag = strip_namespace(info_elem.tag)
141
+ if info_elem.text and info_elem.text.strip():
142
+ data[f"RenderingInfo_{tag}"] = info_elem.text.strip()
143
+
144
+ return data
145
+
146
+
147
+ def _handle_event(event, event_queue):
148
+ # Render event as XML
149
+ event_xml = win32evtlog.EvtRender(event, win32evtlog.EvtRenderEventXml)
150
+ data = None
151
+ try:
152
+ data = _parse_event_xml(event_xml)
153
+ except Et.ParseError as e:
154
+ print(f"Error parsing event XML: {e}")
155
+ except Exception as e:
156
+ print(f"Error getting rendered message: {e}")
157
+
158
+ event_queue.put(data)
159
+
160
+
161
+ def _event_callback(action, context, event):
162
+ event_queue = context['event_queue']
163
+ if action == win32evtlog.EvtSubscribeActionDeliver:
164
+ _handle_event(event, event_queue)
165
+
166
+
167
+ def start_subscription(
168
+ log_channel: str,
169
+ event_queue,
170
+ event_id: str = None,
171
+ provider: str = None
172
+ ):
173
+ """
174
+ Start listening for events in the specified log channel with the given event ID.
175
+
176
+ :param log_channel: The name of the event log channel to subscribe to. Examples:
177
+ Security, System, Application, etc.
178
+ :param event_queue: A queue to store the received events
179
+ :param event_id: The ID of the event to subscribe to.
180
+ Example: 4688 for process creation events in "Security" channel.
181
+ You can only subscribe by event ID or provider, not both.
182
+ :param provider: The name of the provider to subscribe to.
183
+ You can only subscribe by event ID or provider, not both.
184
+ """
185
+
186
+ if event_id is None and provider is None:
187
+ raise ValueError("You must specify either an event ID or provider name to subscribe to.")
188
+ elif event_id and provider:
189
+ raise ValueError("You can only subscribe by event ID or provider, not both.")
190
+
191
+ # This selects the System node within each event.
192
+ # The System node contains metadata about the event, such as the event ID, provider name, timestamp, and more.
193
+ xpath_query = None
194
+ if provider:
195
+ xpath_query = f"*[System/Provider[@Name='{provider}']]"
196
+ elif event_id:
197
+ xpath_query = f"*[System/EventID={event_id}]"
198
+
199
+ subscription = win32evtlog.EvtSubscribe(
200
+ log_channel,
201
+ win32evtlog.EvtSubscribeToFutureEvents,
202
+ SignalEvent=None,
203
+ Query=xpath_query,
204
+ Callback=_event_callback,
205
+ Context={'event_queue': event_queue}
206
+ )
207
+
208
+ try:
209
+ while True:
210
+ time.sleep(1)
211
+ except KeyboardInterrupt:
212
+ print("Stopped listening for events.")
@@ -0,0 +1,57 @@
1
+ from .. import subscribe
2
+ from .... import win_auditw
3
+
4
+
5
+ LOG_CHANNEL: str = 'Security'
6
+ EVENT_ID: int = 4688
7
+
8
+
9
+ class ProcessCreateSubscriber(subscribe.EventLogSubscriber):
10
+ """
11
+ Class for subscribing to Windows Event Log events related to process creation.
12
+
13
+ Usage:
14
+ from atomicshop.wrappers.pywin32w.win_event_log.subscribes import process_create
15
+
16
+ process_create_subscriber = process_create.ProcessCreateSubscriber()
17
+ process_create_subscriber.start()
18
+
19
+ while True:
20
+ event = process_create_subscriber.emit()
21
+ print(event)
22
+ """
23
+ def __init__(self):
24
+ super().__init__(log_channel=LOG_CHANNEL, event_id=EVENT_ID)
25
+
26
+ def start(self):
27
+ """Start the subscription process."""
28
+ win_auditw.enable_audit_process_creation()
29
+ win_auditw.enable_command_line_auditing()
30
+
31
+ super().start()
32
+
33
+ def stop(self):
34
+ """Stop the subscription process."""
35
+ super().stop()
36
+
37
+ def emit(self, timeout: float = None) -> dict:
38
+ """
39
+ Get the next event from the event queue.
40
+
41
+ :param timeout: The maximum time (in seconds) to wait for an event.
42
+ If None, the function will block until an event is available.
43
+ :return: A dictionary containing the event data.
44
+ """
45
+
46
+ data = super().emit(timeout=timeout)
47
+
48
+ data['NewProcessIdInt'] = int(data['NewProcessId'], 16)
49
+ data['ParentProcessIdInt'] = int(data['ProcessId'], 16)
50
+
51
+ # if user_sid != "Unknown":
52
+ # try:
53
+ # user_name, domain, type = win32security.LookupAccountSid(None, user_sid)
54
+ # except Exception as e:
55
+ # print(f"Error looking up account SID: {e}")
56
+
57
+ return data
@@ -0,0 +1,49 @@
1
+ from .. import subscribe
2
+ from .... import win_auditw
3
+
4
+
5
+ LOG_CHANNEL: str = 'Security'
6
+ EVENT_ID: int = 4689
7
+
8
+
9
+ class ProcessTerminateSubscriber(subscribe.EventLogSubscriber):
10
+ """
11
+ Class for subscribing to Windows Event Log events related to process termination.
12
+
13
+ Usage:
14
+ from atomicshop.wrappers.pywin32w.win_event_log.subscribes import process_terminate
15
+
16
+ process_terminate_subscriber = process_terminate.ProcessTerminateSubscriber()
17
+ process_terminate_subscriber.start()
18
+
19
+ while True:
20
+ event = process_terminate_subscriber.emit()
21
+ print(event)
22
+ """
23
+ def __init__(self):
24
+ super().__init__(log_channel=LOG_CHANNEL, event_id=EVENT_ID)
25
+
26
+ def start(self):
27
+ """Start the subscription process."""
28
+ win_auditw.enable_audit_process_termination()
29
+
30
+ super().start()
31
+
32
+ def stop(self):
33
+ """Stop the subscription process."""
34
+ super().stop()
35
+
36
+ def emit(self, timeout: float = None) -> dict:
37
+ """
38
+ Get the next event from the event queue.
39
+
40
+ :param timeout: The maximum time (in seconds) to wait for an event.
41
+ If None, the function will block until an event is available.
42
+ :return: A dictionary containing the event data.
43
+ """
44
+
45
+ data = super().emit(timeout=timeout)
46
+
47
+ data['ProcessIdInt'] = int(data['ProcessId'], 16)
48
+
49
+ return data
@@ -0,0 +1,97 @@
1
+ import winreg
2
+ import sys
3
+
4
+ from .. import subscribe
5
+ from .....print_api import print_api
6
+
7
+
8
+ SCHANNEL_LOGGING_REG_PATH: str = r'SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL'
9
+ SCHANNEL_EVENT_LOGGING_KEY: str = 'EventLogging'
10
+ LOG_CHANNEL: str = 'System'
11
+ PROVIDER: str = 'Schannel'
12
+
13
+
14
+ class SchannelLoggingSubscriber(subscribe.EventLogSubscriber):
15
+ """
16
+ Class for subscribing to Windows Event Log events related to process creation.
17
+
18
+ Usage:
19
+ from atomicshop.wrappers.pywin32w.win_event_log.subscribes import schannel_logging
20
+
21
+ process_create_subscriber = schannel_logging.SchannelLoggingSubscriber()
22
+ process_create_subscriber.start()
23
+
24
+ while True:
25
+ event = process_create_subscriber.emit()
26
+ print(event)
27
+ """
28
+ def __init__(self):
29
+ super().__init__(log_channel=LOG_CHANNEL, provider=PROVIDER)
30
+
31
+ def start(self):
32
+ """Start the subscription process."""
33
+ enable_schannel_logging()
34
+
35
+ super().start()
36
+
37
+ def stop(self):
38
+ """Stop the subscription process."""
39
+ super().stop()
40
+
41
+ def emit(self, timeout: float = None) -> dict:
42
+ """
43
+ Get the next event from the event queue.
44
+
45
+ :param timeout: The maximum time (in seconds) to wait for an event.
46
+ If None, the function will block until an event is available.
47
+ :return: A dictionary containing the event data.
48
+ """
49
+ return super().emit(timeout=timeout)
50
+
51
+
52
+ def enable_schannel_logging(logging_value: int = 1, print_kwargs: dict = None):
53
+ """
54
+ Value Description
55
+ 0x0000 Do not log
56
+ 0x0001 Log error messages
57
+ 0x0002 Log warnings
58
+ 0x0003 Log warnings and error messages
59
+ 0x0004 Log informational and success events
60
+ 0x0005 Log informational, success events and error messages
61
+ 0x0006 Log informational, success events and warnings
62
+ 0x0007 Log informational, success events, warnings, and error messages (all log levels)
63
+ """
64
+
65
+ if is_schannel_logging_enabled(logging_value):
66
+ print_api(
67
+ "Schannel event logging is already enabled.", color='yellow',
68
+ **(print_kwargs or {}))
69
+ return
70
+
71
+ try:
72
+ with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, SCHANNEL_LOGGING_REG_PATH, 0, winreg.KEY_ALL_ACCESS) as key:
73
+ winreg.SetValueEx(key, SCHANNEL_EVENT_LOGGING_KEY, 0, winreg.REG_DWORD, logging_value)
74
+
75
+ print_api(
76
+ "Successfully enabled Schannel logging.",
77
+ color='green', **(print_kwargs or {}))
78
+ print_api(
79
+ "Please restart the computer for the changes to take effect.",
80
+ color='yellow', **(print_kwargs or {}))
81
+ sys.exit()
82
+ except WindowsError as e:
83
+ print_api(
84
+ f"Failed to enable Schannel event logging: {e}", error_type=True,
85
+ color='red', **(print_kwargs or {}))
86
+
87
+
88
+ def is_schannel_logging_enabled(logging_value: int) -> bool:
89
+ try:
90
+ with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, SCHANNEL_LOGGING_REG_PATH, 0, winreg.KEY_READ) as key:
91
+ value, regtype = winreg.QueryValueEx(key, SCHANNEL_EVENT_LOGGING_KEY)
92
+ return value == logging_value
93
+ except FileNotFoundError:
94
+ return False
95
+ except WindowsError as e:
96
+ print(f"Failed to read the Schannel event logging setting: {e}")
97
+ return False
@@ -0,0 +1,19 @@
1
+ from pathlib import Path
2
+
3
+ from win32com.client import Dispatch
4
+
5
+
6
+ def create_shortcut(file_path_to_link: str, shortcut_file_path: str):
7
+ """
8
+ Create a shortcut in the startup folder to the specified file.
9
+
10
+ :param file_path_to_link: The path to the file you want to create a shortcut to.
11
+ :param shortcut_file_path: The name of the shortcut file. Should be with the ".lnk" extension.
12
+ """
13
+
14
+ shell = Dispatch('WScript.Shell')
15
+ shortcut = shell.CreateShortCut(shortcut_file_path)
16
+ shortcut.Targetpath = file_path_to_link
17
+ shortcut.WorkingDirectory = str(Path(file_path_to_link).parent)
18
+ shortcut.Description = f"Shortcut for {Path(file_path_to_link).name}"
19
+ shortcut.save()
File without changes
@@ -0,0 +1,113 @@
1
+ from typing import Optional
2
+
3
+ from win32com.client import CDispatch
4
+
5
+ from . import wmi_helpers
6
+
7
+
8
+ def set_skip_as_source(
9
+ ip_addresses: list[str],
10
+ enable: bool = True,
11
+ wmi_instance: CDispatch = None
12
+ ) -> None:
13
+ """
14
+ Toggle SkipAsSource for every address in *ip_addrs*.
15
+
16
+ Parameters
17
+ ----------
18
+ ip_addresses : list/tuple/iterable of str
19
+ One or more literal IP strings, e.g. "192.168.157.3"
20
+ enable : bool
21
+ True → behave like Set‑NetIPAddress ‑SkipAsSource $true
22
+ False → behave like Set‑NetIPAddress ‑SkipAsSource $false
23
+ wmi_instance : CDispatch
24
+ WMI instance to use. If not provided, a new one will be created.
25
+ 'root\\StandardCimv2'
26
+
27
+ ================
28
+
29
+ Explanation.
30
+ When you add extra IPv4 addresses to the same NIC, Windows treats them all as “first‑class” unless you tell it otherwise.
31
+ Because the two new addresses (192.168.157.3 and .4) are numerically lower than the original one (.129), the TCP/IP stack now prefers one of those lower addresses as the default source for any socket whose program didn’t bind an explicit local IP.
32
+
33
+ What that looks like on the wire
34
+ Client sends SYN → 192.168.157.3 (or .4).
35
+ – Server replies with SYN/ACK ←192.168.157.3 → handshake completes, HTTP works.
36
+
37
+ Client sends SYN → 192.168.157.129.
38
+ – Stack still picks .3 as its favourite and answers SYN/ACK ← 192.168.157.3.
39
+ – Client discards the packet (wrong IP), retransmits the SYN, your code’s accept() wakes up again, and you see an “infinite accept loop”.
40
+
41
+ The flag that fixes it: SkipAsSource
42
+ Tell Windows not to use the extra addresses unless an application asks for them.
43
+
44
+ PowerShell.
45
+ # One‑off: mark the addresses you already added
46
+ Get-NetIPAddress -IPAddress 192.168.157.3 | Set-NetIPAddress -SkipAsSource $true
47
+ Get-NetIPAddress -IPAddress 192.168.157.4 | Set-NetIPAddress -SkipAsSource $true
48
+
49
+ # —OR— add new addresses the right way from the start
50
+ New-NetIPAddress -InterfaceAlias "Ethernet0" `
51
+ -IPAddress 192.168.157.3 `
52
+ -PrefixLength 24 `
53
+ -SkipAsSource $true
54
+ SkipAsSource = $true keeps the address fully routable for incoming traffic and lets programs bind to it explicitly.
55
+
56
+ Windows will never choose that address as the source of an outgoing packet unless the program bound the socket to it.
57
+
58
+ After you flip the flag (no reboot required) the three‑way handshake is symmetrical again and the endless accept() loop disappears.
59
+ """
60
+
61
+ if not wmi_instance:
62
+ wmi_instance, _ = wmi_helpers.get_wmi_instance(namespace='root\\StandardCimv2')
63
+
64
+ for ip in ip_addresses:
65
+ query = f"SELECT * FROM MSFT_NetIPAddress WHERE IPAddress='{ip}'"
66
+ matches = wmi_instance.ExecQuery(query)
67
+ if not matches:
68
+ print(f"[!] {ip}: no such address found")
69
+ continue
70
+
71
+ for obj in matches: # usually just one
72
+ if bool(obj.SkipAsSource) == enable:
73
+ print(f"[=] {ip}: SkipAsSource already {enable}")
74
+ continue
75
+
76
+ obj.SkipAsSource = enable
77
+ obj.Put_() # commit the change
78
+ print(f"[+] {ip}: SkipAsSource set to {enable}")
79
+
80
+
81
+ def is_skip_as_source(
82
+ ip_address: str,
83
+ wmi_instance: CDispatch = None
84
+ ) -> Optional[bool]:
85
+ """
86
+ Check whether *ip_address* currently has SkipAsSource set.
87
+
88
+ Returns
89
+ -------
90
+ True – the flag is enabled
91
+ False – the flag is disabled
92
+ None – no MSFT_NetIPAddress object matches the IP (not present)
93
+
94
+ Notes
95
+ -----
96
+ * Works for both IPv4/IPv6.
97
+ * Uses the same Win32 CIM class (root\\StandardCimv2 › MSFT_NetIPAddress).
98
+ * You can pass an existing `wmi_instance` to avoid reconnecting in tight loops.
99
+ """
100
+ # Get a WMI connection if the caller didn’t hand us one
101
+ if not wmi_instance:
102
+ wmi_instance, _ = wmi_helpers.get_wmi_instance(namespace='root\\StandardCimv2')
103
+
104
+ query = f"SELECT SkipAsSource FROM MSFT_NetIPAddress WHERE IPAddress='{ip_address}'"
105
+ matches = wmi_instance.ExecQuery(query)
106
+
107
+ if not matches: # address not configured on this host/NIC
108
+ return None
109
+
110
+ # There should be only one entry per literal IP, but handle duplicates sanely
111
+ # Return True if *any* matching record has SkipAsSource = True,
112
+ # otherwise False (all are False).
113
+ return any(bool(obj.SkipAsSource) for obj in matches)