我朋友一台 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
):
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
):
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编辑
,原因: