关于键盘驱动

关于键盘驱动

今天想在DOS下用C语言写一个带菜单的程序,一开始没有一点思路,主要是不知道怎样实现菜单的功能,于是上网搜索,得到启发:可以通过读取键盘的扫描码,从而实现菜单的功能。于是我开始研究怎样去获取键盘的输入信息,经过大半天的Google,现在我将关于键盘的知识记录下来。

我用的机器的平台是Intel Atom N270+945GSE+ICH-7M+EMC5035。

所谓的键盘控制器(KBC),也就是Intel 8042;它位于EC中,8042负责读取键盘扫描码并将其存在缓冲器中供程序读取;另外还有一个芯片ECE1077,它负责连接键盘和EC,将键盘动作转换成扫描码。CPU通过两个IO端口与8042通信,这两个IO端口就是0x60,0x64端口。下面介绍一下CPU怎样通过这两个IO端口与8042通信。

8042有四个8位的寄存器,它们是输入寄存器(RO)、输出寄存器(WO)、状态寄存器(RO)和命令寄存器(R/W)。

读输出寄存器:inportb(0x60);

写输入寄存器:outportb(0x60,data);

读状态寄存器:inportb(0x64);

读命令寄存器:先向0x64端口写命令0x20:outportb(0x64,0x20);再从0x60端口读数据:inportb(0x60);

写命令寄存器:先向0x64端口写命令0x60:outportb(0x64,0x60);再向0x69端口写数据:outportb(0x60,data);

状态寄存器和命令寄存器的每一位都是有特定意义的,如下:

状态寄存器:

Bit7: PARITY-EVEN(P_E): 从键盘获得的数据奇偶校验错误

Bit6: RCV-TMOUT(R_T): 接收超时,置1

Bit5: TRANS_TMOUT(T_T): 发送超时,置1

Bit4: KYBD_INH(K_I): 为1,键盘没有被禁止。为0,键盘被禁止。

Bit3: CMD_DATA(C_D): 为1,输入缓冲器中的内容为命令,为0,输入缓冲器中的内容为数据。

Bit2: SYS_FLAG(S_F): 系统标志,加电启动置0,自检通过后置1

Bit1: INPUT_BUF_FULL(I_B_F): 输入缓冲器满置1,i8042 取走后置0

Bit0: OUT_BUF_FULL(O_B_F): 输出缓冲器满置1,CPU读取后置0

命令寄存器:

Bit7: 保留,应该为0

Bit6: 将第二套扫描码翻译为第一套

Bit5: 置1,禁止鼠标

Bit4: 置1,禁止键盘

Bit3: 置1,忽略状态寄存器中的 Bit4

Bit2: 设置状态寄存器中的 Bit2

Bit1: 置1,enable 鼠标中断

Bit0: 置1,enable 键盘中断
有了以上知识,再对照键盘的ScanCode表,我们就可以编写程序读取并判断键盘输入的数据,并根据不同的按键执行不同的动作。

———————————————————————————————————————————————

另外,发给8042的命令除了以上所讲的读/写命令寄存器以外,还有其他一些命令;这些命令可以分为两类:

一类是直接发给8042的命令,包括设置键盘密码,自检,开启和禁用键盘等;

还有一类是先发给8042,再通过8042间接发送给8048的命令。这里的8048类似上述的ECE1077,它将键盘动作转换成ScanCode供8042读取。这类操作命令有设置键盘LED灯,设置扫描码类型,设置键盘工作方式等。

这两类命令的详细信息如下:

① 通过写端口0x64,直接发送给8042的命令:

20h

准备读取8042芯片的Command Byte;其行为是将当前8042 Command Byte的内容放置于Output Register中,下一个从60H端口的读操作将会将其读取出来。

60h

准备写入8042芯片的Command Byte;下一个通过60h写入的字节将会被放入Command Byte。

A4h

测试一下键盘密码是否被设置;测试结果放置在Output Register,然后可以通过60h读取出来。测试结果可以有两种值:FAh=密码被设置;F1h=没有密码。

A5h

设置键盘密码。其结果被按照顺序通过60h端口一个一个被放置在Input Register中。密码的最后是一个空字节(内容为0)。

A6h

让密码生效。在发布这个命令之前,必须首先使用A5h命令设置密码。

AAh

自检。诊断结果放置在Output Register中,可以通过60h读取。55h=OK。

ADh

禁止键盘接口。Command Byte的bit-4被设置。当此命令被发布后,Keyboard将被禁止发送数据到Output Register。

AEh

打开键盘接口。Command Byte的bit-4被清除。当此命令被发布后,Keyboard将被允许发送数据到Output Register。

C0h

准备读取Input Port。Input Port的内容被放置于Output Register中,随后可以通过60h端口读取。

D0h

准备读取Output Port。结果被放在Output Register中,随后通过60h端口读取出来。

D1h

准备写Output Port。随后通过60h端口写入的字节,会被放置在Output Port中。

D2h

准备写数据到Output Register中。随后通过60h写入到Input Register的字节会被放入到Output Register中,此功能被用来模拟来自于Keyboard发送的数据。如果中断被允许,则会触发一个中断。

②通过写端口0x60,间接给8048发送命令:

EDh

设置LED。Keyboard收到此命令后,一个LED设置会话开始。Keyboard首先回复一个ACK(FAh),然后等待从60h端口写入的LED设置字节,如果等到一个,则再次回复一个ACK,然后根据此字节设置LED。然后接着等待。。。直到等到一个非LED设置字节(高位被设置),此时LED设置会话结束。

0xED命令后面跟的命令数据格式

EEh

诊断Echo。此命令纯粹为了检测Keyboard是否正常,如果正常,当Keyboard收到此命令后,将会回复一个EEh字节。

F0h

选择Scan code set。Keyboard系统共可能有3个Scan code set。当Keyboard收到此命令后,将回复一个ACK(FAh),然后等待一个来自于60h端口的Scan code set代码。系统必须在此命令之后发送给Keyboard一个Scan code set代码(01~03)。当Keyboard收到此代码后,将再次回复一个ACK,然后将Scan code set设置为收到的Scan code set代码所要求的。如果数据为0x00,则主机返回当前使用的键盘扫描码集的编号。

F2h

读取Keyboard ID。由于8042芯片后不仅仅能够接Keyboard。此命令是为了读取8042后所接的设备ID。设备ID为2个字节,Keyboard ID为83ABh。当键盘收到此命令后,会首先回复一个ACK(FAh),然后,将2字节的Keyboard ID一个一个回复回去。

F3h

设置Typematic Rate/Delay。当Keyboard收到此命令后,将回复一个ACK(FAh)。然后等待来自于60h的设置字节。一旦收到,将回复一个ACK,然后将Keyboard Rate/Delay设置为相应的值。

F4h

清理键盘的Output Buffer。一旦Keyboard收到此命令,将会将Output buffer清空,然后回复一个ACK(FAh)。然后继续接受Keyboard的击键。

F5h

设置默认状态(w/Disable)。一旦Keyboard收到此命令,将会将Keyboard完全初始化成默认状态。之前所有对它的设置都将失效——Output buffer被清空,Typematic Rate/Delay被设置成默认值。然后回复一个ACK(FAh),接着等待下一个命令。需要注意的是,这个命令被执行后,键盘的击键接受是禁止的。如果想让键盘接受击键输入,必须Enable Keyboard。

F6h

设置默认状态。和F5命令唯一不同的是,当此命令被执行之后,键盘的击键接收是允许的。

FEh

Resend。如果Keyboard收到此命令,则必须将刚才发送到8042 Output Register中的数据重新发送一遍。当系统检测到一个来自于Keyboard的错误之后,可以使用自命令让Keyboard重新发送刚才发送的字节。

FFh

Reset Keyboard。如果Keyboard收到此命令,则首先回复一个ACK(FAh),然后启动自身的Reset程序,并进行自身基本正确性检测(BAT-Basic Assurance Test)。等这一切结束之后,将返回给系统一个单字节的结束码(AAh=Success, FCh=Failed),并将键盘的Scan code set设置为2。

③从0x60读出的数据:

00h/FFh

当击键或释放键时检测到错误时,则在Output Bufer后放入此字节,如果Output Buffer已满,则会将Output Buffer的最后一个字节替代为此字节。使用Scan code set 1时使用00h,Scan code 2和Scan Code 3使用FFh。

AAh

BAT完成代码。如果键盘检测成功,则会将此字节发送到8042 Output Register中。

EEh

Echo响应。Keyboard使用EEh响应从60h发来的Echo请求。

F0h

在Scan code set 2和Scan code set 3中,被用作Break Code的前缀。

FAh

ACK。当Keyboard任何时候收到一个来自于60h端口的合法命令或合法数据之后,都回复一个FAh。

FCh

BAT失败代码。如果键盘检测失败,则会将此字节发送到8042 Output Register中。

FEh

Resend。当Keyboard任何时候收到一个来自于60h端口的非法命令或非法数据之后,或者数据的奇偶交验错误,都回复一个FEh,要求系统重新发送相关命令或数据。

83ABh

当键盘收到一个来自于60h的F2h命令之后,会依次回复83h,ABh。83AB是键盘的ID。

Scan code

除了上述那些特殊字节以外,剩下的都是Scan code。

———————————————————————————————————————————————

关于ScanCode:

当键盘上有键被按下,松开,按住,键盘将产生扫描码( Scan Code ),这些扫描码将被 i8048 直接得到。扫描码有两种,Make Code 和 Break Code。当一个键被按下或按住时产生的是 Make Code ,当一个键被松开产生的是 Break Code。每个键被分配了唯一的 Make Code 和 Break Code ,这样主机通过扫描码就可以知道是哪一个键。简单的说就是按下键,产生一个 Make Code。松开键,产生一个 Break Code。

到目前为止一共有三套扫描码集( Scan Code Set ),ps/2 键盘默认使用第二套。不过可以设置 i8042,让 i8042 把得到的 Scan Code 翻译成 Scan Code Set 1 中的 Scan Code ,这样键盘驱动从 i8042 得到的所有 Scan Code 都是第一套中的 Scan Code(实际中驱动也是这么做的)。所以我们只讨论 Scan Code Set 1 。需要说明的是 Scan Code 和 ASCII码完全不相同。

在 Scan Code Set 1 中,大多数键的 Make Code,Break Code 都是一个字节。他们的 Make Code 的最高位都为0,也就是他们的 Make Code 都小于 0x7F。而他们的 Break Code 为其 Make Code 或运算 80h ,也就是把 Make Code 的低7位不变,最高位设置为1。

还有一些扩展按键,他们的 Scan Code 是双字节的。他们的第一个字节都是E0h,表明这是一个扩展键。第2个字节,和单字节 Scan Code 的情况相同。

还有一个特殊的键,Pause/Break 键,它的 Make Code 为 E1,1D,45 E1,9D,C5,注意是 E1h 开头。而且它没有 Break Code 。

莫尔斯码在线转换

莫尔斯/摩尔斯电码(Morse code)是美国人莫尔斯于1844年发明的,由点(.)、划(-)两种符号组成:
1.一点为一基本信号单位,一划的长度=3点的长度。
2.在一个字母或数字内,各点、划之间的间隔应为两点的长度。
3.字母(数字)与字母(数字)之间的间隔为7点的长度。
莫尔斯/摩尔斯电码(Morse code)曾被用在间谍通信,电报,航海信号等各个领域。





多线程的网络通信程序

起因是学校课要求写一个双机网络通信,并且可以发送文件的程序。

使用的是传统的socket (recv(),send() …..)等。而且是阻塞模式,使用图形界面MFC编写 (VC 6.0)。但为了能让程序不出现假死现象( recv,accept 这样的函数都会出现这样的事情),所以采用了多线程技术,其实也就是用了AfxBeginThread ,TerminateThread等等。这样对于阻塞函数都让他们在新建立的线程里运行就好了。

另外解决的一个大问题就是,创建的新线程无法对窗口进行操作,比如要自在编辑框显示一句话等等。如果直接取得窗口类的句柄操作,会出现wincore的错误,也就是跨线程错误。主要原因也就是——-MFC的线程被自己外部创建的线程调用就会有这个错误。解决的方法就是在线程里用SendMessage给窗口发送一个自定义的消息,比如我这里用的就是。

要实现这样的方法

在BEGIN_MESSAGE_MAP下面要添加

这里写出一些关键的代码,具体程序可以到点击这里下载

我注释的相当详细了。
编译的话,debug版可以正常工作,但release版就无法正常工作了

serverdlg.cpp

clientDlg.cpp

再次回到clientDlg.cpp中,接下来就是程序的主体部分了。

接下来是客户端的程序了,和server一样也要自定义消息

iscc 2009

真的有点搞不下去了

基础关:

还真算是基础,但也学到了很多东西,http–reference算是最大的收获,本地提交也让我知道了,封包截取指示下下策。该死的循环干扰码,用regular expression两次提交都没有通过,估计是太草率了,没有考虑太多,就疯狂的替换了,现在倒是想明白了,可真是没脸再提交了。
最后的autoback,我发现了index.php存在index.php.bak但对于php环境不像asp,php.bak一样可以被解析,无法下载察看代码,虽然index.php.bak里action=basic_4.php不同于index.php,但也实在没找到这个页面,郁闷极了,憋了好几个下午都快吐血了。

脚本关:

前几关怎么过得都快忘干净了,前面会的,很快就通过了,后面德就死活搞不出来。比较欣慰的是数据库连接文件conn.asa总算是猜出来了。后面的倒数第三关好像过滤了space和%,总之就是提交失败。天杀的csrf xss我试了好久,终于绕过了字符过滤。诡异的就是明明提交了adduser的参数,为什么就是没能让管理员添加我,也尝试了cookie窃取,还特意在校内某服务器上搭建了asp环境来截获cookie,可除了自己的一无所获。今天以下午都在这耗着,我真的要放弃这几关了,平日积累真的是不太够,一直没太重视他们。

破解关:

这算是我最自豪的了,刚好最近做的那个创新项目就是研究shell,对于这种汇编代码的分析还比较得心应手,特别是各种anti一眼就看了出来,第五个shell也比较容易脱掉,我就直接带壳调试了,最终也还算运气比较好,跳过了一些环节后直接到了算法部分,其实只靠算法答案有6!种,但我比较幸运猜到了各位的关系。其中jmp eax是直接跳过了,真不知道正常情况下,哪个环节的跳转怎么从堆栈返回。不过这个方法倒是可以借鉴到我的shell编写中。

溢出关:

概念清晰很重要啊,没想到我的概念清晰到每个环节,第一次来真格的进行overflow竟然还真成功了,不过当然也是因为题目简单,思路其实很简单,就是覆盖返回的eip,heap seh等等我生疏的概念一个也用不到,比较头疼的就是最后一个overflow,shellcode因为都是自己写的,代码的选择费了好大的劲,还好不要求功能,要不就累死了。另外发现工具的使用也非常重要,一个得心应手的16进制编辑器是必需的,我的用得不太好,每次几百字节的shellcoded都是自己手动写的机器码,真想吐血。
内核关:虽然我挺喜欢编程序,但看来要搭建环境比较麻烦,把资料下载下来,留待假期研究吧
收获嘛,真的是太大了,感觉一下进步了不少,至少是增长了知识。

QQ对对碰作弊器第二版发布

继第一版发布后,我又修改了一下其中的一些功能,增加了速度,预计在本周末发布2.0版本。

新增加的功能:
增加了算法选择功能,分为普通算法和快速算法。普通算法就是1.0中所采用的算法。快速算法则是从下面开始消去,一定程度上提高了速度。
自动开始游戏功能,这个功能的产生纯属巧合,在使用快速算法+自动点击后,会把开始键当成快处理,从而自动点击开始~~。如果不想自动开始,只要用稳定算法就好了。

新版本的说明可以点击软件左上角,会弹出帮助的。图解说明也可以参照1.0中的解释。
对对碰作弊器1.0版
大家来找茬作弊器1.0版

2.0程序下载的话点击右侧导航栏中的下载与上传或者点击连接:2.0

我自己写的qq对对碰助手

我自己用VC写的qq对对碰的辅助工具哈,第一上传软件~~~

功能上很简单但也很实用     运行程序—>进入游戏—>选择一张桌子坐下—>点击获取画面。这样在我的程序上就会显示出来qq对对碰的画面。

 

在游戏开始后,我的程序上会提示应该点击的方块,在玩家找不到该消那块的时候可以参考。

当然你也可以在这个时候勾选‘自动玩’这样就会由我的程序来操作qq对对碰。

然后玩家要做的就是不断点击有戏的开始键就行了。算法上来讲,我并没有使用最优化的算法,这样虽然不能保证面对高手时一把就赢,但玩十把肯定是赢得多。

另外每次离开一张桌子时,记得点击软件上的‘停止’,并在每次进入桌子时点击获取画面(要2秒钟)。

 

下载地址:duidui.rar

matlab无法正常运行(exception calling main)

在安装完windows sp3补丁后,很多同学发现matlab2007b无法正常运行,总是启动画面闪一下然后就没反应了。或者有时候弹出exception calling main的系统错误提示,解决此问题的办法很简单,右键单击matlab程序图标,选择属性,在兼容性选项卡中勾选用兼容性运行此程序,兼容模式为window NT 4.0(service pack 5),确定后即可恢复正常