KipJM/blackmacro-lib
GitHub: KipJM/blackmacro-lib
一个 MicroPython 固件仿真层库,通过逆向 Speed Editor 的 HID 协议让开源 macropad 原生控制 DaVinci Resolve。
Stars: 6 | Forks: 0
# Blackmacro 固件 (Davinci Resolve Speed Editor 固件仿真层)
#### HID 协议研究及一个概念验证版 micropython 固件,能让支持 HID 的微控制器(例如 Pi Pico 2W)成功仿真 BMD Speed Editor,并与 Davinci Resolve 进行原生交互。
[](https://youtu.be/K808iHzAlDo)
本项目旨在被适配到开源 macropad 固件中,以允许与 Davinci Resolve 进行原生通信。
_目前仅支持 USB,但计划(可能)在未来支持 Bluetooth。_
本项目的所有发现均来源于公开的网络资源(参见参考部分)或通过观察 USB HID 流量得出。
**我没有反编译或逆向工程任何 Davinci Resolve 软件或 Blackmagic 固件。**
**本项目采用 GNU AGPLv3 授权。不允许公司/个人将本项目集成到闭源/专有软件或硬件中。**
# 为什么?
本项目的目标**不是**制造 [Speed editor](https://www.blackmagicdesign.com/products/davinciresolve/keyboard) 的山寨品。
考虑到 Speed editor 相当高的质量并附赠一个 studio 许可证,或者说如果你是在进行专业工作并需要官方支持,它实际上相当划算。
然而,如果你已经拥有一个 studio 许可证,需要特殊的无障碍硬件,或者使用了一个替代的/更好的 macropad(例如我正在开发的、带有[触感飞梭旋钮](https://github.com/scottbez1/smartknob))并能在 Resolve 中使用的开源剪辑键盘,
或者只是想让你现有的 macropad 能在 Resolve 中工作(另外官方设备被锁定只能在 Resolve 中使用),那么这个项目就是为你准备的。
通过虚拟 USB 驱动程序,理论上有人也可以改编这个项目,允许定制他们官方的 speed editor
键盘(例如,在 Davinci Resolve 中重新映射 multicam 按键)。
Davinci Resolve 提供了一个未公开且非常有限的 API,然而它太局限了,并不支持人们期望 macropad 具备的所有基本剪辑
功能。此外,它需要特殊的软件设置,并且无法在 iOS 版本上运行[^1]。
因此,我决定创建一个能够仿真 Speed Editor 协议的固件。最好的情况是让 bmd 为配件开放 api,但由于这短期内不会发生,这是目前最好的选择。
[^1]: iOS 版本的 Davinci Resolve 仅支持通过 bluetooth 工作,不支持 USB。目前这个项目还未实现 Bluetooth 功能,因此目前不支持 iOS。
### 为什么选择 micropython?
本项目并未直接准备好用于生产环境。然而,它提供了大量的注释、详细的说明以及易于理解的 python 代码,
使得 FOSS 固件开发者可以将其适配到自己的项目中。由于 micropython 的 USB 后端是 TinyUSB,
与许多其他微控制器固件一样,将此代码移植到(例如)使用 c++ 的 ESP32 上应该是轻而易举的。
请记住要在你的项目中通过包含 `Speed editor emulation layer licensed from KIP (kip.gay), AGPLv3 License` 来致谢我。
# 运行 / 演示
我为 pi pico/pico 2 及其无线版本提供了编译好的 `.uf2` 演示固件。请注意,最推荐在 pico 2W 上运行。
pi pico 固件已在 Pico 2W type-C 克隆板上进行了测试。如果你使用的是 Windows,我强烈建议在支持无线的 pi pico 开发板(W 系列)上运行此项目。
**当 Windows 检测到伪装的 speed editor VID 时,blackmagic 的驱动程序会完全控制 pico 的 usb,
从而隐藏 USB 串行连接。** 因此,通信是通过 WebREPL 完成的。
我提供了四种不同的演示固件,分别适用于 raspberry pi pico、raspberry pi pico W、raspberry pi pico 2、raspberry pi pico 2W。
理论上,任何 RP2040 或 RP2350 开发板都应该受到支持。
**W 版本和非 W 版本固件之间存在显著差异。**
### 非 W 版本固件
由于没有办法与 pico 通信,pico 将随机模拟 speed editor 的一些功能,
可能是转动飞梭旋钮或按下某些按键。请确保你没有加载到重要的 resolve 项目中!
### W 版本固件
pi pico 将自动创建一个名为 `blackmacro` 的开放 WiFi 网络。连接到该网络,然后使用 IP `192.168.4.1:8266` 和密码 `madebykip` 通过 WebREPL 连接到 pi(由于 HSTS,micropython 的网页版本无法工作),
之后你就可以通过终端 UI 控制固件了。
按 `h` 以显示/刷新当前菜单。按下在 `[]` 中标记的按键来选择菜单项。`>` 提示表示
你需要输入一个多字符值,然后通过回车键提交。
按 `~` 切换 HID 数据包日志的可见性。
设备初始化完成且串行通信关闭后,板载 LED 会亮起。要中断固件
并重新启用串行连接,请在 LED 亮起后按 BOOTSEL 按钮。LED 会熄灭,并且 pico
将自动作为标准的 micropython 串行设备重新连接。
# 许可证
本项目基于 GNU AGPLv3 授权,我重申其中的一些限制:
- 不允许在专有/闭源的硬件和(或)软件中使用/集成此项目。
- 衍生作品必须是自由和开源的。
- **不允许使用本项目的任何部分来训练“生成式 AI” / “LLM”机器学习模型。**
此外,你**不得**原样出售此项目。
# HID 协议
请参见 `notebooks/additional_notes.md` 和 `notebooks/hid_sequence.md`。
这些协议是通过 bmd.py 以及 Poking Technology 视频中的 wireshark 流量来理解的。
# 密钥重建
老实说,理解算法并破解密钥非常有趣,而且并不具有挑战性。**如果你是一个对 USB HID、基本布尔代数或计算机数据结构感兴趣的初学者,我强烈建议你通过下面列出的参考资料自己尝试一下**
(你甚至不需要拥有 speed editor)。一个有趣的分支任务是研究数据集的分布!
看看 `notebooks/` 以获取我的解决方案。
MASK 与 PC 端保持一致。密钥和魔法位掩码(即 if 语句中的 8 位值)被更改了。
密钥和魔法位掩码提取和暴力破解起来非常简单。若要寻求更有趣的挑战,可以尝试逆向工程
MASK 值。
我假设加密算法在 PC 端和键盘端之间是不变的,只是变量发生了变化。
该算法很有趣,因为密钥仅在最后一步通过 `XOR` 应用,并且在包含 16 个密钥的
密钥库中,一次运行中只使用一个(确定性选择),因此对于一组正确加密对的数据集,
反转 `XOR` 以获取原始密钥非常简单。
难点在于确定应用密钥之前的变量,即 `MASK`(64位)和 `magic bitmask`(8位)数字。
如果 `MASK` 发生变化,破解过程会稍微复杂一些,因为它涉及嵌套在其他 `XOR` 中的 `AND`,因此在此过程中会丢失一些数据。然而,由于在按位操作期间位没有发生移位,
通过真值表并逐位处理,我可以使用一个大型数据集通过消除法来确定 `MASK` 的每一位。
然而事实证明 `MASK` 根本没有被更改,仅仅更改了一个 8 位的 `magic bitmask` 值。
可能的值范围(只有 0-255)如此之小,我可以极其迅速地直接暴力破解这个数字。
#### 寻找 `MASK`
如果有必要,`MASK` 也是可以被猜出来的。`MASK` 是 64 位的,因此暴力破解会有点不切实际,
特别是考虑到此时还有大量的未知变量。
`MASK` 在加密过程的最后一步被应用,通过 `v ^ (rol8(v) & MASK) ^ k`。此时,我们既不知道
密钥 `k`,也不知道 magic bitmask(它会影响 `v` 和 `rol8(v)`)。一些观察结果使我们能够减少未知变量的数量,
以在拥有足够大的数据集的情况下推算出 `MASK` 是什么。
为了推算出 `MASK` 是什么,我们首先需要一个已知的 `key`(在观察 5 中解释)。一些有趣的观察结果
使得推算出一个 `key` 成为可能。
#### 观察结果:
1. **magic bitmask 是无关紧要的。** 算法有一个特性,即确保当 n==0 时密钥为奇数。
通过这一点,我们可以计算出当 n==0 时 `v` 和 `rol8(v)` 是什么。因此我们的目标是找出 n==0 时的奇数密钥是什么。
2. `MASK` 和 `key` 都仅在最后一步被应用。这意味着理论上我们只需
反转最后一步的布尔运算即可推算出它们是什么。(当然,由于 `AND` 是破坏性的并且有太多变量,所以并没有那么简单,但这仍然极大地降低了破解的复杂度)
3. 没有位移。如果我们将 `v` 和 `rol8(v)` 视为独立的变量,那么我们
就可以逐位计算。这将我们需要进行的猜测数量从 2^64 = 1.8446744e+19 减少到了
两个值的 2*64 = 128。
4. 我们可以缓存一些值。根据观察 1,我们可以预先计算 `v` 和 `rol8(v)` 的值。由于
我们知道结果(最终加密的消息),该等式变成了一个包含 2 个未知数的布尔代数。_(好吧,这一点其实没那么重要,因为其他技术已经极大地减少了所需的猜测次数,以至于缓存带来的速度提升现在已微不足道)_
5. `MASK` 在所有情况下保持不变,此外 `key` 在 (`n`, 偶数性) 配置中也保持不变。有了偶数 0 密钥,我们就可以推算出 `MASK`,这可以直接应用于推算其余的密钥。
6. `MASK` 直接影响等式结果。如果我们看一下等式 `a ^ (b & c) ^ d` 的真值表,我们会看到:
```
a b c d b∧cb∧c a⊕(b∧c) (a⊕(b∧c))⊕d
1 1 1 1 1 0 1
1 1 1 0 1 0 0
1 1 0 1 0 1 0
1 1 0 0 0 1 1
1 0 1 1 0 1 0
1 0 1 0 0 1 1
1 0 0 1 0 1 0
1 0 0 0 0 1 1
0 1 1 1 1 1 0
0 1 1 0 1 1 1
0 1 0 1 0 0 1
0 1 0 0 0 0 0
0 0 1 1 0 0 1
0 0 1 0 0 0 0
0 0 0 1 0 0 1
0 0 0 0 0 0 0
```
我们看到,对于某些 值,结果直接受 d(即密钥)的影响。
反转真值表,我们发现:
```
# a, b, result: (c, d) 的可能组合
truth_table = {
(0, 0, 0): [(0, 0), (1, 0)], # key can only be 0!
(0, 0, 1): [(0, 1), (1, 1)], # key can only be 1!
(0, 1, 0): [(0, 0), (1, 1)],
(0, 1, 1): [(0, 1), (1, 0)],
(1, 0, 0): [(0, 1), (1, 1)], # key can only be 1!
(1, 0, 1): [(0, 0), (1, 0)], # key can only be 0!
(1, 1, 0): [(0, 1), (1, 0)],
(1, 1, 1): [(0, 0), (1, 1)],
}
```
对于数据集条目中的每一位,如果 result、`v` 和 `rol8(v)` 匹配特殊的配置之一,我们就可以确定
该密钥上的那一位**不是** 0 或 1。通过足够的数据,我们可以使用排除法确定密钥的每一位。
利用相同的原理,通过将 `key` 也代入等式,我们可以使用排除法确定 `MASK` 是什么。
### 复现
要运行密钥重建 notebook,你需要 python、pandas、matplotlib、jupyter 等。
这些 notebook 本身非常杂乱。我在完成项目的过程中留下了笔记。该 notebook 应该能够单独通过数据集推导出
魔法数字,然而一些值被硬编码到了项目中,因为我不想
花时间编写输入处理器或重组数据。
# 参考文献
感谢这些非常有用的在线资源:
- 特别感谢 **https://github.com/smunaut/blackmagic-misc/blob/master/bmd.py**,版权所有 (C) 2021 Sylvain Munaut Apache 2.0 许可证
- 部分来自 https://www.youtube.com/watch?v=UoIlwze5xp4 中 wireshark 屏幕截图的 hid 流量
- https://www.reddit.com/r/codes/comments/mq9yot/i_am_cracking_a_usb_handshake_code_for_davinci/
- https://jonnyelwyn.co.uk/film-and-video-editing/using-the-davinci-resolve-speed-editor-in-other-video-editing-apps/
- https://docs.google.com/spreadsheets/d/1Ms6HO4hXpemLB72hTdQFQ3QOjLT0NYn7WGS1JEWlDac/edit?usp=sharing
- https://commandpost.fcp.cafe/control-surfaces/resolve/ (特别是讨论部分)
- https://github.com/CommandPost/CommandPost/blob/develop/src/plugins/core/controlsurfaces/resolve/manager/init.lua,MIT 许可证
- https://github.com/orgs/micropython/discussions/17410 提供了有关在 micropython 的 HID 库中实现 feature reports 的指导
- Reddit 用户 u/Tree_Tea 提供了他们键盘的报告描述符。
本项目绝不隶属于 blackmagicdesign、Davinci Resolve 或上面列出的参考资料,也未受到它们的认可。
**(c) 2026 KIP**
标签:AGPLv3, DaVinci Resolve, DIY硬件, HID协议, Macropad, MicroPython, NoSQL, Raspberry Pi Pico, Speed Editor, USB HID, 人机接口设备, 仿真层, 低级模拟, 协议分析, 固件开发, 宏键盘, 开源硬件, 微控制器, 无障碍硬件, 权限提升, 硬件研究, 蓝牙, 视频剪辑, 视频编辑控制器, 逆向工具, 键盘模拟, 黑魔法设计