BlackMacro firmware (Speed Editor Reverse Engineering) banner

BlackMacro firmware (Speed Editor Reverse Engineering)

19 devlogs
39h 57m 2s

Hardware research and a micropython firmware/low-level emulation layer library for the Raspberry pi pico, allowing open-source macropads to natively control Davinci Resolve as if they're a blackmagic Speed Editor. This allows access to special fea…

Hardware research and a micropython firmware/low-level emulation layer library for the Raspberry pi pico, allowing open-source macropads to natively control Davinci Resolve as if they’re a blackmagic Speed Editor. This allows access to special features in Davinci, such as smooth jog wheel scrolling or multicam editing. Through virtual usb drivers, this project also potentially allows owners to customize their real speed editors.

This project is created through reverse engineering the low-level USB HID traffic captured between Davinci Resolve and the speed editor purely through online resources. I also cracked the encryption algorithm used for authentication and initialization handshake through algorithm analysis and some clever boolean algebra. The communication protocol is also reverse engineered and implemented.

The result is a lot of writeup and a demo micropython library that can be adapted into FOSS macropad firmware. I included demo videos and a demo firmware.

Kip

(un)sucessfully building micropython firmware….
:(

WSL seems to have some bug where accessing files is very slow.
I dunno if I should move everything to wsl native? Or install windows toolchain

Attachment
0
Kip

Jog dial is now implemented! Man this took alot of work. How davinci reports dial rotation is quite wonky.

But now everything I need is now implemented! I have a RC out, next up would be packaging for release!

0
Kip

Trying to get jog mode to work…

Oh mannnn

Apparantly there are 4 different jog wheel reporting mode (completely separate from the user-facing jog/shtl/scrl modes??? And they have different outputs..

Too bad I can’t for the life of me figure out what they actually should output, and poking technology’s video seem to have incorrect packets???

Attachment
0
Kip

Added a full terminal UI to the firmware, so I don’t have to reflash the firmware everytime I want to tweak something XD

It uses WebREPL, and provides a full modular TUI for basically every function of the firmware + modules. I’m using a non-blocking input receiver that works with single characters, but I can also use input() for the keycode prompt.

Also I added the full keyboard, key led, and jog led modules. All that’s left is the jog wheel!

music is INI LAGI by Labirhin (peak)

0
Kip

Added keyboard module! The pi pico sends input report 4 to send key inputs to davinci resolve, and now I can make use of speed editor exclusive features such as the marker color wheel :)

Also I added the ability for firmware emulation of double-press and hold actions.

On the speed editor, some secondary/tetireary actions are triggered by double pressing / holding / double pressing then holding a specific key. The speed editor does not detect the double presses itself, instead it directly pipes whatever button is currently pressed directly to the PC, which then davinci resolve process it into double press actions. This makes remapping actions way harder, so I added this firmware emulation layer. When the system want to trigger a specific action, it can lookup which speed editor physical key to press and what way to press it. The firwmare will then fake a double/hold press through a 50ms-100ms-50ms template and send it to the PC. This works surprisingyly well!

In the video you can see the play/pause button being simulated (quick press emulation), as well as the exclusive marker color wheel (double-press then hold emulation, WebREPL toggles state)

0
Kip

Spent some time restructuring the project. Now the low-level hid stuff is separtated from actual application logic.

I created a module system, now all functionality are put inside dedicated modules. A module can register itself to handle get/set report of type feature/input/output on a specific id, and when the hid library receives a report, it will route it to SpeedEditorInterface, which will then route it to the correct registered module.

Now it’s way easier to add additional functionality, and I don’t have to reupload the entire project everytime I flash to the pi pico

anyways check out this cool diagram I drew in Affinity on how the project now works.

The serial number/init static calls are now put inside misc, which is just a bunch of singe-purpose static response modules.

Attachment
2

Comments

Kip
Kip 6 days ago

I guess I learned now that Helvetica Neue really doesn’t look good in low resolutions
also the colors i chose oof

damn it doesn’t look that good when heavily compressed :<

Kip
Kip 5 days ago

Correction: there are no set input or get output interfaces. I’ve done goofed

Kip

hahahahahha! Apparantly blackmagic doesn’t verify the battery status, so I can make the pico send whatever amount I want via HID input report 0x07 :3:

I finihsed implemented the authentication state machine, the pi pico receives the authentication from the PC via feature report 6, encrypts it using the keys I reverse engineered, send it back, and sends its own challenge to Davinci based on bmd.py’s keys. After sucessfully finishing the auth sequence, the pi pico sends 0x06 0x04 … to indicate authenticated, then davinci recognizes it as a speed editor!

Too bad micropython doesn’t support enums or switch cases, which made the state machine hell to write cleanly. But other than that, the pi pico is now ready to send whatever it want to Davinci! yay!!

Attachment
1

Comments

Kip
Kip 8 days ago

::3:: how do I post emotes ;-;

Kip

Figured out what the next one is! Get feature report 8 is jsut asking for the serial number of the keyboard. Oddly enough, while the serial number seems to be a hex string, the keyboard sends its serial number to the PC by encoding it in ascii. (for example, if the serial number is …04…, the usb traffic would not be …04…, but …30 34…, the ascii code for the two charcters. I have no idea why it’s done this way….)

But after this is solved, the authentication flows right in, with some set input reports as well! It seems davinci resolve first resets the leds and jog wheel before doing authentication, and if the auth handshake timesout, it checks for battery a few times before giving up.

I cataloged the initialization flow in a md document, and I cleaned up my hid library to give pretty nice visualizations of what each packet means.

I also started working on implementing the authentication state machine, after that I should be able to make the pi directly talk with davinci as if it’s a speed editor!

(that 060000000000… indicates the first stage of authentication!)

Attachment
0
Kip

YEAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

after patching micropython’s usb library to respond to HID feature reports, Davinci resolve now recognizes the emulated device and starts talking! Too bad all the hid reports are vendor defined and I can’t really guess what they mean :(

micropython’s usb library doesn’t support get_report commands, so I patched in get_report support for report type 0x03 (feature reports) in micropython/lib/usb/device/hid.py’s on_interface_control_xfer. Now the pico can capture and respond to get feature reports from davinci resolve.

Based on poking technology’s video I managed to get the appropriate responses for davinci’s requests.

First davinci sends A1 01 01 03 02 00 08 00, get feature report id 1. I guess it’s some sort of initialization? Pico responds 01 4D 02 25 7B 01 05 02. Since the report descriptor is all vendor defined (0xFF07), I have no idea what this does.

Then davinci repeatedly sends A1 01 08 03 02 00 21 00, get feature report id 8. I haven’t implemented responding to this yet, but it seems like davinci will time out after a while and skip to the next step, which is the feature report 6 06 00 00 00 00 00 00 start of auth sequence to reset the handshake state machine!

I can’t find any info on what feature report id 8 is, and the descriptor is all vendor defined :<

But at least it works! I just need to implement the handshake state machine and then the keyboard can communicate with davinci :)

here’s the feature 8 report descriptor btw

    b'\x09' b'\x08'             #   Usage (b'\x08)
    b'\xA1' b'\x01'             #   Collection (Application)
    b'\x85' b'\x08'             #     Report ID (8)
    b'\x06' b'\x07' b'\xFF'     #     Usage Page (Vendor Defined b'\xFF07)
    b'\x15' b'\x00'             #     Logical Minimum (0)
    b'\x26' b'\xFF' b'\x00'     #     Logical Maximum (255)
    b'\x09' b'\x00'             #     Usage (b'\x00)
    b'\x75' b'\x08'             #     Report Size (8)
    b'\x95' b'\x20'             #     Report Count (32)
    b'\xB1' b'\x81'             #     Feature (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile)
    b'\xC0'                     #   End Collection
Attachment
0
Kip

Back to work on this after finishing making shapeworld…

Finished the writeup on the key cracking process. Pretty cool how it all worked out through an oversight on how the algorithm calculates odd/evenness.

Attachment
0
Kip

Ordered parts for the haptic motor pcb, going back to reverse engineering.\

Starting now, I’ll call it a compatibility layer since I feel that’s more accurate, since nothing in my project is ripped from blackmagic’s firmware.\

It has been a few days without a devlog, and while nothing’s particularily finished yet i guess ill still make a devlog.

Currently while the HID descriptor and VID/PID are now emulated, the pi pico is still not receiving any HID data. I’m using micropython since it’s fast for prototyping and porting jupyter notebooks, but micropython’s USB library is incomplete. Digging through its (low-to-high) level API I found its HID report handlers are just not implemented.

So I’ll have to dig through the USB HID standard next week to implement this low level api on my own :)

Attachment
0
Kip

Spent some more time going back and forth with hacking usb hid and researching motor drivers.

I think I’ve decided on using the TMC6300 driver, the same as the original smartknob, the only annoying thing is that it’s a QFN and I only have experience doing through hole stuff :(

on the usb front, a few annoying things: While the panel app recognizes the spoofed ids, I don’t have the proper usb report descriptor, so the pc refuses to send any data to the controller. Thankfully I found someone online willing to provide their usb report descriptor copy.
The other thing is that windows makes blackmagic’s driver take complete control over the usb device, so the serial I use for REPL is just gone. I have to use WebREPL for now (thank god I got the 2W), but I might have to write some communication over HID hackery in the future.

:3

Attachment
0
Kip

Successfully got the blackmagic Control Panel software to recognize my pi pico as a speed editor!
Currently the authentication sequence is not implemeneted yet, so the control panel is purely recognizing based on my spoofed vendor/device id. Unfortunately this means in Windows the blackmagic driver take control of my pi, so its serial interface is gone. I’ll have to figure out another way to let my control software in the future talk to the microcontroller

Oh yeah the pi pico arrived! It’s a chinese clone board with type-c, but they forgot to add resistors so it only works with a-to-c cables :/

Attachment
Attachment
1

Comments

Kip
Kip 29 days ago

oh yeah for some reason blackmagic catalogs their speed editor as a sound device for some weird reason lol

Kip

OH MY GOD I DID IT

Turns out the mask wasn’t changed, so all the 3 hours of work I done was useless. However the one key recovered was indeed correct.

Turns out the magic bitmask (only 1 byte) is changed, and bruteforcing it got all the keys correct, since now all the samples match their keys.

OH MY GODDD
With this, any HID can emulate a speed editor and interface with davinci resolve :)
In case you want them, here they are:
Bitmask: 0x96

EVEN

  • 0x6d82d2aba84359
  • 0x8094f1e1139a3aa6
  • 0x2d3929003020a05c
  • 0xd48c2ddea1133a4f
  • 0xd654c05c5fd009d6
  • 0x4c6fb9a3fd2862e5
  • 0x6fd43b58528cba05
  • 0xdce7a14a8971b6de

ODD

  • NONE
  • 0x655ab52052b84a3d
  • 0x3142691fe0314ad4
  • 0xca2f80438fc1e35e
  • 0x52cc143ed3fabbf4
  • 0xeb4cef3adea60827
  • 0x7bc4f7d3aaffdc1c
  • 0x147d4e5953db2540
Attachment
Attachment
Attachment
1

Comments

Kip
Kip about 1 month ago

btw the markdown in the screenshots are written by me to document the process when the repo eventually goes public
Not ai lol

Kip

Oh my god.

It worked.

I got a key. The boolean algebra meant that for certain cases, a digit of the key can only be either 1 or 0. Through elimination I was able to reconstruct the first key, “even” bank key of index 0, which is
0x6d82d2aba84359!!!
Oh my god oh my god this actually worked

I can then take this and use it to calculate the mask. This took surprisingly little time to run too!

Attachment
0
Kip

Update on the key cracking progress.

After some initial tests, my assumptions were incorrect. BMD changed at least the mask for the editor side of the encryption. Since now there are two variables, it’s a bit harder to reverse engineer.

Thankfully I found found a bug in their algo design. There exist a impossible key case, so I get double the amount of samples for a key combo. With some two-variable boolean algebra I can probably reconstruct both the key and the mask at the same time!

The encryption algo: v ^ (rol8(v) & MASK) ^ K, where MASK and K are unknown. Both are 64 bits.

(img: Some writeup on why the case doesn’t happen!)

(img2: the enormous truth table I now have to wrestle with)

Attachment
Attachment
0
Kip

Waiting for parts to arrive, started reverse engineering the encryption key used for Speed editor authentication.

When connecting, the keyboard and davinci resolve exchange a string of 8 random byte (+2 control bytes) each, which they encrypt with their own algorithms and then send back.

Thanks to blackmagic-misc, the keyboard’s challenge algorithm is already cracked. However after testing, the PC side’s challenge algorithm is apparantly different.

  • more info about nerdy reverse engineering below -
    (string means the 8 bytes / 64bit array / uint64)

Investigating the keyboard algorithm, assuming the only thing changed is the keys, it’s actually not too hard to reverse engineer.

The algorithm basically takes the string, and rotates it based on a special byte, some manipulation later, the bytes are XORed with one of 16 keys chosen through a simple bitwise operation on the rotated string.

There are quite a few vernabilities of this algorithm!
1: All the (not even that slow) slow bitwise operations are done before applying the key, so all this can be cached before bruteforcing the key.
2: Even though there are 16 keys, only one is used for each run, and how it’s chosen is completely deterministic. so instead of trying 2^(1664)=1.710^308 options, we only try 16*2^64 = 2.9 * 10^24 options :)
3: Bruteforcing is not even necessary!
The final step of the encryption is v ^ (rol8(v) & MASK) ^ key. v is deterministic, and if we assume mask doesn’t change, key is applied last, and through XOR we can directly calculate key based on the final output from the sniffed HID packet dataset.
4: All manipulation are shifts, AND, and XOR. They don’t introduce entropy and can be reversed quite easily.

Just one problem. The dataset contains all scenarios except n=0 in the “even” key bank. So there is one key I can’t crack.

Currently I’ve created code to prepare the data for cracking the key, what’s left is to implement the cracking process!

Attachment
Attachment
0
Kip

Waiting for pi pico to arrive. In the meantime I’m reverse engineering the “encrypted” handshake protocol that the official speed editor uses, based on this very useful repo (https://github.com/smunaut/blackmagic-misc/blob/master/bmd.py) and youtube videos of its usb wireshark traffic (since I don’t have the actual device ;-;)

Also spent some time fixing/rewriting the kicad-wakatime plugin to track time more accurately, since it’s orginally only tracking once per save and all the time between saves is basically lost.

Attachment
0
Kip

A lot of research on the motor drivers and which bldc motor to use for the motorized jog wheel in the assembly.
I can get some cheap parts, but man 5 dollars for a TMC6300 is way too expensive. I have to find a cheaper motor driver. On the other hand I found a very nice pico 2 w clone board with type c, which is quite nice (not sure if I’ll add bluetooth/battery to it, but it’s nice to have the option for the future)

Going to be very loosly based on the original blueprint hackpad layout, but everything will be completely redone.

Currently learning about EE and the smartknob project to try adapt it to my project

Attachment
0