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
@@ -1,6 +1,21 @@
1
- from .checks import dns, network, hash, process_running
2
- from .. import filesystem, scheduling
3
- from ..diff_check import DiffChecker
1
+ from typing import Literal, Union
2
+
3
+ from .checks import dns, network, file, url, process_running
4
+
5
+
6
+ DNS__DEFAULT_SETTINGS = {
7
+ 'skip_record_list': [], # List of DNS Records to skip emitting. Example: ['PTR', 'SRV']
8
+ 'learning_mode_create_unique_entries_list': True,
9
+ 'learning_hours': 24, # 0 - the learning will never stop.
10
+ 'alert_about_missing_entries_after_learning': False,
11
+ 'alert_about_missing_entries_always': True,
12
+ 'create_alert_statistics': True,
13
+ 'statistics_rotation_hours': 'midnight' # 'midnight' or float of hours
14
+ }
15
+
16
+ FILE__URL__DEFAULT_SETTINGS = {
17
+ 'store_original_object': False
18
+ }
4
19
 
5
20
 
6
21
  class ChangeMonitor:
@@ -9,32 +24,52 @@ class ChangeMonitor:
9
24
  """
10
25
  def __init__(
11
26
  self,
12
- object_type: str,
13
- check_object_list: list = None,
14
- input_file_directory: str = None,
27
+ check_object: any = None,
15
28
  input_file_name: str = None,
16
- generate_input_file_name: bool = False,
29
+ input_statistics_file_name: str = None,
30
+ input_directory: str = None,
17
31
  input_file_write_only: bool = True,
18
- store_original_object: bool = False,
32
+ object_type: Union[
33
+ Literal[
34
+ 'file',
35
+ 'dns',
36
+ 'network',
37
+ 'process_running',
38
+ 'url_urllib',
39
+ 'url_playwright_html',
40
+ 'url_playwright_pdf',
41
+ 'url_playwright_png',
42
+ 'url_playwright_jpeg'],
43
+ None] = None,
44
+ object_type_settings: dict = None,
45
+ etw_session_name: str = None
19
46
  ):
20
47
  """
21
48
  :param object_type: string, type of object to check. The type must be one of the following:
22
- 'dns': 'check_object_list' will be none, since the DNS events will be queried from the system.
23
- 'file': 'check_object_list' must contain strings of full path to the file.
24
- 'url_urllib': 'check_object_list' must contain strings of full URL to a web page. The page will be
25
- downloaded using 'urllib' library in HTML.
26
- 'url_playwright_html': 'check_object_list' must contain strings of full URL to a web page. The page will
27
- be downloaded using 'playwright' library in HTML.
28
- 'url_playwright_pdf': 'check_object_list' must contain strings of full URL to a web page. The page will
29
- be downloaded using 'playwright' library in PDF.
30
- 'url_playwright_png': 'check_object_list' must contain strings of full URL to a web page. The page will
31
- be downloaded using 'playwright' library in PNG.
32
- 'url_playwright_jpeg': 'check_object_list' must contain strings of full URL to a web page. The page will
33
- be downloaded using 'playwright' library in JPEG.
34
- :param check_object_list: list of objects to check if it changed. The list can contain as many objects as
35
- needed and can contain only one object.
36
- The list can be left empty if the object type is 'dns', 'network_sockets'.
37
- :param input_file_directory: string, full directory path for storing input files for current state of objects,
49
+ 'file': 'check_object' must contain string of full path to the file.
50
+ 'dns': 'check_object' will be none, since the DNS events will be queried from the system.
51
+ 'network': 'check_object' will be none, since the network events will be queried from the system.
52
+ 'process_running': 'check_object' must contain list of strings of process names to check if they are
53
+ running.
54
+ Example: ['chrome.exe', 'firefox.exe']
55
+ No file is written.
56
+ 'url_*': 'check_object' must contain string of full URL to a web page to download.
57
+ 'url_urllib': download using 'urllib' library to HTML file.
58
+ 'url_playwright_html': download using 'playwright' library to HTML file.
59
+ 'url_playwright_pdf': download using 'playwright' library to PDF file.
60
+ 'url_playwright_png': download using 'playwright' library to PNG file.
61
+ 'url_playwright_jpeg': download using 'playwright' library to JPEG file.
62
+ :param object_type_settings: dict, specific settings for the object type.
63
+ 'dns': Check the default settings example in 'DNS__DEFAULT_SETTINGS'.
64
+ 'file': Check the default settings example in 'FILE__URL__DEFAULT_SETTINGS'.
65
+ 'url_*': Check the default settings example in 'FILE__URL__DEFAULT_SETTINGS'.
66
+ :param check_object: The object to check if changed.
67
+ 'dns': empty.
68
+ 'network': empty.
69
+ 'process_running': list of strings, process names to check if they are running.
70
+ 'file': string, full path to the file.
71
+ 'url_*': string, full URL to a web page.
72
+ :param input_directory: string, full directory path for storing input files for current state of objects,
38
73
  to check later if this state isn't updated. If this variable is left empty, all the content will be saved
39
74
  in memory and input file will not be used.
40
75
  If the file is not specified, the update of an object will be checked
@@ -50,91 +85,54 @@ class ChangeMonitor:
50
85
  to the input file whether the object was updated.
51
86
  False: write to input file each time there is an update, and read each check cycle from the file and not
52
87
  from the memory.
53
- :param store_original_object: boolean, if True, the original object will be stored on the disk inside
54
- 'Original' folder, inside 'input_file_directory'.
88
+ :param etw_session_name: string, the name of the ETW session. This should help you manage your ETW sessions
89
+ with logman and other tools: logman query -ets
90
+ If not provided, a default name will be generated.
91
+ 'dns': 'AtomicShopDnsTrace'
55
92
 
56
- If 'input_file_directory' is not specified, the 'input_file_name' is not specified, and
93
+ If 'input_directory' is not specified, the 'input_file_name' is not specified, and
57
94
  'generate_input_file_name' is False, then the input file will not be used and the object will be stored
58
95
  in memory. This means that the object will be checked only during the time that the script is running.
59
96
  """
60
97
 
61
- # =================== Exception section ============================
62
- if not input_file_directory and store_original_object:
63
- raise ValueError('ERROR: [input_file_directory] must be specified if [store_original_object] is True.')
98
+ # === Initialize Main variables ====================================
64
99
 
65
- if not input_file_directory and generate_input_file_name:
66
- raise ValueError('ERROR: [input_file_directory] must be specified if [generate_input_file_name] is True.')
100
+ self.check_object: any = check_object
101
+ self.input_file_name: str = input_file_name
102
+ self.input_statistics_file_name: str = input_statistics_file_name
103
+ self.input_directory: str = input_directory
104
+ self.input_file_write_only: bool = input_file_write_only
105
+ self.object_type = object_type
106
+ self.object_type_settings: dict = object_type_settings
107
+ self.etw_session_name: str = etw_session_name
67
108
 
68
- if not input_file_directory and input_file_name:
69
- raise ValueError('ERROR: [input_file_directory] must be specified if [input_file_name] is specified.')
109
+ # === Additional variables ========================================
70
110
 
71
- if input_file_name and generate_input_file_name:
72
- raise ValueError(
73
- 'ERROR: [input_file_name] and [generate_input_file_name] cannot be both specified and True.')
111
+ self.checks_instance = None
112
+ self._setup_check()
74
113
 
75
- # === EOF Exception section ========================================
76
- # === Initialize Main variables ====================================
114
+ def _setup_check(self):
115
+ if self.object_type == 'file':
116
+ if not self.object_type_settings:
117
+ self.object_type_settings = FILE__URL__DEFAULT_SETTINGS
77
118
 
78
- if not check_object_list:
79
- check_object_list = list()
119
+ self.checks_instance = file.FileCheck(self)
120
+ elif self.object_type.startswith('url_'):
121
+ if not self.object_type_settings:
122
+ self.object_type_settings = FILE__URL__DEFAULT_SETTINGS
80
123
 
81
- self.object_type: str = object_type
82
- self.check_object_list: list = check_object_list
83
- self.input_file_directory: str = input_file_directory
84
- self.input_file_name: str = input_file_name
85
- self.generate_input_file_name: bool = generate_input_file_name
86
- self.input_file_write_only: bool = input_file_write_only
87
- self.store_original_object: bool = store_original_object
88
-
89
- # === EOF Initialize Main variables ================================
90
- # === Initialize Secondary variables ===============================
91
-
92
- # The 'diff_check' will store the list of DiffChecker classes.
93
- self.diff_check_list: list = list()
94
-
95
- # If 'check_object_list' is a list, loop through it and create a DiffChecker object for each object.
96
- if self.check_object_list:
97
- for index in range(len(self.check_object_list)):
98
- self.diff_check_list.append(
99
- DiffChecker(
100
- input_file_write_only=self.input_file_write_only,
101
- )
102
- )
103
- # Else, if 'check_object_list' is None, create a DiffChecker object only once.
124
+ self.checks_instance = url.UrlCheck(self)
125
+ elif self.object_type == 'dns':
126
+ if not self.object_type_settings:
127
+ self.object_type_settings = DNS__DEFAULT_SETTINGS
128
+
129
+ self.checks_instance = dns.DnsCheck(self)
130
+ elif self.object_type == 'network':
131
+ self.checks_instance = network.NetworkCheck(self)
132
+ elif self.object_type == 'process_running':
133
+ self.checks_instance = process_running.ProcessRunningCheck(self)
104
134
  else:
105
- self.diff_check_list.append(
106
- DiffChecker(
107
- input_file_write_only=self.input_file_write_only,
108
- )
109
- )
110
-
111
- self.input_file_path = None
112
- self.original_object_directory = None
113
- self.original_object_file_path = None
114
-
115
- # If 'store_original_object' is True, create directory for original object.
116
- if self.store_original_object:
117
- # Make path for original object.
118
- self.original_object_directory = filesystem.add_object_to_path(
119
- self.input_file_directory, 'Original')
120
- # Create directory if it doesn't exist.
121
- filesystem.create_directory(self.original_object_directory)
122
-
123
- self.first_cycle = True
124
-
125
- # Initialize objects for DNS and Network monitoring.
126
- self.fetch_engine = None
127
- self.thread_looper = scheduling.ThreadLooper()
128
-
129
- def _set_input_file_path(self, check_object_index: int = 0):
130
- if self.first_cycle:
131
- # If 'input_file_directory' and 'input_file_name' are specified, we'll use a filename to store.
132
- if self.input_file_directory and self.input_file_name:
133
- self.input_file_path = filesystem.add_object_to_path(
134
- self.input_file_directory, self.input_file_name)
135
-
136
- # Set the input file path.
137
- self.diff_check_list[check_object_index].input_file_path = self.input_file_path
135
+ raise ValueError(f"ERROR: Unknown object type: {self.object_type}")
138
136
 
139
137
  def check_cycle(self, print_kwargs: dict = None):
140
138
  """
@@ -143,28 +141,6 @@ class ChangeMonitor:
143
141
  :return: None
144
142
  """
145
143
 
146
- return_list = list()
147
-
148
- if (
149
- self.object_type == 'file' or
150
- 'url_' in self.object_type):
151
- return_list = hash._execute_cycle(self, print_kwargs=print_kwargs)
152
- if self.object_type == 'dns':
153
- return_list = dns._execute_cycle(self, print_kwargs=print_kwargs)
154
- elif self.object_type == 'network':
155
- return_list = network._execute_cycle(self, print_kwargs=print_kwargs)
156
- elif self.object_type == 'process_running':
157
- return_list = process_running._execute_cycle(self, print_kwargs=print_kwargs)
158
-
159
- # Set 'first_cycle' to False, since the first cycle is finished.
160
- if self.first_cycle:
161
- self.first_cycle = False
144
+ return_list = self.checks_instance.execute_cycle(print_kwargs=print_kwargs)
162
145
 
163
146
  return return_list
164
-
165
- def run_loop(self, interval_seconds=0, print_kwargs: dict = None):
166
- self.thread_looper.run_loop(
167
- self.check_cycle, kwargs={'print_kwargs': print_kwargs}, interval_seconds=interval_seconds)
168
-
169
- def emit_from_loop(self):
170
- return self.thread_looper.emit_from_loop()
@@ -1,77 +1,146 @@
1
- from ...etw.dns_trace import DnsTrace
1
+ from pathlib import Path
2
+ from typing import Union
3
+
4
+ from ...etws.traces import trace_dns
2
5
  from ...print_api import print_api
6
+ from ...import diff_check
3
7
 
4
8
 
5
- def _execute_cycle(change_monitor_instance, print_kwargs: dict = None):
6
- """
7
- This function executes the cycle of the change monitor: dns.
9
+ INPUT_FILE_DEFAULT_NAME: str = 'known_domains.json'
10
+ INPUT_STATISTICS_FILE_DEFAULT_NAME: str = 'dns_statistics.json'
8
11
 
9
- :param change_monitor_instance: Instance of the ChangeMonitor class.
10
12
 
11
- :return: List of dictionaries with the results of the cycle.
13
+ class DnsCheck:
12
14
  """
13
-
14
- if print_kwargs is None:
15
- print_kwargs = dict()
16
-
17
- if change_monitor_instance.first_cycle:
18
- original_name: str = str()
19
-
20
- # Initialize objects for DNS monitoring.
21
- change_monitor_instance.fetch_engine = DnsTrace(
22
- enable_process_poller=True, attrs=['name', 'cmdline', 'domain', 'query_type'])
23
-
15
+ Class for DNS monitoring.
16
+ """
17
+
18
+ def __init__(self, change_monitor_instance):
19
+ self.change_monitor_instance = change_monitor_instance
20
+ self.diff_checker_aggregation: Union[diff_check.DiffChecker, None] = None
21
+ self.diff_checker_statistics: Union[diff_check.DiffChecker, None] = None
22
+ self.settings: dict = change_monitor_instance.object_type_settings
23
+
24
+ self.etw_session_name: str = change_monitor_instance.etw_session_name
25
+
26
+ self.fetch_engine: trace_dns.DnsRequestResponseTrace = (
27
+ trace_dns.DnsRequestResponseTrace(
28
+ attrs=['name', 'cmdline', 'query', 'query_type'],
29
+ session_name=self.etw_session_name,
30
+ close_existing_session_name=True,
31
+ skip_record_list=self.settings['skip_record_list'],
32
+ )
33
+ )
34
+
35
+ if self.settings['alert_always'] and self.settings['alert_about_missing_entries_after_learning']:
36
+ raise ValueError(
37
+ "ERROR: [alert_always] and [alert_about_missing_entries_after_learning] "
38
+ "cannot be True at the same time.")
39
+
40
+ if not change_monitor_instance.input_file_name:
41
+ change_monitor_instance.input_file_name = INPUT_FILE_DEFAULT_NAME
42
+ input_file_path = (
43
+ str(Path(change_monitor_instance.input_directory, change_monitor_instance.input_file_name)))
44
+
45
+ if not change_monitor_instance.input_statistics_file_name:
46
+ change_monitor_instance.input_statistics_file_name = INPUT_STATISTICS_FILE_DEFAULT_NAME
47
+ input_statistic_file_path = (
48
+ str(Path(change_monitor_instance.input_directory, change_monitor_instance.input_statistics_file_name)))
49
+
50
+ if self.settings['learning_mode_create_unique_entries_list']:
51
+ aggregation_display_name = \
52
+ f'{change_monitor_instance.input_file_name}|{change_monitor_instance.object_type}'
53
+ self.diff_checker_aggregation = diff_check.DiffChecker(
54
+ check_object=list(), # DNS events will be appended to this list.
55
+ return_first_cycle=True,
56
+ operation_type='new_objects',
57
+ input_file_write_only=change_monitor_instance.input_file_write_only,
58
+ check_object_display_name=aggregation_display_name,
59
+ input_file_path=input_file_path,
60
+ new_objects_hours_then_difference=self.settings['learning_hours']
61
+ )
62
+ self.diff_checker_aggregation.initiate_before_action()
63
+
64
+ if self.settings['create_alert_statistics']:
65
+ statistics_display_name = \
66
+ f'{change_monitor_instance.input_statistics_file_name}|{change_monitor_instance.object_type}'
67
+
68
+ self.diff_checker_statistics = diff_check.DiffChecker(
69
+ check_object=list(), # DNS events will be appended to this list.
70
+ return_first_cycle=True,
71
+ operation_type='hit_statistics',
72
+ hit_statistics_enable_queue=True,
73
+ input_file_write_only=change_monitor_instance.input_file_write_only,
74
+ check_object_display_name=statistics_display_name,
75
+ input_file_path=input_statistic_file_path,
76
+ hit_statistics_input_file_rotation_cycle_hours=self.settings['statistics_rotation_hours']
77
+ )
78
+ self.diff_checker_statistics.initiate_before_action()
79
+
24
80
  # Start DNS monitoring.
25
- change_monitor_instance.fetch_engine.start()
26
-
27
- # Change settings for the DiffChecker object.
28
- change_monitor_instance.diff_check_list[0].return_first_cycle = True
29
- change_monitor_instance.diff_check_list[0].aggregation = True
30
-
31
- if change_monitor_instance.generate_input_file_name:
32
- original_name = 'known_domains'
33
- # Make path for 'input_file_name'.
34
- change_monitor_instance.input_file_name = f'{original_name}.json'
35
-
36
- change_monitor_instance.diff_check_list[0].check_object_display_name = \
37
- f'{original_name}|{change_monitor_instance.object_type}'
38
-
39
- # Set the 'check_object' to empty list, since we will append the list of DNS events.
40
- change_monitor_instance.diff_check_list[0].check_object = list()
41
-
42
- # Set the input file path.
43
- change_monitor_instance._set_input_file_path()
44
-
45
- return_list = list()
46
-
47
- # 'emit()' method is blocking (it uses 'get' of queue instance)
48
- # will return a dict with current DNS trace event.
49
- event_dict = change_monitor_instance.fetch_engine.emit()
50
-
51
- change_monitor_instance.diff_check_list[0].check_object = [event_dict]
52
-
53
- # if event_dict not in change_monitor_instance.diff_check_list[0].check_object:
54
- # change_monitor_instance.diff_check_list[0].check_object.append(event_dict)
55
- #
56
- # # Sort list of dicts by process name and then by process cmdline.
57
- # change_monitor_instance.diff_check_list[0].check_object = list_of_dicts.sort_by_keys(
58
- # change_monitor_instance.diff_check_list[0].check_object, ['cmdline', 'name'], case_insensitive=True)
59
-
60
- # Check if 'known_domains' list was updated from previous cycle.
61
- result, message = change_monitor_instance.diff_check_list[0].check_list_of_dicts(
62
- sort_by_keys=['cmdline', 'name'], print_kwargs=print_kwargs)
63
-
64
- if result:
65
- # Get list of new connections only.
66
- # new_connections_only: list = list_of_dicts.get_difference(result['old'], result['updated'])
67
-
68
- for connection in result['updated']:
69
- message = \
70
- f"New domain: {connection['name']} | " \
71
- f"{connection['domain']} | {connection['query_type']} | " \
72
- f"{connection['cmdline']}"
73
- print_api(message, color='yellow', **print_kwargs)
74
-
75
- return_list.append(message)
76
-
77
- return return_list
81
+ self.fetch_engine.start()
82
+
83
+ def execute_cycle(self, print_kwargs: dict = None) -> list:
84
+ """
85
+ This function executes the cycle of the change monitor: dns.
86
+ The function is blocking so while using it, the script will wait for the next DNS event.
87
+ No need to use 'time.sleep()'.
88
+
89
+ :param print_kwargs: print_api kwargs.
90
+ :return: List of dictionaries with the results of the cycle.
91
+ """
92
+
93
+ # 'emit()' method is blocking (it uses 'get' of queue instance)
94
+ # will return a dict with current DNS trace event.
95
+ event_dict = self.fetch_engine.emit()
96
+
97
+ return_list = list()
98
+ if self.settings['learning_mode_create_unique_entries_list']:
99
+ self._aggregation_process(event_dict, return_list, print_kwargs)
100
+
101
+ if self.settings['create_alert_statistics'] and self.settings['alert_always']:
102
+ self._statistics_process(event_dict, return_list, print_kwargs)
103
+
104
+ return return_list
105
+
106
+ def _aggregation_process(self, event_dict: dict, return_list: list, print_kwargs: dict = None):
107
+ self.diff_checker_aggregation.check_object = [event_dict]
108
+
109
+ # Check if 'known_domains' list was updated from previous cycle.
110
+ result, message = self.diff_checker_aggregation.check_list_of_dicts(
111
+ sort_by_keys=['cmdline', 'name'], print_kwargs=print_kwargs)
112
+
113
+ if result:
114
+ # Check if 'updated' key is in the result. This means that this is a regular cycle.
115
+ if 'updated' in result:
116
+ if not result['time_passed']:
117
+ # Get list of new connections only.
118
+ # new_connections_only: list = list_of_dicts.get_difference(result['old'], result['updated'])
119
+
120
+ for connection in result['updated']:
121
+ message = \
122
+ f"[Learning] New Domain Added: {connection['name']} | " \
123
+ f"{connection['domain']} | {connection['query_type']} | " \
124
+ f"{connection['cmdline']}"
125
+ print_api(message, color='yellow', **(print_kwargs or {}))
126
+
127
+ return_list.append(message)
128
+
129
+ # Check if learning time passed, so we can alert the new entries.
130
+ if 'time_passed' in result:
131
+ if result['time_passed']:
132
+ self._statistics_process(result['updated'], return_list, print_kwargs)
133
+
134
+ def _statistics_process(self, event_dict: dict, return_list: list, print_kwargs: dict = None):
135
+ self.diff_checker_statistics.check_object = [event_dict]
136
+
137
+ # Check if 'known_domains' list was updated from previous cycle.
138
+ result, message = self.diff_checker_statistics.check_list_of_dicts(
139
+ sort_by_keys=['cmdline', 'name'], print_kwargs=print_kwargs)
140
+
141
+ if result:
142
+ if 'count' in result:
143
+ message = f"[Alert] DNS Request: {result['entry']} | Times hit: {result['count']}"
144
+ print_api(message, color='yellow', **(print_kwargs or {}))
145
+
146
+ return_list.append(message)
@@ -0,0 +1,77 @@
1
+ from pathlib import Path
2
+
3
+ from ... import filesystem, hashing
4
+ from ... import diff_check
5
+ from ...print_api import print_api
6
+
7
+
8
+ class FileCheck:
9
+ """
10
+ Class for file monitoring.
11
+ """
12
+ def __init__(self, change_monitor_instance):
13
+ self.diff_checker = None
14
+ self.change_monitor_instance = None
15
+ self.store_original_file_path = None
16
+
17
+ if not change_monitor_instance.input_file_name:
18
+ change_monitor_instance.input_file_name = Path(change_monitor_instance.check_object).name
19
+ change_monitor_instance.input_file_name = change_monitor_instance.input_file_name.lower()
20
+ change_monitor_instance.input_file_name = (
21
+ change_monitor_instance.input_file_name.replace(' ', '_').replace('.', '_'))
22
+ change_monitor_instance.input_file_name = f'{change_monitor_instance.input_file_name}.txt'
23
+
24
+ input_file_path = (
25
+ str(Path(change_monitor_instance.input_directory, change_monitor_instance.input_file_name)))
26
+
27
+ # If 'store_original_object' is True, create filename for the store original object.
28
+ if change_monitor_instance.object_type_settings['store_original_object']:
29
+ store_original_file_name: str = f'ORIGINAL_{Path(change_monitor_instance.check_object).name}'
30
+ self.store_original_file_path = str(Path(change_monitor_instance.input_directory, store_original_file_name))
31
+
32
+ self.diff_checker = diff_check.DiffChecker(
33
+ return_first_cycle=False,
34
+ operation_type='single_object',
35
+ input_file_path=input_file_path,
36
+ check_object_display_name=f'{change_monitor_instance.input_file_name}|{change_monitor_instance.object_type}'
37
+ )
38
+ self.diff_checker.initiate_before_action()
39
+ self.change_monitor_instance = change_monitor_instance
40
+
41
+ def execute_cycle(self, print_kwargs: dict = None):
42
+ """
43
+ This function executes the cycle of the change monitor: hash.
44
+
45
+ :param print_kwargs: print_api kwargs.
46
+ :return: List of dictionaries with the results of the cycle.
47
+ """
48
+
49
+ return_list = list()
50
+
51
+ self._get_hash()
52
+
53
+ # Check if the object was updated.
54
+ result, message = self.diff_checker.check_string(
55
+ print_kwargs=print_kwargs)
56
+
57
+ # If the object was updated, print the message in yellow color, otherwise print in green color.
58
+ if result:
59
+ print_api(message, color='yellow', **print_kwargs)
60
+ # create_message_file(message, self.__class__.__name__, logger=self.logger)
61
+
62
+ return_list.append(message)
63
+ else:
64
+ print_api(message, color='green', **print_kwargs)
65
+
66
+ return return_list
67
+
68
+ def _get_hash(self):
69
+ # Copy the file to the original object directory.
70
+ if self.store_original_file_path:
71
+ filesystem.copy_file(self.change_monitor_instance.check_object, self.store_original_file_path)
72
+
73
+ # Get hash of the file.
74
+ hash_string = hashing.hash_file(self.change_monitor_instance.check_object)
75
+
76
+ # Set the hash string to the 'check_object' variable.
77
+ self.diff_checker.check_object = hash_string