In the previous article, we demonstrated that the buttons on a BWallet are indeed wired differently than on a Trezor.
This means that loading a signed Trezor firmware onto a BWallet isnt very useful. The 'unofficial firmware' warning pops up and the buttons do not work.
Perhaps the 'next best thing' would be to use the Trezor source code, modify only the lines to map the CPU pins to the buttons on the BWallet and compile ourselves.
So let's test it!
The lines to modify are in buttons.h:
-#define BTN_PIN_YES GPIO2 -#define BTN_PIN_NO GPIO5 +#define BTN_PIN_YES GPIO10 +#define BTN_PIN_NO GPIO12
Then compile as normal.
This creates the firmware image, but what gets flashed to the device requires a header on top that contains some metadata, including the signatures. Because we have no way of creating signatures that either a BWallet bootloader nor a Trezor bootloader would validate, we can steal the header from a firmware that Trezor distributes.
Here's a terrible python script that does just that (and breaks out the header fields for no good reason):
import sys import binascii import struct with open(sys.argv, 'r') as f: data = f.read() header = data[:256] firmware = data[256:] assert len(header) + len(firmware) == len(data) (magic, codelen, idx1, idx2, idx3, flags, reserved, sig1, sig2, sig3) = struct.unpack("4sissss52s64s64s64s", header) print "magic =\t%s" % binascii.hexlify(magic) print "codelen =\t%s" % codelen print "idx1 =\t%s" % binascii.hexlify(idx1) print "idx2 =\t%s" % binascii.hexlify(idx2) print "idx3 =\t%s" % binascii.hexlify(idx3) print "flags =\t%s" % binascii.hexlify(flags) print "rsvd =\t%s" % binascii.hexlify(reserved) print "sig1 =\t%s" % binascii.hexlify(sig1) print "sig2 =\t%s" % binascii.hexlify(sig2) print "sig3 =\t%s" % binascii.hexlify(sig3) with open("bzor.bin", "rb") as g: payload = g.read() g.close() with open("bzorwithheader.bin", "wb") as h: h.write(header + payload) h.close()
passing in a valid trezor firmware:
$ python fwheaderswap.py trezor-1.2.1.bin magic =54525a52 codelen =161276 idx1 =01 idx2 =02 idx3 =03 flags =01 rsvd =00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 sig1 =7e0606dde7849e5af70975c277f9cd9f1eee1d6e811f6e4ebe6b606c83fbce7403bb4145da1594718e06b13a291068a577f738b56612c01f4275040ae3eb96e3 sig2 =19812e876e6022813a957066422741c34a2cbe5a262d402aebfd654db56f8626d1d9d2b8c8a858a978ceff253909b7e3e7d9fab6aaf3338d3b113bfbd3425528 sig3 =a716ae2e4894bf9ef31c5536256df2c23b95bfacbf06f958f6fe8d9f33d841c044d6c6322a7f6504b9da208db79c19b81a1044c9e3d399b8c20455e3b3ca5acd
I should probably have fixed the magic bytes right in the script, but I did this separately like I did in the last post.
This yields this firmware that behaves exactly like a Trezor, but on a BWallet. Let's test the buttons:
$ python cmdtr.py get_entropy 32 <clicks the button> 5fd6cd915ef841630d023a1ecbf6b2e1046d0b82e8dab80c2cf76a7919e781f4
And the buttons work!
This BWallet-Trezor hybrid will alert on boot that the firmware is 'unofficial' because the signature in the header was not created by a BWallet developer on the firmware we are running. Instead, I pulled the code directly from the Trezor repo, made a trivial change to support the BWallet button mappings, and compiled it myself.
It is true that when it boots up and warns that the firmware is not official, I have no way of telling if its running my compiled firmware, or if an evil hacker made modifications to my BWallet when I wasnt looking.
My solution? I won't leave my BWallet in a place where an evil hacker can get to it.
Also, I'm aware of this risk and will make informed, conscious decisions about how I use it.
Feel free to use the firmware above for yourself. But be aware that if you do choose to use it, you are trusting that I'm not an evil hacker :) I provide no warranty, guarantee, or promises about what will or won't happen if you choose to use it.
I recommend you follow the steps above and compile your own BWallet-compatable Trezor firmware.
blah blah, consider donating for more hardware wallet analysis: 1Adq8SP8WBWJGHyq8N3bGty8n1m9A3ms81