百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

CPU眼里的:键盘驱动(键盘的驱动程序)

gudong366 2025-07-13 18:33 4 浏览

从驱动层改造键盘:一步步带你实现输入黑科技



01

提出问题


假设你对汇编语言只了解皮毛,且没有写过任何 Windows 驱动程序,同时又缺乏编译工具的支持,但任务是要在没有事先准备的情况下,实时修改一个运行中的键盘驱动程序,并且改变键盘的行为。面对这样的挑战,你会如何应对呢?


“CPU眼里python和C”中,我们介绍了WinDbg调试python应用程序的能力,这里我们就可以用它来调试、并在线修改一下Windows的键盘驱动,从而改变键盘的行为。



02

准备开发环境


首先准备一下开发环境,这里被调试设备,也就是目标设备,是一台Windows 7虚拟机。启动虚拟机后,运行命令:msconfig;在boot标签里面,选择:advanced options,并勾选Debug,如图所示:

注意,这里的调试端口是串口COM1,波特率为:115200。最后确认一下,我们就可以暂时把虚拟机关掉了。


随后就是把被调试的虚拟机和用于调试的主机连接起来。这里我们采用管道化的串口连接方式(也就是进程通信)。具体操作是:在虚拟机的设置中,找到串口COM1的设置,选择管道,并填写管道名称,这里我们输入:WinDbg;并拷贝下完整的管道路径,也就是:\\.\pipe\WinDbg,如图所示:

接着就是设置主机了,用administrator模式打开WinDbg;点击Kernel Debug,选择串口(COM)连接,并选中管道方式;然后在端口(port),输入刚才拷贝的管道路径(\\.\pipe\WinDbg)就好,如图所示:

一切顺利的话,点击OK按钮后,WinDbg就会开始等待:被调试设备的连接请求了。



03

代码调试


万事俱备,再次启动虚拟机,不出意外的话,WinDbg的状态,马上就会发生变化,此时WinDbg已经连接上了被调试的虚拟机了,如图所示:

虚拟机顺利进入Windows 7的界面后,打开设备管理器,看看我们将要修改的键盘驱动程序,点击driver和details,我们就可以找到这个驱动程序:i8042prt.sys文件,如图所示:

记住这个文件名(i8042prt.sys),我们马上就要用到了。需要注意的是,虚拟机模拟的是老旧的PS2接口的键盘,如图所示:

所以,无论你用的是蓝牙键盘还是USB键盘,虚拟机看到的都是PS2键盘。

再次打开WinDbg,点击暂停,可以让虚拟机瞬间石化,然后在命令行中,输入命令:x i8042prt!*read*


其中i8042prt就驱动程序的文件名,通过x命令,我们就可以检测出该驱动程序里面,所有包含read字样的函数接口了,如图所示:

很快,我们就发现了一个可疑的函数:I8xReadPortUchar,根据相关文档,我们知道这是用来从PS2中读取键盘数据的函数接口,如果我们能篡改读到的键值,就可以间接改变键盘的行为,这里我们将尝试,把键盘的所有输入都改成字符:a


需要说明一下的是:尽管Windows和Linux的驱动框架有很大的差异,但是数据源头都来自于硬件,我们控制了I/O信息,就相当于控制了操作系统的信息来源。


说干就干,通过命令:u i8042prt!I8xReadPortUchar,我们就可以看到函数I8xReadPortUchar在内存中的样子,也就是函数的CPU指令。WinDbg还非常贴心的把这些指令翻译成了汇编语言,如图所示:

代码出乎意料的简单,只有3条指令。根据“CPU眼里的参数传递”,可以知道:第一条指令是把函数的参数从寄存器cx(rcx的低8位)里面,读取到寄存器edx(rdx的低32位)里面。


这个参数(cx)的意义是PS2接口的端口号,根据文档,如图所示:

PS2有两个I/O端口。一个是0x64端口,用来读取PS2设备的状态;一个是0x60端口,用来读取PS2设备的数据,也包含PS2键盘的键值。


需要注意的是:不同于ARM的I/O统一编址,x86 CPU需要通过专门I/O指令来读取I/O数据。也就是第二条指令:in


它就是从PS2的I/O端口中,把键值或状态数据读入寄存器al(rax的低8位)里面。当然,如“CPU眼里的函数返回值”所说,寄存器al,也担负着存放返回值的职责。


最后一条ret指令,作函数返回。所以,这个函数的功能十分简单,就是读取0x64端口或0x60端口上的数值,对应的C语言,大概是这个样子:

int I8xReadPortUchar(int* port)
{
    return *port;//in al, dx
}

至于0x64端口上的设备状态信息,我们并不关心,这里我们只关注从0x60端口,获得的键值,我们需要把从x60端口读出的键值,改成字符a的键值:0x1E。逻辑非常简单,让我们马上动手,在线修改驱动程序吧。

输入这个命令:a fffff880`03d0323c

这意味着我们将从这个ret指令所在的内存地址(fffff880`03d0323c)处输入汇编指令,该操作会覆盖ret及后面的CPU指令,WinDbg则会自动帮我们把汇编指令转成机器码(CPU指令)。如图所示:

这里,先判断寄存器dx是否是0x60端口,如果是的话,就跳转到后面的代码,去修改键值;修改键值的代码,距离函数首地址的偏移量是11(0xB)个字节,如果写错了这个偏移量也没有关系,我们还可以回过头来修改。


相反,如果不是0x60端口的话,我们就遵从老代码的处理方式:直接ret;随后,就是修改键值的部分了。


通过mov指令,把用来存储函数返回值的寄存器al(寄存器rax的低8位)设置为按键a的键值,也就是0x1E;最后通过ret指令,使函数正常返回。


这样随着函数的逐层返回,操作系统就会误以为读到的键值是:a。代码写完,记得再按一下回车键,结束汇编指令的输入。


最后,还可以通过命令:u i8042prt!I8xReadPortUchar,检查一下刚刚我们写的代码,如图所示:

其对应的C语言代码,大概是这个样子:

int I8xReadPortUchar(int* port)
{
    int value = *port;//in al, dx
    if(port == 0x60)
    {
        value = 0x1e;
    }
    return value;
}

好了,现在可以验证我们的工作成果了,输入命令go,让虚拟机继续运行。用鼠标在虚拟机中打开一个新建的空文本文件,让我们在键盘上输入:1,2,3


如果一切顺利的话,Windows果然认为我们输入的都是:a;由于我们的代码中没有区分键盘的按下,弹起,所以1次按键,会产生2个a;这时,即使我们随意按任何按键,按键的键值都被驱动程序改写成了a的键值。所以,文本文件中只有字符:a。如图所示:

最后,请不要担心你的键盘就会从此失灵了,因为我们只是修改了内存中的键盘驱动程序,并没有修改驱动文件:i8042prt.sys,所以,只要我们重新启动虚拟机,Windows再次把原有的驱动程序从文件i8042prt.sys加载到内存中后,你的键盘就可以重新恢复正常了。



04

总结


1. 驱动程序和应用程序都是程序,都需要使用系统资源,如内存、CPU、存储空间等。许多情况下,驱动程序也是用C/C++语言编写的,它们的运行原理和实现细节与普通应用程序非常相似,例如都需要函数堆栈的支持。


除了少数特殊的CPU指令外(例如本文中用来读取PS2端口的指令:in),许多CPU指令是通用的,既可以用于应用程序,也可以用于驱动程序。


2. 驱动程序运行在内核态,拥有对系统和硬件的完整、全面的控制和访问权限。不同于应用程序有操作系统作兜底的错误处理,一个应用程序的错误通常不会影响其他程序或整个系统。然而,驱动程序往往缺乏完善的错误处理机制,其错误可能导致系统蓝屏或死机。


3. 应用程序和驱动程序的分工不同。应用程序通常为用户提供直接的功能(如文档编辑、浏览网页),而驱动程序通常不与用户直接交互,而是为硬件设备提供必要的支持,以便这些设备能够被应用程序顺利使用。


驱动程序还在硬件与操作系统之间充当中介,帮助操作系统识别和使用计算机硬件,如显卡驱动、打印机驱动和网络适配器驱动等。没有适当的驱动程序,操作系统可能无法正常通信和使用硬件设备,从而导致应用程序无法正常使用这些设备。


总而言之,应用程序主要为用户提供操作和功能,而驱动程序为硬件提供操作系统访问的接口。应用程序通常是面向用户的,而驱动程序是面向系统和硬件的。尽管两者都是计算机软件,但由于功能和运行环境的不同,它们的开发和管理方式也有所差异。



05

更多知识


如果喜欢阿布这种解读方式,希望更加系统学习这些编程知识的话,也可以考虑看看由阿布亲自编写,并由多位微软大佬联袂推荐的新书《CPU眼里的C/C++》



<script type="text/javascript" src="//mp.toutiao.com/mp/agw/mass_profit/pc_product_promotions_js?item_id=7520466649472844342"></script>

相关推荐

U盘文件被删怎么简单恢复(u盘里的文件被误删了怎么找回)

现在这个社会不是靠关系靠路子,主要还是靠实力。刘强在机关工作,人长得帅气,工作能力又强。唯独一样不好,脾气太大,动不动就发火,因为小事常和同事发生口角。一次他火大的差点把办公桌给掀翻了,领导见他野蛮的...

不小心删除了一些文件?9 个最佳免费硬盘恢复软件

恢复您曾经无意或意外删除的所有文件和数据。您是否曾经错误地删除了一个对您的工作至关重要并导致您丢失所有进度的文件?我们为您提供了一些最好的免费硬盘恢复软件,以帮助您恢复意外删除的文件,以解决您的文件删...

Studio 中文版:数据救援神器,误删 / 分区损坏 / RAID 恢复一键找回

Studio中文版:数据救援神器,误删/分区损坏/RAID恢复一键找回当文件意外删除、分区损坏,或RAID阵列崩溃时,一款可靠的数据恢复工具往往能挽回关键损失。R-Studio中文版...

你值得拥有的11款Linux数据恢复工具

如果你使用的是Linux操作系统,那么你一定想知道一旦硬盘崩溃的话又该如何保存和恢复数据。其实,现在有很多Linux数据恢复工具可以让我们摆脱数据安全的困扰。小编已经为各位准备好了一些最好的Linux...

误删文件内容怎么恢复(误删文件内容怎么恢复回来)

  在日常使用电脑的过程中,误删文件的情况时有发生。无论是由于操作失误还是病毒攻击,误删文件都会给我们带来不小的困扰。幸运的是,随着技术的发展,误删文件恢复已不再是难题。本文将介绍几款国内外知名的误删...

u盘如何恢复删除的文件?推荐5款u盘数据恢复软件!

在日常生活与工作中,U盘作为便捷的数据存储载体,频繁用于传输和保存各类重要文件。然而,误删文件的情况却时有发生,无论是珍贵的照片、重要的工作文档,还是精心制作的视频,一旦删除,都可能带来不小的麻烦。...

怎么恢复删除的数据?5种有效的数据恢复方法汇总!

在数字化办公与生活的时代,电脑里的每一份数据都承载着重要信息。然而,一个误操作就可能导致数据被删除,无论是尚未保存的重要文档,还是珍藏多年的照片,都可能瞬间“消失”。但其实,数据删除并不意味着永久丢...

u盘删除文件怎么找回?5个数据恢复工具汇总,助你巧妙恢复数据!

在日常使用U盘的过程中,误删文件的情况时有发生,重要的工作文档、珍贵的照片视频一旦消失,难免让人焦急万分。别担心,只要选对数据恢复工具,被删除的数据仍有找回的可能。下面就为你汇总5款实用的数据...

Linux下恢复误删文件:思路+实践(linux删除如何恢复)

周五篮球群里有人问误删文件了怎么恢复,得知是ext4文件系统之后我推荐了ext4magic这个工具,然后又有人提到了xfs的话怎么办,正好前几天看到DaveChinner在邮件列表里提到了这个问题,...

苹果放大招!不用虚拟机了,Mac直接跑Linux容器,开发者效率翻倍

苹果这次真给开发者送福利了!今天凌晨(6月10日),苹果在官宣的Containerization框架直接炸了技术圈——Mac现在能原生运行Linux容器镜像了!这可不是虚拟机那种“套娃”方案,而是基...

7 款老牌经典软件,值得收藏(经典老歌软件)

Calibrehttps://calibre-ebook.com/Calibre是一个电脑电子书管理软件。肯定有人说了,电子书还要管理?那当然了。它的功能更强大的让你想象不到,首先它可以导入PDF,...

神仙级的免费开源电子书阅读器,还支持听书功能

神仙级的免费开源电子书阅读器,还支持听书功能,极空间部署『KoodoReader』哈喽小伙伴们好,我是Stark-C~前段时间不是给大家分享的电子书管理工具『TaleBook』嘛~,然后就有粉丝私信...

如何在Ubuntu系统中重置root密码(ubuntu忘记密码重置root密码命令)

很多人有个问题,就是喜欢把密码设置得很长很复杂,结果谁也没防住,却成功防住了自己ヽ(.ˇдˇ;)ノ对于现代人,特别是年轻人,都有过忘记密码的经历吧。在这篇文章中,我们来了解如何在Ubuntu1...

5款功能强大的PDF阅读器,让PDF阅读更轻松

分享5款功能强大的PDF阅读器,拥有丰富的PDF阅读工具,支持PDF文档划线、笔记、标记等操作,让PDF阅读更轻松!1.嗨动PDF编辑器一款实用的PDF处理软件,不仅可以阅读PDF文档,还能直接编辑、...

上班摸鱼利器! 免费好用的电子书阅读器,NAS轻松部署Koodo Reader

哈喽,大家好我是生活爱好者。笔者也是一名小说爱好者,平时用手机用某信读书,会员也开了,在家看体验也不错,但是上班的时候,在工作快速完成之后,想摸个鱼用手机就不太方便啦,作为爱折腾的人,必须要工作认真,...