atomicshop 2.14.2__py3-none-any.whl → 2.14.4__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.
Potentially problematic release.
This version of atomicshop might be problematic. Click here for more details.
- atomicshop/__init__.py +1 -1
- atomicshop/datetimes.py +3 -2
- atomicshop/etws/providers.py +18 -2
- atomicshop/etws/sessions.py +1 -1
- atomicshop/etws/trace.py +5 -22
- atomicshop/etws/traces/trace_dns.py +17 -14
- atomicshop/etws/traces/trace_sysmon_process_creation.py +34 -22
- atomicshop/file_io/csvs.py +1 -1
- atomicshop/get_process_list.py +133 -0
- atomicshop/mitm/statistic_analyzer.py +376 -3
- atomicshop/monitor/change_monitor.py +1 -0
- atomicshop/monitor/checks/dns.py +2 -1
- atomicshop/process.py +3 -3
- atomicshop/process_poller/__init__.py +0 -0
- atomicshop/process_poller/pollers/__init__.py +0 -0
- atomicshop/process_poller/pollers/psutil_pywin32wmi_dll.py +95 -0
- atomicshop/process_poller/process_pool.py +208 -0
- atomicshop/process_poller/simple_process_pool.py +112 -0
- atomicshop/process_poller/tracer_base.py +45 -0
- atomicshop/process_poller/tracers/__init__.py +0 -0
- atomicshop/process_poller/tracers/event_log.py +46 -0
- atomicshop/process_poller/tracers/sysmon_etw.py +68 -0
- atomicshop/wrappers/ctyping/etw_winapi/const.py +130 -20
- atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py +141 -5
- atomicshop/wrappers/loggingw/reading.py +20 -19
- atomicshop/wrappers/pywin32w/win_event_log/subscribe.py +0 -2
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +3 -24
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +103 -0
- {atomicshop-2.14.2.dist-info → atomicshop-2.14.4.dist-info}/METADATA +1 -1
- {atomicshop-2.14.2.dist-info → atomicshop-2.14.4.dist-info}/RECORD +34 -24
- atomicshop/process_poller.py +0 -345
- /atomicshop/{process_name_cmd.py → get_process_name_cmd_dll.py} +0 -0
- {atomicshop-2.14.2.dist-info → atomicshop-2.14.4.dist-info}/LICENSE.txt +0 -0
- {atomicshop-2.14.2.dist-info → atomicshop-2.14.4.dist-info}/WHEEL +0 -0
- {atomicshop-2.14.2.dist-info → atomicshop-2.14.4.dist-info}/top_level.txt +0 -0
atomicshop/__init__.py
CHANGED
atomicshop/datetimes.py
CHANGED
|
@@ -47,7 +47,7 @@ class MonthToNumber:
|
|
|
47
47
|
'דצמבר': '12'}
|
|
48
48
|
|
|
49
49
|
|
|
50
|
-
def get_datetime_from_complex_string_by_pattern(complex_string: str, date_pattern: str):
|
|
50
|
+
def get_datetime_from_complex_string_by_pattern(complex_string: str, date_pattern: str) -> tuple[datetime, str, float]:
|
|
51
51
|
"""
|
|
52
52
|
Function will get datetime object from a complex string by pattern.
|
|
53
53
|
|
|
@@ -65,7 +65,8 @@ def get_datetime_from_complex_string_by_pattern(complex_string: str, date_patter
|
|
|
65
65
|
if date_str:
|
|
66
66
|
# Convert the date string to a datetime object based on the given pattern
|
|
67
67
|
date_obj = datetime.datetime.strptime(date_str.group(), date_pattern)
|
|
68
|
-
|
|
68
|
+
date_timestamp = date_obj.timestamp()
|
|
69
|
+
return date_obj, date_str.group(), date_timestamp
|
|
69
70
|
else:
|
|
70
71
|
raise ValueError("No valid date found in the string")
|
|
71
72
|
|
atomicshop/etws/providers.py
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
1
3
|
from ..wrappers.ctyping.etw_winapi import etw_functions
|
|
2
4
|
|
|
3
5
|
|
|
4
|
-
def get_providers():
|
|
5
|
-
return etw_functions.get_all_providers()
|
|
6
|
+
def get_providers(key_as: Literal['name', 'guid'] = 'name'):
|
|
7
|
+
return etw_functions.get_all_providers(key_as=key_as)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_provider_guid_by_name(provider_name):
|
|
11
|
+
providers = get_providers(key_as='name')
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
provider_guid = providers[provider_name]
|
|
15
|
+
except KeyError:
|
|
16
|
+
provider_guid = None
|
|
17
|
+
|
|
18
|
+
if not provider_guid:
|
|
19
|
+
raise ValueError(f"Provider '{provider_name}' not found")
|
|
20
|
+
|
|
21
|
+
return provider_guid
|
atomicshop/etws/sessions.py
CHANGED
atomicshop/etws/trace.py
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
import queue
|
|
2
2
|
import sys
|
|
3
3
|
import time
|
|
4
|
-
from typing import Literal
|
|
5
4
|
|
|
6
5
|
# Import FireEye Event Tracing library.
|
|
7
6
|
import etw
|
|
8
7
|
|
|
9
8
|
from ..print_api import print_api
|
|
10
9
|
from . import sessions
|
|
11
|
-
from .. import
|
|
10
|
+
from ..process_poller import simple_process_pool
|
|
12
11
|
from ..wrappers.psutilw import psutilw
|
|
13
12
|
|
|
14
13
|
|
|
15
|
-
PROCESS_POLLER_ETW_DEFAULT_SESSION_NAME: str = 'AtomicShopProcessTrace'
|
|
16
|
-
|
|
17
14
|
WAIT_FOR_PROCESS_POLLER_PID_SECONDS: int = 3
|
|
18
15
|
WAIT_FOR_PROCESS_POLLER_PID_COUNTS: int = WAIT_FOR_PROCESS_POLLER_PID_SECONDS * 10
|
|
19
16
|
|
|
@@ -26,8 +23,7 @@ class EventTrace(etw.ETW):
|
|
|
26
23
|
event_id_filters: list = None,
|
|
27
24
|
session_name: str = None,
|
|
28
25
|
close_existing_session_name: bool = True,
|
|
29
|
-
enable_process_poller: bool = False
|
|
30
|
-
process_poller_method: Literal['psutil', 'pywin32', 'process_dll', 'sysmon_etw', 'event_log'] = 'event_log'
|
|
26
|
+
enable_process_poller: bool = False
|
|
31
27
|
):
|
|
32
28
|
"""
|
|
33
29
|
:param providers: List of tuples with provider name and provider GUID.
|
|
@@ -41,13 +37,6 @@ class EventTrace(etw.ETW):
|
|
|
41
37
|
:param enable_process_poller: Boolean to enable process poller. Gets the process PID, Name and CommandLine.
|
|
42
38
|
Since the DNS events doesn't contain the process name and command line, only PID.
|
|
43
39
|
Then DNS events will be enriched with the process name and command line from the process poller.
|
|
44
|
-
:param process_poller_method: The method to get the process information. For more information, see the
|
|
45
|
-
'process_poller.ProcessPollerPool' class. Summary:
|
|
46
|
-
'psutil': Uses 'psutil' library to get the process information.
|
|
47
|
-
'pywin32': Uses 'pywin32' library to get the process information.
|
|
48
|
-
'process_dll': Uses 'process' custom DLL to get the process information.
|
|
49
|
-
'sysmon_etw': Uses 'sysmon_etw' uses sysmon and ETW to get the process information.
|
|
50
|
-
'event_log': Uses Security Windows EVent Log channel (event id 4688) to get the process information.
|
|
51
40
|
|
|
52
41
|
------------------------------------------
|
|
53
42
|
|
|
@@ -84,14 +73,8 @@ class EventTrace(etw.ETW):
|
|
|
84
73
|
for provider in providers:
|
|
85
74
|
etw_format_providers.append(etw.ProviderInfo(provider[0], etw.GUID(provider[1])))
|
|
86
75
|
|
|
87
|
-
process_poller_etw_session_name = None
|
|
88
|
-
if process_poller_method == 'sysmon_etw':
|
|
89
|
-
process_poller_etw_session_name = PROCESS_POLLER_ETW_DEFAULT_SESSION_NAME
|
|
90
|
-
|
|
91
76
|
if self.enable_process_poller:
|
|
92
|
-
self.process_poller =
|
|
93
|
-
operation='process', poller_method=process_poller_method,
|
|
94
|
-
sysmon_etw_session_name=process_poller_etw_session_name)
|
|
77
|
+
self.process_poller = simple_process_pool.SimpleProcessPool()
|
|
95
78
|
|
|
96
79
|
super().__init__(
|
|
97
80
|
providers=etw_format_providers, event_callback=function_callable, event_id_filters=event_id_filters,
|
|
@@ -152,8 +135,8 @@ class EventTrace(etw.ETW):
|
|
|
152
135
|
event: tuple = self.event_queue.get()
|
|
153
136
|
|
|
154
137
|
event_dict: dict = {
|
|
155
|
-
'
|
|
156
|
-
'
|
|
138
|
+
'EventId': event[0],
|
|
139
|
+
'EventHeader': event[1],
|
|
157
140
|
'pid': event[1]['EventHeader']['ProcessId']
|
|
158
141
|
}
|
|
159
142
|
|
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import time
|
|
2
|
-
|
|
3
1
|
from .. import trace, const
|
|
4
|
-
from ...wrappers.psutilw import psutilw
|
|
5
2
|
from ...basics import dicts
|
|
6
|
-
from ...process_poller import ProcessPollerPool
|
|
7
|
-
from ...print_api import print_api
|
|
8
3
|
from ... import dns
|
|
9
4
|
|
|
10
5
|
|
|
@@ -24,7 +19,8 @@ class DnsRequestResponseTrace:
|
|
|
24
19
|
self,
|
|
25
20
|
attrs: list = None,
|
|
26
21
|
session_name: str = None,
|
|
27
|
-
close_existing_session_name: bool = True
|
|
22
|
+
close_existing_session_name: bool = True,
|
|
23
|
+
skip_record_list: list = None
|
|
28
24
|
):
|
|
29
25
|
"""
|
|
30
26
|
:param attrs: List of attributes to return. If None, all attributes will be returned.
|
|
@@ -35,6 +31,7 @@ class DnsRequestResponseTrace:
|
|
|
35
31
|
False: if ETW session with 'session_name' exists, you will be notified and the new session will not be
|
|
36
32
|
created. Instead, the existing session will be used. If there is a buffer from the previous session,
|
|
37
33
|
you will get the events from the buffer.
|
|
34
|
+
:param skip_record_list: List of DNS Records to skip emitting. Example: ['PTR', 'SRV']
|
|
38
35
|
|
|
39
36
|
-------------------------------------------------
|
|
40
37
|
|
|
@@ -56,6 +53,7 @@ class DnsRequestResponseTrace:
|
|
|
56
53
|
"""
|
|
57
54
|
|
|
58
55
|
self.attrs = attrs
|
|
56
|
+
self.skip_record_list = skip_record_list
|
|
59
57
|
|
|
60
58
|
if not session_name:
|
|
61
59
|
session_name = ETW_DEFAULT_SESSION_NAME
|
|
@@ -91,23 +89,28 @@ class DnsRequestResponseTrace:
|
|
|
91
89
|
event = self.event_trace.emit()
|
|
92
90
|
|
|
93
91
|
event_dict: dict = {
|
|
94
|
-
'event_id': event['
|
|
95
|
-
'domain': event['
|
|
96
|
-
'query_type_id': str(event['
|
|
97
|
-
'query_type': dns.TYPES_DICT[str(event['
|
|
92
|
+
'event_id': event['EventId'],
|
|
93
|
+
'domain': event['EventHeader']['QueryName'],
|
|
94
|
+
'query_type_id': str(event['EventHeader']['QueryType']),
|
|
95
|
+
'query_type': dns.TYPES_DICT[str(event['EventHeader']['QueryType'])],
|
|
98
96
|
'pid': event['pid'],
|
|
99
97
|
'name': event['name'],
|
|
100
98
|
'cmdline': event['cmdline']
|
|
101
99
|
}
|
|
102
100
|
|
|
101
|
+
# Skip emitting the record if it is in the 'skip_record_list'.
|
|
102
|
+
# Just recall the function to get the next event and return it.
|
|
103
|
+
if event_dict['query_type'] in self.skip_record_list:
|
|
104
|
+
return self.emit()
|
|
105
|
+
|
|
103
106
|
# Defining list if ips and other answers, which aren't IPs.
|
|
104
107
|
list_of_ips = list()
|
|
105
108
|
list_of_other_domains = list()
|
|
106
109
|
# Parse DNS results, only if 'QueryResults' key isn't empty, since many of the events are, mostly due errors.
|
|
107
|
-
if event['
|
|
110
|
+
if event['EventHeader']['QueryResults']:
|
|
108
111
|
# 'QueryResults' key contains a string with all the 'Answers' divided by type and ';' character.
|
|
109
112
|
# Basically, we can parse each type out of string, but we need only IPs and other answers.
|
|
110
|
-
list_of_parameters = event['
|
|
113
|
+
list_of_parameters = event['EventHeader']['QueryResults'].split(';')
|
|
111
114
|
|
|
112
115
|
# Iterating through all the parameters that we got from 'QueryResults' key.
|
|
113
116
|
for parameter in list_of_parameters:
|
|
@@ -127,11 +130,11 @@ class DnsRequestResponseTrace:
|
|
|
127
130
|
event_dict['other_domains'] = list_of_other_domains
|
|
128
131
|
|
|
129
132
|
# Getting the 'QueryStatus' key.
|
|
130
|
-
event_dict['status_id'] = event['
|
|
133
|
+
event_dict['status_id'] = event['EventHeader']['QueryStatus']
|
|
131
134
|
|
|
132
135
|
# Getting the 'QueryStatus' key. If DNS Query Status is '0' then it was executed successfully.
|
|
133
136
|
# And if not, it means there was an error. The 'QueryStatus' indicate what number of an error it is.
|
|
134
|
-
if event['
|
|
137
|
+
if event['EventHeader']['QueryStatus'] == '0':
|
|
135
138
|
event_dict['status'] = 'Success'
|
|
136
139
|
else:
|
|
137
140
|
event_dict['status'] = 'Error'
|
|
@@ -3,6 +3,8 @@ from ...wrappers import sysmonw
|
|
|
3
3
|
from ...basics import dicts
|
|
4
4
|
|
|
5
5
|
|
|
6
|
+
DEFAULT_SESSION_NAME: str = 'AtomicShopSysmonProcessCreationTrace'
|
|
7
|
+
|
|
6
8
|
PROVIDER_NAME: str = const.ETW_SYSMON['provider_name']
|
|
7
9
|
PROVIDER_GUID: str = const.ETW_SYSMON['provider_guid']
|
|
8
10
|
PROCESS_CREATION_EVENT_ID: int = const.ETW_SYSMON['event_ids']['process_create']
|
|
@@ -53,6 +55,9 @@ class SysmonProcessCreationTrace:
|
|
|
53
55
|
self.attrs = attrs
|
|
54
56
|
self.sysmon_directory: str = sysmon_directory
|
|
55
57
|
|
|
58
|
+
if not session_name:
|
|
59
|
+
session_name = DEFAULT_SESSION_NAME
|
|
60
|
+
|
|
56
61
|
self.event_trace = trace.EventTrace(
|
|
57
62
|
providers=[(PROVIDER_NAME, PROVIDER_GUID)],
|
|
58
63
|
# lambda x: self.event_queue.put(x),
|
|
@@ -80,32 +85,39 @@ class SysmonProcessCreationTrace:
|
|
|
80
85
|
print(dns_dict)
|
|
81
86
|
|
|
82
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
|
+
|
|
83
115
|
"""
|
|
84
116
|
|
|
85
117
|
event = self.event_trace.emit()
|
|
86
118
|
|
|
87
|
-
event_dict
|
|
88
|
-
|
|
89
|
-
'pid': event['event']['ProcessId'],
|
|
90
|
-
'process_guid': event['event']['ProcessGuid'],
|
|
91
|
-
'image': event['event']['Image'],
|
|
92
|
-
'file_version': event['event']['FileVersion'],
|
|
93
|
-
'product': event['event']['Product'],
|
|
94
|
-
'company': event['event']['Company'],
|
|
95
|
-
'original_file_name': event['event']['OriginalFileName'],
|
|
96
|
-
'command_line': event['event']['CommandLine'],
|
|
97
|
-
'current_directory': event['event']['CurrentDirectory'],
|
|
98
|
-
'user': event['event']['User'],
|
|
99
|
-
'logon_id': event['event']['LogonId'],
|
|
100
|
-
'logon_guid': event['event']['LogonGuid'],
|
|
101
|
-
'terminal_session_id': event['event']['TerminalSessionId'],
|
|
102
|
-
'integrity_level': event['event']['IntegrityLevel'],
|
|
103
|
-
'hashes': event['event']['Hashes'],
|
|
104
|
-
'parent_process_guid': event['event']['ParentProcessGuid'],
|
|
105
|
-
'parent_process_id': event['event']['ParentProcessId'],
|
|
106
|
-
'parent_image': event['event']['ParentImage'],
|
|
107
|
-
'parent_command_line': event['event']['ParentCommandLine']
|
|
108
|
-
}
|
|
119
|
+
event_dict = {'EventId': event['EventId']}
|
|
120
|
+
event_dict.update(event['EventHeader'])
|
|
109
121
|
|
|
110
122
|
if self.attrs:
|
|
111
123
|
event_dict = dicts.reorder_keys(
|
atomicshop/file_io/csvs.py
CHANGED
|
@@ -36,7 +36,7 @@ def read_csv_to_list_of_dicts_by_header(
|
|
|
36
36
|
All the lines of the CSV file will be considered as content.
|
|
37
37
|
:param file_object: file object of the 'open()' function in the decorator. Decorator executes the 'with open()'
|
|
38
38
|
statement and passes to this function. That's why the default is 'None', since we get it from the decorator.
|
|
39
|
-
:return: list.
|
|
39
|
+
:return: tuple(list of entries, header(list of cell names)).
|
|
40
40
|
"""
|
|
41
41
|
|
|
42
42
|
# The header fields will be separated to list of "csv_reader.fieldnames".
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
from typing import Union, Literal
|
|
2
|
+
|
|
3
|
+
from .wrappers.pywin32w import wmi_win32process
|
|
4
|
+
from .wrappers.psutilw import psutilw
|
|
5
|
+
from .basics import dicts
|
|
6
|
+
from . import get_process_name_cmd_dll
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class GetProcessList:
|
|
10
|
+
"""
|
|
11
|
+
The class is responsible for getting the list of running processes.
|
|
12
|
+
|
|
13
|
+
Example of one time polling with 'pywin32' method:
|
|
14
|
+
from atomicshop import process_poller
|
|
15
|
+
process_list: dict = \
|
|
16
|
+
process_poller.GetProcessList(get_method='pywin32', connect_on_init=True).get_processes(as_dict=True)
|
|
17
|
+
"""
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
get_method: Literal['psutil', 'pywin32', 'process_dll'] = 'process_dll',
|
|
21
|
+
connect_on_init: bool = False
|
|
22
|
+
):
|
|
23
|
+
"""
|
|
24
|
+
:param get_method: str, The method to get the list of processes. Default is 'process_list_dll'.
|
|
25
|
+
'psutil': Get the list of processes by 'psutil' library. Resource intensive and slow.
|
|
26
|
+
'pywin32': Get the list of processes by 'pywin32' library, using WMI. Not resource intensive, but slow.
|
|
27
|
+
'process_dll'. Not resource intensive and fast. Probably works only in Windows 10 x64.
|
|
28
|
+
:param connect_on_init: bool, if True, will connect to the service on init. 'psutil' don't need to connect.
|
|
29
|
+
"""
|
|
30
|
+
self.get_method = get_method
|
|
31
|
+
self.process_polling_instance = None
|
|
32
|
+
|
|
33
|
+
self.connected = False
|
|
34
|
+
|
|
35
|
+
if self.get_method == 'psutil':
|
|
36
|
+
self.process_polling_instance = psutilw.PsutilProcesses()
|
|
37
|
+
self.connected = True
|
|
38
|
+
elif self.get_method == 'pywin32':
|
|
39
|
+
self.process_polling_instance = wmi_win32process.Pywin32Processes()
|
|
40
|
+
elif self.get_method == 'process_dll':
|
|
41
|
+
self.process_polling_instance = get_process_name_cmd_dll.ProcessNameCmdline()
|
|
42
|
+
|
|
43
|
+
if connect_on_init:
|
|
44
|
+
self.connect()
|
|
45
|
+
|
|
46
|
+
def connect(self):
|
|
47
|
+
"""
|
|
48
|
+
Connect to the service. 'psutil' don't need to connect.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
# If poller method is none of the allowed methods.
|
|
52
|
+
if self.get_method not in ['psutil', 'pywin32', 'process_dll']:
|
|
53
|
+
raise ValueError(f"Method '{self.get_method}' is not allowed.")
|
|
54
|
+
|
|
55
|
+
# If the service is not connected yet. Since 'psutil' don't need to connect.
|
|
56
|
+
if not self.connected:
|
|
57
|
+
if self.get_method == 'pywin32':
|
|
58
|
+
self.process_polling_instance.connect()
|
|
59
|
+
self.connected = True
|
|
60
|
+
elif self.get_method == 'process_dll':
|
|
61
|
+
self.process_polling_instance.load()
|
|
62
|
+
self.connected = True
|
|
63
|
+
|
|
64
|
+
def get_processes(self, as_dict: bool = True) -> Union[list, dict]:
|
|
65
|
+
"""
|
|
66
|
+
The function will get the list of opened processes and return it as a list of dicts.
|
|
67
|
+
|
|
68
|
+
:return: dict while key is pid or list of dicts, of opened processes (depending on 'as_dict' setting).
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
if as_dict:
|
|
72
|
+
if self.get_method == 'psutil':
|
|
73
|
+
return self.process_polling_instance.get_processes_as_dict(
|
|
74
|
+
attrs=['pid', 'name', 'cmdline'], cmdline_to_string=True)
|
|
75
|
+
elif self.get_method == 'pywin32':
|
|
76
|
+
processes = self.process_polling_instance.get_processes_as_dict(
|
|
77
|
+
attrs=['ProcessId', 'Name', 'CommandLine'])
|
|
78
|
+
|
|
79
|
+
# Convert the keys from WMI to the keys that are used in 'psutil'.
|
|
80
|
+
converted_process_dict = dict()
|
|
81
|
+
for pid, process_info in processes.items():
|
|
82
|
+
converted_process_dict[pid] = dicts.convert_key_names(
|
|
83
|
+
process_info, {'Name': 'name', 'CommandLine': 'cmdline'})
|
|
84
|
+
|
|
85
|
+
return converted_process_dict
|
|
86
|
+
elif self.get_method == 'process_dll':
|
|
87
|
+
return self.process_polling_instance.get_process_details(as_dict=True)
|
|
88
|
+
else:
|
|
89
|
+
if self.get_method == 'psutil':
|
|
90
|
+
return self.process_polling_instance.get_processes_as_list_of_dicts(
|
|
91
|
+
attrs=['pid', 'name', 'cmdline'], cmdline_to_string=True)
|
|
92
|
+
elif self.get_method == 'pywin32':
|
|
93
|
+
processes = self.process_polling_instance.get_processes_as_list_of_dicts(
|
|
94
|
+
attrs=['ProcessId', 'Name', 'CommandLine'])
|
|
95
|
+
|
|
96
|
+
# Convert the keys from WMI to the keys that are used in 'psutil'.
|
|
97
|
+
for process_index, process_info in enumerate(processes):
|
|
98
|
+
processes[process_index] = dicts.convert_key_names(
|
|
99
|
+
process_info, {'ProcessId': 'pid', 'Name': 'name', 'CommandLine': 'cmdline'})
|
|
100
|
+
|
|
101
|
+
return processes
|
|
102
|
+
elif self.get_method == 'process_dll':
|
|
103
|
+
return self.process_polling_instance.get_process_details(as_dict=as_dict)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def get_process_time_tester(
|
|
107
|
+
get_method: Literal['psutil', 'pywin32', 'process_dll'] = 'process_dll',
|
|
108
|
+
times_to_test: int = 50
|
|
109
|
+
):
|
|
110
|
+
"""
|
|
111
|
+
The function will test the time it takes to get the list of processes with different methods and cycles.
|
|
112
|
+
|
|
113
|
+
:param get_method: str, The method to get the list of processes. Default is 'process_list_dll'.
|
|
114
|
+
'psutil': Get the list of processes by 'psutil' library. Resource intensive and slow.
|
|
115
|
+
'pywin32': Get the list of processes by 'pywin32' library, using WMI. Not resource intensive, but slow.
|
|
116
|
+
'process_dll'. Not resource intensive and fast. Probably works only in Windows 10 x64
|
|
117
|
+
:param times_to_test: int, how many times to test the function.
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
import timeit
|
|
121
|
+
|
|
122
|
+
setup_code = '''
|
|
123
|
+
from atomicshop import process_poller
|
|
124
|
+
get_process_list = process_poller.GetProcessList(get_method=get_method, connect_on_init=True)
|
|
125
|
+
'''
|
|
126
|
+
|
|
127
|
+
test_code = '''
|
|
128
|
+
test = get_process_list.get_processes()
|
|
129
|
+
'''
|
|
130
|
+
|
|
131
|
+
# globals need to be specified, otherwise the setup_code won't work with passed variables.
|
|
132
|
+
times = timeit.timeit(setup=setup_code, stmt=test_code, number=times_to_test, globals=locals())
|
|
133
|
+
print(f'Execution time: {times}')
|