一切从哪里开始
让我们从问题陈述开始。 我们有1(一)台笔记本电脑。 新的游戏玩家笔记本电脑。 键盘上带有RGB背光。 看起来像这样:
图片来自lenovo.com这台笔记本电脑上还安装了一个程序。 那就是控制我们的背光的东西。
一个问题-该程序在Windows下运行,我们希望一切都能在我们最喜欢的Linux上运行。 希望LED闪烁,而漂亮的颜色闪烁,等等。 一个自然的问题出现了,我们是否可以在不进行逆向工程和编写自己的驱动程序的情况下做到所有这些?
一个自然的答案出现了,没有。 让我们打开IDA并开始破解。
第1步-挖掘代码
有三个触发器可以使背光发光。 以升序排列:
1.名为Lenovo Nerve Center的大型buff游戏玩家程序,该程序具有仅用于此背光的大型buff设置菜单。
2.热键组合Fn + Space-也可以由上述程序管理。
3. BIOS。 在装载笔记本电脑时,背光灯会短暂闪烁红色。 也许我们可以使用它?
我必须尝试全部3个。但是只有第一个成功了,所以还是有一些成功的,所以让我们在这里谈论第一个。
我们使用程序打开文件夹:

注意这里! 有一个名称非常有趣的DLL-LedSettingsPlugin.dll。 可能是...吗? 让我们在IDA Pro中打开它,自己看看。

在这里查看屏幕的右半部分-如此多的调试信息! 让我们使用它。 一些字符串在这里看起来像函数名称。 我不知道为什么...

哦,这些
是函数名。 方便! 让我们用自己的名字来调用某些东西,然后再次查看函数列表。 要在IDA中命名事物,可以使用热键N,或右键单击要命名的事物。

查看函数,我们看到一个叫做Y720LedSetHelper :: SetLEDStatusEx的东西。 看起来我们需要什么! 它形成某种字符串,然后将其提供给CHidDevHelper :: HidRequestsByPath。 我们应该关注的有趣部分是var_38,IDA对此进行了重点介绍。
Var_34也很有趣。 它紧随var_38之后-在汇编程序的传统中,变量以相反的顺序存储在RSP下。 IDA中的Var_34只是常量的名称--34h。
从var_38开始,我们的程序放置一个零,然后放置样式,颜色,数字3和块-键盘上将获得该颜色的部分。 (稍后,实验将显示数字3实际上是亮度。在其上添加控件将使我们的驱动程序比官方的更好!)
现在,让我们深入研究HidRequestsByPath并尝试弄清楚我们需要发送什么以及在哪里发送。

看,两个功能。 HidD_GetFeature和HidD_SetFeature。
在文件中没有跟踪它们...但是在
此处和
这里的 Microsoft官方文档中对其进行了非常好的跟踪。
好吧,我们现在可以轻拍一下。 这是岩石底部,无处可寻。 Linux具有这两个功能-我们只是回过头来,并用相同的参数调用它们。 ...对吗?
第2步-启动原型...?
不完全是 让我们回到Linux并打开lsusb。 我们会在那找到键盘,然后向它发送一些东西。

集成技术快递有限公司 是这里最有趣的一个。 让我们使用流行的工具/ dev / hidraw。 我们只需查看相应的/ sys / class / hidraw / hidraw / hidraw * / device / uevent,就能找到合适的。

这一个 所有数字都匹配-这意味着/ dev / hidraw0是我们的设备。 但是,让我们尝试发送一些东西……什么也没有发生! 为什么 此时,倦怠开始了。 也许不是凡人,这是反向工程吗?
但是,让我们继续尝试。 如果作者更擅长于此,他本来可以使Nerve Center更加逆转并提出ha解决方案。。。但是我们没有头脑。 让我们重新启动到Windows,有一个主意。
Windows中有这个东西-设备管理器,他们称之为。 有很多功能-但是我们对其中一个感兴趣。 它允许您禁用设备。 简单而权威。
因此,让我们禁用所有设备,直到我们的LED停止闪烁!

做到了。 如果我们看一下它的硬件ID,我们将看到它是什么,那个神秘的LED设备。

看-是他。

多年来困扰我dmesg的设备。
[为什么它没有在lsusb中显示? 当然,它根本不是USB! 背光使用一种称为I2C HID的协议-它允许制造商将设备隐藏起来,以防邪恶的DIY人们用手将HID小工具安装到计算机本身的系统总线上。跨步2.5-让我们提交
对正确设备的搜索已被大量删节。 按照最初的说法,在我意识到为什么什么都不起作用之前,我不得不几乎一直打开到内核的安装程序。 另外,每次解锁计算机时,我都不喜欢显示给我的dmesg日志。 既然我们在这里-为什么不去写一个简短的提交呢?
我们需要找到两件事-处理I2C HID设备的位置以及存储其怪癖的位置。
在这里 我们不要太费力地看看错误:报告不完整。 让我们完成它。

添加一个新的怪癖,我们称它为I2C_HID_QUIRK_BAD_INPUT_SIZE或类似的名称。 为了保持主题。

另外,让我们将设备添加到已古怪的列表中。 到目前为止,我们已经完成了什么:
1.在搜索引擎中查找“ i2c隐藏的Linux内核”。 在DuckDuckGo中单击了第4个结果。
2.用英语写了三个(!)单词-BAD_INPUT_SIZE
3.在BIT(4)中增加一个。 结果-BIT(5)。
4.在hid-ids.h中添加了一个数字-我们设备的ID(未显示,但难度相似)
我们是程序员,让我们现在进行一些编程。
看到这行:
ret_size = ihid->inbuf[0] | ihid->inbuf[1] << 8;
然后它抱怨ret_size不是它的值。
只要我们的怪癖是活跃的,让我们这样做,但倒退。

将补丁发送到邮件列表...(预先测试!)。 老实说,进入该邮件列表比实际补丁要复杂。 无论如何这都不简单。

就是这样!
步骤3-司机!
在这一点上,我记得-我正在尝试编写驱动程序。 决定我还不会将其提交给内核-问题开始出现,在这一点上,您确实必须考虑一些问题。 如果有任何阅读本文的人擅长于内核并且可以咨询我,我将很高兴与您交谈。
让我们打开python。 (曾经是bash,但是您使用这种语言很快就会改变主意)。 让我们使用流行的工具/ dev / hidraw。
/ dev / hidraw0,/ dev / hidraw1-无论如何,这些文件如何工作? 对于简单的I / O,您可以将它们与其他任何I / O一起使用,这似乎是可行的。 还有GetFeature和SetFeature-好吧,这完全是另一回事了。
StackOverflow(或者我不记得的其他人)告诉我,我必须研究名为ioctl的东西。 这是处理不常见文件(例如HID设备,终端和类似令人恶心的东西)的一种特殊方式。
表面上看似乎很简单-为它提供一个打开的文件句柄(不是Python级别的,不是OS级别的!如果您想知道,请
在这里阅读有关OS句柄的更多信息。),一些数字和一个缓冲区-然后它确实具有该缓冲区的东西,并将其还给您。 我并不是在这里变得机智,只是它几乎完全依赖于实现。 这是一个示例:0xC0114806。 那是什么 那就是SetFeature。 那也是
(6 << 29) | (ord('H') << 8) | (0x06 << 0) | (0x11 << 16).
前6个表示文件将同时打开以供读取和写入。 我们只写,但是文档说6表示我们放6。Ord('H')代表HID。 有时,它代表其他内容,具体取决于文件。 但是现在是HID。
0x06是命令本身。 HID的第六个命令是SetFeature,这是我们需要的。 最后一部分? 缓冲区的大小。
剩下的就是将它们放到一个ioctl调用中,您就得到了一个驱动程序。
可以用 。
作者的后记
希望这篇文章是有趣的阅读。 甚至可能是有用的读物。 为了简洁起见,某些部分被省略或缩短了-更加细心的读者可能会注意到驱动程序可以读取键盘的当前状态,而set_status函数具有第二个ioctl调用,该调用甚至在文本中都没有提及。 硬件开发和Linux内核是一件很重要的事情,只有一个故事不能涵盖全部。 归根结底,也许这篇文章不是关于这个的。 也许仅仅是为开源或为自己做一件小事和好事,一点都不难。 您只需要找到一个星期的免费晚上,喝杯茶,并希望在代码中挖掘内容就可以了。