├── README.md
├── bustr
├── __init__.py
└── core
│ ├── enums.py
│ ├── export.py
│ ├── generate.py
│ ├── monitor.py
│ ├── parser.py
│ └── utils.py
└── main.py
/README.md:
--------------------------------------------------------------------------------
1 | # Bustr
2 |
3 | ```
4 | ____ __
5 | / __ )__ _______/ /______
6 | / /_/ / / / / ___/ __/ ___/
7 | / /_/ / /_/ (__ ) /_/ /
8 | /_____/\__,_/____/\__/_/ Version 1.0.0
9 | ```
10 |
11 | Bustr is a utility built to discover if any new USB, Storage, Phone or Bluetooth device has been attached/paired with the operating system, by monitoring registry artifacts. If a discovery is made, generate HTML page containing log results and registry data. Tested this with 4 different USB manufacturers and Android and iPhone.
12 |
13 | #### Preview
14 | 
15 |
16 | #### Ability to monitor activity of these registry artifacts simultaneously:
17 | * SYSTEM\MountedDevices
18 | * SYSTEM\CurrentControlSet\Enum\USB
19 | * SYSTEM\CurrentControlSet\Enum\SCSI
20 | * SYSTEM\CurrentControlSet\Enum\BTHENUM
21 | * SYSTEM\CurrentControlSet\Enum\USBSTOR
22 | * SYSTEM\CurrentControlSet\Enum\STORAGE\Volume
23 | * SOFTWARE\Microsoft\Windows Portable Devices\Device
24 | * SYSTEM\CurrentControlSet\Enum\SWD\WPDBUSENUM
25 | * SYSTEM\CurrentControlSet\Services\BTHPORT\Parameters\Devices
26 | * Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2\CPC\Volume
27 | * Software\Microsoft\Windows\CurrentVersion\Explorer\AutoplayHandlers\KnownDevices
28 |
--------------------------------------------------------------------------------
/bustr/__init__.py:
--------------------------------------------------------------------------------
1 | #init
--------------------------------------------------------------------------------
/bustr/core/enums.py:
--------------------------------------------------------------------------------
1 | from bustr.core.utils import utils
2 | from sys import _getframe
3 | from os import path
4 | import logging
5 |
6 | try:
7 | import _winreg
8 | except ImportError:
9 | import winreg as _winreg
10 |
11 | logging.basicConfig(level=logging.DEBUG)
12 | debug = logging.getLogger(" enum_debugger ")
13 | debug.disabled = True
14 |
15 | class enum:
16 | """ Class to handle enumeration """
17 | def __init__(self):
18 | self.results = []
19 | self.devices = []
20 | self.path_mounteddevices = r"SYSTEM\MountedDevices"
21 | self.path_usb = r"SYSTEM\CurrentControlSet\Enum\USB"
22 | self.path_scsi = r"SYSTEM\CurrentControlSet\Enum\SCSI"
23 | self.path_bthenum = r"SYSTEM\CurrentControlSet\Enum\BTHENUM"
24 | self.path_usbstor = r"SYSTEM\CurrentControlSet\Enum\USBSTOR"
25 | self.path_storage = r"SYSTEM\CurrentControlSet\Enum\STORAGE\Volume"
26 | self.path_wpd = r"SOFTWARE\Microsoft\Windows Portable Devices\Devices"
27 | self.path_wpdbusenum = r"SYSTEM\CurrentControlSet\Enum\SWD\WPDBUSENUM"
28 | self.path_bthport = r"SYSTEM\CurrentControlSet\Services\BTHPORT\Parameters\Devices"
29 | self.path_mountpoints = r"Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2\CPC\Volume"
30 | self.path_knowndevices = r"Software\Microsoft\Windows\CurrentVersion\Explorer\AutoplayHandlers\KnownDevices"
31 | self.dump_mounteddevices = "dump_mounteddevices.reg"
32 | self.dump_knowndevices = "dump_knowndevices.reg"
33 | self.dump_mountpoints = "dump_mountpoints.reg"
34 | self.dump_wpdbusenum = "dump_wpdbusenum.reg"
35 | self.dump_bthport = "dump_bthport.reg"
36 | self.dump_storage = "dump_storage.reg"
37 | self.dump_usbstor = "dump_usbstor.reg"
38 | self.dump_bthenum = "dump_bthenum.reg"
39 | self.dump_scsi = "dump_scsi.reg"
40 | self.dump_usb = "dump_usb.reg"
41 | self.dump_wpd = "dump_wpd.reg"
42 |
43 | def debug(self):
44 | """ Disable stdout to console window """
45 | debug.disabled = False
46 |
47 | def EnumSCSI(self):
48 | """ Enumerate SCSI registry artifacts and return results.
49 | If registry key does not exist it returns False """
50 | try:
51 | key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
52 | path.join(self.path_scsi),
53 | 0,
54 | _winreg.KEY_READ)
55 | except WindowsError as error:
56 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
57 | return False
58 | else:
59 | for index in range(0, _winreg.QueryInfoKey(key)[0]):
60 | try:
61 | self.devices.append(_winreg.EnumKey(key, index))
62 | except WindowsError as error:
63 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
64 | pass
65 | else:
66 | debug.debug("Appended ({data}) to devices list".format(data=_winreg.EnumKey(key, index)))
67 |
68 | for device in self.devices:
69 | try:
70 | key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
71 | path.join(self.path_scsi, device),
72 | 0,
73 | _winreg.KEY_READ)
74 | except WindowsError as error:
75 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
76 | pass
77 | else:
78 | self.results.append(path.join(self.path_scsi, device))
79 | debug.debug("Appended ({data}) to results list".format(data=path.join(self.path_scsi, device)))
80 |
81 | _winreg.CloseKey(key)
82 | finally:
83 | return self.results
84 |
85 | def EnumBTHENUM(self):
86 | """ Enumerate BTHENUM registry artifacts and return results.
87 | If registry key does not exist it returns False """
88 | try:
89 | key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
90 | path.join(self.path_bthenum),
91 | 0,
92 | _winreg.KEY_READ)
93 | except WindowsError as error:
94 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
95 | return False
96 | else:
97 | for index in range(0, _winreg.QueryInfoKey(key)[0]):
98 | try:
99 | self.devices.append(_winreg.EnumKey(key, index))
100 | except WindowsError as error:
101 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
102 | pass
103 | else:
104 | debug.debug("Appended ({data}) to devices list".format(data=_winreg.EnumKey(key, index)))
105 |
106 | for device in self.devices:
107 | try:
108 | key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
109 | path.join(self.path_bthenum, device),
110 | 0,
111 | _winreg.KEY_READ)
112 | except WindowsError as error:
113 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
114 | pass
115 | else:
116 | self.results.append(path.join(self.path_bthenum, device))
117 | debug.debug("Appended ({data}) to results list".format(data=path.join(self.path_bthenum, device)))
118 |
119 | _winreg.CloseKey(key)
120 | finally:
121 | return self.results
122 |
123 | def EnumBTHPORT(self):
124 | """ Enumerate BTHPORT registry artifacts and return results.
125 | If registry key does not exist it returns False """
126 | try:
127 | key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
128 | path.join(self.path_bthport),
129 | 0,
130 | _winreg.KEY_READ)
131 | except WindowsError as error:
132 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
133 | return False
134 | else:
135 | for index in range(0, _winreg.QueryInfoKey(key)[0]):
136 | try:
137 | self.results.append(_winreg.EnumKey(key, index))
138 | except WindowsError as error:
139 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
140 | pass
141 | else:
142 | debug.debug("Appended ({data}) to results list".format(data=_winreg.EnumKey(key, index)))
143 |
144 | _winreg.CloseKey(key)
145 | finally:
146 | return self.results
147 |
148 | def EnumKnownDevices(self):
149 | """ Enumerate KnownDevices registry artifacts and return results.
150 | If registry key does not exist it returns False """
151 | try:
152 | key = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER,
153 | path.join(self.path_knowndevices),
154 | 0,
155 | _winreg.KEY_READ)
156 | except WindowsError as error:
157 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
158 | return False
159 | else:
160 | for index in range(0, _winreg.QueryInfoKey(key)[0]):
161 | try:
162 | self.devices.append(_winreg.EnumKey(key, index))
163 | except WindowsError as error:
164 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
165 | pass
166 | else:
167 | debug.debug("Appended ({data}) to devices list".format(data=_winreg.EnumKey(key, index)))
168 |
169 | for device in self.devices:
170 | try:
171 | key = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER,
172 | path.join(self.path_knowndevices, device),
173 | 0,
174 | _winreg.KEY_READ)
175 | except WindowsError as error:
176 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
177 | pass
178 | else:
179 | self.results.append(path.join(self.path_knowndevices, device))
180 | debug.debug("Appended ({data}) to results list".format(data=path.join(self.path_knowndevices, device)))
181 |
182 | _winreg.CloseKey(key)
183 | finally:
184 | return self.results
185 |
186 | def EnumWPD(self):
187 | """ Enumerate WPD registry artifacts and return results.
188 | If registry key does not exist it returns False """
189 | try:
190 | key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
191 | path.join(self.path_wpd),
192 | 0,
193 | _winreg.KEY_READ)
194 | except WindowsError as error:
195 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
196 | return False
197 | else:
198 | for index in range(0, _winreg.QueryInfoKey(key)[0]):
199 | try:
200 | self.devices.append(_winreg.EnumKey(key, index))
201 | except WindowsError as error:
202 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
203 | pass
204 | else:
205 | debug.debug("Appended ({data}) to devices list".format(data=_winreg.EnumKey(key, index)))
206 |
207 | for device in self.devices:
208 | try:
209 | key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
210 | path.join(self.path_wpd, device),
211 | 0,
212 | _winreg.KEY_READ)
213 | except WindowsError as error:
214 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
215 | pass
216 | else:
217 | self.results.append(path.join(self.path_wpd, device))
218 | debug.debug("Appended ({data}) to results list".format(data=path.join(self.path_wpd, device)))
219 |
220 | _winreg.CloseKey(key)
221 | finally:
222 | return self.results
223 |
224 | def EnumSTORAGE(self):
225 | """ Enumerate STORAGE registry artifacts and return results.
226 | If registry key does not exist it returns False """
227 | try:
228 | key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
229 | path.join(self.path_storage),
230 | 0,
231 | _winreg.KEY_READ)
232 | except WindowsError as error:
233 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
234 | return False
235 | else:
236 | for index in range(0, _winreg.QueryInfoKey(key)[0]):
237 | try:
238 | self.devices.append(_winreg.EnumKey(key, index))
239 | except WindowsError as error:
240 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
241 | pass
242 | else:
243 | debug.debug("Appended ({data}) to devices list".format(data=_winreg.EnumKey(key, index)))
244 |
245 | for device in self.devices:
246 | try:
247 | key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
248 | path.join(self.path_storage, device),
249 | 0,
250 | _winreg.KEY_READ)
251 | except WindowsError as error:
252 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
253 | pass
254 | else:
255 | self.results.append(path.join(self.path_storage, device))
256 | debug.debug("Appended ({data}) to results list".format(data=path.join(self.path_storage, device)))
257 |
258 | _winreg.CloseKey(key)
259 | finally:
260 | return self.results
261 |
262 | def EnumWPDBUSENUM(self):
263 | """ Enumerate WPDBUSENUM registry artifacts and return results.
264 | If registry key does not exist it returns False """
265 | try:
266 | key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
267 | path.join(self.path_wpdbusenum),
268 | 0,
269 | _winreg.KEY_READ)
270 | except WindowsError as error:
271 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
272 | return False
273 | else:
274 | for index in range(0, _winreg.QueryInfoKey(key)[0]):
275 | try:
276 | self.devices.append(_winreg.EnumKey(key, index))
277 | except WindowsError as error:
278 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
279 | pass
280 | else:
281 | debug.debug("Appended ({data}) to devices list".format(data=_winreg.EnumKey(key, index)))
282 |
283 | for device in self.devices:
284 | try:
285 | key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
286 | path.join(self.path_wpdbusenum, device),
287 | 0,
288 | _winreg.KEY_READ)
289 | except WindowsError as error:
290 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
291 | pass
292 | else:
293 | self.results.append(path.join(self.path_wpdbusenum, device))
294 | debug.debug("Appended ({data}) to results list".format(data=path.join(self.path_wpdbusenum, device)))
295 |
296 | _winreg.CloseKey(key)
297 | finally:
298 | return self.results
299 |
300 | def EnumUSB(self):
301 | """ Enumerate USB registry artifacts and return results.
302 | If registry key does not exist it returns False """
303 | try:
304 | key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
305 | path.join(self.path_usb),
306 | 0,
307 | _winreg.KEY_READ)
308 | except WindowsError as error:
309 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
310 | return False
311 | else:
312 | for index in range(0, _winreg.QueryInfoKey(key)[0]):
313 | try:
314 | self.devices.append(_winreg.EnumKey(key, index))
315 | except WindowsError as error:
316 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
317 | pass
318 | else:
319 | debug.debug("Appended ({data}) to devices list".format(data=_winreg.EnumKey(key, index)))
320 |
321 | for device in self.devices:
322 | try:
323 | key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
324 | path.join(self.path_usb, device),
325 | 0,
326 | _winreg.KEY_READ)
327 | except WindowsError as error:
328 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
329 | pass
330 | else:
331 | self.results.append(path.join(self.path_usb, device))
332 | debug.debug("Appended ({data}) to results list".format(data=path.join(self.path_usb, device)))
333 |
334 | _winreg.CloseKey(key)
335 | finally:
336 | return self.results
337 |
338 | def EnumUSBSTOR(self):
339 | """ Enumerate USBSTOR registry artifacts and return results.
340 | If registry key does not exist it returns False """
341 | try:
342 | key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
343 | path.join(self.path_usbstor),
344 | 0,
345 | _winreg.KEY_READ)
346 | except WindowsError as error:
347 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
348 | return False
349 | else:
350 | for index in range(0, _winreg.QueryInfoKey(key)[0]):
351 | try:
352 | self.devices.append(_winreg.EnumKey(key, index))
353 | except WindowsError as error:
354 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
355 | pass
356 | else:
357 | debug.debug("Appended ({data}) to devices list".format(data=_winreg.EnumKey(key, index)))
358 |
359 | for device in self.devices:
360 | try:
361 | key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
362 | path.join(self.path_usbstor, device),
363 | 0,
364 | _winreg.KEY_READ)
365 | except WindowsError as error:
366 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
367 | pass
368 | else:
369 | self.results.append(path.join(self.path_usbstor, device))
370 | debug.debug("Appended ({data}) to results list".format(data=path.join(self.path_usbstor, device)))
371 |
372 | _winreg.CloseKey(key)
373 | finally:
374 | return self.results
375 |
376 | def EnumMountedDevices(self):
377 | """ Enumerate MountedDevices registry artifacts and return results.
378 | If registry key does not exist it returns False """
379 | try:
380 | key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
381 | path.join(self.path_mounteddevices),
382 | 0,
383 | _winreg.KEY_READ)
384 | except WindowsError as error:
385 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
386 | return False
387 | else:
388 | for index in range(0, _winreg.QueryInfoKey(key)[1]):
389 | try:
390 | self.results.append(_winreg.EnumValue(key, index))
391 | except WindowsError as error:
392 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
393 | pass
394 | else:
395 | debug.debug("Appended ({data}) to results list".format(data=_winreg.EnumValue(key, index)))
396 |
397 | _winreg.CloseKey(key)
398 | finally:
399 | return self.results
400 |
401 | def EnumMountPoints2(self):
402 | """ Enumerate MountPoints2 registry artifacts and return results.
403 | If registry key does not exist it returns False """
404 | try:
405 | key = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER,
406 | path.join(self.path_mountpoints),
407 | 0,
408 | _winreg.KEY_READ)
409 | except WindowsError as error:
410 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
411 | return False
412 | else:
413 | for index in range(0, _winreg.QueryInfoKey(key)[0]):
414 | try:
415 | self.results.append(_winreg.EnumKey(key, index))
416 | except WindowsError as error:
417 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
418 | pass
419 | else:
420 | debug.debug("Appended ({data}) to results list".format(data=_winreg.EnumKey(key, index)))
421 |
422 | _winreg.CloseKey(key)
423 | finally:
424 | return self.results
--------------------------------------------------------------------------------
/bustr/core/export.py:
--------------------------------------------------------------------------------
1 | from bustr.core.utils import utils
2 | from os import path, getcwd, makedirs, remove
3 | from subprocess import PIPE, run
4 | from sys import _getframe
5 | import datetime
6 | import logging
7 |
8 | logging.basicConfig(level=logging.DEBUG)
9 | debug = logging.getLogger(" export_debugger ")
10 | debug.disabled = True
11 |
12 | class registry:
13 | """ Class to export registry files """
14 | def __init__(self):
15 | self.folder = path.join(getcwd(),
16 | "dumps")
17 |
18 | def debug(self):
19 | """ Disable stdout to console window """
20 | debug.disabled = False
21 |
22 | def export(self, hkey, key, name):
23 | """ Export registry file to disk """
24 | debug.debug("Checking if path exists")
25 | if not path.exists(path.join(self.folder, str(datetime.date.today()))):
26 | debug.debug("Path does not exist, creating directory stucture")
27 | try:
28 | makedirs(path.join(self.folder, str(datetime.date.today())),
29 | mode=0o777,
30 | exist_ok=False)
31 | except FileExistsError:
32 | pass
33 | else:
34 | debug.debug("Directory stucture was created successfully")
35 |
36 | debug.debug("Checking if file exists")
37 | if path.isfile(path.join(path.join(self.folder, str(datetime.date.today())), name)):
38 | debug.debug("File exists, removing file from disk")
39 | try:
40 | remove(path.join(path.join(self.folder, str(datetime.date.today())), name))
41 | except Exception as error:
42 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
43 | return False
44 | else:
45 | debug.debug("Successfully removed file from disk")
46 |
47 | debug.debug("Attempting to export registry data to directory")
48 | try:
49 | result = run("reg export {path} {output}".format(path=path.join(hkey, key),
50 | output=path.join(path.join(self.folder, str(datetime.date.today())), name)),
51 | check=True,
52 | stdout=PIPE)
53 | except Exception as error:
54 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
55 | return(False, 0)
56 | else:
57 | if result.returncode == 0:
58 | if path.isfile(path.join(path.join(self.folder, str(datetime.date.today())), name)):
59 | debug.debug("Successfully exported registry data to directory")
60 | return(True, result.returncode)
61 | else:
62 | debug.debug("Unable to export registry data to directory")
63 | return(False, result.returncode)
64 | else:
65 | debug.debug("Unable to export registry data to directory")
66 | return(False, result.returncode)
--------------------------------------------------------------------------------
/bustr/core/generate.py:
--------------------------------------------------------------------------------
1 | from bustr.core.parser import parse
2 | from os import path, getcwd, makedirs, walk, remove
3 | from sys import _getframe
4 | import datetime
5 | import logging
6 |
7 | logging.basicConfig(level=logging.DEBUG)
8 | debug = logging.getLogger(" generate_debugger ")
9 | debug.disabled = True
10 |
11 | class generate:
12 | """ Class to generate html based reports and log messages """
13 | def __init__(self):
14 | self.path_log = path.join(getcwd(), "logs")
15 | self.path_report = path.join(getcwd(), "reports")
16 | self.path_dumps = path.join(getcwd(), "dumps")
17 |
18 | def debug(self):
19 | """ Disable stdout to console window """
20 | debug.disabled = False
21 |
22 | def log(self, message):
23 | """ Save message to log file with timestamps
24 | generate().log("This is a log message") """
25 | debug.debug("Checking if path exists")
26 | if not path.exists(path.join(self.path_log, str(datetime.date.today()))):
27 | debug.debug("Path does not exist, creating directory structure")
28 | try:
29 | makedirs(path.join(self.path_log, str(datetime.date.today())),
30 | mode=0o777,
31 | exist_ok=False)
32 | except FileExistsError:
33 | pass
34 | else:
35 | debug.debug("Directory structure was created successfully")
36 |
37 | debug.debug("Attempting to write to log file")
38 | with open(path.join(self.path_log, str(datetime.date.today()) + "\\" + str(datetime.date.today()) + ".log"), "a+") as log:
39 | log.write("{date} - {message}\n".format(date=datetime.datetime.now(), message=str(message)))
40 | debug.debug("Wrote ({message}) to log file".format(message=str(message)))
41 |
42 | def report(self):
43 | """ Generate a html based report containing the data we exported
44 | from parse().regfile("regfile.reg") or/and parse().logfile("logfile.log") """
45 | debug.debug("Checking if path exists")
46 | if not path.exists(path.join(self.path_report, str(datetime.date.today()))):
47 | debug.debug("Path does not exist, creating directory structure")
48 | try:
49 | makedirs(path.join(self.path_report, str(datetime.date.today())),
50 | mode=0o777,
51 | exist_ok=False)
52 | except FileExistsError:
53 | pass
54 | else:
55 | debug.debug("Directory structure was created successfully")
56 |
57 | debug.debug("Checking if file exists")
58 | if path.isfile(path.join(path.join(self.path_report, str(datetime.date.today())), "report.html")):
59 | debug.debug("File exists, removing file from disk")
60 | try:
61 | remove(path.join(path.join(self.path_report, str(datetime.date.today())), "report.html"))
62 | except Exception as error:
63 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
64 | return False
65 | else:
66 | debug.debug("Successfully removed file from disk")
67 |
68 | debug.debug("Attempting to write HTML report to disk")
69 | with open(path.join(path.join(self.path_report, str(datetime.date.today())), "report.html"), "a+") as report:
70 | report.write("\n")
71 | report.write("
\n")
72 | report.write("\n")
89 | report.write("\n")
90 |
91 | report.write("\nMonitoring log results:
\n")
92 | if path.isdir(self.path_log):
93 | report.write("\n")
94 | report.write("\n")
95 | for p, s, f in walk(self.path_log):
96 | for n in f:
97 | if path.isfile(path.join(p, n)):
98 | data = parse().logfile(path.join(p, n))
99 | if data:
100 | for d in (data[0]):
101 | report.write("
" + d.strip("\n") + " |
\n")
102 | else:
103 | report.write("No available data | \n")
104 | else:
105 | report.write("No available data | \n")
106 | report.write("\n")
107 | report.write("
\n")
108 | else:
109 | report.write("\n")
110 | report.write("\n")
111 | report.write("No available data | \n")
112 | report.write("
\n")
113 | report.write("
\n")
114 |
115 | report.write("\nExported data log results:
\n")
116 | if path.isdir(self.path_dumps):
117 | report.write("\n")
118 | for p, s, f in walk(self.path_dumps):
119 | for n in f:
120 | if path.isfile(path.join(p, n)):
121 | data = parse().regfile(path.join(p, n))
122 | if data:
123 | for l in range(len(data)):
124 | if len(data[l]) == 1:
125 | if "HKEY_" in data[l][0]:
126 | report.write("" + data[l][0] + " |
\n")
127 | if len(data[l]) == 2:
128 | report.write("" + data[l][0] + " : " + data[l][1] + " |
\n")
129 | else:
130 | report.write("No available data | \n")
131 | else:
132 | report.write("No available data | \n")
133 | else:
134 | report.write("\n")
135 | report.write("\n")
136 | report.write("No available data | \n")
137 | report.write("
\n")
138 | report.write("
\n")
139 |
140 | report.write("
\n")
141 | report.write("\n")
142 |
143 | if path.isfile(path.join(path.join(self.path_report, str(datetime.date.today())), "report.html")):
144 | debug.debug("Successfully created HTML report")
145 | return True
146 | else:
147 | debug.debug("Unable to create HTML report")
148 | return False
--------------------------------------------------------------------------------
/bustr/core/monitor.py:
--------------------------------------------------------------------------------
1 | from bustr.core.enums import enum
2 | from bustr.core.generate import generate
3 | from bustr.core.export import registry
4 | from time import sleep
5 | from os import path
6 | from sys import _getframe
7 | import logging
8 |
9 | logging.basicConfig(level=logging.DEBUG)
10 | debug = logging.getLogger(" monitor_debugger ")
11 | debug.disabled = True
12 |
13 | class monitor:
14 | """ Class to monitor registry artifacts in real-time """
15 | def __init__(self):
16 | self.results = []
17 | self.fcheck = []
18 | self.scheck = []
19 |
20 | def debug(self):
21 | """ Disable stdout to console window """
22 | debug.disabled = False
23 |
24 | def scsi(self):
25 | """
26 | This registry artifact is persistent so if the device is unplugged
27 | we cannot detect it with registry changes
28 |
29 | Path and variable associated with this function:
30 | > enum().path_scsi -- Registry path as string
31 | > enum().dump_scsi -- Name of export output
32 | """
33 | if enum().EnumSCSI():
34 | debug.debug("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
35 | generate().log("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
36 | for data in enum().EnumSCSI():
37 | self.fcheck.append(data)
38 |
39 | while True:
40 | for data in enum().EnumSCSI():
41 | self.scheck.append(data)
42 |
43 | for change in set(self.fcheck).symmetric_difference(self.scheck):
44 | if len(self.fcheck) < len(self.scheck):
45 | if not change in self.results:
46 | debug.debug("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
47 | generate().log("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
48 | self.results.append(change)
49 | if registry().export("HKLM", enum().path_scsi, enum().dump_scsi)[0]:
50 | debug.debug("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
51 | dpath=path.join(registry().folder, enum().dump_scsi)))
52 | generate().log("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
53 | dpath=path.join(registry().folder, enum().dump_scsi)))
54 | if generate().report():
55 | debug.debug("Generated HTML report containing log messages and exported data")
56 | generate().log("Generated HTML report containing log messages and exported data")
57 | else:
58 | debug.debug("Unable to generate HTML report containing log messages and exported data")
59 | generate().log("Unable to generate HTML report containing log messages and exported data")
60 | else:
61 | debug.debug("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
62 | dpath=path.join(registry().folder, enum().dump_scsi)))
63 | generate().log("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
64 | dpath=path.join(registry().folder, enum().dump_scsi)))
65 | self.scheck = []
66 | sleep(1)
67 | else:
68 | debug.debug("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
69 | generate().log("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
70 | return False
71 |
72 | def bthenum(self):
73 | """
74 | This registry artifact is persistent so if the device is unplugged
75 | we cannot detect it with registry changes
76 |
77 | Path and variable associated with this function:
78 | > enum().path_bthenum -- Registry path as string
79 | > enum().dump_bthenum -- Name of export output
80 | """
81 | if enum().EnumBTHENUM():
82 | debug.debug("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
83 | generate().log("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
84 | for data in enum().EnumBTHENUM():
85 | self.fcheck.append(data)
86 |
87 | while True:
88 | for data in enum().EnumBTHENUM():
89 | self.scheck.append(data)
90 |
91 | for change in set(self.fcheck).symmetric_difference(self.scheck):
92 | if len(self.fcheck) < len(self.scheck):
93 | if not change in self.results:
94 | debug.debug("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
95 | generate().log("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
96 | self.results.append(change)
97 | if registry().export("HKLM", enum().path_bthenum, enum().dump_bthenum)[0]:
98 | debug.debug("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
99 | dpath=path.join(registry().folder, enum().dump_bthenum)))
100 | generate().log("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
101 | dpath=path.join(registry().folder, enum().dump_bthenum)))
102 | if generate().report():
103 | debug.debug("Generated HTML report containing log messages and exported data")
104 | generate().log("Generated HTML report containing log messages and exported data")
105 | else:
106 | debug.debug("Unable to generate HTML report containing log messages and exported data")
107 | generate().log("Unable to generate HTML report containing log messages and exported data")
108 | else:
109 | debug.debug("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
110 | dpath=path.join(registry().folder, enum().dump_bthenum)))
111 | generate().log("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
112 | dpath=path.join(registry().folder, enum().dump_bthenum)))
113 | self.scheck = []
114 | sleep(1)
115 | else:
116 | debug.debug("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
117 | generate().log("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
118 | return False
119 |
120 | def bthport(self):
121 | """
122 | This registry artifact is persistent so if the device is unplugged
123 | we cannot detect it with registry changes
124 |
125 | Path and variable associated with this function:
126 | > enum().path_bthport -- Registry path as string
127 | > enum().dump_bthport -- Name of export output
128 | """
129 | if enum().EnumBTHPORT():
130 | debug.debug("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
131 | generate().log("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
132 | for data in enum().EnumBTHPORT():
133 | self.fcheck.append(data)
134 |
135 | while True:
136 | for data in enum().EnumBTHPORT():
137 | self.scheck.append(data)
138 |
139 | for change in set(self.fcheck).symmetric_difference(self.scheck):
140 | if len(self.fcheck) < len(self.scheck):
141 | if not change in self.results:
142 | debug.debug("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
143 | generate().log("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
144 | self.results.append(change)
145 | if registry().export("HKLM", enum().path_bthport, enum().dump_bthport)[0]:
146 | debug.debug("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
147 | dpath=path.join(registry().folder, enum().dump_bthport)))
148 | generate().log("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
149 | dpath=path.join(registry().folder, enum().dump_bthport)))
150 | if generate().report():
151 | debug.debug("Generated HTML report containing log messages and exported data")
152 | generate().log("Generated HTML report containing log messages and exported data")
153 | else:
154 | debug.debug("Unable to generate HTML report containing log messages and exported data")
155 | generate().log("Unable to generate HTML report containing log messages and exported data")
156 | else:
157 | debug.debug("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
158 | dpath=path.join(registry().folder, enum().dump_bthport)))
159 | generate().log("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
160 | dpath=path.join(registry().folder, enum().dump_bthport)))
161 | self.scheck = []
162 | sleep(1)
163 | else:
164 | debug.debug("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
165 | generate().log("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
166 | return False
167 |
168 | def mountpoints(self):
169 | """
170 | This registry artifact is dynamic, when a USB for an example
171 | gets inserted a mountpoint GUID will be created in the registry and
172 | removed when the USB is unplugged
173 |
174 | Path and variable associated with this function:
175 | > enum().path_mountpoints -- Registry path as string
176 | > enum().dump_mountpoints -- Name of export output
177 | """
178 | if enum().EnumMountPoints2():
179 | debug.debug("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
180 | generate().log("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
181 | for data in enum().EnumMountPoints2():
182 | self.fcheck.append(data)
183 |
184 | while True:
185 | for data in enum().EnumMountPoints2():
186 | self.scheck.append(data)
187 |
188 | for change in set(self.fcheck).symmetric_difference(self.scheck):
189 | if len(self.fcheck) < len(self.scheck):
190 | if not change in self.results:
191 | debug.debug("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
192 | generate().log("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
193 | self.results.append(change)
194 | if registry().export("HKCU", enum().path_mountpoints, enum().dump_mountpoints)[0]:
195 | debug.debug("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
196 | dpath=path.join(registry().folder, enum().dump_mountpoints)))
197 | generate().log("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
198 | dpath=path.join(registry().folder, enum().dump_mountpoints)))
199 | if generate().report():
200 | debug.debug("Generated HTML report containing log messages and exported data")
201 | generate().log("Generated HTML report containing log messages and exported data")
202 | else:
203 | debug.debug("Unable to generate HTML report containing log messages and exported data")
204 | generate().log("Unable to generate HTML report containing log messages and exported data")
205 | else:
206 | debug.debug("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
207 | dpath=path.join(registry().folder, enum().dump_mountpoints)))
208 | generate().log("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
209 | dpath=path.join(registry().folder, enum().dump_mountpoints)))
210 |
211 | for device in self.results:
212 | if device in self.scheck:
213 | pass
214 | else:
215 | debug.debug("Function ({fname}) detected ({device}) was unplugged or removed from registry".format(fname=_getframe().f_code.co_name, device=device))
216 | generate().log("Function ({fname}) detected ({device}) was unplugged or removed from registry".format(fname=_getframe().f_code.co_name, device=device))
217 | self.results.remove(device)
218 |
219 | self.scheck = []
220 | sleep(1)
221 | else:
222 | debug.debug("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
223 | generate().log("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
224 | return False
225 |
226 | def mounteddevices(self):
227 | """
228 | This registry artifact is persistent so if the device is unplugged
229 | we cannot detect it with registry changes.
230 |
231 | Improvements:
232 | * Add ability to check if drive letter or volume is present
233 |
234 | Path and variable associated with this function:
235 | > enum().path_mounteddevices -- Registry path as string
236 | > enum().dump_mounteddevices -- Name of export output
237 | """
238 | if enum().EnumMountedDevices():
239 | debug.debug("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
240 | generate().log("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
241 | for data in enum().EnumMountedDevices():
242 | self.fcheck.append(data)
243 |
244 | while True:
245 | for data in enum().EnumMountedDevices():
246 | self.scheck.append(data)
247 |
248 | for change in set(self.fcheck).symmetric_difference(self.scheck):
249 | if len(self.fcheck) < len(self.scheck):
250 | if not change in self.results:
251 | debug.debug("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
252 | generate().log("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
253 | self.results.append(change)
254 | if registry().export("HKLM", enum().path_mounteddevices, enum().dump_mounteddevices)[0]:
255 | debug.debug("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
256 | dpath=path.join(registry().folder, enum().dump_mounteddevices)))
257 | generate().log("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
258 | dpath=path.join(registry().folder, enum().dump_mounteddevices)))
259 | if generate().report():
260 | debug.debug("Generated HTML report containing log messages and exported data")
261 | generate().log("Generated HTML report containing log messages and exported data")
262 | else:
263 | debug.debug("Unable to generate HTML report containing log messages and exported data")
264 | generate().log("Unable to generate HTML report containing log messages and exported data")
265 | else:
266 | debug.debug("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
267 | dpath=path.join(registry().folder, enum().dump_mounteddevices)))
268 | generate().log("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
269 | dpath=path.join(registry().folder, enum().dump_mounteddevices)))
270 | self.scheck = []
271 | sleep(1)
272 | else:
273 | debug.debug("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
274 | generate().log("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
275 | return False
276 |
277 | def storage(self):
278 | """
279 | This registry artifact is persistent so if the device is unplugged
280 | we cannot detect it with registry changes
281 |
282 | Path and variable associated with this function:
283 | > enum().path_storage -- Registry path as string
284 | > enum().dump_storage -- Name of export output
285 | """
286 | if enum().EnumSTORAGE():
287 | debug.debug("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
288 | generate().log("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
289 | for data in enum().EnumSTORAGE():
290 | self.fcheck.append(data)
291 |
292 | while True:
293 | for data in enum().EnumSTORAGE():
294 | self.scheck.append(data)
295 |
296 | for change in set(self.fcheck).symmetric_difference(self.scheck):
297 | if len(self.fcheck) < len(self.scheck):
298 | if not change in self.results:
299 | debug.debug("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
300 | generate().log("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
301 | self.results.append(change)
302 | if registry().export("HKLM", enum().path_storage, enum().dump_storage)[0]:
303 | debug.debug("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
304 | dpath=path.join(registry().folder, enum().dump_storage)))
305 | generate().log("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
306 | dpath=path.join(registry().folder, enum().dump_storage)))
307 | if generate().report():
308 | debug.debug("Generated HTML report containing log messages and exported data")
309 | generate().log("Generated HTML report containing log messages and exported data")
310 | else:
311 | debug.debug("Unable to generate HTML report containing log messages and exported data")
312 | generate().log("Unable to generate HTML report containing log messages and exported data")
313 | else:
314 | debug.debug("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
315 | dpath=path.join(registry().folder, enum().dump_storage)))
316 | generate().log("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
317 | dpath=path.join(registry().folder, enum().dump_storage)))
318 | self.scheck = []
319 | sleep(1)
320 | else:
321 | debug.debug("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
322 | generate().log("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
323 | return False
324 |
325 | def wpdbusenum(self):
326 | """
327 | This registry artifact is persistent so if the device is unplugged
328 | we cannot detect it with registry changes
329 |
330 | Path and variable associated with this function:
331 | > enum().path_wpdbusenum -- Registry path as string
332 | > enum().dump_wpdbusenum -- Name of export output
333 | """
334 | if enum().EnumWPDBUSENUM():
335 | debug.debug("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
336 | generate().log("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
337 | for data in enum().EnumWPDBUSENUM():
338 | self.fcheck.append(data)
339 |
340 | while True:
341 | for data in enum().EnumWPDBUSENUM():
342 | self.scheck.append(data)
343 |
344 | for change in set(self.fcheck).symmetric_difference(self.scheck):
345 | if len(self.fcheck) < len(self.scheck):
346 | if not change in self.results:
347 | debug.debug("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
348 | generate().log("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
349 | self.results.append(change)
350 | if registry().export("HKLM", enum().path_wpdbusenum, enum().dump_wpdbusenum)[0]:
351 | debug.debug("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
352 | dpath=path.join(registry().folder, enum().dump_wpdbusenum)))
353 | generate().log("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
354 | dpath=path.join(registry().folder, enum().dump_wpdbusenum)))
355 | if generate().report():
356 | debug.debug("Generated HTML report containing log messages and exported data")
357 | generate().log("Generated HTML report containing log messages and exported data")
358 | else:
359 | debug.debug("Unable to generate HTML report containing log messages and exported data")
360 | generate().log("Unable to generate HTML report containing log messages and exported data")
361 | else:
362 | debug.debug("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
363 | dpath=path.join(registry().folder, enum().dump_wpdbusenum)))
364 | generate().log("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
365 | dpath=path.join(registry().folder, enum().dump_wpdbusenum)))
366 | self.scheck = []
367 | sleep(1)
368 | else:
369 | debug.debug("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
370 | generate().log("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
371 | return False
372 |
373 | def usbstor(self):
374 | """
375 | This registry artifact is persistent so if the device is unplugged
376 | we cannot detect it with registry changes
377 |
378 | Path and variable associated with this function:
379 | > enum().path_usbstor -- Registry path as string
380 | > enum().dump_usbstor -- Name of export output
381 | """
382 | if enum().EnumUSBSTOR():
383 | debug.debug("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
384 | generate().log("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
385 | for data in enum().EnumUSBSTOR():
386 | self.fcheck.append(data)
387 |
388 | while True:
389 | for data in enum().EnumUSBSTOR():
390 | self.scheck.append(data)
391 |
392 | for change in set(self.fcheck).symmetric_difference(self.scheck):
393 | if len(self.fcheck) < len(self.scheck):
394 | if not change in self.results:
395 | debug.debug("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
396 | generate().log("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
397 | self.results.append(change)
398 | if registry().export("HKLM", enum().path_usbstor, enum().dump_usbstor)[0]:
399 | debug.debug("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
400 | dpath=path.join(registry().folder, enum().dump_usbstor)))
401 | generate().log("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
402 | dpath=path.join(registry().folder, enum().dump_usbstor)))
403 | if generate().report():
404 | debug.debug("Generated HTML report containing log messages and exported data")
405 | generate().log("Generated HTML report containing log messages and exported data")
406 | else:
407 | debug.debug("Unable to generate HTML report containing log messages and exported data")
408 | generate().log("Unable to generate HTML report containing log messages and exported data")
409 | else:
410 | debug.debug("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
411 | dpath=path.join(registry().folder, enum().dump_usbstor)))
412 | generate().log("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
413 | dpath=path.join(registry().folder, enum().dump_usbstor)))
414 | self.scheck = []
415 | sleep(1)
416 | else:
417 | debug.debug("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
418 | generate().log("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
419 | return False
420 |
421 | def usb(self):
422 | """
423 | This registry artifact is persistent so if the device is unplugged
424 | we cannot detect it with registry changes
425 |
426 | Path and variable associated with this function:
427 | > enum().path_usb -- Registry path as string
428 | > enum().dump_usb -- Name of export output
429 | """
430 | if enum().EnumUSB():
431 | debug.debug("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
432 | generate().log("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
433 | for data in enum().EnumUSB():
434 | self.fcheck.append(data)
435 |
436 | while True:
437 | for data in enum().EnumUSB():
438 | self.scheck.append(data)
439 |
440 | for change in set(self.fcheck).symmetric_difference(self.scheck):
441 | if len(self.fcheck) < len(self.scheck):
442 | if not change in self.results:
443 | debug.debug("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
444 | generate().log("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
445 | self.results.append(change)
446 | if registry().export("HKLM", enum().path_usb, enum().dump_usb)[0]:
447 | debug.debug("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
448 | dpath=path.join(registry().folder, enum().dump_usb)))
449 | generate().log("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
450 | dpath=path.join(registry().folder, enum().dump_usb)))
451 | if generate().report():
452 | debug.debug("Generated HTML report containing log messages and exported data")
453 | generate().log("Generated HTML report containing log messages and exported data")
454 | else:
455 | debug.debug("Unable to generate HTML report containing log messages and exported data")
456 | generate().log("Unable to generate HTML report containing log messages and exported data")
457 | else:
458 | debug.debug("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
459 | dpath=path.join(registry().folder, enum().dump_usb)))
460 | generate().log("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
461 | dpath=path.join(registry().folder, enum().dump_usb)))
462 | self.scheck = []
463 | sleep(1)
464 | else:
465 | debug.debug("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
466 | generate().log("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
467 | return False
468 |
469 | def wpd(self):
470 | """
471 | This registry artifact is persistent so if the device is unplugged
472 | we cannot detect it with registry changes
473 |
474 | Path and variable associated with this function:
475 | > enum().path_wpd -- Registry path as string
476 | > enum().dump_wpd -- Name of export output
477 | """
478 | if enum().EnumWPD():
479 | debug.debug("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
480 | generate().log("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
481 | for data in enum().EnumWPD():
482 | self.fcheck.append(data)
483 |
484 | while True:
485 | for data in enum().EnumWPD():
486 | self.scheck.append(data)
487 |
488 | for change in set(self.fcheck).symmetric_difference(self.scheck):
489 | if len(self.fcheck) < len(self.scheck):
490 | if not change in self.results:
491 | debug.debug("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
492 | generate().log("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
493 | self.results.append(change)
494 | if registry().export("HKLM", enum().path_wpd, enum().dump_wpd)[0]:
495 | debug.debug("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
496 | dpath=path.join(registry().folder, enum().dump_wpd)))
497 | generate().log("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
498 | dpath=path.join(registry().folder, enum().dump_wpd)))
499 | if generate().report():
500 | debug.debug("Generated HTML report containing log messages and exported data")
501 | generate().log("Generated HTML report containing log messages and exported data")
502 | else:
503 | debug.debug("Unable to generate HTML report containing log messages and exported data")
504 | generate().log("Unable to generate HTML report containing log messages and exported data")
505 | else:
506 | debug.debug("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
507 | dpath=path.join(registry().folder, enum().dump_wpd)))
508 | generate().log("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
509 | dpath=path.join(registry().folder, enum().dump_wpd)))
510 | self.scheck = []
511 | sleep(1)
512 | else:
513 | debug.debug("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
514 | generate().log("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
515 | return False
516 |
517 | def knowndevices(self):
518 | """
519 | This registry artifact is persistent so if the device is unplugged
520 | we cannot detect it with registry changes
521 |
522 | Path and variable associated with this function:
523 | > enum().path_knowndevices -- Registry path as string
524 | > enum().dump_knowndevices -- Name of export output
525 | """
526 | if enum().EnumKnownDevices():
527 | debug.debug("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
528 | generate().log("Monitoring function ({fname}) is running".format(fname=_getframe().f_code.co_name))
529 | for data in enum().EnumKnownDevices():
530 | self.fcheck.append(data)
531 |
532 | while True:
533 | for data in enum().EnumKnownDevices():
534 | self.scheck.append(data)
535 |
536 | for change in set(self.fcheck).symmetric_difference(self.scheck):
537 | if len(self.fcheck) < len(self.scheck):
538 | if not change in self.results:
539 | debug.debug("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
540 | generate().log("Function ({fname}) detected a change ({change})".format(fname=_getframe().f_code.co_name, change=change))
541 | self.results.append(change)
542 | if registry().export("HKLM", enum().path_knowndevices, enum().dump_knowndevices)[0]:
543 | debug.debug("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
544 | dpath=path.join(registry().folder, enum().dump_knowndevices)))
545 | generate().log("Exported {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
546 | dpath=path.join(registry().folder, enum().dump_knowndevices)))
547 | if generate().report():
548 | debug.debug("Generated HTML report containing log messages and exported data")
549 | generate().log("Generated HTML report containing log messages and exported data")
550 | else:
551 | debug.debug("Unable to generate HTML report containing log messages and exported data")
552 | generate().log("Unable to generate HTML report containing log messages and exported data")
553 | else:
554 | debug.debug("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
555 | dpath=path.join(registry().folder, enum().dump_knowndevices)))
556 | generate().log("Unable to export {fname} data to ({dpath}) directory".format(fname=_getframe().f_code.co_name,
557 | dpath=path.join(registry().folder, enum().dump_knowndevices)))
558 | self.scheck = []
559 | sleep(1)
560 | else:
561 | debug.debug("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
562 | generate().log("Monitoring function ({fname}) stopped, returned False".format(fname=_getframe().f_code.co_name))
563 | return False
--------------------------------------------------------------------------------
/bustr/core/parser.py:
--------------------------------------------------------------------------------
1 | from os import path
2 | from sys import _getframe
3 | import logging
4 |
5 | logging.basicConfig(level=logging.DEBUG)
6 | debug = logging.getLogger(" parse_debugger ")
7 | debug.disabled = True
8 |
9 | class parse:
10 | """ Class to parse exported registry files """
11 | def __init__(self):
12 | self.logdata = []
13 | self.regdata = []
14 |
15 | def debug(self):
16 | """ Disable stdout to console window """
17 | debug.disabled = False
18 |
19 | def logfile(self, file):
20 | """ Return received file data to function """
21 | debug.debug("Checking if file exists")
22 | if path.isfile(path.join(file)):
23 | debug.debug("File detected, attempting to read file data")
24 | try:
25 | with open(path.join(file), "r") as f:
26 | data = f.readlines()
27 | except Exception as error:
28 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
29 | return False
30 | else:
31 | debug.debug("Appended ({data}) to logdata list".format(data=data))
32 | self.logdata.append(data)
33 | return self.logdata
34 | else:
35 | debug.debug("Log file does not exist")
36 | return False
37 |
38 | def regfile(self, file):
39 | """ Return received file data to function """
40 | debug.debug("Checking if file exists")
41 | if path.isfile(path.join(file)):
42 | debug.debug("Registry file detected, attempting to read file data")
43 | try:
44 | with open(path.join(file), "r", encoding="utf-8") as f:
45 | data = str(f.read())
46 | except UnicodeDecodeError:
47 | with open(path.join(file), "r", encoding="utf-16") as f:
48 | data = str(f.read())
49 |
50 | debug.debug("Attempting to split and sanitize the registry data")
51 | for d in data.split():
52 | self.regdata.append(d.replace('"="', " ").replace('"=', " ").strip('"').split())
53 |
54 | debug.debug("Appended ({data}) to regdata list".format(data=self.regdata))
55 | return self.regdata
56 | else:
57 | debug.debug("Registry file does not exist")
58 | return False
--------------------------------------------------------------------------------
/bustr/core/utils.py:
--------------------------------------------------------------------------------
1 | from winsound import Beep
2 | from sys import _getframe
3 | import ctypes
4 | import logging
5 |
6 | logging.basicConfig(level=logging.DEBUG)
7 | debug = logging.getLogger(" utils_debugger ")
8 | debug.disabled = True
9 |
10 | class utils:
11 | def __init__(self):
12 | self.frequency = 2500
13 | self.duration = 1000
14 |
15 | def debug(self):
16 | """ Disable stdout to console window """
17 | debug.disabled = False
18 |
19 | def hide(self):
20 | """ Hide the console window """
21 | debug.debug("Attempting to hide console window using Windows API ShowWindow")
22 | try:
23 | ctypes.windll.user32.ShowWindow(ctypes.windll.kernel32.GetConsoleWindow(),0)
24 | except Exception as error:
25 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
26 | return False
27 | else:
28 | debug.debug("Successfully hidden console window using Windows API ShowWindow")
29 | return True
30 |
31 | def lock(self):
32 | """ Locks the running system (Mimics CTRL+ALT+DEL > Lock) """
33 | debug.debug("Attempting to lock running system mimicking CTRL+ALT+DEL > Lock")
34 | if ctypes.windll.user32.LockWorkStation() == 0:
35 | debug.debug("Unable to lock system using Windows API LockWorkStation")
36 | return False
37 | else:
38 | debug.debug("Successfully locked system using Windows API LockWorkStation")
39 | return False
40 |
41 | def beep(self):
42 | """ Sends a high pitched beep for 1 second """
43 | debug.debug("Attempting to send a high pitched beep")
44 | try:
45 | Beep(self.frequency, self.duration)
46 | except RuntimeError as error:
47 | debug.debug("Exception in function ({fname}) error message ({error})".format(fname=_getframe().f_code.co_name, error=error))
48 | return False
49 | else:
50 | debug.debug("Successfully sent high pitched beep")
51 | return True
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | from bustr.core.monitor import monitor
2 | from bustr.core.generate import generate
3 | from bustr.core.enums import enum
4 | from bustr.core.utils import utils
5 | from bustr.core.export import registry
6 | from bustr.core.parser import parse
7 | from multiprocessing import Pool, freeze_support
8 | import argparse
9 |
10 | #enum().debug()
11 | #generate().debug()
12 | #utils().debug()
13 | #monitor().debug()
14 | #registry().debug()
15 | #parse().debug()
16 |
17 | if __name__ == "__main__":
18 | """ Support if being compiled to executable """
19 | freeze_support()
20 |
21 | """ Script and executable arguments """
22 | parser = argparse.ArgumentParser()
23 | parser.add_argument("-m", "--monitor", action="store_true", help="monitor registry artifacts in real-time and log the results", required=False)
24 | parser.add_argument("-q", "--quite", action="store_true", help="hides the console window, logging is still active", required=False)
25 | parser.add_argument("-r", "--report", action="store_true", help="parse logs and exported data and generate HTML report", required=False)
26 | args = parser.parse_args()
27 |
28 | """ Hide the console window """
29 | if args.quite:
30 | utils().hide()
31 |
32 | """ Parse through logs and exported data and generate a
33 | HTML file using simple tables """
34 | if args.report:
35 | with Pool(processes=1) as pool:
36 | p = pool.apply_async(generate().report,())
37 | p.wait()
38 |
39 | """ Multiple watchdogs """
40 | if args.monitor:
41 | watchdogs = {"mounteddevices" : monitor().mounteddevices,
42 | "knowndevices" : monitor().knowndevices,
43 | "mountpoints" : monitor().mountpoints,
44 | "wpdbusenum" : monitor().wpdbusenum,
45 | "storage" : monitor().storage,
46 | "usbstor" : monitor().usbstor,
47 | "bthport" : monitor().bthport,
48 | "bthenum" : monitor().bthenum,
49 | "scsi" : monitor().scsi,
50 | "wpd" : monitor().wpd,
51 | "usb" : monitor().usb}
52 |
53 | jobs = 0
54 | with Pool(processes=len(watchdogs)) as pool:
55 | for function in watchdogs:
56 | p = pool.apply_async(watchdogs[function],())
57 | jobs += 1
58 | if jobs == len(watchdogs):
59 | p.wait()
--------------------------------------------------------------------------------