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,80 @@
1
+ import json
2
+ import subprocess
3
+ from typing import List, Literal
4
+
5
+
6
+ def get_interface_ips(
7
+ interface_name: str,
8
+ ip_type: Literal["virtual", "dynamic", "all"] = "virtual"
9
+ ) -> List[str]:
10
+ """
11
+ Return IPv4 addresses on an interface, filtered by 'mode'.
12
+
13
+ ip_type:
14
+ - "virtual": only static/virtual IPs (PrefixOrigin != 'Dhcp')
15
+ - "dynamic": only DHCP IPs (PrefixOrigin == 'Dhcp')
16
+ - "all": all IPv4 IPs on the interface
17
+
18
+ If the interface does not exist or has no IPv4 addresses, returns [].
19
+ """
20
+
21
+ ps_script = f"""
22
+ try {{
23
+ Get-NetIPAddress -InterfaceAlias "{interface_name}" -AddressFamily IPv4 |
24
+ Select-Object IPAddress,
25
+ @{{
26
+ Name = 'PrefixOrigin';
27
+ Expression = {{ [string]$_.PrefixOrigin }}
28
+ }} |
29
+ ConvertTo-Json -Depth 3
30
+ }} catch {{
31
+ # Return empty JSON array if nothing found / interface missing
32
+ '[]'
33
+ }}
34
+ """
35
+
36
+ try:
37
+ result = subprocess.run(
38
+ ["powershell", "-NoProfile", "-Command", ps_script],
39
+ capture_output=True,
40
+ text=True,
41
+ check=True
42
+ )
43
+ except subprocess.CalledProcessError as e:
44
+ # If anything unexpected happens, raise a clearer error
45
+ msg = (e.stderr or e.stdout or "").strip()
46
+ raise RuntimeError(f"PowerShell Get-NetIPAddress failed: {msg}") from e
47
+
48
+ stdout = result.stdout.strip()
49
+ if not stdout:
50
+ return []
51
+
52
+ # At this point stdout should be valid JSON (list or single object)
53
+ data = json.loads(stdout)
54
+
55
+ if isinstance(data, dict):
56
+ data = [data]
57
+
58
+ ips: List[str] = []
59
+ ip_type = ip_type.lower()
60
+
61
+ for entry in data:
62
+ ip = entry.get("IPAddress")
63
+ origin_raw = entry.get("PrefixOrigin", "")
64
+ origin = str(origin_raw).lower()
65
+
66
+ if not ip:
67
+ continue
68
+
69
+ if ip_type == "virtual":
70
+ if origin != "dhcp":
71
+ ips.append(ip)
72
+ elif ip_type == "dynamic":
73
+ if origin == "dhcp":
74
+ ips.append(ip)
75
+ elif ip_type == "all":
76
+ ips.append(ip)
77
+ else:
78
+ raise ValueError(f"Unsupported mode: {ip_type!r}")
79
+
80
+ return ips
@@ -0,0 +1,81 @@
1
+ import os
2
+ import time
3
+
4
+ import psutil
5
+
6
+ from ...print_api import print_api
7
+ from ..ctyping import file_details_winapi
8
+
9
+
10
+ def wait_for_process(pid: int):
11
+ """
12
+ Wait for the process with the given PID to finish.
13
+ :param pid: int, PID of the process to wait for.
14
+ :return:
15
+ """
16
+ try:
17
+ # Create a process object for the given PID
18
+ process = psutil.Process(pid)
19
+
20
+ # Wait for the process to terminate
21
+ while process.is_running():
22
+ print(f"Process with PID {pid} is still running...")
23
+ time.sleep(1) # Sleep for 1 second before checking again
24
+
25
+ # Refresh process status and get the exit code
26
+ process.wait()
27
+ print(f"Process with PID [{pid}] has finished.")
28
+ except psutil.NoSuchProcess:
29
+ print(f"No process found with PID {pid}")
30
+ except psutil.AccessDenied:
31
+ print(f"Access denied to process with PID {pid}")
32
+
33
+
34
+ def kill_process_by_pid(pid: int, print_kwargs: dict = None):
35
+ try:
36
+ print_api(f"Terminating process: {pid}.", **(print_kwargs or {}))
37
+ proc = psutil.Process(pid)
38
+ proc.terminate() # or proc.kill() if you want to forcefully kill it
39
+ proc.wait(timeout=5) # Wait up to 5 seconds for the process to terminate
40
+ except psutil.NoSuchProcess:
41
+ # print(f"No process found with PID {pid}.")
42
+ pass
43
+ except psutil.AccessDenied:
44
+ # print(f"Access denied to terminate process with PID {pid}.")
45
+ pass
46
+ except psutil.TimeoutExpired:
47
+ # print(f"Process {pid} did not terminate in time.")
48
+ pass
49
+
50
+
51
+ def get_running_processes_with_exe_info() -> list[dict]:
52
+ """
53
+ Retrieve information about all running processes on the system.
54
+ """
55
+ processes_info: list[dict] = []
56
+
57
+ for proc in psutil.process_iter(attrs=["pid", "name", "exe"]):
58
+ try:
59
+ pid = proc.info["pid"]
60
+ name = proc.info["name"]
61
+ exe = proc.info["exe"]
62
+
63
+ if exe and os.path.isfile(exe):
64
+ # Get file properties
65
+ file_properties = file_details_winapi.get_file_properties(exe)
66
+
67
+ # Add process info to the list
68
+ processes_info.append({
69
+ "PID": pid,
70
+ "Name": name,
71
+ "FilePath": exe,
72
+ "FileDescription": file_properties["FileDescription"],
73
+ "FileVersion": file_properties["FileVersion"],
74
+ "ProductName": file_properties["ProductName"],
75
+ "ProductVersion": file_properties["ProductVersion"],
76
+ })
77
+ except (psutil.AccessDenied, psutil.NoSuchProcess, psutil.ZombieProcess):
78
+ # Skip processes that cannot be accessed
79
+ continue
80
+
81
+ return processes_info
@@ -0,0 +1,85 @@
1
+ from typing import Union
2
+ import shlex
3
+ import socket
4
+
5
+ import psutil
6
+
7
+ from ... import networks
8
+
9
+
10
+ def get_process_using_port(ip_port: str) -> Union[dict, None]:
11
+ """
12
+ Function to find the process using the port.
13
+ :param ip_port: string, Listening IP and port number. Example: '192.168.0.1:443'
14
+ :return: dict['pid', 'name', 'cmdline'] or None.
15
+ """
16
+
17
+ ip_address, port = ip_port.split(':')
18
+ port = int(port)
19
+
20
+ for proc in psutil.process_iter(['pid', 'name', 'cmdline']):
21
+ try:
22
+ connections = proc.connections(kind='inet')
23
+ for conn in connections:
24
+ # if conn.laddr.port == port:
25
+ # Status LISTEN is for TCP sockets and NONE is for UDP sockets.
26
+ # Sometimes after socket close, the port will be in TIME_WAIT state.
27
+ if (conn.laddr.port == port and (conn.status == 'LISTEN' or conn.status == 'NONE')) and conn.laddr.ip == ip_address:
28
+ cmdline = proc.info['cmdline']
29
+ if not cmdline:
30
+ cmdline = '<EMPTY: TRY RUNNING AS ADMIN>'
31
+ else:
32
+ cmdline = shlex.join(cmdline)
33
+ return {
34
+ 'pid': proc.info['pid'],
35
+ 'name': proc.info['name'],
36
+ 'cmdline': cmdline
37
+ }
38
+ except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
39
+ pass
40
+ return None
41
+
42
+
43
+ def get_processes_using_port_list(ips_ports: list) -> Union[dict, None]:
44
+ """
45
+ Function to find the process using the port.
46
+ :param ips_ports: List of listening ips and port numbers. Example:
47
+ ['192.168.0.1:443', '192.168.0.2:443']
48
+ :return: dict[port: {'pid', 'name', 'cmdline'}] or None.
49
+ """
50
+ port_process_map = {}
51
+ for ip_port in ips_ports:
52
+ process_info = get_process_using_port(ip_port)
53
+ if process_info:
54
+ port_process_map[ip_port] = process_info
55
+
56
+ return port_process_map
57
+
58
+
59
+ def get_default_connection_name() -> Union[dict, None]:
60
+ """
61
+ Function to get the default network interface.
62
+ :return: dict[interface_name: details] or None.
63
+ """
64
+ # Get all interfaces.
65
+ interfaces: dict = psutil.net_if_addrs()
66
+ default_ip_address: str = networks.get_default_internet_ipv4()
67
+
68
+ for interface, details in interfaces.items():
69
+ for address in details:
70
+ # Check if the address is an IPv4 address (AF_INET) and not a loopback (127.0.0.1)
71
+ if address.family == socket.AF_INET and not address.address.startswith('127.'):
72
+ # Check if the address is the default IP address.
73
+ if address.address == default_ip_address:
74
+ return {interface: details}
75
+
76
+ return None
77
+
78
+
79
+ def list_network_interfaces() -> list:
80
+ """
81
+ Function to list all network interfaces.
82
+ :return: list of interface names.
83
+ """
84
+ iface_names = list(psutil.net_if_addrs().keys())
85
+ return iface_names
@@ -164,6 +164,15 @@ def filter_processes_with_present_connections(processes) -> list:
164
164
 
165
165
 
166
166
  class PsutilProcesses:
167
+ """
168
+ Class to get all the current processes.
169
+
170
+ Example get current running processes as dicts as
171
+ {'<pid'>: {'name': '<process_name>', 'cmdline': '<process_cmdline>'}}:
172
+ from atomicshop.wrappers.psutilw import psutilw
173
+ processes = psutilw.PsutilProcesses().get_processes_as_dict(
174
+ attrs=['pid', 'name', 'cmdline'], cmdline_to_string=True)
175
+ """
167
176
  def __init__(self):
168
177
  self.processes = None
169
178
 
@@ -1,4 +1,4 @@
1
- import random
1
+ from secrets import randbits
2
2
  from OpenSSL import crypto
3
3
 
4
4
  from .. import certificates
@@ -121,7 +121,14 @@ def generate_server_certificate_empty(
121
121
  """
122
122
 
123
123
  cert = crypto.X509()
124
- cert.set_serial_number(random.randint(0, 2 ** 64 - 1))
124
+
125
+ # RFC 5280: serial must be positive and non-zero
126
+ # 1 … 2⁶⁴-1
127
+ cert.set_serial_number(randbits(64))
128
+ current_serial = cert.get_serial_number()
129
+ if current_serial <= 0:
130
+ raise RuntimeError(f"Refusing to create a certificate with non-positive serial: {str(current_serial)}")
131
+
125
132
  cert.get_subject().CN = certname
126
133
 
127
134
  cert.set_version(2)
File without changes
@@ -0,0 +1,116 @@
1
+ from typing import Literal
2
+ import win32crypt as wcrypt
3
+
4
+ from ...print_api import print_api
5
+ from ... import certificates
6
+
7
+
8
+ # lpszStoreProvider
9
+ CERT_STORE_PROV_SYSTEM = 0x0000000A
10
+ # dwFlags
11
+ CERT_SYSTEM_STORE_LOCAL_MACHINE = 0x00020000
12
+ CERT_SYSTEM_STORE_CURRENT_USER = 0x00010000
13
+ CERT_CLOSE_STORE_FORCE_FLAG = 0x00000001
14
+ CRYPT_STRING_BASE64HEADER = 0x00000000
15
+ X509_ASN_ENCODING = 0x00000001
16
+ CERT_STORE_ADD_REPLACE_EXISTING = 3
17
+
18
+
19
+ STORE_LOCATION_TO_CERT_SYSTEM_STORE: dict = {
20
+ "ROOT": CERT_SYSTEM_STORE_LOCAL_MACHINE,
21
+ "CA": CERT_SYSTEM_STORE_LOCAL_MACHINE,
22
+ "MY": CERT_SYSTEM_STORE_CURRENT_USER
23
+ }
24
+
25
+
26
+ def delete_certificate_by_issuer_name(
27
+ issuer_name: str,
28
+ store_location: Literal[
29
+ "ROOT",
30
+ "CA",
31
+ "MY"] = "ROOT",
32
+ print_kwargs: dict = None
33
+ ):
34
+ """
35
+ NEED ADMIN RIGHTS.
36
+ The function will remove all certificates with the specified issuer name.
37
+ There can be several certificates with this name.
38
+
39
+ :param issuer_name: string, issuer name to search for.
40
+ :param store_location: string, store location to search in. Default is "ROOT".
41
+ :param print_kwargs: dict, print_api kwargs.
42
+ """
43
+
44
+ """
45
+ WinAPI doesn't like to do 2 actions in one iteration. So, first we will collect all certificates to remove,
46
+ and in the second iteration remove them.
47
+
48
+ Full Explanation:
49
+ When you iterate with for cert in store.CertEnumCertificatesInStore(): and call
50
+ cert.CertDeleteCertificateFromStore() inside that loop, you’re modifying the underlying certificate store
51
+ while its internal enumeration is still active. This can lead to a segmentation fault (access violation 0xC0000005).
52
+ By collecting the certificates in the first pass, you freeze the iteration so the store
53
+ doesn’t get mutated mid-enumeration.
54
+ In the second pass, when you actually remove them, you’re no longer in the middle of enumerating.
55
+ This prevents the store’s pointer from becoming invalid.
56
+
57
+ This approach should stop the Process finished with exit code -1073741819 (0xC0000005) issue.
58
+ """
59
+
60
+ store = wcrypt.CertOpenStore(
61
+ CERT_STORE_PROV_SYSTEM,
62
+ 0,
63
+ None,
64
+ STORE_LOCATION_TO_CERT_SYSTEM_STORE[store_location],
65
+ store_location
66
+ )
67
+
68
+ # Collect all matching certificates in a list
69
+ certs_to_remove = []
70
+ for cert in store.CertEnumCertificatesInStore():
71
+ # Certificate properties.
72
+ # cert.CertEnumCertificateContextProperties()
73
+ subject_string: str = wcrypt.CertNameToStr(cert.Subject)
74
+ if subject_string == issuer_name:
75
+ # Remove the certificate.
76
+ certs_to_remove.append(cert)
77
+
78
+ # Remove all certificates from the list.
79
+ for cert in certs_to_remove:
80
+ cert.CertDeleteCertificateFromStore()
81
+ print_api(f"Removed the Certificate from store [{store_location}] with issuer [{issuer_name}]", **(print_kwargs or {}))
82
+
83
+ # There is an exception about store close.
84
+ # store.CertCloseStore()
85
+
86
+
87
+ def install_certificate_file(
88
+ file_path: str,
89
+ store_location: Literal[
90
+ "ROOT", "CA", "MY"] = "ROOT",
91
+ print_kwargs: dict = None
92
+ ):
93
+ """
94
+ NEED ADMIN RIGHTS.
95
+ The function will install the certificate from the file to the specified store location.
96
+
97
+ :param file_path: string, full file path to the certificate file.
98
+ :param store_location: string, store location to install the certificate. Default is "ROOT".
99
+ :param print_kwargs: dict, print_api kwargs.
100
+ """
101
+
102
+ with open(file_path, 'r') as f:
103
+ certificate_string = f.read()
104
+
105
+ certificate_pem = certificates.get_pem_certificate_from_string(certificate_string)
106
+
107
+ certificate_bytes = wcrypt.CryptStringToBinary(certificate_pem, CRYPT_STRING_BASE64HEADER)[0]
108
+
109
+ store = wcrypt.CertOpenStore(
110
+ CERT_STORE_PROV_SYSTEM, 0, None, STORE_LOCATION_TO_CERT_SYSTEM_STORE[store_location], store_location)
111
+
112
+ store.CertAddEncodedCertificateToStore(X509_ASN_ENCODING, certificate_bytes, CERT_STORE_ADD_REPLACE_EXISTING)
113
+ store.CertCloseStore(CERT_CLOSE_STORE_FORCE_FLAG)
114
+
115
+ message = f"Certificate installed to the store: [{store_location}] from file: [{file_path}]"
116
+ print_api(message, **(print_kwargs or {}))
@@ -0,0 +1,34 @@
1
+ import win32api
2
+ import win32con
3
+
4
+
5
+ class ConsoleHandler:
6
+ """
7
+ This class is used to handle console events.
8
+ Currently used to handle the 'CTRL_CLOSE_EVENT' event - Meaning what to do when the user closes the console by
9
+ clicking on X in the top right corner.
10
+ """
11
+ def __init__(
12
+ self,
13
+ cleanup_action: callable = None,
14
+ args: tuple = None,
15
+ kwargs: dict = None
16
+ ):
17
+ """
18
+ :param cleanup_action: The action to run when user closes the console.
19
+ :param args: The arguments to pass to the cleanup action.
20
+ :param kwargs: The keyword arguments to pass to the cleanup action.
21
+ """
22
+ self.cleanup_action = cleanup_action
23
+ self.args = args
24
+ self.kwargs = kwargs
25
+
26
+ def _console_handler(self, event):
27
+ if event == win32con.CTRL_CLOSE_EVENT:
28
+ if self.cleanup_action and callable(self.cleanup_action):
29
+ self.cleanup_action(*self.args, **self.kwargs)
30
+ return True
31
+ return False
32
+
33
+ def register_handler(self):
34
+ win32api.SetConsoleCtrlHandler(self._console_handler, True)
File without changes
@@ -0,0 +1,174 @@
1
+ import win32evtlog
2
+ import win32security
3
+ import win32con
4
+
5
+
6
+ def get_latest_events(
7
+ server_ip: str = ".",
8
+ username: str = None,
9
+ password: str = None,
10
+ domain: str = ".",
11
+ log_name: str = "Security",
12
+ count: int = None,
13
+ event_id_list: list[int] | None = None
14
+ ):
15
+ """
16
+ Fetch latest `count` events from a Windows Event Log (local or remote) using pywin32.
17
+
18
+ - If username/password are None => use current security context.
19
+ - If server_ip is ".", "localhost", "127.0.0.1", "" or None => open local log.
20
+ - If count is None => return *all* events in the log.
21
+ - If event_id_list is not None => only return events whose EventID is in that list.
22
+
23
+ :param server_ip: IPv4/hostname of remote machine, or "." / None for local
24
+ :param username: Username to authenticate with (optional)
25
+ :param password: Password for the user (optional)
26
+ :param domain: Domain or computer name; ignored if username is None.
27
+ If None and username is given, "." is used.
28
+ :param log_name: Log name (e.g. "Security", "System", "Application")
29
+ :param count: Number of most recent events to return, or None for all
30
+ :param event_id_list: List of Event IDs (low 16-bit) to include, or None for all
31
+ :return: List of dicts describing events (most recent first)
32
+ """
33
+
34
+ # Normalize server for OpenEventLog: None means "local machine"
35
+ normalized_server = server_ip
36
+ if server_ip in (None, "", ".", "localhost", "127.0.0.1"):
37
+ normalized_server = None
38
+
39
+ # Max events logic: None => infinite
40
+ max_events = float("inf") if count is None else count
41
+
42
+ # Precompute set of event IDs for fast membership checks
43
+ event_ids_set = set(event_id_list) if event_id_list is not None else None
44
+
45
+ # Decide whether we need impersonation
46
+ use_impersonation = username is not None and password is not None
47
+
48
+ h_user = None
49
+ events = []
50
+
51
+ try:
52
+ if use_impersonation:
53
+ if domain is None:
54
+ domain = "."
55
+
56
+ # Log on with explicit credentials and impersonate for the remote call
57
+ # LOGON32_LOGON_NEW_CREDENTIALS lets us use these creds for remote access
58
+ # while keeping the local token mostly unchanged.
59
+ h_user = win32security.LogonUser(
60
+ username,
61
+ domain,
62
+ password,
63
+ win32con.LOGON32_LOGON_NEW_CREDENTIALS,
64
+ win32con.LOGON32_PROVIDER_WINNT50,
65
+ )
66
+
67
+ win32security.ImpersonateLoggedOnUser(h_user)
68
+
69
+ # Connect to remote event log
70
+ # `server_ip` can be an IP or hostname; no need for leading "\\".
71
+ # local if normalized_server is None.
72
+ h_log = win32evtlog.OpenEventLog(normalized_server, log_name)
73
+
74
+ flags = (
75
+ win32evtlog.EVENTLOG_BACKWARDS_READ
76
+ | win32evtlog.EVENTLOG_SEQUENTIAL_READ
77
+ )
78
+
79
+ offset = 0 # not used with BACKWARDS_READ + SEQUENTIAL_READ, but kept for clarity
80
+
81
+ while len(events) < max_events:
82
+ records = win32evtlog.ReadEventLog(h_log, flags, offset)
83
+ if not records:
84
+ break
85
+
86
+ for ev in records:
87
+ # Low 16 bits are the actual Event ID
88
+ eid = ev.EventID & 0xFFFF
89
+
90
+ # If filtering by event IDs, skip others
91
+ if event_ids_set is not None and eid not in event_ids_set:
92
+ continue
93
+
94
+ raw_strings = list(ev.StringInserts or [])
95
+ strings_dict = _parse_strings(eid, ev.SourceName, raw_strings)
96
+
97
+ evt = {
98
+ "RecordNumber": ev.RecordNumber,
99
+ "TimeGenerated": ev.TimeGenerated.Format(), # string time
100
+ "ComputerName": ev.ComputerName,
101
+ "SourceName": ev.SourceName,
102
+ # Low 16 bits are the actual Event ID
103
+ "EventID": ev.EventID & 0xFFFF,
104
+ "EventType": ev.EventType,
105
+ "EventCategory": ev.EventCategory,
106
+ "Strings": raw_strings,
107
+ "StringsDict": strings_dict,
108
+ }
109
+ events.append(evt)
110
+
111
+ if len(events) >= max_events:
112
+ break
113
+
114
+ win32evtlog.CloseEventLog(h_log)
115
+
116
+ finally:
117
+ # Clean up impersonation if we used it, Always revert impersonation and close handle
118
+ if use_impersonation and h_user is not None:
119
+ win32security.RevertToSelf()
120
+ h_user.Close()
121
+
122
+ # `events` is in newest to oldest already because of BACKWARDS_READ.
123
+ return events
124
+
125
+
126
+ def _parse_strings(event_id: int, source_name: str, strings: list[str]) -> dict:
127
+ """
128
+ Convert the raw 'Strings' list into a dictionary with friendly field names
129
+ for specific event IDs. For unknown events, fall back to String1, String2, ...
130
+
131
+ Currently has a special mapping for:
132
+ - 5156 (Security log, WFP allowed connection)
133
+ """
134
+ if not strings:
135
+ return {}
136
+
137
+ # Normalize source name a bit
138
+ src = (source_name or "").lower()
139
+
140
+ # Special-case: Security 5156 (Windows Filtering Platform has permitted a connection)
141
+ # Insertion strings (in order) are:
142
+ # 1 Process ID
143
+ # 2 Application Name
144
+ # 3 Direction
145
+ # 4 Source Address
146
+ # 5 Source Port
147
+ # 6 Destination Address
148
+ # 7 Destination Port
149
+ # 8 Protocol
150
+ # 9 Filter Run-Time ID
151
+ # 10 Layer Name
152
+ # 11 Layer Run-Time ID
153
+ if event_id == 5156 and "security-auditing" in src:
154
+ keys_5156 = [
155
+ "Process ID",
156
+ "Application Name",
157
+ "Direction",
158
+ "Source Address",
159
+ "Source Port",
160
+ "Destination Address",
161
+ "Destination Port",
162
+ "Protocol",
163
+ "Filter Run-Time ID",
164
+ "Layer Name",
165
+ "Layer Run-Time ID",
166
+ ]
167
+ return {
168
+ key: strings[i]
169
+ for i, key in enumerate(keys_5156)
170
+ if i < len(strings)
171
+ }
172
+
173
+ # Default: generic mapping
174
+ return {f"String{i+1}": s for i, s in enumerate(strings)}