├── 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 | ![bustr](https://i.imgur.com/DJUg7Oj.jpg) 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("\n

Monitoring 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("\n") 102 | else: 103 | report.write("\n") 104 | else: 105 | report.write("\n") 106 | report.write("\n") 107 | report.write("
" + d.strip("\n") + "
No available dataNo available data
\n") 108 | else: 109 | report.write("\n") 110 | report.write("\n") 111 | report.write("\n") 112 | report.write("\n") 113 | report.write("
No available data
\n") 114 | 115 | report.write("\n

Exported 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("\n") 127 | if len(data[l]) == 2: 128 | report.write("\n") 129 | else: 130 | report.write("\n") 131 | else: 132 | report.write("\n") 133 | else: 134 | report.write("
" + data[l][0] + "
" + data[l][0] + " : " + data[l][1] + "
No available dataNo available data
\n") 135 | report.write("\n") 136 | report.write("\n") 137 | report.write("\n") 138 | report.write("
No available data
\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() --------------------------------------------------------------------------------