atomicshop 2.19.10__py3-none-any.whl → 2.19.11__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/a_installs/win/robocorp.py +3 -0
- atomicshop/etws/trace.py +10 -22
- atomicshop/etws/traces/trace_dns.py +1 -1
- atomicshop/etws/traces/trace_tcp.py +130 -0
- atomicshop/process_poller/simple_process_pool.py +41 -5
- {atomicshop-2.19.10.dist-info → atomicshop-2.19.11.dist-info}/METADATA +1 -1
- {atomicshop-2.19.10.dist-info → atomicshop-2.19.11.dist-info}/RECORD +11 -10
- {atomicshop-2.19.10.dist-info → atomicshop-2.19.11.dist-info}/LICENSE.txt +0 -0
- {atomicshop-2.19.10.dist-info → atomicshop-2.19.11.dist-info}/WHEEL +0 -0
- {atomicshop-2.19.10.dist-info → atomicshop-2.19.11.dist-info}/top_level.txt +0 -0
atomicshop/__init__.py
CHANGED
|
@@ -41,6 +41,9 @@ def main():
|
|
|
41
41
|
print_api("Initializing Robocorp Browser.")
|
|
42
42
|
subprocess.check_call(["rfbrowser", "init"])
|
|
43
43
|
|
|
44
|
+
print_api("Installing Additional modules.")
|
|
45
|
+
subprocess.check_call(["pip", "install", "--upgrade", "matplotlib", "imagehash"])
|
|
46
|
+
|
|
44
47
|
print_api("Installing Tesseract OCR.")
|
|
45
48
|
github_wrapper = githubw.GitHubWrapper(
|
|
46
49
|
user_name="tesseract-ocr",
|
atomicshop/etws/trace.py
CHANGED
|
@@ -83,7 +83,7 @@ class EventTrace(etw.ETW):
|
|
|
83
83
|
|
|
84
84
|
self.self_hosted_poller: bool = False
|
|
85
85
|
if self.enable_process_poller:
|
|
86
|
-
if
|
|
86
|
+
if self.process_pool_shared_dict_proxy is None:
|
|
87
87
|
self.self_hosted_poller = True
|
|
88
88
|
self.process_poller = simple_process_pool.SimpleProcessPool()
|
|
89
89
|
self.multiprocessing_manager: multiprocessing.managers.SyncManager = multiprocessing.Manager()
|
|
@@ -98,7 +98,7 @@ class EventTrace(etw.ETW):
|
|
|
98
98
|
)
|
|
99
99
|
|
|
100
100
|
def start(self):
|
|
101
|
-
if self.enable_process_poller:
|
|
101
|
+
if self.enable_process_poller and self.self_hosted_poller:
|
|
102
102
|
self.process_poller.start()
|
|
103
103
|
|
|
104
104
|
# Check if the session name already exists.
|
|
@@ -123,11 +123,10 @@ class EventTrace(etw.ETW):
|
|
|
123
123
|
def stop(self):
|
|
124
124
|
super().stop()
|
|
125
125
|
|
|
126
|
-
if self.
|
|
126
|
+
if self.self_hosted_poller:
|
|
127
127
|
self.process_poller.stop()
|
|
128
128
|
|
|
129
|
-
|
|
130
|
-
self.multiprocessing_manager.shutdown()
|
|
129
|
+
self.multiprocessing_manager.shutdown()
|
|
131
130
|
|
|
132
131
|
def emit(self):
|
|
133
132
|
"""
|
|
@@ -146,32 +145,21 @@ class EventTrace(etw.ETW):
|
|
|
146
145
|
:return: etw event object.
|
|
147
146
|
"""
|
|
148
147
|
|
|
149
|
-
# Get the processes first, since we need the process name and command line.
|
|
150
|
-
# If they're not ready, we will get just pids from DNS tracing.
|
|
151
|
-
if self.enable_process_poller:
|
|
152
|
-
self._get_processes_from_poller()
|
|
153
|
-
|
|
154
148
|
event: tuple = self.event_queue.get()
|
|
155
149
|
|
|
156
150
|
event_dict: dict = {
|
|
157
151
|
'EventId': event[0],
|
|
158
|
-
'EventHeader': event[1]
|
|
159
|
-
'pid': event[1]['EventHeader']['ProcessId']
|
|
152
|
+
'EventHeader': event[1]
|
|
160
153
|
}
|
|
161
154
|
|
|
155
|
+
if 'ProcessId' not in event[1]:
|
|
156
|
+
event_dict['pid'] = event[1]['EventHeader']['ProcessId']
|
|
157
|
+
else:
|
|
158
|
+
event_dict['pid'] = event[1]['ProcessId']
|
|
159
|
+
|
|
162
160
|
if self.enable_process_poller:
|
|
163
161
|
process_info: dict = self.pid_process_converter.get_process_by_pid(event_dict['pid'])
|
|
164
162
|
event_dict['name'] = process_info['name']
|
|
165
163
|
event_dict['cmdline'] = process_info['cmdline']
|
|
166
164
|
|
|
167
165
|
return event_dict
|
|
168
|
-
|
|
169
|
-
def _get_processes_from_poller(self):
|
|
170
|
-
processes: dict = {}
|
|
171
|
-
while not processes:
|
|
172
|
-
processes = self.process_poller.get_processes()
|
|
173
|
-
|
|
174
|
-
if isinstance(processes, BaseException):
|
|
175
|
-
raise processes
|
|
176
|
-
|
|
177
|
-
return processes
|
|
@@ -47,7 +47,7 @@ class DnsRequestResponseTrace:
|
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
dns_trace_w = dns_trace.DnsTrace(
|
|
50
|
-
attrs=['pid', 'name', 'cmdline', '
|
|
50
|
+
attrs=['pid', 'name', 'cmdline', 'query', 'query_type'],
|
|
51
51
|
session_name='MyDnsTrace',
|
|
52
52
|
close_existing_session_name=True,
|
|
53
53
|
enable_process_poller=True
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import multiprocessing.managers
|
|
2
|
+
|
|
3
|
+
from .. import trace, const, providers
|
|
4
|
+
from ...basics import dicts
|
|
5
|
+
from ... import dns, ip_addresses
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
ETW_DEFAULT_SESSION_NAME: str = 'AtomicShopTcpTrace'
|
|
9
|
+
|
|
10
|
+
PROVIDER_NAME: str = "Microsoft-Windows-TCPIP"
|
|
11
|
+
PROVIDER_GUID: str = '{' + providers.get_provider_guid_by_name(PROVIDER_NAME) + '}'
|
|
12
|
+
REQUEST_RESP_EVENT_ID: int = 1033
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TcpIpNewConnectionsTrace:
|
|
16
|
+
"""
|
|
17
|
+
TcpIpNewConnectionsTrace class use to trace new connection events from Windows Event Tracing:
|
|
18
|
+
Provider: Microsoft-Windows-TCPIP
|
|
19
|
+
EventId: 1033
|
|
20
|
+
"""
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
attrs: list = None,
|
|
24
|
+
session_name: str = None,
|
|
25
|
+
close_existing_session_name: bool = True,
|
|
26
|
+
process_pool_shared_dict_proxy: multiprocessing.managers.DictProxy = None
|
|
27
|
+
):
|
|
28
|
+
"""
|
|
29
|
+
:param attrs: List of attributes to return. If None, all attributes will be returned.
|
|
30
|
+
:param session_name: The name of the session to create. If not provided, a UUID will be generated.
|
|
31
|
+
:param close_existing_session_name: Boolean to close existing session names.
|
|
32
|
+
True: if ETW session with 'session_name' exists, you will be notified and the session will be closed.
|
|
33
|
+
Then the new session with this name will be created.
|
|
34
|
+
False: if ETW session with 'session_name' exists, you will be notified and the new session will not be
|
|
35
|
+
created. Instead, the existing session will be used. If there is a buffer from the previous session,
|
|
36
|
+
you will get the events from the buffer.
|
|
37
|
+
:param process_pool_shared_dict_proxy: multiprocessing.managers.DictProxy, multiprocessing shared dict proxy
|
|
38
|
+
that contains current processes.
|
|
39
|
+
Check the 'atomicshop\process_poller\simple_process_pool.py' SimpleProcessPool class for more information.
|
|
40
|
+
|
|
41
|
+
For this specific class it means that you can run the process poller outside of this class and pass the
|
|
42
|
+
'process_pool_shared_dict_proxy' to this class. Then you can get the process name and command line for
|
|
43
|
+
the DNS events from the 'process_pool_shared_dict_proxy' and use it also in other classes.
|
|
44
|
+
|
|
45
|
+
-------------------------------------------------
|
|
46
|
+
|
|
47
|
+
Usage Example:
|
|
48
|
+
from atomicshop.etw import tcp_trace
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
tcp_trace_w = tcp_trace.TcpIpNewConnectionsTrace(
|
|
52
|
+
attrs=['pid', 'name', 'cmdline', 'domain', 'query_type'],
|
|
53
|
+
session_name='MyTcpTrace',
|
|
54
|
+
close_existing_session_name=True,
|
|
55
|
+
enable_process_poller=True
|
|
56
|
+
)
|
|
57
|
+
tcp_trace_w.start()
|
|
58
|
+
while True:
|
|
59
|
+
tcp_dict = tcp_trace_w.emit()
|
|
60
|
+
print(tcp_dict)
|
|
61
|
+
tcp_trace_w.stop()
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
self.attrs = attrs
|
|
65
|
+
self.process_pool_shared_dict_proxy: multiprocessing.managers.DictProxy = process_pool_shared_dict_proxy
|
|
66
|
+
|
|
67
|
+
if not session_name:
|
|
68
|
+
session_name = ETW_DEFAULT_SESSION_NAME
|
|
69
|
+
|
|
70
|
+
self.event_trace = trace.EventTrace(
|
|
71
|
+
providers=[(PROVIDER_NAME, PROVIDER_GUID)],
|
|
72
|
+
# lambda x: self.event_queue.put(x),
|
|
73
|
+
event_id_filters=[REQUEST_RESP_EVENT_ID],
|
|
74
|
+
session_name=session_name,
|
|
75
|
+
close_existing_session_name=close_existing_session_name,
|
|
76
|
+
enable_process_poller=True,
|
|
77
|
+
process_pool_shared_dict_proxy=self.process_pool_shared_dict_proxy
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
def start(self):
|
|
81
|
+
self.event_trace.start()
|
|
82
|
+
|
|
83
|
+
def stop(self):
|
|
84
|
+
self.event_trace.stop()
|
|
85
|
+
|
|
86
|
+
def emit(self):
|
|
87
|
+
"""
|
|
88
|
+
Function that will return the next event from the queue.
|
|
89
|
+
The queue is blocking, so if there is no event in the queue, the function will wait until there is one.
|
|
90
|
+
|
|
91
|
+
Usage Example:
|
|
92
|
+
while True:
|
|
93
|
+
tcp_dict = tcp_trace.emit()
|
|
94
|
+
print(tcp_dict)
|
|
95
|
+
|
|
96
|
+
:return: Dictionary with the event data.
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
# Get the event from ETW as is.
|
|
100
|
+
event = self.event_trace.emit()
|
|
101
|
+
|
|
102
|
+
local_address_port: str = event['EventHeader']['LocalAddress']
|
|
103
|
+
remote_address_port: str = event['EventHeader']['RemoteAddress']
|
|
104
|
+
|
|
105
|
+
if 'ffff' in local_address_port:
|
|
106
|
+
pass
|
|
107
|
+
|
|
108
|
+
local_address, local_port = local_address_port.rsplit(':', 1)
|
|
109
|
+
local_address = local_address.replace('[', '').replace(']', '')
|
|
110
|
+
|
|
111
|
+
remote_address, remote_port = remote_address_port.rsplit(':', 1)
|
|
112
|
+
remote_address = remote_address.replace('[', '').replace(']', '')
|
|
113
|
+
|
|
114
|
+
event_dict: dict = {
|
|
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
|
|
@@ -23,6 +23,40 @@ class SimpleProcessPool:
|
|
|
23
23
|
The idea is similar to the process_poller.process_pool.ProcessPool class, but this class is simpler and uses
|
|
24
24
|
only the pywin32 tracing of the Windows Event Log Process Creation and Process Termination events.
|
|
25
25
|
The simple process pool is used to get things simpler than the process_pool.ProcessPool class.
|
|
26
|
+
|
|
27
|
+
Example of starting the process pool in multiprocess:
|
|
28
|
+
import sys
|
|
29
|
+
|
|
30
|
+
from atomicshop.process_poller import simple_process_pool
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def start_process_pool(process_pool_shared_dict_proxy):
|
|
34
|
+
process_poller = simple_process_pool.SimpleProcessPool(
|
|
35
|
+
process_pool_shared_dict_proxy=process_pool_shared_dict_proxy)
|
|
36
|
+
process_poller.start()
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
# Keep the process alive.
|
|
40
|
+
while True:
|
|
41
|
+
time.sleep(1)
|
|
42
|
+
except KeyboardInterrupt:
|
|
43
|
+
process_poller.stop()
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def main():
|
|
47
|
+
# Create the shared multiprocessing dictionary of the process pool.
|
|
48
|
+
manager = multiprocessing.Manager()
|
|
49
|
+
multiprocess_dict_proxy = manager.dict()
|
|
50
|
+
|
|
51
|
+
# Start the process pool in a separate process.
|
|
52
|
+
pool_process = multiprocessing.Process(target=start_process_pool, args=(multiprocess_dict_proxy,))
|
|
53
|
+
pool_process.start()
|
|
54
|
+
|
|
55
|
+
# Pass the shared dict proxy to other functions.
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
if __name__ == '__main__':
|
|
59
|
+
sys.exit(main())
|
|
26
60
|
"""
|
|
27
61
|
|
|
28
62
|
def __init__(
|
|
@@ -79,7 +113,7 @@ class SimpleProcessPool:
|
|
|
79
113
|
self._processes = get_process_list.GetProcessList(
|
|
80
114
|
get_method='pywin32', connect_on_init=True).get_processes(as_dict=True)
|
|
81
115
|
|
|
82
|
-
thread_get_queue = threading.Thread(target=self._start_main_thread)
|
|
116
|
+
thread_get_queue = threading.Thread(target=self._start_main_thread, args=(self.process_pool_shared_dict_proxy,))
|
|
83
117
|
thread_get_queue.daemon = True
|
|
84
118
|
thread_get_queue.start()
|
|
85
119
|
|
|
@@ -93,7 +127,7 @@ class SimpleProcessPool:
|
|
|
93
127
|
def get_processes(self):
|
|
94
128
|
return self._processes
|
|
95
129
|
|
|
96
|
-
def _start_main_thread(self):
|
|
130
|
+
def _start_main_thread(self, process_pool_shared_dict_proxy):
|
|
97
131
|
get_instance = process_create.ProcessCreateSubscriber()
|
|
98
132
|
get_instance.start()
|
|
99
133
|
|
|
@@ -109,9 +143,9 @@ class SimpleProcessPool:
|
|
|
109
143
|
}
|
|
110
144
|
|
|
111
145
|
# Update the multiprocessing shared dict proxy.
|
|
112
|
-
if
|
|
113
|
-
|
|
114
|
-
|
|
146
|
+
if process_pool_shared_dict_proxy is not None:
|
|
147
|
+
process_pool_shared_dict_proxy.clear()
|
|
148
|
+
process_pool_shared_dict_proxy.update(self._processes)
|
|
115
149
|
|
|
116
150
|
# print_api(f'Process [{process_id}] added to the pool.', color='blue')
|
|
117
151
|
|
|
@@ -186,6 +220,7 @@ class PidProcessConverter:
|
|
|
186
220
|
process_dict: dict = dict()
|
|
187
221
|
while counter < WAIT_FOR_PROCESS_POLLER_PID_COUNTS:
|
|
188
222
|
if pid not in self.process_pool_shared_dict_proxy:
|
|
223
|
+
# print(dict(self.process_pool_shared_dict_proxy))
|
|
189
224
|
time.sleep(0.1)
|
|
190
225
|
counter += 1
|
|
191
226
|
else:
|
|
@@ -193,6 +228,7 @@ class PidProcessConverter:
|
|
|
193
228
|
break
|
|
194
229
|
|
|
195
230
|
if counter == WAIT_FOR_PROCESS_POLLER_PID_COUNTS and not process_dict:
|
|
231
|
+
print_api(f"Error: The PID [{pid}] is not in the pool, trying DLL snapshot.", color='yellow')
|
|
196
232
|
# Last resort, try to get the process name by current process snapshot.
|
|
197
233
|
processes = self.get_process_with_dll_instance.get_process_details(as_dict=True)
|
|
198
234
|
if pid not in processes:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
atomicshop/__init__.py,sha256=
|
|
1
|
+
atomicshop/__init__.py,sha256=mHi1iDugkcLgj5LyCc_4EL-QVNq95QCoQWv522BGF1c,124
|
|
2
2
|
atomicshop/_basics_temp.py,sha256=6cu2dd6r2dLrd1BRNcVDKTHlsHs_26Gpw8QS6v32lQ0,3699
|
|
3
3
|
atomicshop/_create_pdf_demo.py,sha256=Yi-PGZuMg0RKvQmLqVeLIZYadqEZwUm-4A9JxBl_vYA,3713
|
|
4
4
|
atomicshop/_patch_import.py,sha256=ENp55sKVJ0e6-4lBvZnpz9PQCt3Otbur7F6aXDlyje4,6334
|
|
@@ -57,7 +57,7 @@ atomicshop/a_installs/win/fibratus.py,sha256=TU4e9gdZ_zI73C40uueJ59pD3qmN-UFGdX5
|
|
|
57
57
|
atomicshop/a_installs/win/mongodb.py,sha256=AqyItXu19aaoe49pppDxtEkXey6PMy0PoT2Y_RmPpPE,179
|
|
58
58
|
atomicshop/a_installs/win/nodejs.py,sha256=U519Dyt4bsQPbEg_PwnZL5tsbfqDr1BbhxwoQFZsSKo,200
|
|
59
59
|
atomicshop/a_installs/win/pycharm.py,sha256=j_RSd7aDOyC3yDd-_GUTMLlQTmDrqtVFG--oUfGLiZk,140
|
|
60
|
-
atomicshop/a_installs/win/robocorp.py,sha256=
|
|
60
|
+
atomicshop/a_installs/win/robocorp.py,sha256=ExdMR705fW4iyNDZnH9YZMrio4FYEwNH_8nEP1GWkjM,2383
|
|
61
61
|
atomicshop/a_installs/win/wsl_ubuntu_lts.py,sha256=dZbPRLNKFeMd6MotjkE6UDY9cOiIaaclIdR1kGYWI50,139
|
|
62
62
|
atomicshop/a_mains/dns_gateway_setting.py,sha256=ncc2rFQCChxlNP59UshwmTonLqC6MWblrVAzbbz-13M,149
|
|
63
63
|
atomicshop/a_mains/github_wrapper.py,sha256=F-PoZknVCxWPN0PTO6l7ZNiaYvo7OVFKFI_zlPt56ps,169
|
|
@@ -117,10 +117,11 @@ atomicshop/etws/_pywintrace_fix.py,sha256=nHrtnAb796eOZ6FlCqcsuRh_TSqSPp6JXLN6TB
|
|
|
117
117
|
atomicshop/etws/const.py,sha256=v3x_IdCYeSKbCGywiZFOZln80ldpwKW5nuMDuUe51Jg,1257
|
|
118
118
|
atomicshop/etws/providers.py,sha256=CXNx8pYdjtpLIpA66IwrnE64XhY4U5ExnFBMLEb8Uzk,547
|
|
119
119
|
atomicshop/etws/sessions.py,sha256=b_KeiOvgOBJezJokN81TRlrvJiQNJlIWN4Z6UVjuxP0,1335
|
|
120
|
-
atomicshop/etws/trace.py,sha256=
|
|
120
|
+
atomicshop/etws/trace.py,sha256=p-5wegZ-5SuJ3UsprCCnlor8g2LPkF9ZOynLCYaEvXQ,7647
|
|
121
121
|
atomicshop/etws/traces/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
122
|
-
atomicshop/etws/traces/trace_dns.py,sha256=
|
|
122
|
+
atomicshop/etws/traces/trace_dns.py,sha256=SWeex1mK7rrMzCmmL3qiGaD_jzbRiiwJ_mhMZz5TwJc,6879
|
|
123
123
|
atomicshop/etws/traces/trace_sysmon_process_creation.py,sha256=OM-bkK38uYMwWLZKNOTDa0Xdk3sO6sqsxoMUIiPvm5g,4656
|
|
124
|
+
atomicshop/etws/traces/trace_tcp.py,sha256=pQF4A_qM-HjEhzMQUyTmUqOWdvSaqqAg5PwnkVn2fy4,5236
|
|
124
125
|
atomicshop/file_io/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
125
126
|
atomicshop/file_io/csvs.py,sha256=zv0kKjRT-ZWRi0WpMIUQ_FKyP9Dt0f5Bc98Qsj6ClPU,9495
|
|
126
127
|
atomicshop/file_io/docxs.py,sha256=Nyt3hSpzwqUKZEP5p5efqNpjFs9XqkK40Kp7BbbPo7E,6245
|
|
@@ -168,7 +169,7 @@ atomicshop/permissions/ubuntu_permissions.py,sha256=n8z1vcIXDts4zLVue33dtJiTopjg
|
|
|
168
169
|
atomicshop/permissions/win_permissions.py,sha256=eDQm1jfK9x_hkbLqIJjFTwfqinAWQ0iSr0kW3XrF1BE,1272
|
|
169
170
|
atomicshop/process_poller/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
170
171
|
atomicshop/process_poller/process_pool.py,sha256=4Qs427qd7OcBxu5PMFU5PTmyuxRy0vgj2GLsRt0IoEw,9565
|
|
171
|
-
atomicshop/process_poller/simple_process_pool.py,sha256=
|
|
172
|
+
atomicshop/process_poller/simple_process_pool.py,sha256=E0w66imLQQ0phHuTQfTaApOTurX0duE9vw1trjUY7rI,9894
|
|
172
173
|
atomicshop/process_poller/tracer_base.py,sha256=IOiHcnmF-MccOSCErixN5mve9RifZ9cPnGVHCIRchrs,1091
|
|
173
174
|
atomicshop/process_poller/pollers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
174
175
|
atomicshop/process_poller/pollers/psutil_pywin32wmi_dll.py,sha256=XRRfOIy62iOYU8IKRcyECWiL0rqQ35DeYbPsv_SHDVM,4510
|
|
@@ -327,8 +328,8 @@ atomicshop/wrappers/socketw/statistics_csv.py,sha256=fgMzDXI0cybwUEqAxprRmY3lqbh
|
|
|
327
328
|
atomicshop/wrappers/winregw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
328
329
|
atomicshop/wrappers/winregw/winreg_installed_software.py,sha256=Qzmyktvob1qp6Tjk2DjLfAqr_yXV0sgWzdMW_9kwNjY,2345
|
|
329
330
|
atomicshop/wrappers/winregw/winreg_network.py,sha256=AENV88H1qDidrcpyM9OwEZxX5svfi-Jb4N6FkS1xtqA,8851
|
|
330
|
-
atomicshop-2.19.
|
|
331
|
-
atomicshop-2.19.
|
|
332
|
-
atomicshop-2.19.
|
|
333
|
-
atomicshop-2.19.
|
|
334
|
-
atomicshop-2.19.
|
|
331
|
+
atomicshop-2.19.11.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
|
|
332
|
+
atomicshop-2.19.11.dist-info/METADATA,sha256=tSnPcFSBceRSRX3c335xVMPu5zruA6fmE8ifV12MW-8,10631
|
|
333
|
+
atomicshop-2.19.11.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
334
|
+
atomicshop-2.19.11.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
|
|
335
|
+
atomicshop-2.19.11.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|