外星人笔记本键盘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 发送数据时需要指定 bmRequestTypebRequestwValuewIndex,这些信息也可以在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,所以我们可以通过改变这三个字节来改变按键的颜色。包格式如下:

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

KeyCodeKeyCodeKeyCodeKeyCode
esc1f45u0x31lshift0x52
f12f56i0x32z0x54
f23f67o0x33x0x55
f34f78p0x34c0x56
f8930x18[0x35v0x57
f90xa40x19]0x36b0x58
f100xb50x1a\0x38n0x59
f110xc60x1ba0x3fm0x5a
f120xd70x1cs0x40,0x5b
home0xe80x1dd0x41.0x5c
end0xf90x1ef0x42/0x5d
del0x1000x1fg0x43rshift0x5f
`0x15-0x20h0x44up0x73
10x16=0x21j0x45lctrl0x65
20x17back0x24k0x46fn0x66
tab0x29caps0x3el0x47lwin0x68
q0x2benter0x4b;0x48lalt0x69
w0x2cspace0x6a'0x49ralt0x70
e0x2drwin0x6eright0x88rctrl0x71
r0x2eralt0x70down0x87left0x86
t0x2fmicrophone0x14voice00x11voice+0x13
y0x30voice-0x12voice+0x13voice-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())

    = 0

    a_color = 0

    = 0

    b_color = 0

    for i, k in enumerate(chars):

        key = keymap[k]

        = key

        a_color = 0xff0000

        = 0

        b_color = 0

        if i > 0:

            = 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)会显得明显更亮和饱和。所以,这些颜色大部分是相似的。

 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/189584.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Django(三、数据的增删改查、Django生命周期流程图)

文章目录 一、 基于ORM进行的CURDuser_list&#xff1a;作为主页使用路由文件urls.py配置如下&#xff1a;add.html&#xff1a;用于新增用户的数据页add页面视图函数如下:edit.html&#xff1a;修改数据的页面那么来总结一下上序所操作所用到的内容。 导入已存在的表其方式有两…

Unity 使用INI文件存储数据或配置参数预设

法1&#xff1a;调用外部Capi库 具体使用&#xff1a; public class Ini{//读取INI文件需要调用C的APP[System.Runtime.InteropServices.DllImport("kernel32")]private static extern long WritePrivateProfileString(string section, string key, string val, st…

Leetcode—20.有效的括号【简单】

2023每日刷题&#xff08;二十七&#xff09; Leetcode—20.有效的括号 C实现代码 class Solution { public:bool isValid(string s) {stack<char> arr;int len s.size();if(len 1) {return false;}for(int i 0; i < len; i) {if(s[i] ( || s[i] [ || s[i] {)…

SSM框架Demo: 简朴博客系统

文章目录 1. 前端页面效果2. 项目创建3. 前期配置3.1. 创建数据库数据表3.2. 配置文件 4. 创建实体类5. 统一处理5.1. 统一返回格式处理5.2. 统一异常处理 6. 全局变量7. Session工具类8. 登录拦截器9. 密码加盐加密10. 线程池组件11. dao层11.1. UserMapper11.2. ArticleMappe…

Linux 基本语句_10_进程

进程和程序的区别&#xff1a; 程序是一段静态的代码&#xff0c;是保存在非易失储存器上的制令和数据的有序集合&#xff0c;没有任何执行的概念&#xff1b;而进程是一个动态的概念&#xff0c;它是程序的一次执行过程&#xff0c;包括了动态创建、调度、执行和消亡的整个过程…

面向切面编程AOP

2023.11.12 本章学习spring另一大核心——AOP。AOP是一种编程技术&#xff0c;底层是使用动态代理来实现的。Spring的AOP使用的动态代理是&#xff1a;JDK动态代理 CGLIB动态代理技术。Spring在这两种动态代理中灵活切换&#xff0c;如果是代理接口&#xff0c;会默认使用JDK动…

KDE Plasma 6 将不支持较旧的桌面小部件

KDE Plasma 6 进行了一些修改&#xff0c;需要小部件作者进行调整。开发人员&#xff0c;移植时间到了&#xff01; KDE Plasma 6 是备受期待的桌面环境版本升级版本。 最近&#xff0c;其发布时间表公布&#xff0c;第一个 Alpha 版本将于 2023 年 11 月 8 日上线&#xff0…

【JVM系列】- 寻觅·方法区的内容

寻觅方法区的内容 &#x1f604;生命不息&#xff0c;写作不止 &#x1f525; 继续踏上学习之路&#xff0c;学之分享笔记 &#x1f44a; 总有一天我也能像各位大佬一样 &#x1f31d;分享学习心得&#xff0c;欢迎指正&#xff0c;大家一起学习成长&#xff01; 文章目录 寻觅…

一个java文件的JVM之旅

准备 我是小C同学编写得一个java文件&#xff0c;如何实现我的功能呢&#xff1f;需要去JVM(Java Virtual Machine)这个地方旅行。 变身 我高高兴兴的来到JVM&#xff0c;想要开始JVM之旅&#xff0c;它确说&#xff1a;“现在的我还不能进去&#xff0c;需要做一次转换&#x…

解析Python的深浅拷贝机制

引言 在Python编程中&#xff0c;我们经常会遇到数据复制的问题。有时候&#xff0c;我们只是需要复制一份数据的引用&#xff0c;有时候&#xff0c;我们则需要复制数据本身。这就涉及到了Python中的深浅拷贝问题。深浅拷贝是Python中的一个重要概念&#xff0c;理解它对于编…

微软和Red Hat合体:帮助企业更方便部署容器

早在2015年&#xff0c;微软就已经和Red Hat达成合作共同为企业市场开发基于云端的解决方案。时隔两年双方在企业市场的多个方面开展更紧密的合作&#xff0c;今天两家公司再次宣布帮助企业更方便地部署容器。 双方所开展的合作包括在微软Azure上部署Red Hat OpenShift&#xf…

Pyside6/PYQT6如何实现无边框设计,解决无边框窗口无法移动的问题

文章目录 💢 问题 💢💯 解决方案 💯🍔 准备工作🐾 操作步骤🐾 窗口无边框🐾 窗口透明🐾 实现窗口可移动⚓️ 相关链接 ⚓️💢 问题 💢 有时候我们需要一个无边框的UI设计来实现/美化一些功能,如:制作一个桌面时钟,进度条展示等,要实现无边框其实很简…

从开源项目聊鱼眼相机的“360全景拼接”

目录 概述 从360全景的背景讲起 跨过参数标定聊透视变化 拼接图片后处理 参考文献 概述 写这篇文章的原因完全源于开源项目(GitHub参阅参考文献1)。该项目涵盖了环视系统的较为全貌的制作过程&#xff0c;包含完整的标定、投影、拼接和实时运行流程。该篇文章主要是梳理全…

机器学习数据预处理——Word2Vec的使用

引言&#xff1a; Word2Vec 是一种强大的词向量表示方法&#xff0c;通常通过训练神经网络来学习词汇中的词语嵌入。它可以捕捉词语之间的语义关系&#xff0c;对于许多自然语言处理任务&#xff0c;包括情感分析&#xff0c;都表现出色。 代码&#xff1a; 重点代码&#…

科技改变农业:合成数据农业中的应用

介绍 农业在我们的生活中起着至关重要的作用&#xff0c;它为我们提供了生存的食物。如今&#xff0c;它遇到了各种困难&#xff0c;例如气候变化的影响、缺乏工人以及全球流行病造成的中断。这些困难影响了耕作用水和土地的供应&#xff0c;而这些水和土地正变得越来越稀缺。…

PROFINET和UDP、MODBUS-RTU通信速度对比实验

这篇博客我们介绍PROFINET 和MODBUS-RTU通信实验时的数据刷新速度,以及这种速度不同对控制系统带来的挑战都有哪些,在介绍这篇对比实验之前大家可以参考下面的文章链接: S7-1200PLC和SMART PLC的PN智能从站通信 S7-200 SMART 和 S7-1200PLC进行PROFINET IO通信-CSDN博客文…

Adobe Photoshop 2020给证件照换底

1.导入图片 2.用魔法棒点击图片 3.点选择&#xff0c;反选 4.选择&#xff0c;选择并遮住 5.用画笔修饰证件照边缘 6. 7.更换要换的底的颜色 8.新建图层 9.使用快捷键altdelete键填充颜色。 10.移动图层&#xff0c;完成换底。

计算机中丢失msvcr120.dll文件怎么修复?找不到msvcr120.dll五种完美修复方案

今天我想和大家分享的是关于“msvcr120.dll丢失的问题的5个解决方法”。在我们日常的工作生活中&#xff0c;或许大家都曾遇到过这样的问题&#xff0c;那么&#xff0c;了解它的解决方法是非常必要的。 首先&#xff0c;让我们来了解一下msvcr120.dll是什么文件。简单来说&am…

基于springboot实现桥牌计分管理系统项目【项目源码】

基于springboot实现桥牌计分管理系统演示 JAVA简介 JavaScript是一种网络脚本语言&#xff0c;广泛运用于web应用开发&#xff0c;可以用来添加网页的格式动态效果&#xff0c;该语言不用进行预编译就直接运行&#xff0c;可以直接嵌入HTML语言中&#xff0c;写成js语言&#…

单链表按位序与指定结点 删除

按位序删除(带头结点) #define NULL 0 #include<stdlib.h>typedef struct LNode {int data;struct LNode* next; }LNode, * LinkList;//按位序删除&#xff08;带头结点&#xff09; bool ListInsert(LinkList& L, int i, int& e) {if (i < 1)return false;L…