首页
社区
课程
招聘
[原创]外星人笔记本键盘USB协议逆向
发表于: 2023-10-24 15:19 11685

[原创]外星人笔记本键盘USB协议逆向

2023-10-24 15:19
11685

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

通过 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设备,然后观察键盘的变化。

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

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

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

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

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

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

效果如下:

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

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

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

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

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

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

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

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

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

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

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))
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:

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2023-10-24 15:22 被evilbeast编辑 ,原因:
收藏
免费 12
支持
分享
最新回复 (11)
雪    币: 5512
活跃值: (390208)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2023-10-24 15:26
0
雪    币: 3594
活跃值: (31031)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2023-10-25 16:45
1
雪    币: 20
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4

牛啊,我也是同款电脑,待会仿做一下试试

最后于 2023-11-4 16:25 被不良帅编辑 ,原因:
2023-11-4 16:24
0
雪    币: 20
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
能留个联系方式吗,我在测试的时候遇到了问题
2023-11-4 16:40
0
雪    币: 2106
活跃值: (2654)
能力值: ( LV4,RANK:55 )
在线值:
发帖
回帖
粉丝
6
不良帅 牛啊,我也是同款电脑,待会仿做一下试试
什么问题
2023-11-4 23:47
0
雪    币: 3785
活跃值: (3947)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
7
感谢分享。
2023-11-5 00:03
0
雪    币: 217
活跃值: (376)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
nb
2023-11-7 15:52
0
雪    币: 1230
活跃值: (1775)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
厉害了 ing 
2023-11-9 20:17
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
蓝牙协议可以解析吗,想试试优化耳机音质
2024-8-10 22:11
0
雪    币: 4024
活跃值: (3878)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
牛逼 学习思路
2024-8-10 22:48
0
雪    币: 1612
活跃值: (1049)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
12
你现在可以在键盘上玩贪吃蛇和俄罗斯方块了
2024-8-11 09:58
0
游客
登录 | 注册 方可回帖
返回
//