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,126 @@
1
+ from .. import trace, const
2
+ from ...wrappers import sysmonw
3
+ from ...basics import dicts
4
+
5
+
6
+ DEFAULT_SESSION_NAME: str = 'AtomicShopSysmonProcessCreationTrace'
7
+
8
+ PROVIDER_NAME: str = const.ETW_SYSMON['provider_name']
9
+ PROVIDER_GUID: str = const.ETW_SYSMON['provider_guid']
10
+ PROCESS_CREATION_EVENT_ID: int = const.ETW_SYSMON['event_ids']['process_create']
11
+
12
+
13
+ class SysmonProcessCreationTrace:
14
+ def __init__(
15
+ self,
16
+ attrs: list = None,
17
+ session_name: str = None,
18
+ close_existing_session_name: bool = True,
19
+ sysmon_directory: str = None
20
+ ):
21
+ """
22
+ DnsTrace class use to trace DNS events from Windows Event Tracing for EventId 3008.
23
+
24
+ :param attrs: List of attributes to return. If None, all attributes will be returned.
25
+ :param session_name: The name of the session to create. If not provided, a UUID will be generated.
26
+ :param close_existing_session_name: Boolean to close existing session names.
27
+ True: if ETW session with 'session_name' exists, you will be notified and the session will be closed.
28
+ Then the new session with this name will be created.
29
+ False: if ETW session with 'session_name' exists, you will be notified and the new session will not be
30
+ created. Instead, the existing session will be used. If there is a buffer from the previous session,
31
+ you will get the events from the buffer.
32
+ :param sysmon_directory: The directory where Sysmon is located. If not provided, "C:\\Windows\\Sysmon" will be
33
+ used. If 'Sysmon.exe' is not found in the directory, it will be downloaded from the internet.
34
+
35
+ -------------------------------------------------
36
+
37
+ Usage Example:
38
+ from atomicshop.etw import dns_trace
39
+
40
+
41
+ dns_trace_w = dns_trace.DnsTrace(
42
+ attrs=['pid', 'name', 'cmdline', 'domain', 'query_type'],
43
+ session_name='MyDnsTrace',
44
+ close_existing_session_name=True,
45
+ enable_process_poller=True,
46
+ process_poller_etw_session_name='MyProcessTrace'
47
+ )
48
+ dns_trace_w.start()
49
+ while True:
50
+ dns_dict = dns_trace_w.emit()
51
+ print(dns_dict)
52
+ dns_trace_w.stop()
53
+ """
54
+
55
+ self.attrs = attrs
56
+ self.sysmon_directory: str = sysmon_directory
57
+
58
+ if not session_name:
59
+ session_name = DEFAULT_SESSION_NAME
60
+
61
+ self.event_trace = trace.EventTrace(
62
+ providers=[(PROVIDER_NAME, PROVIDER_GUID)],
63
+ # lambda x: self.event_queue.put(x),
64
+ event_id_filters=[PROCESS_CREATION_EVENT_ID],
65
+ session_name=session_name,
66
+ close_existing_session_name=close_existing_session_name
67
+ )
68
+
69
+ def start(self):
70
+ sysmonw.start_as_service(
71
+ installation_path=self.sysmon_directory, download_sysmon_if_not_found=True, skip_if_running=True)
72
+ self.event_trace.start()
73
+
74
+ def stop(self):
75
+ self.event_trace.stop()
76
+
77
+ def emit(self):
78
+ """
79
+ Function that will return the next event from the queue.
80
+ The queue is blocking, so if there is no event in the queue, the function will wait until there is one.
81
+
82
+ Usage Example:
83
+ while True:
84
+ dns_dict = dns_trace.emit()
85
+ print(dns_dict)
86
+
87
+ :return: Dictionary with the event data.
88
+
89
+ -----------------------------------------------
90
+
91
+ Structure of the returned dictionary:
92
+ {
93
+ 'event_id': int,
94
+ 'ProcessId': int,
95
+ 'ProcessGuid': str,
96
+ 'Image': str,
97
+ 'FileVersion': str,
98
+ 'Product': str,
99
+ 'Company': str,
100
+ 'OriginalFileName': str,
101
+ 'CommandLine': str,
102
+ 'CurrentDirectory': str,
103
+ 'User': str,
104
+ 'LogonId': str,
105
+ 'LogonGuid': str,
106
+ 'TerminalSessionId': int,
107
+ 'IntegrityLevel': str,
108
+ 'Hashes': dict,
109
+ 'ParentProcessGuid': str,
110
+ 'ParentProcessId': int,
111
+ 'ParentImage': str,
112
+ 'ParentCommandLine': str
113
+ }
114
+
115
+ """
116
+
117
+ event = self.event_trace.emit()
118
+
119
+ event_dict = {'EventId': event['EventId']}
120
+ event_dict.update(event['EventHeader'])
121
+
122
+ if self.attrs:
123
+ event_dict = dicts.reorder_keys(
124
+ event_dict, self.attrs, skip_keys_not_in_list=True)
125
+
126
+ return event_dict
@@ -0,0 +1,130 @@
1
+ import multiprocessing.managers
2
+
3
+ from .. import trace, providers
4
+ from ...basics import dicts
5
+
6
+
7
+ ETW_DEFAULT_SESSION_NAME: str = 'AtomicShopTcpTrace'
8
+
9
+ PROVIDER_NAME: str = "Microsoft-Windows-TCPIP"
10
+ PROVIDER_GUID: str = '{' + providers.get_provider_guid_by_name(PROVIDER_NAME) + '}'
11
+ REQUEST_RESP_EVENT_ID: int = 1033
12
+
13
+
14
+ class TcpIpNewConnectionsTrace:
15
+ """
16
+ TcpIpNewConnectionsTrace class use to trace new connection events from Windows Event Tracing:
17
+ Provider: Microsoft-Windows-TCPIP
18
+ EventId: 1033
19
+ """
20
+ def __init__(
21
+ self,
22
+ attrs: list = None,
23
+ session_name: str = None,
24
+ close_existing_session_name: bool = True,
25
+ process_pool_shared_dict_proxy: multiprocessing.managers.DictProxy = None
26
+ ):
27
+ """
28
+ :param attrs: List of attributes to return. If None, all attributes will be returned.
29
+ :param session_name: The name of the session to create. If not provided, a UUID will be generated.
30
+ :param close_existing_session_name: Boolean to close existing session names.
31
+ True: if ETW session with 'session_name' exists, you will be notified and the session will be closed.
32
+ Then the new session with this name will be created.
33
+ False: if ETW session with 'session_name' exists, you will be notified and the new session will not be
34
+ created. Instead, the existing session will be used. If there is a buffer from the previous session,
35
+ you will get the events from the buffer.
36
+ :param process_pool_shared_dict_proxy: multiprocessing.managers.DictProxy, multiprocessing shared dict proxy
37
+ that contains current processes.
38
+ Check the 'atomicshop\process_poller\simple_process_pool.py' SimpleProcessPool class for more information.
39
+
40
+ For this specific class it means that you can run the process poller outside of this class and pass the
41
+ 'process_pool_shared_dict_proxy' to this class. Then you can get the process name and command line for
42
+ the DNS events from the 'process_pool_shared_dict_proxy' and use it also in other classes.
43
+
44
+ -------------------------------------------------
45
+
46
+ Usage Example:
47
+ from atomicshop.etw import tcp_trace
48
+
49
+
50
+ tcp_trace_w = tcp_trace.TcpIpNewConnectionsTrace(
51
+ attrs=['pid', 'name', 'cmdline', 'domain', 'query_type'],
52
+ session_name='MyTcpTrace',
53
+ close_existing_session_name=True,
54
+ enable_process_poller=True
55
+ )
56
+ tcp_trace_w.start()
57
+ while True:
58
+ tcp_dict = tcp_trace_w.emit()
59
+ print(tcp_dict)
60
+ tcp_trace_w.stop()
61
+ """
62
+
63
+ self.attrs = attrs
64
+ self.process_pool_shared_dict_proxy: multiprocessing.managers.DictProxy = process_pool_shared_dict_proxy
65
+
66
+ if not session_name:
67
+ session_name = ETW_DEFAULT_SESSION_NAME
68
+
69
+ self.event_trace = trace.EventTrace(
70
+ providers=[(PROVIDER_NAME, PROVIDER_GUID)],
71
+ # lambda x: self.event_queue.put(x),
72
+ event_id_filters=[REQUEST_RESP_EVENT_ID],
73
+ session_name=session_name,
74
+ close_existing_session_name=close_existing_session_name,
75
+ enable_process_poller=True,
76
+ process_pool_shared_dict_proxy=self.process_pool_shared_dict_proxy
77
+ )
78
+
79
+ def start(self):
80
+ self.event_trace.start()
81
+
82
+ def stop(self):
83
+ self.event_trace.stop()
84
+
85
+ def emit(self):
86
+ """
87
+ Function that will return the next event from the queue.
88
+ The queue is blocking, so if there is no event in the queue, the function will wait until there is one.
89
+
90
+ Usage Example:
91
+ while True:
92
+ tcp_dict = tcp_trace.emit()
93
+ print(tcp_dict)
94
+
95
+ :return: Dictionary with the event data.
96
+ """
97
+
98
+ # Get the event from ETW as is.
99
+ event = self.event_trace.emit()
100
+
101
+ local_address_port: str = event['EventHeader']['LocalAddress']
102
+ remote_address_port: str = event['EventHeader']['RemoteAddress']
103
+
104
+ if 'ffff' in local_address_port:
105
+ pass
106
+
107
+ local_address, local_port = local_address_port.rsplit(':', 1)
108
+ local_address = local_address.replace('[', '').replace(']', '')
109
+
110
+ remote_address, remote_port = remote_address_port.rsplit(':', 1)
111
+ remote_address = remote_address.replace('[', '').replace(']', '')
112
+
113
+ event_dict: dict = {
114
+ 'timestamp': event['timestamp'],
115
+ 'event_id': event['EventId'],
116
+ 'local_ip': local_address,
117
+ 'local_port': local_port,
118
+ 'remote_ip': remote_address,
119
+ 'remote_port': remote_port,
120
+ 'status': event['EventHeader']['Status'],
121
+ 'pid': event['pid'],
122
+ 'name': event['name'],
123
+ 'cmdline': event['cmdline']
124
+ }
125
+
126
+ if self.attrs:
127
+ event_dict = dicts.reorder_keys(
128
+ event_dict, self.attrs, skip_keys_not_in_list=True)
129
+
130
+ return event_dict
@@ -1,29 +1,42 @@
1
1
  import csv
2
+ import io
2
3
  from typing import Tuple, List
3
4
 
4
- from .file_io import read_file_decorator
5
5
  from . import file_io
6
6
 
7
7
 
8
- @read_file_decorator
9
- def read_csv_to_list(file_path: str,
10
- file_mode: str = 'r',
11
- encoding=None,
12
- header: list = None,
13
- file_object=None,
14
- **kwargs) -> Tuple[List, List | None]:
8
+ @file_io.read_file_decorator
9
+ def read_csv_to_list_of_dicts_by_header(
10
+ file_path: str,
11
+ file_mode: str = 'r',
12
+ encoding=None,
13
+ header: list = None,
14
+ file_object=None,
15
+ **kwargs
16
+ ) -> Tuple[List, List | None]:
15
17
  """
16
18
  Function to read csv file and output its contents as list of dictionaries for each row.
19
+ Each key of the dictionary is a header field.
20
+
21
+ Example:
22
+ CSV file:
23
+ name,age,city
24
+ John,25,New York
25
+
26
+ Output:
27
+ [{'name': 'John', 'age': '25', 'city': 'New York'}]
17
28
 
18
29
  :param file_path: String with full file path to json file.
19
30
  :param file_mode: string, file reading mode. Examples: 'r', 'rb'. Default is 'r'.
20
31
  :param encoding: string, encoding of the file. Default is 'None'.
21
32
  :param header: list, list of strings that will be the header of the CSV file. Default is 'None'.
22
- If you want to use the header from the CSV file, use 'None'. In this case, the first row of the CSV file will
23
- be the header.
33
+ None: the header from the CSV file will be used. The first row of the CSV file will be the header.
34
+ Meaning, that the first line will be skipped and the second line will be the first row of the content.
35
+ List: the list will be used as header.
36
+ All the lines of the CSV file will be considered as content.
24
37
  :param file_object: file object of the 'open()' function in the decorator. Decorator executes the 'with open()'
25
38
  statement and passes to this function. That's why the default is 'None', since we get it from the decorator.
26
- :return: list.
39
+ :return: tuple(list of entries, header(list of cell names)).
27
40
  """
28
41
 
29
42
  # The header fields will be separated to list of "csv_reader.fieldnames".
@@ -39,25 +52,92 @@ def read_csv_to_list(file_path: str,
39
52
  return csv_list, header
40
53
 
41
54
 
42
- def write_list_to_csv(csv_list: list, csv_filepath: str) -> None:
55
+ @file_io.read_file_decorator
56
+ def read_csv_to_list_of_lists(
57
+ file_path: str,
58
+ file_mode: str = 'r',
59
+ encoding=None,
60
+ exclude_header_from_content: bool = False,
61
+ file_object=None,
62
+ **kwargs
63
+ ) -> Tuple[List, List | None]:
64
+ """
65
+ Function to read csv file and output its contents as list of lists for each row.
66
+
67
+ Example:
68
+ CSV file:
69
+ name,age,city
70
+ John,25,New York
71
+
72
+ Output:
73
+ [['name', 'age', 'city'], ['John', '25', 'New York']]
74
+
75
+ :param file_path: String with full file path to json file.
76
+ :param file_mode: string, file reading mode. Examples: 'r', 'rb'. Default is 'r'.
77
+ :param encoding: string, encoding of the file. Default is 'None'.
78
+ :param exclude_header_from_content: Boolean, if True, the header will be excluded from the content.
79
+ :param file_object: file object of the 'open()' function in the decorator. Decorator executes the 'with open()'
80
+ statement and passes to this function. That's why the default is 'None', since we get it from the decorator.
81
+ :param kwargs: Keyword arguments for 'read_file' function.
82
+ :return: list.
43
83
  """
44
- Function to write list object that each iteration of it contains dict object with same keys and different values.
45
84
 
46
- :param csv_list: List object that each iteration contains dictionary with same keys and different values.
47
- :param csv_filepath: Full file path to CSV file.
85
+ # Read CSV file to list of lists.
86
+ csv_reader = csv.reader(file_object)
87
+
88
+ csv_list = list(csv_reader)
89
+
90
+ # Get the header if there is only something in the content.
91
+ if csv_list:
92
+ header = csv_list[0]
93
+ else:
94
+ header = []
95
+
96
+ if exclude_header_from_content and csv_list:
97
+ csv_list.pop(0)
98
+
99
+ return csv_list, header
100
+
101
+
102
+ def write_list_to_csv(
103
+ content_list: list,
104
+ file_path: str,
105
+ mode: str = 'w',
106
+ encoding: str = None
107
+ ) -> None:
108
+ """
109
+ This function got dual purpose:
110
+ 1. Write list object that each iteration of it contains list object with same length.
111
+ 2. Write list object that each iteration of it contains dict object with same keys and different values.
112
+ The dictionary inside the function will be identified by the first iteration of the list.
113
+ Other objects (inside the provided list) than dictionary will be identified as regular objects.
114
+
115
+ :param content_list: List object that each iteration contains dictionary with same keys and different values.
116
+ :param file_path: Full file path to CSV file.
117
+ :param mode: String, file writing mode. Default is 'w'.
118
+ :param encoding: String, encoding of the file. Default is 'None'.
119
+ Example: 'utf-8', 'utf-16', 'cp1252'.
48
120
  :return: None.
49
121
  """
50
122
 
51
- with open(csv_filepath, mode='w') as csv_file:
52
- # Create header from keys of the first dictionary in list.
53
- header = csv_list[0].keys()
54
- # Create CSV writer.
55
- writer = csv.DictWriter(csv_file, fieldnames=header, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
123
+ with open(file_path, mode=mode, newline='', encoding=encoding) as csv_file:
124
+ if len(content_list) > 0 and isinstance(content_list[0], dict):
125
+ # Treat the list as list of dictionaries.
126
+ header = content_list[0].keys()
56
127
 
57
- # Write header.
58
- writer.writeheader()
59
- # Write list of dits as rows.
60
- writer.writerows(csv_list)
128
+ # Create CSV writer.
129
+ writer = csv.DictWriter(csv_file, fieldnames=header, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
130
+
131
+ # Write header.
132
+ writer.writeheader()
133
+ # Write list of dits as rows.
134
+ writer.writerows(content_list)
135
+ # Else, treat the list as list of lists.
136
+ else:
137
+ # Create CSV writer.
138
+ writer = csv.writer(csv_file)
139
+ # Write list of lists as rows.
140
+ writer.writerows(content_list)
61
141
 
62
142
 
63
143
  def get_header(file_path: str, print_kwargs: dict = None) -> list:
@@ -78,3 +158,121 @@ def get_header(file_path: str, print_kwargs: dict = None) -> list:
78
158
  # Split the header to list of keys.
79
159
  header = header.split(',')
80
160
  return header
161
+
162
+
163
+ def _escape_csv_value_ref(text):
164
+ """
165
+ FOR REFERENCE ONLY, better use csv module to do it natively.
166
+ Function to escape text for CSV file.
167
+ This function escapes commas (,) and double quotes (") for csv cell (between commas).
168
+
169
+ Example:
170
+ test1 = 'test1'
171
+ test2 = 'test,2'
172
+ test3 = 'test3,"3",3'
173
+
174
+ csv_line = f'{escape_csv_value(test1)},{escape_csv_value(test2)},{escape_csv_value(test3)}'
175
+
176
+ Output: 'test1,"test,2","test3,""3"",3"'
177
+ """
178
+
179
+ if '"' in text:
180
+ text = text.replace('"', '""') # Escape double quotes
181
+ if ',' in text or '"' in text:
182
+ text = f'"{text}"' # Enclose in double quotes if there are commas or double quotes
183
+ return text
184
+
185
+
186
+ def escape_csv_value(value):
187
+ """
188
+ Function to escape text for CSV file.
189
+ This function escapes commas (,) and double quotes (") for csv cell (between commas).
190
+
191
+ Example:
192
+ test1 = 'test1'
193
+ test2 = 'test,2'
194
+ test3 = 'test3,"3",3'
195
+
196
+ csv_line = f'{escape_csv_value(test1)},{escape_csv_value(test2)},{escape_csv_value(test3)}'
197
+
198
+ Output: 'test1,"test,2","test3,""3"",3"'
199
+ """
200
+ output = io.StringIO()
201
+ writer = csv.writer(output, quoting=csv.QUOTE_MINIMAL)
202
+ writer.writerow([value])
203
+ return output.getvalue().strip()
204
+
205
+
206
+ def escape_csv_line_to_string(csv_line: list) -> str:
207
+ """
208
+ Function to escape list of strings for CSV file.
209
+ This function escapes commas (,) and double quotes (") for csv cell (between commas).
210
+
211
+ Example:
212
+ test1 = 'test1'
213
+ test2 = 'test,2'
214
+ test3 = 'test3,"3",3'
215
+
216
+ csv_line = escape_csv_line_to_string([test1, test2, test3])
217
+
218
+ Output:
219
+ csv_line == 'test1,"test,2","test3,""3"",3"'
220
+ """
221
+
222
+ # Prepare the data as a list of lists
223
+ data = [csv_line]
224
+
225
+ # Use StringIO to create an in-memory file-like object
226
+ output = io.StringIO()
227
+ writer = csv.writer(output, quoting=csv.QUOTE_MINIMAL)
228
+
229
+ # Write the data to the CSV writer
230
+ writer.writerows(data)
231
+
232
+ # Get the CSV string from the StringIO object, Strip to remove any trailing newlines.
233
+ csv_line = output.getvalue().strip()
234
+
235
+ return csv_line
236
+
237
+
238
+ def escape_csv_line_to_list(csv_line: list) -> list:
239
+ """
240
+ Function to escape list of strings for CSV file.
241
+ This function escapes commas (,) and double quotes (") for csv cell (between commas).
242
+
243
+ Example:
244
+ test1 = 'test1'
245
+ test2 = 'test,2'
246
+ test3 = 'test3,"3",3'
247
+
248
+ csv_entries_list = escape_csv_line_to_list([test1, test2, test3])
249
+
250
+ Output:
251
+ csv_entries_list == ['test1', '"test,2"', '"test3,""3"",3"']
252
+ """
253
+
254
+ result_csv_entries: list = []
255
+ for entry in csv_line:
256
+ result_csv_entries.append(escape_csv_value(entry))
257
+
258
+ return result_csv_entries
259
+
260
+
261
+ def get_number_of_cells_in_string_line(line: str) -> int:
262
+ """
263
+ Function to get number of cells in CSV line.
264
+
265
+ :param line: String, line of CSV file.
266
+ :return: int, number of cells in the line.
267
+ """
268
+
269
+ # Create CSV reader from 'input_file'. By default, the first row will be the header if 'fieldnames' is None.
270
+ csv_reader = csv.reader([line])
271
+
272
+ # Get the first row of the CSV file.
273
+ csv_list = list(csv_reader)
274
+
275
+ # Get the number of cells in the first row.
276
+ number_of_cells = len(csv_list[0])
277
+
278
+ return number_of_cells
@@ -12,7 +12,7 @@ def get_hyperlinks(docx_path):
12
12
  :return: list of strings, hyperlinks.
13
13
  """
14
14
 
15
- hyperlinks: list = list()
15
+ hyperlinks: list[dict] = list()
16
16
 
17
17
  try:
18
18
  doc = Document(docx_path)
@@ -26,7 +26,19 @@ def get_hyperlinks(docx_path):
26
26
  if not paragraph.hyperlinks:
27
27
  continue
28
28
  for hyperlink in paragraph.hyperlinks:
29
- hyperlinks.append(hyperlink.address)
29
+ # Hyperlinks are stored in docx (document.xml) without the fragment part.
30
+ # Fragment is the anchor of the link, for example: 'https://www.example.com#anchor'.
31
+ # So the hyperlink.address is stored as 'https://www.example.com'.
32
+ # And the fragment is stored in the hyperlink.fragment as 'anchor'.
33
+ # For the full hyperlink, we need to concatenate the address and the fragment.
34
+ # If there is no anchor in the link the fragment will be empty string ('').
35
+ # Basically, we don't need to add the fragment to the hyperlink if it's empty, we can just use the url.
36
+ # if hyperlink.fragment:
37
+ # hyperlinks.append(hyperlink.address + "#" + hyperlink.fragment)
38
+ hyperlinks.append({
39
+ 'url': hyperlink.url,
40
+ 'text': hyperlink.text
41
+ })
30
42
 
31
43
  return hyperlinks
32
44
 
@@ -62,28 +74,31 @@ def search_for_hyperlink_in_files(directory_path: str, hyperlink: str, relative_
62
74
  input('press Enter')
63
75
  """
64
76
 
65
- if not filesystem.check_directory_existence(directory_path):
77
+ if not filesystem.is_directory_exists(directory_path):
66
78
  raise NotADirectoryError(f"Directory doesn't exist: {directory_path}")
67
79
 
68
80
  # Get all the docx files in the specified directory.
69
- files = filesystem.get_file_paths_from_directory(
70
- directory_path, file_name_check_pattern="*\.docx",
81
+ files = filesystem.get_paths_from_directory(
82
+ directory_path, get_file=True, file_name_check_pattern="*.docx",
71
83
  add_relative_directory=True, relative_file_name_as_directory=True)
72
84
 
73
- found_in_files: list = list()
85
+ found_in_files: list[dict] = list()
74
86
  for file_path in files:
75
- hyperlinks = get_hyperlinks(file_path['file_path'])
76
- if hyperlink in hyperlinks:
77
- found_in_files.append(file_path)
87
+ doc_hyperlinks = get_hyperlinks(file_path.path)
88
+ for doc_link in doc_hyperlinks:
89
+ if hyperlink in doc_link['url']:
90
+ if relative_paths:
91
+ path: str = file_path.relative_dir
92
+ else:
93
+ path: str = file_path.path
78
94
 
79
- if relative_paths:
80
- result_list = list()
81
- for found_file in found_in_files:
82
- result_list.append(found_file['relative_dir'])
83
- else:
84
- result_list = found_in_files
95
+ found_in_files.append({
96
+ 'path':path,
97
+ 'link':doc_link['url'],
98
+ 'text':doc_link['text']
99
+ })
85
100
 
86
- return result_list
101
+ return found_in_files
87
102
 
88
103
 
89
104
  def search_for_hyperlink_in_files_interface_main(script_directory: str = None):
@@ -126,10 +141,12 @@ def search_for_hyperlink_in_files_interface_main(script_directory: str = None):
126
141
  found_in_files = search_for_hyperlink_in_files(
127
142
  config['directory_path'], config['hyperlink'], relative_paths=config['relative_paths'])
128
143
 
129
- print_api(f"Found in [{len(found_in_files)}] files:", color="blue")
144
+ print_api(f"Found [{len(found_in_files)}] links:", color="blue")
130
145
 
131
146
  for index, found_file in enumerate(found_in_files):
132
147
  print_api(f"[{index+1}]", print_end="", color="green")
133
- print_api(f" {found_file}")
148
+ print_api(f" {found_file['path']}")
149
+ print_api(f" {found_file['link']}", color="cyan")
150
+ print_api(f" {found_file['text']}", color="orange")
134
151
 
135
152
  input('[*] Press [Enter] to exit...')