当前位置: 首页 > news >正文

电子商务网站建设的平台seo推广优化外包公司

电子商务网站建设的平台,seo推广优化外包公司,网站模板 html5,一级a做爰片偷拍免费网站文章目录 技术原理Windows中从击键到内核流程键盘硬件原理键盘过滤的框架搭建应用设备扩展键盘过滤模块的动态卸载键盘过滤的请求处理通常的处理PNP的处理读的处理读完成的处理从请求中打印出按键信息从缓冲区中获得KEYBOARD_INPUT_DATA从KEYBOARD_INPUT_DATA中得到键从MakeCod…

文章目录

  • 技术原理
    • Windows中从击键到内核
      • 流程
  • 键盘硬件原理
  • 键盘过滤的框架搭建
  • 应用设备扩展
  • 键盘过滤模块的动态卸载
  • 键盘过滤的请求处理
    • 通常的处理
  • PNP的处理
  • 读的处理
  • 读完成的处理
  • 从请求中打印出按键信息
    • 从缓冲区中获得KEYBOARD_INPUT_DATA
  • 从KEYBOARD_INPUT_DATA中得到键
  • 从MakeCode得到实际字符
  • 完整代码

技术原理

Windows中从击键到内核

  • 打开任务管理器,可以看到一个“csrss.exe”进程,这个进程很关键,它有一个线程叫做win32!RawInputThread,这个线程通过一个GUID(GUID_CLASS_KEYBOARD)来获得键盘设备栈的PDO(Phsiycal Device Object)的符号连接名。
  • csrss.exe通常是系统的正常进程,所在的进程文件是csrss或csrss.exe,是微软客户端、服务端运行时子系统,windows的核心进程之一。管理Windows图形相关任务,对系统的正常运行非常重要。csrss是Client/Server Runtime Server Subsystem的简称,即客户/服务器运行子系统,用以控制Windows图形相关子系统,必须一直运行。csrss用于维持Windows的控制,创建或者删除线程和一些16位的虚拟MS-DOS环境。也有可能是W32.Netsky.AB@mm等病毒创建的
  • 应用程序是不能直接依据设备名来打开设备的,一般都可以使用CreateFile通过符号链接名来打开。

流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hqwzYeCz-1581949420750)(E:\笔记\Windows内核安全与驱动开发\第二部分-开发\第八章-键盘的过滤\原理及框架.assets\1578474035408.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YxmUr6Wf-1581949420758)(E:\笔记\Windows内核安全与驱动开发\第二部分-开发\第八章-键盘的过滤\原理及框架.assets\1578474054145.png)]

  • 上面一大段调用过程暂时不用仔细去理解,简单来说就是win32k!RawInputThread线程总是调用nt!ZwReadFile函数要求读入数据,然后等待键盘上的键被按下,当键盘上的键被按下时,win32k!RawInputThread处理nt!ZwReadFile得到的数据,然后nt!ZwReadFile要求读入数据,再等待键盘上的键被按下。
  • 我们一般看到的PS/2(Personal System2,常用于链接电脑键盘、鼠标等设备的接口)键盘的设备栈,如果自己没有安装另外其他键盘过滤程序,那么设备栈的情况就如下:
    • 最顶层的设备对象是驱动KbdClass生成的设备对象
    • 中间层的设备对象是驱动i8042prt生成的设备对象
    • 最底层的设备对象是驱动ACPI生成得设备对象

键盘硬件原理

  • 键盘并不用字符来表示键,而是给每一个键规定了一个扫描码,当然因为键盘的排布方式不同,所以去搞清楚每个键的扫描码时多时是没有意义的。
  • 键盘和CPU的交互方式是通过中断和读取端口,这是个串行操作。发生依次中断,就等于键盘给了CPU依次通知,这个通知只能通知一个事件;某个键被按下或弹起。CPU不会主动去“查看”任何键,只是接收通知并读取端口的扫描码。
  • 所以一个键需要两个扫描码:一个表示键按下,另一个表示键弹起。依据网上的资料来看,如果按下的键的扫描码为X,那么同一个键弹起的扫描码就为X+0x80.
  • XP下端口和和中断号都是定死的,即中断号为0x93,端口号为0x60。每次中断时发生时,CPU都去读取端口0x60中的扫描码,0x60中只保存一个字节,但是扫描码是可以有两个字节的,此时就会发生两次中断,CPU会先后读到扫描码的两个字节。

键盘过滤的框架搭建

  • 如果绑定了KbdClass驱动的所有设备对象,那么代表键盘的设备一定也在其中。

  • 获取一个驱动全部设备对象可以有下面的方法:

    • 驱动对象结构DRIVER_OBJECT下有一个DeviceObject的域,有因为每一个DeviceObject中又有一个叫做NextDevice的域指向了驱动中的下一个设备,所以这实际上就是一个设备链,可以从这里获取到驱动的所有设备。
    • 另一种方法是调用函数IoEnumerateDeviceObjectList,这个函数可以枚举出一个驱动下的所有设备。
  • 依据开源的键盘过滤示例Ctr12Cap的源码和书中作者的代码,完成自己的键盘过滤驱动:

  • 这里用到了一个新的函数-ObRefferenceObjectByName,函数可以通过一个名字来获得一个对象的指针。

//函数需要自己声明
NTSTATUS ObReferenceObjectByName(PUNICODE_STRING ObjectName,ULONG Attribute,PACCESS_STATE AccessState,ACCESS_MASK DesiredAccess,POBJECT_TYPE ObjectType,KPROCESSOR_MODE AccessMode,PVOID ParseContext,PVOID *Object
);

应用设备扩展

  • 在之前串口过滤的例子中,用到了两个数组:一个用于保存所有的过滤设备;另一个用于保存所有的真实设备。两个数组依据下标形成一个一一映射的表的作用,拿到过滤设备的指针,马上就可以找到真实设备的指针。

  • 但是实际上我们可以在生成一个过滤设备时,为这个设备指定一个任意长度的“设备扩展”,扩展中的内容可以任意填写,形成一个自定义的数据结构。这样就可以把真实设备的指针保存在虚拟的设备对象中,更加方便查询。

  • 在代码中有体现,定义了一个拓展结构,然后在使用IoCrreateDevice创建设备对象时第二个参数这次填入结构体的长度如:


//设备拓展结构体
typedef struct _C2P_DEVICE_EXT
{//结构体大小ULONG thisSize;	//过滤设备对象PDEVICE_OBJECT pFilterDeviceObject;//同时调用时的保护锁KSPIN_LOCK IoRequestsSpinLock;//进程间同步处理KEVENT IoInprogressEvent;//绑定的设备对象PDEVICE_OBJECT targetDeviceObject;//绑定前底层设备对象PDEVICE_OBJECT lowerDeviceObject;
}C2P_DEVICE_EXT,*PC2P_DEVICE_EXT;
//创建示例
status=IoCreateDevice(pDriver,sizeof(C2P_DEVICE_EXT),NULL,pTargetDeviceObject->DeviceType,pTargetDeviceObject->Characteristics,FALSE,&pFilterDeviceObject
);
  • 具体设备扩展的使用体现在了完整代码中,可以将填写设备扩展中的内容封装在了一个MyC2pDeviceExtInit自定义函数中,这样更加方便使用。

键盘过滤模块的动态卸载

  • 键盘的过滤模块的动态卸载和前面的串口过滤稍有不同,回忆之前的内容,可以想到键盘总是处于“有一个读请求没有完成”的状态。

  • 简单在回顾一下就是:当键盘上有键被按下时,将触发键盘的中断,引起中断服务历程的执行,键盘中断的中断服务历程由键盘驱动提供,键盘驱动从端口读取扫描码,经过一系列的处理之后,把从键盘的到的数据交给IRP,然后结束这个IRP。

    这个IRP的结束将导致win32k!RawInputThread这个线程对读操作的等待结束,win32k!RawInputThread线程会对得到的数据进行处理,发送给合适的进程。一旦把输入的数据处理完之后,win32k!RawInputThread会立即再调用一个nt!ZwReadFile向键盘驱动请求读入数据,也就是在开始一次等待,等待键盘上的键被按下。

  • 因此,即使向串口一样等待5秒,这个等待请求也不会完成。这是如果卸载了过滤驱动,那么可能造成蓝屏崩溃。

  • 实际实现在完整代码中。

键盘过滤的请求处理

通常的处理

  • 最通常的处理就是直接发送到真实设备,跳过虚拟设备的处理,类似于前面串口过滤用过的方法一样。
  • 代码示例如下:
NTSTATUS MyC2pDispatchGeneral(IN PDEVICE_OBJECT pDevice,IN PIRP pIrp
)
{//其它不处理的IRP直接skip然后再用IoCallDriver把IRP发送到帧数设备的设备对象上Kdprintf(("Other Dispatch\r\n"));IoSkipCurrentIrpStackLocation(pIrp);return IoCallDriver(((PC2P_DEVICE_EXT)pDriver->DeviceExtension)->LowerDeviceObject,Irp);
}
  • 与电源相关的IRP的处理相对不同:
    • 在调用IoSipCurrentIrpStackLocation前,先调用了PoStartNextPowerIrp
    • PoCallDriver代替了IoCallDriver
NTSTATUS MyC2pPowerDispatch(IN PDEVICE_OBJECT pDevice,IN PIRP pIrp
)
{PC2P_DEVICE_EXT devExt=(PC2P_DEVICE_EXT)pDevice->DeviceExtension;PoStartNextPowerIrp(pIrp);IoSkipCurrentirpStackLocation(pIrp);return PoCallDriver(devExt->lowerDeviceObject,pIrp);
}

PNP的处理

  • 前面说到的PNP,对其唯一需要处理的是,当有一个设备被拔出时,解除绑定,并删除过滤设备。
  • 当PNP请求过来时,是没有必要担心是否还有未完成的IRP的,因为这是Windows系统要求卸载设备,此时Windows自己应该已经处理掉了未决的IRP,所以不用向之前一样自己在进行处理。
  • 具体操作看完整代码。

读的处理

  • 处理键盘读请求时,像之前那样处理完毕后直接下发不再可行。
  • 因为当一个键盘读请求带来时,我们只能拦截到一个键扫描码值,但是在完成前并不知道这个值是多少。但是我们要达到获取键的值的目的,所以使用如下的步骤进行过滤:
    1. 调用IoCopyCurrentIrpStackLocationToNext把当前IRP栈空间拷贝到下一个栈空间。
    2. 使用函数IoSetCompletionRoutine给这个IRP设置一个完成函数,完成函数的含义是,如果这个IRP完成了,系统就会回调这个函数。
    3. 调用IoCallDriver把请求发送到下一个设备,也就是真实设备。

读完成的处理

  • 也就是上面设置的完成回调函数的编写,这里是读请求完成后的调用,应该用来获得缓冲区,按键信息就存在输出缓冲区中。

  • 这个时候打印出的按键信息其实并不是我们想要的可读的信息,所以我们要对信息做进一步的处理。

从请求中打印出按键信息

从缓冲区中获得KEYBOARD_INPUT_DATA

  • 上面已经通过pIrp->AssociatedIrp.SystemBuffer中获取到了缓冲区的数据,不过这个缓冲区有固定的格式,其中可能含有n个KEYBOARD_INPUT_DATA结构,结构体定义如下:
typedef struct _KEYBOARD_INPUT_DATA{//在头文件里解释如下:对于设备\Device\KeyboardPort0,这个值是0,对于\Device\KeyboardPort1,这个值是1,依次类推USHORT UnitId;//扫描码USHORT MakeCode;//一个标志,标志着键是按下还是弹起USHORT Flags;//保留USHORT Reserved;//扩展信息ULONG ExtraInformation;
}KEYBOARD_INPUT_DATA,*PKEYBOARD_INPUT_DATA;
  • Flags可能的取值可以有如下这些:
#define KEY_MAKE 	0
#define KEY_BREAK 	1
#define KEY_E0		2
#define KEY_E1		3
#define KEY_TERMSRV_SET_LED  8
#define KEY_TERMSRV_SHADOW   0x10
#define KEY_TERMSRV_VKPACKET 0x20

从KEYBOARD_INPUT_DATA中得到键

  • KEYBOARD_INPUT_DATA下的MakeCode就是扫描码,不过暂时只考虑Flags为KEY_MAKE(0)KEY_BREAK(非0)两种可能,一种表示按下;另一种表示弹起。

从MakeCode得到实际字符

  • 大小写字符的ASCII码不同,但是它们的按键码却是相同的,具体是哪个会取决于如Shift、Caps Lock键的状态,因此必须先把这几个控制键的状态保存下来。
  • 然后对于不同的控制键使用不同的过滤方法。

完整代码

#include <ntddk.h>
#include <ntddkbd.h>//全局的一个对象类型,IoDriverObjectType实际上是一个全局变量
//但是在头文件中灭有,需要声明
extern  POBJECT_TYPE *IoDriverObjectType;ULONG g_C2PKeyCount = 0;	//存储未决请求的个数//函数ObRegerenceObjectByName原型声明
NTSTATUS ObReferenceObjectByName(PUNICODE_STRING ObjectName,ULONG Attribute,PACCESS_STATE AccessState,ACCESS_MASK DesiredAccess,POBJECT_TYPE ObjectType,KPROCESSOR_MODE AccessMode,PVOID ParseContext,PVOID *Object
);//全局的KbdClass驱动的名称
#define KBD_DRIVER_NAME L"\\Driver\\Kbdclass"//设备拓展结构体
typedef struct _C2P_DEVICE_EXT
{//结构体大小ULONG thisSize;	//过滤设备对象PDEVICE_OBJECT pFilterDeviceObject;//同时调用时的保护锁KSPIN_LOCK IoRequestsSpinLock;//进程间同步处理KEVENT IoInprogressEvent;//绑定的设备对象PDEVICE_OBJECT targetDeviceObject;//绑定前底层设备对象PDEVICE_OBJECT lowerDeviceObject;
}C2P_DEVICE_EXT,*PC2P_DEVICE_EXT;//初始化设备扩展
NTSTATUS MyC2pDeviceExtInit(IN PC2P_DEVICE_EXT devExt,IN PDEVICE_OBJECT pFilterDeviceObject,IN PDEVICE_OBJECT pTargetDeviceObject,IN PDEVICE_OBJECT pLowerDeviceObject
)
{memset(devExt, 0, sizeof(C2P_DEVICE_EXT));devExt->thisSize = sizeof(C2P_DEVICE_EXT);devExt->pFilterDeviceObject = pFilterDeviceObject;KeInitializeSpinLock<
http://www.hkea.cn/news/773335/

相关文章:

  • .net 网站管理系统湖南企业竞价优化首选
  • 南山区住房与建设局官方网站网络赚钱推广
  • wordpress mycred汉化seo引擎搜索入口
  • 在线教育网站用什么做百度搜索的优势
  • 甘肃省住房城乡建设厅网站首页智能建站模板
  • 智能科技网站模板下载地址百度学术论文查重
  • 网站要怎么做才能让360收录推广品牌的策划方案
  • 做网站前景营销课程培训视频
  • 青海做网站广告开户南京seo
  • wordpress写软文赚钱seo快速培训
  • 南宁网站建设接单陕西省人民政府
  • wordpress网站价格seo域名综合查询
  • 支付网站怎么做的网络自动推广软件
  • js做网站统计品牌关键词优化
  • 微信公众号管理平台官网谷歌seo建站
  • 鲜花购物网站源码企业网站营销的优缺点
  • 表白网站制作在线日照网站优化公司
  • 企业网站建设策划书 前言徐州关键词优化排名
  • 一级a做爰片视频网站全国新闻媒体发稿平台
  • 唐山网站建设哪家专业高德北斗导航
  • wordpress 地址 .html企业网站seo贵不贵
  • 提供网站制作公司哪家好网络软文范文
  • 做原型网站枣庄网络推广seo
  • 品牌网站开发设计外贸网站平台
  • 网站做留言板网站推广在线
  • 长春服务好的网络营销seo网站推广的主要目的
  • 搜索引擎优化和关键词竞价广告的区别宿州百度seo排名软件
  • 一搜同志网站建设电话青岛网站seo优化
  • 官方做任务网站网络营销公司注册找哪家
  • django做视频网站网络营销推广专家