#!/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') | |
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()) |
This comment has been minimized.
This comment has been minimized.
Great code, thanks! |
This comment has been minimized.
This comment has been minimized.
This worked perfectly on Fedora 28. I created a username just to let you know how much I appreciate this code! THANK YOU! |
This comment has been minimized.
This comment has been minimized.
Hey, this works great on Ubuntu. Thank you. |
This comment has been minimized.
This comment has been minimized.
Buddy, you made my day! |
This comment has been minimized.
This comment has been minimized.
Thanks you so much |
This comment has been minimized.
This comment has been minimized.
Great, it works! Thanks! |
This comment has been minimized.
This comment has been minimized.
Replacing |
This comment has been minimized.
This comment has been minimized.
I really appreciate your share, but it doesn't work on my computer. Maybe that is because of the same address of mouse on my Windows and Ubuntu. |
This comment has been minimized.
This comment has been minimized.
No CRSK key is being generated in my BTKeys.reg when running psexec so the code throws this error. Any advice? Exporting to file '/tmp/tmpv3dr3u3e.reg'... |
This comment has been minimized.
This comment has been minimized.
@Wahidur-Rahman I have not tested it out but maybe @corecoding's fork could be useful to you. |
This comment has been minimized.
This comment has been minimized.
Yes, that has worked, thanks! |
This comment has been minimized.
This comment has been minimized.
@Wahidur-Rahman Thanks for confirming! I have merged the relevant changes from @corecoding's fork. |
This comment has been minimized.
This comment has been minimized.
Running into a similar error but with IRK. No CSRK is being generated in my case either. [Manjaro ~]# python3 export-ble-infos.py BTKeys.reg Output: [HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\BTHPORT\Parameters\Keys] [HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\BTHPORT\Parameters\Keys\8878732352bb] [HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\BTHPORT\Parameters\Keys\8878732352bb\c9bf519382e9] I did try editing the script to MasterIRK and the same error was presented KeyError being updated to MasterIRK. |
This comment has been minimized.
This comment has been minimized.
New to linux, sorry in advance. I'm getting an error that appears to result from not being able to make the output directory for some reason. This is the error, with the output_dir variable printed out right above it bluetooth/48:45:20:92:0F:30/F1:9F:12:F6:F0:18 Edit: Solved the issue, was trying to run the script in a directory in my Windows partition, so the colon was not allowed. |
This comment has been minimized.
This comment has been minimized.
How do i run this script? on windows/linux? I tried to run this script on visual code in windows and go this error: Traceback (most recent call last): |
This comment has been minimized.
This comment has been minimized.
So, I tried to run on Linux, I guess i don't run this script properly but in any case i got error of some modules that can't be loaded. Is it the right way to run this script? |
This comment has been minimized.
This comment has been minimized.
@n1vgabay - seems you are missing the appropriate python module. Might be that you don't have the dependency chntpw installed. Try 'sudo apt install chntpw' if that doesn't work, try manually installing the package to python with 'pip install configparser' |
This comment has been minimized.
This comment has been minimized.
I'm using also designer mouse but mouse cant connecting after run these script and commands. The CSRK key was blank, I added it from BTkeys. Unfortunately still not working on fedora 32. |
This comment has been minimized.
This comment has been minimized.
So i installed this package with python-pip as well, now i've got this massege: reged version 0.1 140201, (c) Petter N Hagen Any ideas how to solve this issue to make it work finally? And something i wondered since i saw this script, Usage: I'm assuming that the path I see in the script isn't working.. i mout windows and linux but maybe it's not enough. |
This comment has been minimized.
This comment has been minimized.
Is it still working? I'm trying to use it, the result is the same of the one that I've generated by hand but my mouse cannot connect properly. Any help? Edit: |
This comment has been minimized.
This comment has been minimized.
Fantastic. I'm not really a Python guru, so I can't tell what's going on here, but it works |
This comment has been minimized.
This comment has been minimized.
Thanks @thymbahutymba commented out this line(by adding the # sign) and my bluetooth keyboard now works both on windows and linux.
|
This comment has been minimized.
This comment has been minimized.
It turns out that the default template doesn't have the right configuration for my mouse. I manually copied some of the keys from the scripts output into my mouse's info file and it worked. Then after checking the script a little closer I found that if you connect your device to Linux first, then connect it in Windows, and then come back to Linux and run the script, the script will apply the keys it grabbed from Windows and add them into your mouse's already existing info file. (I don't know if it's necessary, but I also turned off my mouse after pairing it in Windows and didn't turn it back on until after I ran the script and moved the files as directed.) Note: I had to run the script as root in order for the script to be able to find my mouse's already existing info file. |
This comment has been minimized.
This comment has been minimized.
I found for the following line #L137: I need to change it to: At least for Python3.8/Ubuntu 20.04 and Windows 10.. unsure if that works on other combos.. i see the quoting logic exists in read_reg () though. |
This comment has been minimized.
This comment has been minimized.
In Windows 10 2h20 when connect Designer mouse no such keys in regedit. |
This comment has been minimized.
This comment has been minimized.
Very useful - thanks! Worked perfectly (Win 10/Ubuntu 18.04 on Dell XPS). Only problem I had was:
Solved by installing chntpw, then all good :) |
This comment has been minimized.
This comment has been minimized.
Is this supposed to be run from Windows or Linux? |
This comment has been minimized.
This comment has been minimized.
@Mygod what license is this under? |
This comment has been minimized.
This comment has been minimized.
@jamincollins Hi I added APL-2.0 license for this. Cheers! |
This comment has been minimized.
This comment has been minimized.
This is exactly what I needed. Just ran the script, copied the values and it just works. Thank you so much! |
This comment has been minimized.
I might have a dumb problem but can't fix it
Do you have any suggestion?
--Update--
Nevermind, I believe there was a problem accessing the file or something like that. It has been working since I mounted my windows drive on boot with fstab on a folder accessible by all users. It might have been due to /Windows/System32/config/SYSTEM access restrictions.