ZUDN

博客园 首页 新随笔 联系 订阅 管理

现在的计算机键盘除开传统的PS/2键盘以外另有USB键盘,本文只先容普通的PS/2键盘,是以本文的举出例子代码也只撑持PS/2键盘,对USB键盘无效。我们懂得计算机使得到键盘的信息,必需与键盘举行通信。计算机与外设的通信都是依靠I/O操作完成的,键盘也不列外,当键盘上一个键被按下后,键盘就需要发送一个信息到主机。主机怎么懂得键盘什么时候发送了信息呢?有两种方式:轮询和中断。轮询就是说主机不停的扣问键盘是不是有新的信息,这是以前I/O操作最传统的方式。中断则是一种比力先进的方式,不是由主机来不停的扣问键盘,而是由键盘主动告诉主机:有新的信息来了,这样主机就会执行一段中断处置惩罚程序,来处置惩罚键盘的数据。好了,那末Windows是用哪一种方式处置惩罚键盘的呢?固然必然以中断方式的,因为这样主机不必不断轮询装备,大大提高了效率。事实上Windows中有一个键盘中断处置惩罚程序,一旦键盘中断孕育发生后,该程序就会被执行,然后将处置惩罚后的数据提供给更高条理的程序施用。键盘中断处置惩罚程序是Ring0下的一段代码,在它之上另有更高层的键盘驱动程序,和其它更抽象的硬件办理类驱动程序,再往上走,到了Ring3层,也就是用户层,会起首由user32.dll处置惩罚,这样硬件事件会被编码为windows动静,这些动静再发给相应的应用程序。了解了这样一个条理关系后,你就可以很容易判断出一个键盘记录器处于哪一个条理,也就能懂得它到底能多大程度上精确记录键盘操作而不被欺骗。这样看来,键盘记录器固然是越底层越好,惋惜的是,越底层做起来也越难,固然是空话 ^_^ 现在我们懂得Windows是靠键盘中断来处置惩罚输入的,也就是说,所有在Windows上运行的程序要感知到键盘输入,都是靠着阿谁中断,除非...

  实在键盘中断是可以关掉的 ^_^ 如果关掉了的话,当键盘有键被按下,键盘仍然会将数据送到主机,但是中断不会被被触动引发,也就是说,键盘中断处置惩罚程序不会执行,那末也就没人理会键盘了。所以只管键盘仍然很尽职的传输按钮数据,但是Windows说:谁理你啊...

  我理,我理~! 该我们的代码上场了,前边说过了,除开中断,还可以用古老的轮询方式来获取键盘数据,所以,此时虽然中断被关掉,我们仍然可以轮询键盘的按钮,这样我们就懂得哪些键被按下了。而且很棒的是,因为此时中断已被关掉,你再也不用担心键盘中断处置惩罚程序会跟你抢数据,一个也不会漏掉~(固然,实际操作的时候也不能一直在那里轮询,不然CPU占用会暴走到100%的)!但是有个问题有可能你已经注意到了,虽然我们的程序可以轮询键盘获得输入,但是其它的程序不行啊,它们傲然眼巴巴的盼着Windows送来动静,所以结果是,虽然我们自己的程序现在可以感知键盘了,但是Windows的其它程序(包括内核里依赖键盘中断的其它驱动程序)都感知不到键盘,看中去好像键盘被我们的程序独占了一样 - - 天啦,这叫什么键盘记录器,太烂了...

  额,等等,刚才你说什么来的? "看中去好像键盘被我们的程序独占了一样"?让我想一想,哈哈,这东东好像有正确的用处~~~ 看,安全密码框!有效守势键盘记录器!"国际先进"技能~ (就像QQ的键盘加密保护吹的那样- -) 让我试一下它的强度怎样吧,GetKeyState--无效(有效才怪);全局键盘钩子(动静钩子)--无效;DirectX--无效;键盘过滤驱动--无效;站在你违后偷窥-- 汗-_-| 哈哈,还正确吧,为何键盘过滤驱动也会无效呢(那可是驱动级的记录器),因为过滤驱动位于键盘中断处置惩罚程序的上层,既是中断都关掉了,我想它也没什么好"过滤"了的吧。你会问,好吧,这个密码框还算安全,但是如果此时系统中有个记录器也是依靠轮询键盘来工作的呢,那不就都记下来啦。嗯嗯,这是一个问题,我们来解决它。怎么做呢,好办,当我们在轮询中取走键盘数据后,将键盘控制器的缓和冲突区清空,这样别的记录器就轮询不到啦,哈哈。

  (在一边看了N久的)键盘记录器制笔者说话了:别开心地太早了,要懂得键盘还撑持一个指令&HFE(键盘指令),该指令可让键盘重新发送上一次的数据给主机,本来是用于接收中浮现错误时重传数据的。但我也可以哄骗该指令在你清空缓和冲突区后让键盘重传数据,这样你的保护就失效啦 (我得意的笑,我得意的笑~)

  安全密码框制笔者:难不倒我,键盘控制器还撑持一条环回指令&HD2(控制器指令),该指令可以直接将发送给键盘的数据回传到输入缓和冲突器(意思就是说,可以将输出缓和冲突器的数据"复制"到输入缓和冲突器。再简单点就是可以发送一个数据到控制器,然后控制器将这个数据模拟成是从键盘发出的。网上那末多通过IO操作来模拟键盘按钮的方法,实在就是哄骗了这条指令:通过该指令可以将一个数据模拟成是从键盘发出的,也就是模拟按钮啦。鼠标也撑持一条环回指令&HD3,可以模拟鼠标操作),我在取走键盘端口的数据后,再用&HD2指令回传一条值为0的数据,这样键盘"上一次"发送给主机的数据也就变成为了0,再施用&HFE重发数据也没用啦... (记录器大叫一声,昏倒在地,良久不醒...)

  到这里,下面将次给出的举出例子代码之一的"安全密码框"的原理也就基本上明了了。先关闭键盘中断,然后采用轮询的办法获得键盘输入,在每一次轮询中一旦取走了键盘数据立刻向键盘控制器发送&HD2指令断根上一次的按钮信息,这样就可以有效防止别的记录器也采用轮询的办法来记录键盘。同时,由于关闭了键盘中断,Windows中所的程序都没有办法感知到键盘输入,无论全局HOOK还是别的什么,统统失效。所以,这个密码框的保护强度还是很正确的。从键盘的角度说,QQ的键盘加密保护也是采用了类似的方法,不过又稍有不同。QQ的键盘加密技能并没有关闭键盘中断来轮询,而是采用了另一个办法:替代掉系统默认的键盘中断处置惩罚程序,换成为了QQ自己的键盘中断处置惩罚,这个QQ的中断程序并不会把键盘动静发送给Windows的上层办事,而是擅自处置惩罚了这些动静,将用户的键盘输入加密,然后将密文直接通报给了QQ,是以任何位于上层的键盘记录器都记录不了QQ的密码输入啦。QQ2008早期版本的键盘加密驱动在取走键盘端口的数据后,同样会有一个清空键盘输入缓和冲突区的操作,让别的程序即使轮询也轮询不了。但是阿谁版本的兼容性却不太好,特别是导致施用USB键盘的用户时常蓝屏,腾讯厥后改进了保护方式。在QQ2008的后期版本中,键盘加密的不改变性别提高了,但是保护强度却减低了,并且也没有了清空输入缓和冲突区的动作,而是改用另一个思路:通过不断注入垃圾字符来匹敌键盘记录器。但是这样的话施用普通轮询的方法也可以中途截获到用户的输入了,这也许是腾讯在保护强度和不改变性别之间做出的一个折中。好啦,另有个问题,你用上面所说的原理做了个安全密码框,在密码框中倒是可以输入了,但是你关了程序以后,发现键盘失效啦,Windows所有程序都对键盘一点反映也没有 - - 哈哈,刚才说啦,键盘中断不是被关闭了吗,Windows靠中断来感知键盘,既是关掉了,固然键盘就不灵了,所以密码框在实际制作的时候应该这样:当密码框获得输入核心的时候才关闭键盘中断,当密码框失去核心时应该立刻重新打开键盘中断,当窗体失去核心时也应该开中断,当登录完成或程序结束时都要打开中断,不然别的程序就不能感知键盘了。另外,轮询键盘端口得到的数据都是键盘扫描码,你还需要转换成虚拟键码和对应的ASCII字符才行的。

  说完了安全密码框,现在也来说说哄骗这个原理怎么制作键盘记录器,好在物质都是两面的。我的思路是这样:可以简单轮询,就是设置一个定时器,每30毫秒读取一次键盘数据端口,就可以懂得有没有键被按下了。这个方法对大多数程序有效,对现在版本的QQ2008也有效(上面说过现在它的保护强度减低了嘛)。但是对于早期版本的QQ2008是无效的,因为那时的QQ键盘加密有个动作,就是取完了数据后会将键盘端口清零。而且键盘中断的反映速度永远比用轮询的方法快(原因很较着,中断是由装备通知的,老是在"熬头时间"被激活,而轮询则不是),所以轮询到的数据永远是被QQ清空后的零。而且简单轮询另有个错误错差,你需要自己来通过别的寄放器状态辨认轮询到的是键盘数据还是鼠标数据

  因为,你梗概已经懂得,在PS/2装备中,键盘控制器和鼠标控制器是共用的,而且它们的输入缓和冲突区也是共用的,也就是说,键盘数据和鼠标数据是会混拼凑的,如果你只是简单轮询&H60端口的话,你就需要靠别的办法来区分键盘和鼠标数据了(在举出例子代码中,你将可以看到如何举行简单轮询)。现在我们施用一种改进的办法来轮询,它可以解决上面所说的问题,并对早期版本的QQ2008也有效。思路是:起首关闭键盘中断,这时QQ密码框也不会获得任何输入了,然后用轮询的方法判断键盘有没有输入。

  因为此时中断已被关掉,再也不会有谁跟我们抢数据了,所以获得的键盘输入老是"熬头手的"。在本文的开头已经先容了这个思路。下面的问题是,轮询完结后,怎样让QQ也能获得输入(注意此时键盘中断已被关闭)?解决方法是打开中断,然后哄骗上面的&HFE指令或者&HD2指令。我们可以在每次轮询结束后,如果发现有按钮动静,则打开键盘中断,然后用&HFE指令让键盘重发上一次的数据,或者用&HD2指令将我们轮询到的数据塞回输入缓和冲突区。注意实际测试时发现&HFE指令似乎不能再次激发键盘中断,所以我用&HD2来将我们取走的数据重新塞回去,这个操作可以同时激发一次键盘中断,由于此时中断已经打开,中断处置惩罚程序被激活,会取走我们塞回去的数据,这样QQ或者其他任何程序都能接收到键盘输入了。注意中断处置惩罚程序取走的可是我们塞回去的数据哦,实际上我们想塞进去几都可以,好比我轮询到的是A键被按下,但是我纯粹可以欺骗系统是B键被按下。所以,这个思路另有另一个用途,修改实际按钮,而且该修改是很底层的,足以欺骗键盘中断处置惩罚程序和任何位于它上层的程序。好了,现在中断处置惩罚程序已经处置惩罚完结,系统已经收到了按钮动静(若是QQ密码框,那末这个密码框也收到了按钮),注意它们都是在我们的程序然后(并且经过我们程序的赞成)才收到这一动静的,是以可以以为,键盘已经被我们的程序从较底层给HOOK了,接下来,再次关闭键盘中断,然后等待下一次轮询。

  可以看到,在中断关闭时期其它程序都得不到键盘动静,而中断打开时我们的程序已经处置惩罚完键盘数据,所以可以包管我们的程序总在"最前边"得到按钮信息。你可以设置一个定时器,然后轮流训练距离为30毫秒左右,时间不能太长,否则键盘记录器反映很慢,也不能太短,否则太占系统资源。你要问了,按照这个思路的话,每一秒钟键盘中断都要打开关闭很多多少次,对性能有影响吗?谜底是肯定的,这个记录器确实会在一定程度上减低键盘的反映速度,不过它的性能比我预想的要好得多,实际测试时,对性能并没有太大影响,甚至不太感到它的存在 ^_^

  最后,另有一些重要的工具没说到呢。好比怎样轮询键盘,这样关闭键盘中断?在这里我试图尝试一种只需要通过I/O操作就能完成上面所说的使命的方法。

  轮询键盘,实在就是读取键盘控制器的数据,通过两个I/O端口来完成:&H64(控制端口)和&H60(数据端口)。

  从&H60端口读取就可以得到键盘(或鼠标)发送来的数据(实际读取的是输入缓和冲突区),读取该端口还会清零IBF(输入缓和冲突区满)标志,系统正是根据这个标志来被触动引发键盘中断,读取&H64端口可以懂得键盘控制器的状态。

  写入&H60端口会被写到输出缓和冲突区,通常是发送给键盘的数据。写入&H64端口则会被理解为向键盘控制器发送号令。号令分两种,键盘控制器号令和键盘号令,键盘控制器号令是操作控制器的,控制器也许需要再操作键盘才能完成此号令,但也有可能不需要;键盘号令是直接发送给键盘的。发送控制器号令需要起首将控制字写入&H64端口,如果号令有参数,参数写入&H60端口,发送键盘号令的话,直接将控制字写入&H60端口就可以了,参数紧跟控制字也写入&H60端口。无论哪一种号令,如果有什么返次数据的话,都通过&H60端口读取。下面列举一部门控制器号令和键盘号令。

  控制器号令:

  &HA1:获得版本号。 &HA4:获得密码。 &HA5:设置密码 &HA6:比力密码

  &HA7:禁用鼠标 &HA8:启用鼠标 &HAD:禁用键盘 &HAE:启用键盘

  &HD2:写键盘缓和冲突区的环回指令(模拟键盘可以用这个) &HD3:写鼠标缓和冲突区的环回指令(可以模拟鼠标操作)

  键盘号令:

  &HFF:复位键盘 &HFE:重新发送上一次的数据给主机 &HED:在此号令然后需要追随一个参数字节,用于设置键盘上那三个指示灯的状态

  那末现在懂得怎样在控制器上直接关掉键盘中断了吧,只需要发送一个号令给控制器就可以了,具体的号令和参数可以参见最下面给出的举出例子代码。最后另有一个问题没解决:怎样才能直接读写键盘的端口?要懂得在Windows中普通的应用程序是无权直接操作端口的,需要有Ring0的职权范围才行。这个问题的解放方式可以是很多的,我在举出例子代码中施用了一个开源的组件WinIO,WinIO是一个可以用来直接在应用程序中读取I/O端口和物理内存的组件,它被时常用在工控上操作IO卡之类。要了解WinIO的详细用法可以在网上搜索此关键词。要注意一个问题是由于WinIO组件时常被用来干坏事,名气又那末大,现在已是被不少安全类软件打入另册了。所以在实际实践中你未必非要用它,只要能想办法直接读写端口就可以使成为事实键盘记录了。

  这时昏迷良久的记录器遽然醒了,对密码框大叫:有办法了,我可以HOOK掉你WinIO中的函数GetPortVal,这样就能在你之前中途截获到键盘输入了!

  密码框:那我换一个其它组件来操作端口你不就失效了。而且这类办法也超出了记录器的讨论范围 - -

  记录器:那我可以下I/O断点,这样就能断掉你的IO操作并抢在你前边中途截获键盘输入~

  密码框:下断不是不能检测的,如果检测到被断则可以通知用户密码框保护已失效。并且这样做也很复杂,弄欠好的话会泼天减低系统不改变性别,那样用户也能发现。

  记录器:我还可以...

  密码框:......

  看来这两个永远是一对冤家了 ^_^

  最后的最后,是我的举出例子代码的地址,它包罗两个举出例子:键盘记录器和安全密码框,都是根据上面所说的原理制成。(如果要在调试模式下运行此代码的话,需要把名称为winio的那几个文件复制到VB的安装目次下才行)你说,要是用你的矛戳你的盾会怎么样呢。哈哈,幸好WinIO永远不赞成恁地做 ^_^

  源码下载地址: http://www.pen88.com/download/keysafe.rar

  我的QQ1304538366欢迎交流

  最后,另有一些重要的工具没说到呢。好比怎样轮询键盘,这样关闭键盘中断?在这里我试图尝试一种只需要通过I/O操作就能完成上面所说的使命的方法。轮询键盘,实在就是读取键盘控制器的数据,通过两个I/O端口来完成:&H64(控制端口)和&H60(数据端口)。

  要是能所有事情都用VB来做固然也好,问题是,VB并不是做所有事都是不肯低头。VB也可以编译出驱动来,某高人以前干过,VB也可以写出能倒出函数的标准DLL,方法网上有。问题是这并不是VB擅长的,要是作为研究倒可以,实际施用就不是最好了。

  恁地说来VB内嵌汇编也不能算是VB程序,因为关键的事情都是汇编干的,VB调用API也不是VB了,因为那API不是VB写的咯。

  于要防止在使命办理器中关闭的话,虽然并不是这个帖子要讨论的,不过在这里也说一下winio驱动的高级用法。winio驱动虽然不是VB写的,但是在VB中却可以很好的施用,就现在VB中施用其它第三方控件一样发挥最大的用途。注意WinIO是可以直接读写物理内存的。网上有一个经典的VB隐蔽进程的代码,原理是施用windows的内核对象直接操作物理内存然后修改了进程链表,到达隐蔽的目的。但是厥后阿谁代码实效了,因为windows在厥后的补钉中关闭了阿谁内核对象,所以没办法直接读写物理内存了,但是WinIO可以做到,所以可以哄骗WinIO改进阿谁代码,也就能隐蔽进程了。更多的用途是,WinIO允许你直接在Ring3层执行Ring0代码。你说WinIO好像没这功能吧?但是WinIO不是可以写物理内存的,你纯粹可以哄骗它构造一个调用门,再结合VB内嵌汇编的技能,下面就懂得该怎么做了吧。WinIO只是一个通用驱动组件,它无非是给我们提供一个直接读写物理内存和端口的功能。但正是这些基本功能,可让我们做很多事,至于具体还能做什么,就要看自己的施用了。

  后,另有一些重要的工具没说到呢。好比怎样轮询键盘,这样关闭键盘中断?在这里我试图尝试一种只需要通过I/O操作就能完成上面所说的使命的方法。轮询键盘,实在就是读取键盘控制器的数据,通过两个I/O端口来完成:&H64(控制端口)和&H60(数据端口)。从&H60端口读取就可以得到键盘(或鼠标)发送来的数据(实际读取的是输入缓和冲突区),读取该端口还会清零IBF(输入缓和冲突区满)标志,系统正是根据这个标志来被触动引发键盘中断,读取&H64端口可以懂得键盘控制器的状态。写入&H60端口会被写到输出缓和冲突区,通常是发送给键盘的数据。写入&H64端口则会被理解为向键盘控制器发送号令。号令分两种,键盘控制器号令和键盘号令,键盘控制器号令是操作控制器的,控制器也许需要再操作键盘才能完成此号令,但也有可能不需要;键盘号令是直接发送给键盘的。发送控制器号令需要起首将控制字写入&H64端口,如果号令有参数,参数写入&H60端口,发送键盘号令的话,直接将控制字写入&H60端口就可以了,参数紧跟控制字也写入&H60端口。无论哪一种号令,如果有什么返次数据的话,都通过&H60端口读取。下面列举一部门控制器号令和键盘号令。

  控制器号令:

  &HA1:获得版本号。 &HA4:获得密码。 &HA5:设置密码 &HA6:比力密码

  &HA7:禁用鼠标 &HA8:启用鼠标 &HAD:禁用键盘 &HAE:启用键盘

  &HD2:写键盘缓和冲突区的环回指令(模拟键盘可以用这个) &HD3:写鼠标缓和冲突区的环回指令(可以模拟鼠标操作)

  键盘号令:

  &HFF:复位键盘 &HFE:重新发送上一次的数据给主机 &HED:在此号令然后需要追随一个参数字节,用于设置键盘上那三个指示灯的状态

  那末现在懂得怎样在控制器上直接关掉键盘中断了吧,只需要发送一个号令给控制器就可以了,具体的号令和参数可以参见最下面给出的举出例子代码。最后另有一个问题没解决:怎样才能直接读写键盘的端口?要懂得在Windows中普通的应用程序是无权直接操作端口的,需要有Ring0的职权范围才行。这个问题的解放方式可以是很多的,我在举出例子代码中施用了一个开源的组件WinIO,WinIO是一个可以用来直接在应用程序中读取I/O端口和物理内存的组件,它被时常用在工控上操作IO卡之类。要了解WinIO的详细用法可以在网上搜索此关键词。要注意一个问题是由于WinIO组件时常被用来干坏事,名气又那末大,现在已是被不少安全类软件打入另册了。所以在实际实践中你未必非要用它,只要能想办法直接读写端口就可以使成为事实键盘记录了。

  这时昏迷良久的记录器遽然醒了,对密码框大叫:有办法了,我可以HOOK掉你WinIO中的函数GetPortVal,这样就能在你之前中途截获到键盘输入了!

  密码框:那我换一个其它组件来操作端口你不就失效了。而且这类办法也超出了记录器的讨论范围 - -

  记录器:那我可以下I/O断点,这样就能断掉你的IO操作并抢在你前边中途截获键盘输入~

  密码框:下断不是不能检测的,如果检测到被断则可以通知用户密码框保护已失效。并且这样做也很复杂,弄欠好的话会泼天减低系统不改变性别,那样用户也能发现。

  记录器:我还可以...

  密码框:......

  看来这两个永远是一对冤家了 ^_^

  最后的最后,是我的举出例子代码的地址,它包罗两个举出例子:键盘记录器和安全密码框,都是根据上面所说的原理制成。(如果要在调试模式下运行此代码的话,需要把名称为winio的那几个文件复制到VB的安装目次下才行)你说,要是用你的矛戳你的盾会怎么样呢。哈哈,幸好WinIO永远不赞成恁地做 ^_^

  我在源码天际发了很多原创文章,大家可以去看看。我的QQID就是我不想做独一

  大家看了说下自己的经验感觉。

posted on 2010-12-20 11:47  ZUDN  阅读(11117)  评论(0编辑  收藏  举报