外星人笔记本键盘USB协议逆向

前言

我朋友一台 dell g16 购买时直接安装了linux系统,但是linux上没有官方的键盘控制中心,所以无法控制键盘灯光,于是我就想着能不能逆向一下键盘的协议,然后自己写一个控制键盘灯光的程序。我自己的外星人笔记本是m16,所以我就先从m16开始逆向。

USB协议分析

通过 chatgpt 得知,AlienFX设备通常通过USB接口连接到计算机。键盘的灯光控制是通过HID (人机接口设备) 协议进行的。当你使用AlienFX软件时,这些程序会发送特定的命令到键盘,告诉它如何设置灯光效果。

现在wireshark已经支持HID协议的解析,所以我们可以直接使用wireshark来分析USB协议。在安装wireshark是需要勾选安装USBPcap

打开wireshark,选择USBPcap1

设置要捕获的usb设备,然后点击start

打开 alienware command center,设置键盘灯光,在灯光效果除设置颜色为红色,然后点击应用。

然后我们就可以在wireshark中看到usb协议的数据包了, 我们可以看到有两个数据包,一个是发送数据包,一个是接收数据包。可以通过设置过滤器来过滤掉接收数据包,只看发送数据包,过滤设置为 usb.src == "host"

发现仅仅是改了一个按键的颜色,就发送了很多数据包,而且每个数据包的长度都不一样,这是因为每个数据包都是一个命令,而且每个命令的长度都不一样,所以我们需要找到每个命令的格式,然后才能解析出每个命令的含义。

验证数据包

这个时候我们需要写一个测试程序,来分析哪一个包让键盘改变了颜色,然后再分析这个包的格式。这里我们使用python将数据重发到usb设备,然后观察键盘的变化。

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | import logging import time import usb from usb ``import USBError class AlienwareUSBDriver: ``VENDOR_ID ``= 0xd62 ``PRODUCT_ID ``= 0xc2b0 ``SEND_BM_REQUEST_TYPE ``= 0x21 ``SEND_B_REQUEST ``= 0x09 ``SEND_W_VALUE ``= 0x3cc ``SEND_W_INDEX ``= 0x0 ``PACKET_LENGTH ``= 63 ``def __init__(``self``): ``self``._control_taken ``= False ``self``._device ``= None ``def acquire(``self``): ``""" Acquire control of the USB controller.""" ``if self``._control_taken: ``return ``self``._device ``= usb.core.find(idVendor``=``AlienwareUSBDriver.VENDOR_ID, idProduct``=``AlienwareUSBDriver.PRODUCT_ID) ``if self``._device ``is None``: ``logging.error(``"ERROR: No AlienFX USB controller found; tried VID {}, PID {}" ``.``format``(AlienwareUSBDriver.VENDOR_ID, AlienwareUSBDriver.PRODUCT_ID)) ``try``: ``self``._device.set_configuration() ``except USBError as exc: ``logging.error(``"Cant set configuration. Error : {}"``.``format``(exc.strerror)) ``try``: ``usb.util.claim_interface(``self``._device, ``0``) ``except USBError as exc: ``logging.error(``"Cant claim interface. Error : {}"``.``format``(exc.strerror)) ``self``._control_taken ``= True ``logging.debug(``"USB device acquired, VID={}, PID={}"``.``format``(``hex``(AlienwareUSBDriver.VENDOR_ID), ``hex``(AlienwareUSBDriver.PRODUCT_ID))) ``def release(``self``): ``if not self``._control_taken: ``return ``try``: ``usb.util.release_interface(``self``._device, ``0``) ``except USBError as exc: ``logging.error(``"Cant release interface. Error : {}"``.``format``(exc.strerror)) ``try``: ``self``._device.attach_kernel_driver(``0``) ``except USBError as exc: ``logging.error(``"Cant re-attach. Error : {}"``.``format``(exc.strerror)) ``self``._control_taken ``= False ``logging.debug(``"USB device released, VID={}, PID={}"``.``format``(``hex``(AlienwareUSBDriver.VENDOR_ID), ``hex``(AlienwareUSBDriver.PRODUCT_ID))) ``def write_packet(``self``, pkt): ``if not self``._control_taken: ``return ``try``: ``num_bytes_sent ``= self``._device.ctrl_transfer( ``self``.SEND_BM_REQUEST_TYPE, ``self``.SEND_B_REQUEST, ``self``.SEND_W_VALUE, ``self``.SEND_W_INDEX, ``pkt, ``0``) ``logging.debug(``"wrote: {}, {} bytes"``.``format``(pkt, ``len``(pkt))) ``if len``(pkt) !``= num_bytes_sent: ``logging.error(``"writePacket: intended to write {} of {} bytes but wrote {} bytes" ``.``format``(pkt, ``len``(pkt), num_bytes_sent)) ``return num_bytes_sent ``except USBError as exc: ``logging.error(``"writePacket: {}"``.``format``(exc)) |

其中设备信息可以在wireshark中查看

|-----|---------------------------------------------------|
| 1 2 | VENDOR_ID ``= 0xd62 PRODUCT_ID ``= 0xc2b0 |

在使用 device.ctrl_transfer 发送数据时需要指定 bmRequestType, bRequest, wValue, wIndex,这些信息也可以在wireshark中查看

|---------|---------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 | OUT_BM_REQUEST_TYPE ``= 0x21 OUT_B_REQUEST ``= 0x09 OUT_W_VALUE ``= 0x3cc OUT_W_INDEX ``= 0x0 |

尝试将wireshark中的数据包发送到键盘,通过测试发现,其中一条数据包发送后,Q键的灯光才会改变

|-------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 | if __name__ ``=``= '__main__'``: ``device ``= AlienwareUSBDriver() ``device.acquire() ``data ``= bytes.fromhex(``'cc8c020073072f46121278b56519a6f9661799e568127ab7691aaaff6a2aaaff6c2aaaff6e137fbf7019a6f9711aaaff8608334b8708334b8808334b2bfc0000'``) ``device.write_packet(data) |

数据包格式分析

通过分析得知,每次改变颜色,awcc 会通过CC 8C 02 00 命令把所有按键的颜色发送一遍 ,经过多次测试,发现每个按键的颜色都是由三个字节表示,分别是 R G B,所以我们可以通过改变这三个字节来改变按键的颜色。包格式如下:

经过多次尝试后,将整个键盘的对应序号,得到如下表格

Key Code Key Code Key Code Key Code
esc 1 f4 5 u 0x31 lshift 0x52
f1 2 f5 6 i 0x32 z 0x54
f2 3 f6 7 o 0x33 x 0x55
f3 4 f7 8 p 0x34 c 0x56
f8 9 3 0x18 [ 0x35 v 0x57
f9 0xa 4 0x19 ] 0x36 b 0x58
f10 0xb 5 0x1a \ 0x38 n 0x59
f11 0xc 6 0x1b a 0x3f m 0x5a
f12 0xd 7 0x1c s 0x40 , 0x5b
home 0xe 8 0x1d d 0x41 . 0x5c
end 0xf 9 0x1e f 0x42 / 0x5d
del 0x10 0 0x1f g 0x43 rshift 0x5f
` 0x15 - 0x20 h 0x44 up 0x73
1 0x16 = 0x21 j 0x45 lctrl 0x65
2 0x17 back 0x24 k 0x46 fn 0x66
tab 0x29 caps 0x3e l 0x47 lwin 0x68
q 0x2b enter 0x4b ; 0x48 lalt 0x69
w 0x2c space 0x6a ' 0x49 ralt 0x70
e 0x2d rwin 0x6e right 0x88 rctrl 0x71
r 0x2e ralt 0x70 down 0x87 left 0x86
t 0x2f microphone 0x14 voice0 0x11 voice+ 0x13
y 0x30 voice- 0x12 voice+ 0x13 voice- 0x12

可以用一个例子来验证上面的keymap是否正确

|-------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | if __name__ ``=``= '__main__'``: ``device ``= AlienwareUSBDriver() ``device.acquire() ``keymap ``= { ``'esc'``: ``1``, ``'f1'``: ``2``, ``'f2'``: ``3``, ``'f3'``: ``4``, ``'f4'``: ``5``, ``'f5'``: ``6``, ``'f6'``: ``7``, ``'f7'``: ``8``, ``'f8'``: ``9``, ``'f9'``: ``0xa``, ``'f10'``: ``0xb``, ``'f11'``: ``0xc``, ``'f12'``: ``0xd``, ``'home'``: ``0xe``, ``'end'``: ``0xf``, ``'del'``: ``0x10``, ```''```: 0x15, '1': 0x16, '2': 0x17, '3': 0x18, '4': 0x19, '5': 0x1a, '6': 0x1b, '7': 0x1c, '8': 0x1d, '9': 0x1e, '0': 0x1f, '-': 0x20, '=': 0x21, 'back': 0x24, 'microphone': 0x14, 'tab': 0x29, 'q': 0x2b, 'w': 0x2c, 'e': 0x2d, 'r': 0x2e, 't': 0x2f, 'y': 0x30, 'u': 0x31, 'i': 0x32, 'o': 0x33, 'p': 0x34, '[': 0x35, ']': 0x36, '\\': 0x38, 'voice0': 0x11, 'caps': 0x3e, 'a': 0x3f, 's': 0x40, 'd': 0x41, 'f': 0x42, 'g': 0x43, 'h': 0x44, 'j': 0x45, 'k': 0x46, 'l': 0x47, ';': 0x48, '\'': 0x49, 'enter': 0x4b, 'voice+': 0x13, 'lshift': 0x52, 'z': 0x54, 'x': 0x55, 'c': 0x56, 'v': 0x57, 'b': 0x58, 'n': 0x59, 'm': 0x5a, ',': 0x5b, '.': 0x5c, '/': 0x5d, 'rshift': 0x5f, 'up': 0x73, 'voice-': 0x12, 'lctrl': 0x65, 'fn': 0x66, 'lwin': 0x68, 'lalt': 0x69, 'space': 0x6a, 'ralt': 0x70, 'rwin': 0x6e, 'rctrl': 0x71, 'left': 0x86, 'down': 0x87, 'right': 0x88` ` }` ` def` `get_key_bytes(a, b, a_color, b_color):` ` header =` `bytes.fromhex('cc8c0200')` ` a_bytes =` `(a << 24` `| a_color).to_bytes(4, byteorder='big')` ` b_bytes =` `(b << 24` `| b_color).to_bytes(4, byteorder='big')` ` data =` `header +` `a_bytes +` `b_bytes` ` out =` `data +` `bytes(64` `-` `len(data))` ` return` `out` ` chars =` `list(keymap.keys())` ` a =` `0` ` a_color =` `0` ` b =` `0` ` b_color =` `0` ` for` `i, k in` `enumerate(chars):` ` key =` `keymap[k]` ` a =` `key` ` a_color =` `0xff0000` ` b =` `0` ` b_color =` `0` ` if` `i > 0:` ` b =` `keymap[chars[i -` `1]]` ` b_color =` `0x00ff00` ` device.write_packet(get_key_bytes(a, b, a_color, b_color))` ` time.sleep(0.3)` ` a_color =` `0x00ff00` ` b_color =` `0x00ff00` ` ``device.write_packet(get_key_bytes(a, b, a_color, b_color))` |

效果如下:

这样我们就可以根据需要,来动态设置每个按键的颜色了。

其他命令

其中还有清除灯光的命令,格式如下:

|---|------------------------------------------------------------------------------------------------------------------------------------|
| 1 | cc8c1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 |

关闭波动灯光的命令,格式如下:

|-----|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 | cc8c0500010101010101010101010101010101010101010101010101010101010101010101010101000000000100010101010101010101010101010100000000 cc8c0600000101010101010101010101010101000000000000010001010101010101010101000100000000000101000101010001000100010100010000000000 |

开启波动灯光的命令,格式如下:

|---|------------------------------------------------------------------------------------------------------------------------------------|
| 1 | cc800305000001010101000000000000050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 |

最后

在分析过程中,也是花费了不少时间, 主要是 alineware command center 在全键盘设置成一个颜色时,会发送很多数据包,而且每个键对应的颜色值还不一样,我以为有特殊的算法

比如我设置成绿色时,发送的数据包如下:

他会为每个键随机生成颜色相近的值, 这些值同样是以十六进制表示的RGB颜色代码。我们可以解析这些代码来看看这些颜色是否相似。

以下是解析的颜色及其RGB值:

  1. 00 3F 11 - RGB(0, 63, 17)
  2. 00 FF 4A - RGB(0, 255, 74)
  3. 00 8E 29 - RGB(0, 142, 41)
  4. 00 91 2A - RGB(0, 145, 42)
  5. 00 A3 2F - RGB(0, 163, 47)
  6. 00 9E 2D - RGB(0, 158, 45)
  7. 00 9B 2D - RGB(0, 155, 45)
  8. 00 99 2C - RGB(0, 153, 44)
  9. 00 A0 2E - RGB(0, 160, 46)
  10. 00 91 2A - RGB(0, 145, 42)
  11. 00 8E 29 - RGB(0, 142, 41)
  12. 00 9B 2D - RGB(0, 155, 45)
  13. 00 CC 3B - RGB(0, 204, 59)
  14. 00 8E 29 - RGB(0, 142, 41)
  15. 00 FF 4A - RGB(0, 255, 74)

从这些解析的值可以看出,这些颜色大多是绿色调,但是其中有不同的亮度和饱和度。例如,00 FF 4A是一个明亮的绿色,而00 8E 29是一个相对较深的绿色。

总的来说,这些颜色都是绿色调,并且大部分的颜色是相似的。不过,其中的一些颜色(如00 FF 4A)会显得明显更亮和饱和。所以,这些颜色大部分是相似的。

相关推荐
hgdlip4 小时前
如何快速切换电脑的ip地址
网络·tcp/ip·电脑
missmisslulu7 小时前
电容笔值得买吗?2024精选盘点推荐五大惊艳平替电容笔!
学习·ios·电脑·平板
GEEKVIP8 小时前
手机使用技巧:8 个 Android 锁屏移除工具 [解锁 Android]
android·macos·ios·智能手机·电脑·手机·iphone
GEEKVIP8 小时前
如何在 Windows 10 上恢复未保存/删除的 Word 文档
macos·ios·智能手机·电脑·word·笔记本电脑·iphone
奇客软件9 小时前
iPhone使用技巧:如何恢复变砖的 iPhone 或 iPad
数码相机·macos·ios·电脑·笔记本电脑·iphone·ipad
小白电脑技术17 小时前
USB 3.0?USB 3.1?USB 3.2?怎么区分?
电脑
哲伦贼稳妥1 天前
一天认识一个硬件之电源
运维·其他·电脑·硬件工程
奇客软件1 天前
如何从相机的记忆棒(存储卡)中恢复丢失照片
深度学习·数码相机·ios·智能手机·电脑·笔记本电脑·iphone
丶21361 天前
【网络】用网线连接两台电脑实现远程桌面
网络·电脑
极客先躯2 天前
Win10鼠标总是频繁自动失去焦点-非常有效-重启之后立竿见影
计算机外设·win10·重启·频繁失去焦点·有效