我们为趣味和利润编写笔记本电脑驱动程序,或者即使您是傻瓜也如何提交内核

一切如何开始


让我们从提出问题开始。 鉴于:一台笔记本电脑。 新的笔记本电脑,游戏。 具有RGB背光。 这是一台像这样的笔记本电脑:

图片
图片取自lenovo.com

该笔记本电脑还有一个程序。 该程序仅控制该背光。

唯一的问题是Windows程序,但我希望所有功能都能在您喜欢的Linux中运行。 和灯泡一起发光,使美丽的色彩闪烁。 是的,这就是这样做的方法,这样就无需进行逆向工程并且无需编写驱动程序? 简单的答案很快就来了-没办法。 好吧,让我们去写一个驱动程序。

第1步-深入研究代码


我们在三个地方可以看到背光如何闪烁。 为了增加难度:

1.大型且充实的游戏程序Lenovo Nerve Center-其中具有配置所有这些背光的功能。

2. Fn +空格热键可以组合使用。 它由同一程序处理。

3. BIOS。 在笔记本电脑加载过程中,背光也闪烁-但只有红色,并且只有一秒钟。

展望未来,我会说我必须尝试全部三个,但是只有在第一个阶段我取得了一些成功。 我们将谈论她。

好了,打开程序文件夹:

资料夹

我们立即注意到,有一个有趣的名称DLL-LedSettingsPlugin.dll。 是我们的吗...? 让我们在IDA Pro中打开并看看。

右半

注意屏幕的右半部分。 程序员留下了很多信息-我们将使用它。 我们看到由于某种原因,有很多行与方法名称相似。 怎么了

功能名称

这些是方法的名称。 多么方便! 让我们说说我们可以使用自己的名称做什么,然后再次查看功能列表。 要在IDA中命名,您可以使用N热键,​​或者右键单击我们要调用的内容。

setledstatusex

我们看一下函数... Y720LedSetHelper :: SetLEDStatusEx。 看来我们需要! 我们注意到在这里形成了类似字符串的内容,然后将其传递给某个CHidDevHelper :: HidRequestsByPath。 对var_38特别感兴趣,IDA为我们指定了所有变种。

Var_34对我们也很有趣。 它紧随var_38之后-在汇编传统中,变量在RSP下以相反的顺序存储。 Var_34这里只是常量的名称--34h。

从var_38开始,我们将程序置零,然后样式,颜色,数字3和块是该颜色将应用到键盘的一部分。 (展望未来,我要说的是这里的亮度值是三。使其易于管理,我们得到的驱动器甚至比原始驱动器还要凉!)

让我们进入HidRequestsByPath,最后了解它的运行方式。

开发助手

我们看到两个函数HidD_GetFeature和HidD_SetFeature。 文件中的这两个都没有被跟踪...但是在Microsoft的官方文档中( 此处此处)都很好地跟踪了它们。

您可以为此祝贺自己-我们到了。 这是底部,无需深入研究。 在Linux中,有这样的函数-您只需要使用相同的参数来调用它们,一切都应该可以工作……是真的吗?

第2步-启动原型...?


不完全是 让我们开始简单并运行lsusb。 因此,我们找到了键盘,并向其发送了一些东西。

lsusb

集成技术快递有限公司 在这里看起来最有趣。 我们将使用著名的工具/ dev / hidraw。 我们找到合适的一个……这是通过在文件/ sys / class / hidraw / hidraw * / device / uevent中进行简单搜索而完成的。

Hidraw

这是一个。 数字相同-表示此设备为hidraw0。 但是我们正在尝试发送数据,但是什么也没有发生! 废话。 在这个阶段,双手开始放下……也许,不是仅仅为了凡人,这是反向工程吗?

但是,让我们继续。 我们会尽力的。 如果作者能理解所有这些内容,那么他​​将在同一神经中心反向搜索我们的驱动程序... ...但是我们没有大脑。 让我们回到Windows,有一个想法。

Windows中有这样的事情-设备管理器。 它可以让您做很多事情-我们对它可以切断设备的事实很感兴趣。 简单而毫不妥协。

让我们一次切断一个设备,直到灯泡的状态停止变化。

禁用设备

这个被切掉了。 因此,如果您查看硬件ID,我们将看到他的名字和他吃的东西。

我们的设备

我们看-是他。

dmesg

我在dmesg中已使用了数年的设备。

[他为什么不出现在lsusb中? 根本没有USB。 它使用I2C HID协议,该协议可让您从工匠的好奇手中隐藏设备,以便在计算机本身的总线上安装HID小工具。]

抒情离题-让我们提交


为了寻找正确的设备,我几乎将安装安装到了内核中。 另外,我真的不喜欢每次锁前显示此dmesg表的内容。 既然我在这里,为什么不写一个简短的提交呢? 反正手痒。

我们需要看到的是这些设备在I2C HID上的位置,以及在哪里写这些设备固有的奇特之处。 在这里 事不宜迟,让我们听听这个错误-输入长度错误。 让我们使其正确。

输入大小错误

添加一个新的怪癖,命名为I2C_HID_QUIRK_BAD_INPUT_SIZE。 类似于现有的。

怪癖

将我们的设备添加到quirkut列表中。 到目前为止,我们所做的是:

1.在Internet上搜索“ i2c隐藏的Linux内核”。 单击对DuckDuckGo的第四个响应。

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,它们可以像任何普通文件一样使用,并且可以正常工作。 但是GetFeature和SetFeature必须修补...

StackOverflow(或其他我不记得的人)建议它需要一些ioctl。 这是用于处理异常文件(例如HID设备,终端等)的特殊方法。

Ioctl的工作原理是这样的。 您给他一个打开的文件描述符(谁对它感兴趣,它有到Wikipedia的链接 ),一个数字和一个缓冲区-之后,他使用此缓冲区执行某些操作并将其返回。 我不会夸大其词,只有很多事情取决于实现。 让我举一个例子:0xC0114806,或者我们已经很熟悉SetFeature。 是

(6 << 29) | (ord('H') << 8) | (0x06 << 0) | (0x11 << 16).

这里的前6个表示该文件将打开供写入和读取。 为什么阅读不是很清楚-但写是这样做的,也许应该如此。 Ord('H')此处-缩写HID。 取决于文件,可能还有其他含义。 在这种情况下,为HID。
0x06-团队本身。 拥有HID的第六支队伍是SetFeature。 最后一部分是缓冲区的长度。

仅使用这些值调用ioctl即可,并且输出是驱动程序。 他在工作

后记


我希望阅读有趣。 甚至有用。 有些被省略或缩写-敏锐的读者也许会在驱动程序中找到状态的读数,而第二个SetFeature则没有在本文中提及。 驱动程序和Linux内核的开发是一件大事,它们无法完全掌握在一辆自行车上。 本文更可能不是关于此,而是关于以下事实:将一件小巧而令人愉悦的事情,开放源代码或为自己制作,一点都不难。 您只需要找到一个晚上的下午茶时间,并渴望深入研究代码。

Source: https://habr.com/ru/post/zh-CN484564/


All Articles