Skip to content

Commit

Permalink
Bluetooth details (#160)
Browse files Browse the repository at this point in the history
## Pull Request Template

### Prerequisites

<!-- Take a couple of minutes to help our maintainers work faster by
checking of the pre-requisites. -->
<!-- To tick the checkboxes replace the space with an 'x', so [ ]
becomes [x] . -->

- [x] I have
[searched](https://github.com/DefinetlyNotAI/Logicytics/pulls) for
duplicate or closed issues.
- [x] I have read the [contributing
guidelines](https://github.com/DefinetlyNotAI/Logicytics/blob/main/CONTRIBUTING.md).
- [x] I have followed the instructions in the
[wiki](https://github.com/DefinetlyNotAI/Logicytics/wiki) about
contributions.
- [x] I have updated the documentation accordingly, if required.
- [x] I have tested my code with the `--dev` flag, if required.

### PR Type

<!-- Take a couple of minutes to help our maintainers work faster by
telling us what is the PR guided on. -->
<!-- To tick the checkboxes replace the space with an 'x', so [ ]
becomes [x] . -->

- [x] Bug fix <!-- Non-Breaking Bug Fix - Usually relates to fixing an
issue -->
- [x] New feature <!-- Non-Breaking Change that adds a new feature -->
- [x] Refactoring <!-- Non-Breaking Change that modifies existing code
to refactor it to become more organised -->
- [ ] Documentation
update <!-- Non-Breaking Change that modifies existing documentation to
refactor it or add extra comments - either wiki, md files or code is
included here -->
- [ ] ⚠️ Breaking change ⚠️ <!-- Breaking Bug Fix / New Addition that
changes how Logicytics works -->

### Description

Retrieves and logs detailed information about Bluetooth devices on the
system.

The function connects to the Windows Management Instrumentation (WMI)
service and queries for devices
whose names contain the term 'Bluetooth'. It writes the information to a
text file named 'Bluetooth Info.txt'.

    Information for each device includes:
    - Name
    - Device ID
    - Description
    - Manufacturer
    - Status
    - PNP Device ID

<!-- REQUIRED: Provide a summary of the PR and what you expected to
happen. -->

### Motivation and Context

I thought that giving logicytics bluetooth capabilities would be a
really good addition.

<!-- REQUIRED: Why is this PR required? What problem does it solve? Why
do you want to do it? -->

### Credit

<!-- If this PR is a contribution, please mention the contributors here
using the appropriate syntax. -->

<!--
### File-Created/CONTRIBUTION by MAIN-Username
What you did, created, removed, refactored, fixed, or discovered.
- [Your GitHub Username](https://github.com/YourGitHubLink)
- [Your GitHub Username](https://github.com/YourGitHubLink) etc...
-->
_N/A_

### Issues Fixed

<!-- REQUIRED: What issues will be fixed? (Format: "#50, #23" etc.) if
none exist type _N/A_ -->
_N/A_

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Introduced a script to retrieve and log detailed information about
Bluetooth devices on Windows.
- Added functionality for collecting and logging Bluetooth-related data,
including paired devices and event logs.

- **Bug Fixes**
	- Enhanced error handling and logging in packet sniffing functionality.

- **Chores**
	- Updated version number in configuration file.
	- Modified dependencies in requirements by adding new packages.
	- Excluded virtual environment folder from project configuration.
- Assigned code ownership for `bluetooth_details.py` and
`bluetooth_logger.py`.
- Updated documentation to reflect new Bluetooth data handling
capabilities.
	- Removed outdated CSV editor configuration file.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
DefinetlyNotAI authored Dec 16, 2024
2 parents 72c0a43 + 6f06fd8 commit 448a35b
Show file tree
Hide file tree
Showing 11 changed files with 282 additions and 49 deletions.
4 changes: 3 additions & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
* @DefinetlyNotAI
wifi_stealer.py @ski-sketch
packet_sniffer.py @ski-sketch
packet_sniffer.py @ski-sketch
bluetooth_details.py @ski-sketch
bluetooth_logger.py @ski-sketch
1 change: 1 addition & 0 deletions .idea/Logicytics.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 0 additions & 16 deletions .idea/csv-editor.xml

This file was deleted.

30 changes: 15 additions & 15 deletions CODE/Logicytics.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,14 @@ def get_flags():
If the flags are not a tuple, it prints the help message and exits the program.
"""
global ACTION, SUB_ACTION
if isinstance(Flag.data(), tuple):
global ACTION, SUB_ACTION
try:
# Get flags
ACTION, SUB_ACTION = Flag.data()
except Exception:
ACTIONS = Flag.data()
ACTION = ACTIONS[0]
except ValueError:
actions = Flag.data()
ACTION = actions[0]
SUB_ACTION = None
else:
parser = Flag.data()
Expand Down Expand Up @@ -274,12 +274,12 @@ def threaded_execution(execution_list_thread, index_thread):

log.debug("Using threading")
threads = []
EXECUTION_LIST = generate_execution_list()
for index, file in enumerate(EXECUTION_LIST):
execution_list = generate_execution_list()
for index, _ in enumerate(execution_list):
thread = threading.Thread(
target=threaded_execution,
args=(
EXECUTION_LIST,
execution_list,
index,
),
)
Expand All @@ -290,14 +290,14 @@ def threaded_execution(execution_list_thread, index_thread):
thread.join()
elif ACTION == "performance_check":
execution_times = []
EXECUTION_LIST = generate_execution_list()
for file in range(len(EXECUTION_LIST)):
execution_list = generate_execution_list()
for file in range(len(execution_list)):
start_time = datetime.now()
log.parse_execution(Execute.script(EXECUTION_LIST[file]))
log.parse_execution(Execute.script(execution_list[file]))
end_time = datetime.now()
elapsed_time = end_time - start_time
execution_times.append((file, elapsed_time))
log.info(f"{EXECUTION_LIST[file]} executed in {elapsed_time}")
log.info(f"{execution_list[file]} executed in {elapsed_time}")

table = PrettyTable()
table.field_names = ["Script", "Execution Time"]
Expand All @@ -313,10 +313,10 @@ def threaded_execution(execution_list_thread, index_thread):
log.info("Performance check complete! Performance log found in ACCESS/LOGS/PERFORMANCE")
else:
try:
EXECUTION_LIST = generate_execution_list()
for file in range(len(EXECUTION_LIST)): # Loop through List
log.parse_execution(Execute.script(EXECUTION_LIST[file]))
log.info(f"{EXECUTION_LIST[file]} executed")
execution_list = generate_execution_list()
for script in execution_list: # Loop through List
log.parse_execution(Execute.script(script))
log.info(f"{script} executed")
except UnicodeDecodeError as e:
log.error(f"Error in code: {e}")
except Exception as e:
Expand Down
19 changes: 15 additions & 4 deletions CODE/_dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def _prompt_user(question: str, file_to_open: str = None, special: bool = False)
"""
try:
answer = input(question + " (yes or no):- ")
if answer.lower() != "yes":
if answer.lower() != "yes" or answer.lower() != "y":
if file_to_open:
subprocess.run(["start", file_to_open], shell=True)
if not special:
Expand Down Expand Up @@ -88,9 +88,20 @@ def dev_checks() -> None:

# Get the list of code files in the current directory
files = Get.list_of_code_files(".")
added_files = [f.replace('"', '') for f in files if f not in CURRENT_FILES]
removed_files = [f.replace('"', '') for f in CURRENT_FILES if f not in files]
normal_files = [f.replace('"', '') for f in files if f in CURRENT_FILES]
added_files, removed_files, normal_files = [], [], []
clean_files_list = [file.replace('"', '') for file in CURRENT_FILES]

for f in files:
clean_f = f.replace('"', '')
if clean_f in clean_files_list:
normal_files.append(clean_f)
else:
added_files.append(clean_f)

for f in clean_files_list:
clean_f = f.replace('"', '')
if clean_f not in files:
removed_files.append(clean_f)

# Print the list of added, removed, and normal files in color
print("\n".join([f"\033[92m+ {file}\033[0m" for file in added_files])) # Green +
Expand Down
119 changes: 119 additions & 0 deletions CODE/bluetooth_details.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import subprocess
import json
from logicytics import Log, DEBUG

if __name__ == "__main__":
log = Log({"log_level": DEBUG})


def get_bluetooth_device_details():
"""
Retrieves and logs detailed information about Bluetooth devices on the system.
The function runs a PowerShell command to query devices whose names contain the term 'Bluetooth'.
It writes the information to a text file named 'Bluetooth Info.txt'.
Information for each device includes:
- Name
- Device ID
- Description
- Manufacturer
- Status
- PNP Device ID
Logs errors if any issues are encountered during the process.
Returns:
None
"""
log.info("Fetching detailed info for Bluetooth devices...")
try:
devices = _query_bluetooth_devices()
_write_device_info_to_file(devices, "Bluetooth Info.txt")
except Exception as e:
log.error(f"Error: {e}")
exit(1)


def _query_bluetooth_devices():
"""
Queries the system for Bluetooth devices using PowerShell commands.
Returns:
list: A list of device information dictionaries.
"""
try:
# Run PowerShell command to get Bluetooth devices
command = (
"Get-PnpDevice | Where-Object { $_.FriendlyName -like '*Bluetooth*' } | "
"Select-Object FriendlyName, DeviceID, Description, Manufacturer, Status, PnpDeviceID | "
"ConvertTo-Json -Depth 3"
)
result = subprocess.run(["powershell", "-Command", command], capture_output=True, text=True, check=True)
devices = json.loads(result.stdout)
except subprocess.CalledProcessError as e:
log.error(f"Failed to query Bluetooth devices: {e}")
exit(1)
except json.JSONDecodeError as e:
log.error(f"Failed to parse device information: {e}")
exit(1)

if isinstance(devices, dict):
devices = [devices] # Handle single result case

device_info_list = []
for device in devices:
device_info = {
'Name': device.get('FriendlyName', 'Unknown'),
'Device ID': device.get('DeviceID', 'Unknown'),
'Description': device.get('Description', 'Unknown'),
'Manufacturer': device.get('Manufacturer', 'Unknown'),
'Status': device.get('Status', 'Unknown'),
'PNP Device ID': device.get('PnpDeviceID', 'Unknown')
}
log.debug(f"Retrieved device: {device_info['Name']}")
device_info_list.append(device_info)

return device_info_list


def _write_device_info_to_file(devices, filename):
"""
Writes the details of the Bluetooth devices to a file.
Args:
devices (list): List of device information dictionaries.
filename (str): Name of the file to write to.
Returns:
None
"""
try:
with open(filename, "w", encoding="UTF-8") as file:
for device_info in devices:
_write_single_device_info(file, device_info)
except Exception as e:
log.error(f"Failed to write device information to file: {e}")
exit(1)


def _write_single_device_info(file, device_info):
"""
Writes information for a single Bluetooth device to the file.
Args:
file (TextIO): File object to write to.
device_info (dict): Dictionary containing device information.
Returns:
None
"""
file.write(f"Name: {device_info.get('Name', 'Unknown')}\n")
for key, value in device_info.items():
if key != 'Name':
file.write(f" {key}: {value}\n")
file.write("\n") # Separate devices with a blank line


if __name__ == "__main__":
get_bluetooth_device_details()
109 changes: 109 additions & 0 deletions CODE/bluetooth_logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import subprocess
import re
import datetime
from logicytics import Log, DEBUG

if __name__ == "__main__":
log = Log({"log_level": DEBUG})


# Utility function to log data to a file
def save_to_file(filename, section_title, data):
"""Logs data to a text file with a section title."""
try:
with open(filename, 'a', encoding='utf-8') as file:
file.write(f"\n{'=' * 50}\n{section_title}\n{'=' * 50}\n")
file.write(f"{data}\n" if isinstance(data, str) else "\n".join(data) + "\n")
file.write(f"{'=' * 50}\n")
except Exception as e:
log.error(f"Error writing to file {filename}: {e}")


# Utility function to run PowerShell commands
def run_powershell_command(command):
"""Runs a PowerShell command and returns the output."""
try:
result = subprocess.run(["powershell", "-Command", command], capture_output=True, text=True)
if result.returncode != 0:
log.error(f"PowerShell command failed with return code {result.returncode}")
return []
return result.stdout.splitlines()
except Exception as e:
log.error(f"Error running PowerShell command: {e}")
return []


# Unified parsing function for PowerShell output
def parse_output(lines, regex, group_names):
"""Parses command output using a regex and extracts specified groups."""
results = []
for line in lines:
match = re.match(regex, line)
if match:
results.append({name: match.group(name) for name in group_names})
else:
log.debug(f"Skipping unrecognized line: {line}")
return results


# Function to get paired Bluetooth devices
def get_paired_bluetooth_devices():
"""Retrieves paired Bluetooth devices with names and MAC addresses."""
command = (
'Get-PnpDevice -Class Bluetooth | Where-Object { $_.Status -eq "OK" } | Select-Object Name, DeviceID'
)
output = run_powershell_command(command)
log.debug(f"Raw PowerShell output for paired devices:\n{output}")

devices = parse_output(
output,
regex=r"^(?P<Name>.+?)\s+(?P<DeviceID>.+)$",
group_names=["Name", "DeviceID"]
)

# Extract MAC addresses
for device in devices:
mac_match = re.search(r"BLUETOOTHDEVICE_(?P<MAC>[A-F0-9]{12})", device["DeviceID"], re.IGNORECASE)
device["MAC"] = mac_match.group("MAC") if mac_match else "Address Not Found"

return [f"Name: {device['Name']}, MAC: {device['MAC']}" for device in devices]


# Function to log all Bluetooth data
def log_bluetooth():
"""Logs Bluetooth device data and event logs."""
log.info("Starting Bluetooth data logging...")
filename = "bluetooth_data.txt"
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
save_to_file(filename, "Bluetooth Data Collection - Timestamp", timestamp)

# Collect and log paired devices
log.info(f"Collecting paired devices...")
paired_devices = get_paired_bluetooth_devices()
section_title = "Paired Bluetooth Devices"
save_to_file(filename, section_title, paired_devices or ["No paired Bluetooth devices found."])
log.debug(f"{section_title}: {paired_devices}")

# Collect and log event logs
def collect_logs(title, command):
logs = run_powershell_command(command)
save_to_file(filename, title, logs or ["No logs found."])
log.info(f"Getting {title}...")

collect_logs(
"Bluetooth Connection/Disconnection Logs",
'Get-WinEvent -LogName "Microsoft-Windows-Bluetooth-BthLEServices/Operational" '
'| Select-Object TimeCreated, Id, Message | Format-Table -AutoSize'
)

collect_logs(
"Bluetooth File Transfer Logs",
'Get-WinEvent -LogName "Microsoft-Windows-Bluetooth-BthLEServices/Operational" '
'| Select-String -Pattern "file.*transferred" | Format-Table -AutoSize'
)

log.info("Finished Bluetooth data logging.")


if __name__ == "__main__":
log_bluetooth()
4 changes: 2 additions & 2 deletions CODE/config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ delete_old_logs = false

[System Settings]
# Do not play with these settings unless you know what you are doing
version = 3.1.0
files = "browser_miner.ps1, cmd_commands.py, dir_list.py, dump_memory.py, event_log.py, Logicytics.py, log_miner.py, media_backup.py, netadapter.ps1, packet_sniffer.py, property_scraper.ps1, registry.py, sensitive_data_miner.py, ssh_miner.py, sys_internal.py, tasklist.py, tree.ps1, vulnscan.py, wifi_stealer.py, window_feature_miner.ps1, wmic.py, _debug.py, _dev.py, _extra.py, logicytics\Checks.py, logicytics\Execute.py, logicytics\FileManagement.py, logicytics\Flag.py, logicytics\Get.py, logicytics\Logger.py, logicytics\__init__.py, VulnScan\tools\_study_network.py, VulnScan\tools\_test_gpu_acceleration.py, VulnScan\tools\_vectorizer.py, VulnScan\v2-deprecated\_generate_data.py, VulnScan\v2-deprecated\_train.py, VulnScan\v3\_generate_data.py, VulnScan\v3\_train.py"
version = 3.1.1
files = "bluetooth_details.py, bluetooth_logger.py, browser_miner.ps1, cmd_commands.py, dir_list.py, dump_memory.py, event_log.py, Logicytics.py, log_miner.py, media_backup.py, netadapter.ps1, packet_sniffer.py, property_scraper.ps1, registry.py, sensitive_data_miner.py, ssh_miner.py, sys_internal.py, tasklist.py, tree.ps1, vulnscan.py, wifi_stealer.py, window_feature_miner.ps1, wmic.py, _debug.py, _dev.py, _extra.py, logicytics\Checks.py, logicytics\Execute.py, logicytics\FileManagement.py, logicytics\Flag.py, logicytics\Get.py, logicytics\Logger.py, logicytics\__init__.py, VulnScan\tools\_study_network.py, VulnScan\tools\_test_gpu_acceleration.py, VulnScan\tools\_vectorizer.py, VulnScan\v2-deprecated\_generate_data.py, VulnScan\v2-deprecated\_train.py, VulnScan\v3\_generate_data.py, VulnScan\v3\_train.py"

###################################################
# The following settings are for specific modules #
Expand Down
Loading

0 comments on commit 448a35b

Please sign in to comment.