Wiimote Hacking: Brute Force Method #1

(Update: While entertaining, this entire exercise was unnecessary. See this post for more information.)

With only a Wiimote and no Wii, I am pretty much consigned to exploring brute force PIN discovery methods, assuming that the Wiimote will pair with any device if presented with the right PIN.

As I learned earlier, the host computer can tell if the PIN is incorrect, so an easy brute force method is to simply try many PINs. To pull this off, you need to be able to initiate pairing with a fixed PIN in a programmatic way (i.e. I don’t have to sit here and click 1000 times), and you need a way to keep the Wiimote in discoverable mode. Normally, the Wiimote immediately leaves discoverable mode when pairing fails. For a while I though it would be necessary to construct some sort of mechanism to keep activating the sync button over and over again. Just holding down the sync button does not work, so I started constructing a really hilarious looking contraption to push the sync button every 5 seconds using an oscillating table fan, a pen, and some wire twist-ties. Thankfully while putting this Rube Goldberg machine together, I stumbled upon the 1-2 sync method (hold 1 and 2 buttons down at same time), which has the nice feature that constant button pressure keeps the remote in discoverable mode. With a big eraser and some velcro cable straps, I was able to keep the 1 and 2 buttons pressed indefinitely:
Wiimote in Permanent Sync Mode
The remaining issue was now software.

Initiating Pairing Programmatically

The only Bluetooth hardware I have is in my MacBook, so I am pretty much stuck using OS X to do my Bluetooth testing. Initially, I tried using the Apple C/ObjC Bluetooth framework, IOBluetooth, to run the pairing process automatically. It was not too hard with PyObjC to experiment with the framework in Python, but eventually I hit a wall. In typical Apple fashion, IOBluetooth provides an API which only exposes the functionality you “ought” to need, and hides the lower-level Bluetooth functions. There is in fact no way to pair a device programmatically, though a related framework, IOBluetoothUI, does give you a very easy way to pop up a pairing dialog for the user to click on. However, at that point, you might as well use the Bluetooth Setup Assistant directly.

GUI Scripting

Having gotten nowhere with the ObjC frameworks, I turned to the GUI scripting features which are enabled by Apple’s Universal Access API. By allowing software to interact directly with GUI objects, like buttons and text boxes, Apple created an interface for both accessibility software, like screen readers, and for GUI scripting tools. A relatively easy way to interact with the GUI is through AppleScript, perhaps the ugliest scripting language I have ever seen. The syntax of AppleScript appears to be an attempt to make programming look as much like English as possible. In practice, it seems to combine the needless verbosity of COBOL with the confusing implicitness of Perl. (However, until I learn how to do the same thing with Python and PyObjC, it is worth putting up with.) After several hours futzing around, and making good use of UIElementInspector to discover the hierarchy of GUI elements in the Bluetooth Setup Assistant Window, I was able to generate the following code:

set the log_filename to (((path to desktop folder) as text) & "PinScan.txt")

repeat with pin from 2100 to 2500
	copy pin as string to pin_str

	tell application "System Events"
		tell application process "Bluetooth Setup Assistant"
			tell group 1 of window "Bluetooth Setup Assistant"
				set value of text field 1 to pin_str
			end tell
			click button "Continue" of window "Bluetooth Setup Assistant"
			delay 4
			tell group 1 of window "Bluetooth Setup Assistant"
				get value of static text 3
				copy result to outcome
			end tell

			click button "Go Back" of window "Bluetooth Setup Assistant"
		end tell
	end tell

	set the log_file to open for access file log_filename with write permission
	write pin_str & "
" & outcome & "
" as «class utf8» to the log_file starting at eof
	close access the log_file
end repeat

(Incidentally, I don’t even know how to type the symbols around “class utf8″. I cut and paste that entire word from a webpage directly into Script Editor.)

The repeat line is where I set the range of of PINs to test (in this case 2100 to 2500), and I have to manually get the Bluetooth Setup Assistant to the PIN input window:
PIN Input Window
And then start the script going. The 4 second pause is long enough to allow the pairing to fail if the Wiimote is already in discoverable mode. If the Wiimote has fallen out of discoverable mode, it can take the computer up to 15 seconds to fail. As it happens then, the short delay is a good failsafe to ensure the script will fail if for whatever reason the Wiimote stops being discoverable. That is preferable to having a bunch of trial PINs show up as no good when in fact the Wiimote was just off at the time.

The output of the script is a file which will contain lines like:

2100
The pairing attempt was unsuccessful. Make sure you are entering the proper passkey on your device, as displayed above. When ready, click Continue to try again.
2101
The pairing attempt was unsuccessful. Make sure you are entering the proper passkey on your device, as displayed above. When ready, click Continue to try again.
2102
The pairing attempt was unsuccessful. Make sure you are entering the proper passkey on your device, as displayed above. When ready, click Continue to try again.
2103
The pairing attempt was unsuccessful. Make sure you are entering the proper passkey on your device, as displayed above. When ready, click Continue to try again.

If the pairing were to be successful, then either the text will be different, or the script itself will bomb out since the text element it attempts to read might not even be present. In either case, it is easy to figure out which number succeeded and retry it manually to verify.

This GUI-based pin method can try 1000 PINs in a little under 2 hours. If Nintendo only used a 4-digit PIN, then it is quite feasible to find it this way in less than a day. A 5-digit PIN can be found in a week (stock up on AA batteries!), and I would regard a 6-digit PIN as impossible to discover with this method. I have found you can only run this script while not using the computer for anything else, so it will take me 2 runs overnight to finish testing all the 4 digit PINs, at which point I’ll be sure to report any successes.

Assuming the PIN is not found this way, then we will have to move to a more sophisticated technique, such as the method outlined by Shaked and Wool. Their technique requires recording the packet exchange during a successful pairing (like with a Wii) and then brute-forcing the PIN mathematically. Their performance numbers show that a 7 digit PIN can be found in 40 minutes using a Pentium III 450 MHz with no algorithmic optimization. By being clever about the calculation, they were able to get a factor of 10 improvement in speed on the same hardware, and moving to a more modern Pentium IV 3.2 GHz gets you another factor of 4. If we then throw the problem at a cluster of 5 CPUs, it would be feasible to extract an 11 digit PIN in about a week. Unfortunately, that’s only 36 of the 128 possible PIN bits, so if Nintendo used all possible bits, we would still be out of luck using a brute-force method.

For now, I’ll have to be content with the GUI method, and wait to get a hold of a Wii to start investigating the packet structure.

Leave a Reply

Entries (RSS)