Running Trezor Firmware on BWallet

The Trezor devs claim that you can run Trezor firmware on the BWallet, but due to differences the the hardware, the buttons will not work.

So let's test it!

I'm using the cmdtr.py code from python-trezor that you can use to flash firmware images to trezors.

$ python cmdtr.py firmware_update -f trezor-1.2.1.bin

Firmware fingerprint: 0f8685ee46632162b549eb22b99a1e4e013d6796ae536ea6acb877a491f564f6

True

 

Cool, no problems there.

However, when re-plugging the BWallet:

But it works just fine on a Trezor. . .

But it works just fine on a Trezor. . .

"Firmware appears to be broken"

Let's find out why.

On line 119 of the BWallet bootloader code:

void check_firmware_sanity(void)
{
int broken = 0;
if (memcmp((void *)FLASH_META_MAGIC, "BDXW", 4)) { // magic does not match
broken++;
}

....
  
if (broken) {
layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Firmware appears", "to be broken.", NULL, "Unplug your BWALLET", "and see our support", "page: mybwallet.com");
system_halt();
}
}

So the bootloader is checking for the first bytes of the firmware to be the string "BDXW", and the Trezor firmware starts with "TRZR".  This is easy enough to fix in your favorite hex editor (in vim, :%!xxd, make your edits, and :%!xxd -r to return and then save):

$ xxd trezor-1.2.1.bin |head
0000000: 5452 5a52 fc75 0200 0102 0301 0000 0000TRZR.u..........
0000010: 0000 0000 0000 0000 0000 0000 0000 0000................
0000020: 0000 0000 0000 0000 0000 0000 0000 0000................
0000030: 0000 0000 0000 0000 0000 0000 0000 0000................
0000040: 7e06 06dd e784 9e5a f709 75c2 77f9 cd9f~......Z..u.w...
0000050: 1eee 1d6e 811f 6e4e be6b 606c 83fb ce74...n..nN.k`l...t
0000060: 03bb 4145 da15 9471 8e06 b13a 2910 68a5..AE...q...:).h.
0000070: 77f7 38b5 6612 c01f 4275 040a e3eb 96e3w.8.f...Bu......
0000080: 1981 2e87 6e60 2281 3a95 7066 4227 41c3....n`".:.pfB'A.
0000090: 4a2c be5a 262d 402a ebfd 654d b56f 8626J,.Z&-@*..eM.o.&

$ xxd MODtrezor-1.2.1.bin |head
0000000: 4244 5857 fc75 0200 0102 0301 0000 0000BDXW.u..........
0000010: 0000 0000 0000 0000 0000 0000 0000 0000................
0000020: 0000 0000 0000 0000 0000 0000 0000 0000................
0000030: 0000 0000 0000 0000 0000 0000 0000 0000................
0000040: 7e06 06dd e784 9e5a f709 75c2 77f9 cd9f~......Z..u.w...
0000050: 1eee 1d6e 811f 6e4e be6b 606c 83fb ce74...n..nN.k`l...t
0000060: 03bb 4145 da15 9471 8e06 b13a 2910 68a5..AE...q...:).h.
0000070: 77f7 38b5 6612 c01f 4275 040a e3eb 96e3w.8.f...Bu......
0000080: 1981 2e87 6e60 2281 3a95 7066 4227 41c3....n`".:.pfB'A.
0000090: 4a2c be5a 262d 402a ebfd 654d b56f 8626J,.Z&-@*..eM.o.&

 

Then cmdtr.py to push your modified firmware:

$ python cmdtr.py firmware_update -f MODtrezor-1.2.1.bin 
Traceback (most recent call last):
File "cmdtr.py", line 400, in <module>
main()
File "cmdtr.py", line 392, in main
res = args.func(cmds, args)
File "cmdtr.py", line 185, in firmware_update
raise Exception("Trezor firmware header expected")
Exception: Trezor firmware header expected

Failed.  cmdtr.py is checking for a 'TRZR' in the firmware header, but we just changed that.  Comment out the check in firmware_update:

def firmware_update(self, args):
if not args.file:
raise Exception("Must provide firmware filename")
fp = open(args.file, 'r')
#if fp.read(4) != 'TRZR':
#raise Exception("Trezor firmware header expected")

Now pushing the modified firmware should work:

$ python cmdtr.py firmware_update -f MODtrezor-1.2.1.bin 
Firmware fingerprint: 0f8685ee46632162b549eb22b99a1e4e013d6796ae536ea6acb877a491f564f6
True
That's a Trezor logo on a BWallet (after an unofficial firmware warning message)

That's a Trezor logo on a BWallet (after an unofficial firmware warning message)

And after dismissing a warning about running an 'unofficial' (not signed by BWallet) firmware, the Trezor firmware (signed by Trezor) appears to be running on a BWallet.  Lets try something requiring a button press:

$ python cmdtr.py get_entropy 1024
My eyes, the button does nothing!

My eyes, the button does nothing!

And the button does nothing.

So, now we've demonstrated that the BWallet isnt an exact duplicate of the Trezor; at a minimum the buttons are wired differently.

This can also be inferred from the source code, highlighted nicely by imahotdoglol:

BWallet button.h
#define BTN_PORTGPIOC
#define BTN_PIN_YES GPIO10
#define BTN_PIN_NOGPIO12

Trezor button.h
#define BTN_PORTGPIOC
#define BTN_PIN_YES GPIO2
#define BTN_PIN_NOGPIO5

But it was _possible_ that the buttons were wired to both the Trezor and BWallet pins in hardware, allowing for firmwares from either manufacturer to work.

Hopefully, I've been able to describe clearly what I've done to come to a conclusion.  My goal is to show and explain in enough detail for you to believe me, but also provide enough detail so anyone can duplicate my results for themselves.

You know, be open.  So you can exactly copy my work, if you so desire  :)

Next, I'm going to try to work around this 'button not working' problem two different ways, one in hardware and one in software.

If you enjoy this type of analysis, consider donating to me at 1Adq8SP8WBWJGHyq8N3bGty8n1m9A3ms81 .  I've purchased several Trezors and BWallets and other supplies to perform teardowns and experiments.

Also, please ask any questions I can help answer in the comments.

Thanks!