Skip to content

Commit 448a35b

Browse files
Bluetooth details (#160)
## 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 -->
2 parents 72c0a43 + 6f06fd8 commit 448a35b

File tree

11 files changed

+282
-49
lines changed

11 files changed

+282
-49
lines changed

.github/CODEOWNERS

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
* @DefinetlyNotAI
22
wifi_stealer.py @ski-sketch
3-
packet_sniffer.py @ski-sketch
3+
packet_sniffer.py @ski-sketch
4+
bluetooth_details.py @ski-sketch
5+
bluetooth_logger.py @ski-sketch

.idea/Logicytics.iml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/csv-editor.xml

Lines changed: 0 additions & 16 deletions
This file was deleted.

CODE/Logicytics.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,14 @@ def get_flags():
8383
If the flags are not a tuple, it prints the help message and exits the program.
8484
8585
"""
86+
global ACTION, SUB_ACTION
8687
if isinstance(Flag.data(), tuple):
87-
global ACTION, SUB_ACTION
8888
try:
8989
# Get flags
9090
ACTION, SUB_ACTION = Flag.data()
91-
except Exception:
92-
ACTIONS = Flag.data()
93-
ACTION = ACTIONS[0]
91+
except ValueError:
92+
actions = Flag.data()
93+
ACTION = actions[0]
9494
SUB_ACTION = None
9595
else:
9696
parser = Flag.data()
@@ -274,12 +274,12 @@ def threaded_execution(execution_list_thread, index_thread):
274274

275275
log.debug("Using threading")
276276
threads = []
277-
EXECUTION_LIST = generate_execution_list()
278-
for index, file in enumerate(EXECUTION_LIST):
277+
execution_list = generate_execution_list()
278+
for index, _ in enumerate(execution_list):
279279
thread = threading.Thread(
280280
target=threaded_execution,
281281
args=(
282-
EXECUTION_LIST,
282+
execution_list,
283283
index,
284284
),
285285
)
@@ -290,14 +290,14 @@ def threaded_execution(execution_list_thread, index_thread):
290290
thread.join()
291291
elif ACTION == "performance_check":
292292
execution_times = []
293-
EXECUTION_LIST = generate_execution_list()
294-
for file in range(len(EXECUTION_LIST)):
293+
execution_list = generate_execution_list()
294+
for file in range(len(execution_list)):
295295
start_time = datetime.now()
296-
log.parse_execution(Execute.script(EXECUTION_LIST[file]))
296+
log.parse_execution(Execute.script(execution_list[file]))
297297
end_time = datetime.now()
298298
elapsed_time = end_time - start_time
299299
execution_times.append((file, elapsed_time))
300-
log.info(f"{EXECUTION_LIST[file]} executed in {elapsed_time}")
300+
log.info(f"{execution_list[file]} executed in {elapsed_time}")
301301

302302
table = PrettyTable()
303303
table.field_names = ["Script", "Execution Time"]
@@ -313,10 +313,10 @@ def threaded_execution(execution_list_thread, index_thread):
313313
log.info("Performance check complete! Performance log found in ACCESS/LOGS/PERFORMANCE")
314314
else:
315315
try:
316-
EXECUTION_LIST = generate_execution_list()
317-
for file in range(len(EXECUTION_LIST)): # Loop through List
318-
log.parse_execution(Execute.script(EXECUTION_LIST[file]))
319-
log.info(f"{EXECUTION_LIST[file]} executed")
316+
execution_list = generate_execution_list()
317+
for script in execution_list: # Loop through List
318+
log.parse_execution(Execute.script(script))
319+
log.info(f"{script} executed")
320320
except UnicodeDecodeError as e:
321321
log.error(f"Error in code: {e}")
322322
except Exception as e:

CODE/_dev.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def _prompt_user(question: str, file_to_open: str = None, special: bool = False)
4848
"""
4949
try:
5050
answer = input(question + " (yes or no):- ")
51-
if answer.lower() != "yes":
51+
if answer.lower() != "yes" or answer.lower() != "y":
5252
if file_to_open:
5353
subprocess.run(["start", file_to_open], shell=True)
5454
if not special:
@@ -88,9 +88,20 @@ def dev_checks() -> None:
8888

8989
# Get the list of code files in the current directory
9090
files = Get.list_of_code_files(".")
91-
added_files = [f.replace('"', '') for f in files if f not in CURRENT_FILES]
92-
removed_files = [f.replace('"', '') for f in CURRENT_FILES if f not in files]
93-
normal_files = [f.replace('"', '') for f in files if f in CURRENT_FILES]
91+
added_files, removed_files, normal_files = [], [], []
92+
clean_files_list = [file.replace('"', '') for file in CURRENT_FILES]
93+
94+
for f in files:
95+
clean_f = f.replace('"', '')
96+
if clean_f in clean_files_list:
97+
normal_files.append(clean_f)
98+
else:
99+
added_files.append(clean_f)
100+
101+
for f in clean_files_list:
102+
clean_f = f.replace('"', '')
103+
if clean_f not in files:
104+
removed_files.append(clean_f)
94105

95106
# Print the list of added, removed, and normal files in color
96107
print("\n".join([f"\033[92m+ {file}\033[0m" for file in added_files])) # Green +

CODE/bluetooth_details.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import subprocess
2+
import json
3+
from logicytics import Log, DEBUG
4+
5+
if __name__ == "__main__":
6+
log = Log({"log_level": DEBUG})
7+
8+
9+
def get_bluetooth_device_details():
10+
"""
11+
Retrieves and logs detailed information about Bluetooth devices on the system.
12+
13+
The function runs a PowerShell command to query devices whose names contain the term 'Bluetooth'.
14+
It writes the information to a text file named 'Bluetooth Info.txt'.
15+
16+
Information for each device includes:
17+
- Name
18+
- Device ID
19+
- Description
20+
- Manufacturer
21+
- Status
22+
- PNP Device ID
23+
24+
Logs errors if any issues are encountered during the process.
25+
26+
Returns:
27+
None
28+
"""
29+
log.info("Fetching detailed info for Bluetooth devices...")
30+
try:
31+
devices = _query_bluetooth_devices()
32+
_write_device_info_to_file(devices, "Bluetooth Info.txt")
33+
except Exception as e:
34+
log.error(f"Error: {e}")
35+
exit(1)
36+
37+
38+
def _query_bluetooth_devices():
39+
"""
40+
Queries the system for Bluetooth devices using PowerShell commands.
41+
42+
Returns:
43+
list: A list of device information dictionaries.
44+
"""
45+
try:
46+
# Run PowerShell command to get Bluetooth devices
47+
command = (
48+
"Get-PnpDevice | Where-Object { $_.FriendlyName -like '*Bluetooth*' } | "
49+
"Select-Object FriendlyName, DeviceID, Description, Manufacturer, Status, PnpDeviceID | "
50+
"ConvertTo-Json -Depth 3"
51+
)
52+
result = subprocess.run(["powershell", "-Command", command], capture_output=True, text=True, check=True)
53+
devices = json.loads(result.stdout)
54+
except subprocess.CalledProcessError as e:
55+
log.error(f"Failed to query Bluetooth devices: {e}")
56+
exit(1)
57+
except json.JSONDecodeError as e:
58+
log.error(f"Failed to parse device information: {e}")
59+
exit(1)
60+
61+
if isinstance(devices, dict):
62+
devices = [devices] # Handle single result case
63+
64+
device_info_list = []
65+
for device in devices:
66+
device_info = {
67+
'Name': device.get('FriendlyName', 'Unknown'),
68+
'Device ID': device.get('DeviceID', 'Unknown'),
69+
'Description': device.get('Description', 'Unknown'),
70+
'Manufacturer': device.get('Manufacturer', 'Unknown'),
71+
'Status': device.get('Status', 'Unknown'),
72+
'PNP Device ID': device.get('PnpDeviceID', 'Unknown')
73+
}
74+
log.debug(f"Retrieved device: {device_info['Name']}")
75+
device_info_list.append(device_info)
76+
77+
return device_info_list
78+
79+
80+
def _write_device_info_to_file(devices, filename):
81+
"""
82+
Writes the details of the Bluetooth devices to a file.
83+
84+
Args:
85+
devices (list): List of device information dictionaries.
86+
filename (str): Name of the file to write to.
87+
88+
Returns:
89+
None
90+
"""
91+
try:
92+
with open(filename, "w", encoding="UTF-8") as file:
93+
for device_info in devices:
94+
_write_single_device_info(file, device_info)
95+
except Exception as e:
96+
log.error(f"Failed to write device information to file: {e}")
97+
exit(1)
98+
99+
100+
def _write_single_device_info(file, device_info):
101+
"""
102+
Writes information for a single Bluetooth device to the file.
103+
104+
Args:
105+
file (TextIO): File object to write to.
106+
device_info (dict): Dictionary containing device information.
107+
108+
Returns:
109+
None
110+
"""
111+
file.write(f"Name: {device_info.get('Name', 'Unknown')}\n")
112+
for key, value in device_info.items():
113+
if key != 'Name':
114+
file.write(f" {key}: {value}\n")
115+
file.write("\n") # Separate devices with a blank line
116+
117+
118+
if __name__ == "__main__":
119+
get_bluetooth_device_details()

CODE/bluetooth_logger.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import subprocess
2+
import re
3+
import datetime
4+
from logicytics import Log, DEBUG
5+
6+
if __name__ == "__main__":
7+
log = Log({"log_level": DEBUG})
8+
9+
10+
# Utility function to log data to a file
11+
def save_to_file(filename, section_title, data):
12+
"""Logs data to a text file with a section title."""
13+
try:
14+
with open(filename, 'a', encoding='utf-8') as file:
15+
file.write(f"\n{'=' * 50}\n{section_title}\n{'=' * 50}\n")
16+
file.write(f"{data}\n" if isinstance(data, str) else "\n".join(data) + "\n")
17+
file.write(f"{'=' * 50}\n")
18+
except Exception as e:
19+
log.error(f"Error writing to file {filename}: {e}")
20+
21+
22+
# Utility function to run PowerShell commands
23+
def run_powershell_command(command):
24+
"""Runs a PowerShell command and returns the output."""
25+
try:
26+
result = subprocess.run(["powershell", "-Command", command], capture_output=True, text=True)
27+
if result.returncode != 0:
28+
log.error(f"PowerShell command failed with return code {result.returncode}")
29+
return []
30+
return result.stdout.splitlines()
31+
except Exception as e:
32+
log.error(f"Error running PowerShell command: {e}")
33+
return []
34+
35+
36+
# Unified parsing function for PowerShell output
37+
def parse_output(lines, regex, group_names):
38+
"""Parses command output using a regex and extracts specified groups."""
39+
results = []
40+
for line in lines:
41+
match = re.match(regex, line)
42+
if match:
43+
results.append({name: match.group(name) for name in group_names})
44+
else:
45+
log.debug(f"Skipping unrecognized line: {line}")
46+
return results
47+
48+
49+
# Function to get paired Bluetooth devices
50+
def get_paired_bluetooth_devices():
51+
"""Retrieves paired Bluetooth devices with names and MAC addresses."""
52+
command = (
53+
'Get-PnpDevice -Class Bluetooth | Where-Object { $_.Status -eq "OK" } | Select-Object Name, DeviceID'
54+
)
55+
output = run_powershell_command(command)
56+
log.debug(f"Raw PowerShell output for paired devices:\n{output}")
57+
58+
devices = parse_output(
59+
output,
60+
regex=r"^(?P<Name>.+?)\s+(?P<DeviceID>.+)$",
61+
group_names=["Name", "DeviceID"]
62+
)
63+
64+
# Extract MAC addresses
65+
for device in devices:
66+
mac_match = re.search(r"BLUETOOTHDEVICE_(?P<MAC>[A-F0-9]{12})", device["DeviceID"], re.IGNORECASE)
67+
device["MAC"] = mac_match.group("MAC") if mac_match else "Address Not Found"
68+
69+
return [f"Name: {device['Name']}, MAC: {device['MAC']}" for device in devices]
70+
71+
72+
# Function to log all Bluetooth data
73+
def log_bluetooth():
74+
"""Logs Bluetooth device data and event logs."""
75+
log.info("Starting Bluetooth data logging...")
76+
filename = "bluetooth_data.txt"
77+
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
78+
save_to_file(filename, "Bluetooth Data Collection - Timestamp", timestamp)
79+
80+
# Collect and log paired devices
81+
log.info(f"Collecting paired devices...")
82+
paired_devices = get_paired_bluetooth_devices()
83+
section_title = "Paired Bluetooth Devices"
84+
save_to_file(filename, section_title, paired_devices or ["No paired Bluetooth devices found."])
85+
log.debug(f"{section_title}: {paired_devices}")
86+
87+
# Collect and log event logs
88+
def collect_logs(title, command):
89+
logs = run_powershell_command(command)
90+
save_to_file(filename, title, logs or ["No logs found."])
91+
log.info(f"Getting {title}...")
92+
93+
collect_logs(
94+
"Bluetooth Connection/Disconnection Logs",
95+
'Get-WinEvent -LogName "Microsoft-Windows-Bluetooth-BthLEServices/Operational" '
96+
'| Select-Object TimeCreated, Id, Message | Format-Table -AutoSize'
97+
)
98+
99+
collect_logs(
100+
"Bluetooth File Transfer Logs",
101+
'Get-WinEvent -LogName "Microsoft-Windows-Bluetooth-BthLEServices/Operational" '
102+
'| Select-String -Pattern "file.*transferred" | Format-Table -AutoSize'
103+
)
104+
105+
log.info("Finished Bluetooth data logging.")
106+
107+
108+
if __name__ == "__main__":
109+
log_bluetooth()

CODE/config.ini

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ delete_old_logs = false
99

1010
[System Settings]
1111
# Do not play with these settings unless you know what you are doing
12-
version = 3.1.0
13-
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"
12+
version = 3.1.1
13+
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"
1414

1515
###################################################
1616
# The following settings are for specific modules #

0 commit comments

Comments
 (0)