Last active
August 30, 2024 02:28
-
-
Save Mygod/f390aabf53cf1406fc71166a47236ebf to your computer and use it in GitHub Desktop.
Export your Windows Bluetooth LE keys into Linux!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
""" | |
Copyright 2021 Mygod | |
Licensed under the Apache License, Version 2.0 (the "License"); | |
you may not use this file except in compliance with the License. | |
You may obtain a copy of the License at | |
http://www.apache.org/licenses/LICENSE-2.0 | |
Unless required by applicable law or agreed to in writing, software | |
distributed under the License is distributed on an "AS IS" BASIS, | |
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
See the License for the specific language governing permissions and | |
limitations under the License. | |
What is this: Export your Windows Bluetooth LE keys into Linux! | |
Thanks to: | |
* http://console.systems/2014/09/how-to-pair-low-energy-le-bluetooth.html | |
* https://gist.github.com/corecoding/eac76d3da20c7e427a1848b8aed8e334/revisions#diff-6eeb0d27c24cc10680e8574f75648585 | |
Usage: | |
$ ./export-ble-infos.py <args> | |
$ sudo bash -c 'cp -r ./bluetooth /var/lib && service bluetooth force-reload' | |
$ rm -r bluetooth | |
""" | |
import os | |
import shutil | |
import subprocess | |
import sys | |
import tempfile | |
from configparser import ConfigParser | |
from optparse import OptionParser | |
default_template = """ | |
[General] | |
Name=Designer Mouse | |
Appearance=0x03c2 | |
AddressType=static | |
SupportedTechnologies=LE; | |
Trusted=true | |
Blocked=false | |
Services=00001800-0000-1000-8000-00805f9b34fb;00001801-0000-1000-8000-00805f9b34fb;0000180a-0000-1000-8000-00805f9b34fb;0000180f-0000-1000-8000-00805f9b34fb;00001812-0000-1000-8000-00805f9b34fb; | |
[IdentityResolvingKey] | |
Key= | |
[LocalSignatureKey] | |
Key= | |
Counter=0 | |
Authenticated=false | |
[LongTermKey] | |
Key= | |
Authenticated=0 | |
EncSize=16 | |
EDiv= | |
Rand= | |
[DeviceID] | |
Source=2 | |
Vendor=1118 | |
Product=2053 | |
Version=272 | |
[ConnectionParameters] | |
MinInterval=6 | |
MaxInterval=6 | |
Latency=60 | |
Timeout=300 | |
""" | |
def main(): | |
parser = OptionParser() | |
parser.add_option("-v", "--verbose", action='store_true', dest='verbose') | |
parser.add_option("-s", "--system", dest="system", metavar="FILE", | |
default="/mnt/Windows/System32/config/SYSTEM", | |
help="SYSTEM file in Windows. Usually at /Windows/System32/config/system.") | |
parser.add_option("-k", "--key", dest="key", metavar="KEY", | |
default=r"ControlSet001\Services\BTHPORT\Parameters\Keys", | |
help="Registry key for BT. [default: %default]") | |
parser.add_option("-o", "--output", dest="output", metavar="DIR", default="bluetooth", | |
help="Output directory. [default: %default]") | |
parser.add_option("-t", "--template", dest="template", metavar="FILE", help="Template file.") | |
parser.add_option("-a", "--attributes", dest='attributes', help="Additional attributes file to be copied.") | |
options, args = parser.parse_args() | |
if options.template: | |
with open(options.template) as file: | |
template = file.read() | |
else: | |
template = default_template | |
out = tempfile.mktemp(".reg") | |
reged = subprocess.Popen(["reged", "-x", options.system, '\\', options.key, out], stdout=sys.stderr) | |
reged.wait() | |
if reged.returncode: | |
return reged.returncode | |
dump = ConfigParser() | |
with open(out) as file: | |
reged_out = file.read() | |
if options.verbose: | |
print(reged_out) | |
dump.read_string(reged_out.split('\n', 1)[1]) | |
os.unlink(out) | |
for section in dump: | |
path = section[len(options.key) + 2:].split('\\') | |
assert not path[0] | |
if len(path) == 3: | |
path[1] = ':'.join([path[1][i:i + 2] for i in range(0, len(path[1]), 2)]).upper() | |
path[2] = ':'.join([path[2][i:i + 2] for i in range(0, len(path[2]), 2)]).upper() | |
print("Dumping {}/{}...".format(path[1], path[2])) | |
config = ConfigParser() | |
config.optionxform = str | |
# See if device has been paired in Linux before | |
existing_template = '/var/lib/bluetooth/{}/{}/info'.format(path[1], path[2]) | |
if (os.path.exists(existing_template)): | |
with open(existing_template) as file: | |
config.read_string(file.read()) | |
else: | |
config.read_string(template) | |
def read_reg(key, expected_type): | |
def read_reg_actual(key, expected_type): | |
actual_type, content = dump[section]['"{}"'.format(key)].split(':', 1) | |
if expected_type == 'hex16': | |
assert actual_type == 'hex' | |
content = content.split(',') | |
assert len(content) == 16 | |
return ''.join(content).upper() | |
if expected_type == 'qword': | |
assert actual_type == 'hex(b)' | |
content = content.split(',') | |
assert len(content) == 8 | |
return str(int(''.join(content[::-1]), 16)) | |
if expected_type == 'dword': | |
assert actual_type == expected_type | |
return str(int(content, 16)) | |
assert False | |
result = read_reg_actual(key, expected_type) | |
if options.verbose: | |
print("{} of type {}: {}".format(key, expected_type, result)) | |
return result | |
config['LongTermKey']['Key'] = read_reg('LTK', 'hex16') | |
# KeyLength ignored for now | |
config['LongTermKey']['Rand'] = read_reg('ERand', 'qword') | |
config['LongTermKey']['EDiv'] = read_reg('EDIV', 'dword') | |
if '"IRK"' in dump[section]: | |
config['IdentityResolvingKey']['Key'] = read_reg('IRK', 'hex16') | |
if '"CSRK"' in dump[section]: | |
config['LocalSignatureKey']['Key'] = read_reg('CSRK', 'hex16') | |
output_dir = os.path.join(options.output, path[1], path[2]) | |
os.makedirs(output_dir, exist_ok=True) | |
with open(os.path.join(output_dir, 'info'), 'w') as file: | |
config.write(file, False) | |
if options.attributes: | |
shutil.copyfile(options.attributes, os.path.join(output_dir, 'attributes')) | |
if __name__ == "__main__": | |
sys.exit(main()) |
I'm trying this and no output directory is created. Any idea what is wrong?
This is the command and console output:
steve@aragorn:~$ sudo python3 ./export-ble-infos.py -s /media/steve/BOOTCAMP/Windows/System32/config/SYSTEM
reged version 0.1 140201, (c) Petter N Hagen
Exporting to file '/tmp/tmpfkmkggfk.reg'...
Exporting key 'Keys' with 1 subkeys and 0 values...
Exporting key '5cf370809d45' with 0 subkeys and 3 values...
Should the output directory be in my current directory or somewhere else?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks o: