鼠标屏幕取词原理

合集下载

鼠标屏幕取词技术的原理和实现

鼠标屏幕取词技术的原理和实现

鼠标屏幕取词技术的原理和实现鼠标屏幕取词技术的原理和实现“鼠标屏幕取词”技术是在电子字典中得到广泛地应用的,如四通利方和金山词霸等软件,这个技术看似简单,其实在windows系统中实现却是非常复杂的,总的来说有两种实现方式:第一种:采用截获对部分gdi的api调用来实现,如textout,textouta等。

第二种:对每个设备上下文(dc)做一分copy,并跟踪所有修改上下文(dc)的操作。

第二种方法更强大,但兼容性不好,而第一种方法使用的截获windowsapi的调用,这项技术的强大可能远远超出了您的想象,毫不夸张的说,利用windowsapi 拦截技术,你可以改造整个操作系统,事实上很多外挂式windows中文平台就是这么实现的~而这项技术也正是这篇文章的主题。

截windowsapi的调用,具体的说来也可以分为两种方法:第一种方法通过直接改写winapi 在内存中的映像,嵌入汇编代码,使之被调用时跳转到指定的地址运行来截获;第二种方法则改写iat(import address table 输入地址表),重定向winapi函数的调用来实现对winapi的截获。

第一种方法的实现较为繁琐,而且在win95、98下面更有难度,这是因为虽然微软说win16的api只是为了兼容性才保留下来,程序员应该尽可能地调用32位的api,实际上根本就不是这样~win 9x内部的大部分32位api经过变换调用了同名的16位api,也就是说我们需要在拦截的函数中嵌入16位汇编代码~我们将要介绍的是第二种拦截方法,这种方法在win95、98和nt下面运行都比较稳定,兼容性较好。

由于需要用到关于windows虚拟内存的管理、打破进程边界墙、向应用程序的进程空间中注入代码、pe(portable executable)文件格式和iat(输入地址表)等较底层的知识,所以我们先对涉及到的这些知识大概地做一个介绍,最后会给出拦截部分的关键代码。

灵格斯翻译家使用手册

灵格斯翻译家使用手册

灵格斯翻译家使用手册安装灵格斯1、从灵格斯翻译家网站下载软件的安装程序到本机硬盘.2、双击安装程序, 进行安装.3、安装过程中, 如果没有特别的需求, 可以一路按“下一步” 直至安装完成.注意:∙请从官方网站或官方指定的下载网站获取灵格斯的安装程序, 切勿下载来源不明或所谓的绿色版, 以免造成不必要的损失和使用上的种种故障.∙安装前, 请确认已经关闭了其他程序, 特别是防病毒软件和防火墙软件, 以便正常顺利安装.设置主程序灵格斯翻译家的主程序已经安装到操作系统中了, 为了更好地使用灵格斯翻译家带来的便利, 我们需要在使用前对主程序进行设置.首先, 启动灵格斯翻译家, 点击程序界面左侧选项中的“设置”, 激活设置面板.屏幕取词点击“翻译” 选项标签, 对鼠标屏幕取词进行设置.∙鼠标取词: 用鼠标将光标移到词上面时, 再加上组合键就可翻译该词.∙鼠标左键取词: 用鼠标将光标移到词上面时, 按下〔鼠标左键+组合键〕就可翻译该词.∙鼠标右键取词: 用鼠标将光标移到词上面时, 按下〔鼠标右键+组合键〕就可翻译该词.∙鼠标中键取词: 用鼠标将光标移到词上面时, 按下〔鼠标中键+组合键〕就可翻译该词.∙延迟: 做以上动作时延迟几毫秒才做翻译动作.∙支持本地语言映射: 选中后, 在简体中文用户界面下, 会自动转换词典中的繁体中文内容为简体;在繁体中文用户界面下, 则会自动转换词典中的简体中文内容为繁体. (注: 本功能需要配合支持映射功能的词典使用)常规接着, 点击“常规” 标签, 对软件的常规项目进行设置.∙选择用于Web 搜索的搜索引擎: 当我们在右上角搜索框内输入文字, 并按下Enter 键时, 会连到互联网搜索引擎.∙保存的查询历史个数: 查询的词语的历史纪录.∙登录至Windows 时, 运行Lingoes: 打勾此项, 则会在开机时启动此程式.∙启动后最小化: 开启此程式的, 会缩到工具列上.热键∙打开主窗口: 即打开Lingoes 的视窗.∙鼠标取词开关: 按此热键会“关闭/打开” 使用滑鼠取词.∙朗读: 会朗诵所选取的文字.∙剪贴簿取词开关: 按此热键会“关闭/打开” 使用剪贴簿取词. ∙复制解释: 会把该查询的解释结果复制至剪贴簿.语音∙音量: 调整发音时的音量大小.∙音调: 调整发音时的音调.∙速度: 调整发音时的速度.∙即时发音: 取词时随便朗诵该词语.如果要下载更多的语言发音, 或是听不到语言发音的话, 可以点击一下“下载TTS 语言引擎和语言包...”, 然后会连结官方网站的网页. 下载后, 双击即可完成安装.安装及设置词典操作如下:1. 首先, 按一下, 接着会出现如下图:2. Lingoes 把词典分成三个方向, 每个方向都可以独立运作:∙词典安装列表: 即输入词语会查询的词典.∙索引组: 即输入词语, 会不会出现相近词语.屏幕取词组: 即取词翻译.3. 如果要下载更多词典, 只要按一下“从Lingoes 下载词典即可”, 然后会连到作者的网站, 选择你要下载的词典, 下载完毕后按两下安装即可.查阅单词的翻译及更多资料1. 首先, 找到2. 在里面输入词语后, 按Enter 键即可, 如下图:3. 而若要查询单一词典的结果, 只要在左侧选择相关词典即可.4. 而如果要找该词语的更多搜寻结果, 请在右上角输入内容, 并按Enter键便可以在新的浏览器窗口中打开搜索引擎的搜索结果.Tips: 您可以按放大镜旁向下的小箭头, 以使用不同的搜寻引擎.全文翻译当你有一段文章看不懂时, 或有一段文章想要翻译时, 即可输入该段文章, 来进行全文翻译.操作如下:1. 按一下「文本翻译」, 如下图:2. 白色空白处为输入文本框, 输入完后选择翻译引擎, 设置一下源语言和目标语言, 按一下“翻译”, 稍后即可得到翻译结果.3. 翻译的结果不一定都是准确无误的, 建议多比较几字翻译引擎翻出来的结果, 及多充实单词和语法的知识, 才是解决问题的根本.注: 全文翻译功能需要联机到互联网.发音查询的词汇Lingoes 利用操作系统附带的TTS语音引擎, 让您听到英文单词、短语、句子的发音. 您也可以通过安装其他语种的语音引擎得到对应语种的文本朗读效果.操作如下:1. 输入完查询的词语, 按Enter 会出现结果.2. 选择所要发音的文本部分, 并按一下, 或者按一下你所设定的发音热键.3. 接着, 就可以听到Lingoes 朗读选中的文本了.复制, 列印与储存查询结果我们可以利用Lingoes 轻松地把查询结果复制, 打印, 与保存起来.操作如下:1. 首先, 反白你所要处理的部份.2. 找到以下图示:o: 复制选择的内容.o: 保存查询的内容.o: 打印查询的内容.3. 以打印而言, 我们可以按钮, 以将查询的内容列印出来.下载真人发音及TTS 合成发音的语音库使用真人发音安装真人发音语音库安装真人语音库的方法非常简单,只要打开”灵格斯安装目录“下的speech文件夹, 在里面创建一个子文件夹(文件夹命名是随意的,建议使用语音库的名称),然后将下载到的语音库压缩文件解压到这个目录下即可。

Delphi屏幕取词

Delphi屏幕取词

Delphi屏幕取词屏幕取词(Delphi)(1)“ 屏幕取词”的实现//-----------------------------------------------------------------1用SetWindowsHookEx()安装鼠标钩子MouseProc;2在屏幕上移动鼠标时,系统就会调用鼠标钩子MouseProc;3进入MouseProc,获得鼠标的坐标(x,y),设置对T extOut()、ExtTextOut()等的跟踪程序,用invalidateRect()告诉系统该点(x,y)“失效”;4系统发出WM_PAINT消息,指示该点(x,y)处的应用程序重绘“失效”的区域。

5负责绘制该点()的应用程序在受到 WM_PAINT 消息后,就有机会调用TextOut()、 ExtTextOut()等函数。

6调用的函数被拦截进入跟踪程序:设置好了的跟踪程序截获了该次调用,从应用程序的堆栈中取出该点(x,y)“文字”的指针;7从应用程序的数据段中将“文字”指针的内容取出,即完成了一次“屏幕抓字”;8退出跟踪程序,返回到鼠标钩子MouseProc;9在MouseProc中解除对TextOut() ExtTextOut()的跟踪;10退出MouseProc鼠标钩子程序,控制权交给系统。

11在屏幕上移动鼠标,开始下一次“屏幕抓字”,返回步骤2。

//-----------------------------------------------------------------Dll工程.GetWordDll.dpr//-----------------------------------------------------------------------------------library GetWordDll;usesWindows,SysUtils,Classes,UnitHookDll in 'UnitHookDll.pas',UnitNt2000Hook in 'UnitNt2000Hook.pas',UnitHookType in 'UnitHookType.pas';exportsStartHook,StopHook,// MouseWndProc,{以下导出列表都是必须的,不能少,因为程序要取其地址}NewBeginPaint,NewCreateCompatibleDC,NewTextOutA,NewTextOutW,NewExtTextOutA,NewExtTextOutW,NewDrawTextA,NewDrawTextW;beginend.UnitHookType.pasunit UnitHookType;interfaceuses windows, messages;constMaxStringLen = 100;WM_MOUSEPT = WM_USER + 1138; MappingFileName = 'GetWord32 for 9x NT 2000'; fBeginPaint=0;fGetWindowDC=1;fGetDC=2;fCreateCompatibleDC=3;fTextOutA=4;fTextOutW=5;fExtTextOutA=6;fExtTextOutW=7;fDrawTextA=8;fDrawTextW=9;typePPointer = ^Pointer;TShareMem = packed recordhProcWnd: HWND; {主应用窗口句柄}hHookWnd: HWND; {鼠标所在窗口}pMouse: TPoint; {鼠标信息}DCMouse,DCCompatible: HDC;fTimerID: integer;fStrMouseQueue: array[0..MaxStringLen] of Char; {鼠标信息串} nTimePassed: integer; {鼠标停留的时间}bCanSpyNow: Boolean; {开始取词}Text: array[0..MaxStringLen] of Char; {字符串}end;PShareMem = ^TShareMem;implementationend.UnitNt2000Hook.pas//-----------------------------------------------------------------------------------unit UnitNt2000Hook;interfaceuses classes, Windows,SysUtils, messages,dialogs;typeTImportCode = packed recordJumpInstruction: Word;AddressOfPointerT oFunction: PPointer;end;PImportCode = ^TImportCode;PImage_Import_Entry = ^Image_Import_Entry;Image_Import_Entry = recordCharacteristics: DWORD;TimeDateStamp: DWORD;MajorVersion: Word;MinorVersion: Word;Name: DWORD;LookupTable: DWORD;end;TLongJmp = packed recordJmpCode: ShortInt; {指令,用$E9来代替系统的指令}FuncAddr: DWORD; {函数地址}end;THookClass = classprivateTrap:boolean; {调用方式:True陷阱式,False改引入表式}hProcess: Cardinal; {进程句柄,只用于陷阱式}AlreadyHook:boolean; {是否已安装Hook,只用于陷阱式}AllowChange:boolean; {是否允许安装、卸载Hook,只用于改引入表式}Oldcode: array[0..4]of byte; {系统函数原来的前5个字节}Newcode: TLongJmp; {将要写在系统函数的前5个字节}privatepublicOldFunction,NewFunction:Pointer;{被截函数、自定义函数}constructor Create(IsTrap:boolean;OldFun,NewFun:pointer);constructor Destroy;procedure Restore;procedure Change;publishedend;implementation{取函数的实际地址。

API HOOK 金山词霸取词功能原理

API HOOK 金山词霸取词功能原理
不固定,所以需要从指令流里面动态析出它的地址。
3.4 动态生成JMP指令
动态生成的JMP指令占用5个字节,保存在一个数组里面。以生成跳转到TextOut的替
代函数myTextOut的JMP指令为例:
BYTE ins[5]; //保存JMP指令
符串:
. 代码拦截:Windows以DLL方式提供系统服务,可以方便地获取Windows字符输出API的地址,修改其入口代码,拦截应用程序对它们的调用。
. 鼠标HOOK:安装WH-MOUSEPROC类型的全局鼠标HOOK过程,监视鼠标在整个屏幕上的移动。
数入口的代码,再调用TextOut()执行正常的字符输出,接下来SpyCode()在被拦截函数
入口再次放入JMP指令,最后返回调用进程。
3.3 获取被拦截API的动态链接地址
TextOut和ExtTextOut的地址可以通过GetProcAddress取得,而TextOut16W和ExtTextOut16W既未公 开于文档,也没有用字符串或序号从gdi.exe中引出,无法使用GetProcAddress取得它们的地址。下面讨论如何解决这个问题。
. 获取GDI代码段的基地址和界限;
. 用当前DS复制一个新的段选择子,该选择子的描述符具有可读写的属性;
. 将复制得到的选择子的基地址和界限设置为GDI代码段的基地址和界限;
. 将复制得到的选择子的基地址和界限设置为GDI代码段的基地址和界限;
不同的索引来从该表格里面取目的地址。ExtTextOutW和TextOutW分别使用索引B2H和30
H,取表中相应元素作为ExtTextOut16W和TextOut16W的地址。取得这个数组的起始位置

藏文鼠标屏幕取词的原理与实现

藏文鼠标屏幕取词的原理与实现
信息技术
《 西藏科技)08 1 期( ) 0 年 1 总第 18 2 8 期)
藏 文 鼠 标 屏 幕 取 词 的 原 理 与 实 现
小尼 玛扎 西 珠 杰 杨 帆 ( 西藏 大学工学院 , 西藏 拉 萨 80 0 ) 50 0
摘 要 : 文讨 论 了藏 文 鼠标屏 幕取 词技 术 的原理 , 点 阐述 了所 涉及 到 的若 干 关键 技 术 , 出 了利 用 本 重 给
78
钩 子 的本 质 是 Wi3 n2操 作 系统 中 一 段 用 以处 理
系统消息或特定事件的函数 , 通过系统调用将其挂人 到系统。钩子根据其对消息监视范 围的不同而分为系
《 西藏科技 ̄08 1 期【 20 年 1 总第 18 8 期)
统全 局钩 子 和 线 程 局 部 钩子 ( oa H o ) 大 类 , Lcl ok 两 其 中线 程局 部钩 子 只能监 视 本 进 程 中某 个 指定 的线 程 , 而全 局钩 子则 可对 在 当前 系统下 运行 的所 有线程 进 行 监视 。由于 “ 文 鼠标 屏 幕 取 词 ” 藏 中用 到 的是 系统 鼠

, 冒 r

的若 干关 键 技术 进 行讨 论 。使 用全 局 钩子 ( l a Go l b
Ho ) ok 打破 进程 边界 , 修改 P 并 E文 件 的输 入 地址 表 来 实 现对 系统 A I P 函数 的截 获 , 而实 现 藏 文 鼠标屏 幕 从
取词。
蓬_ _ -
图 2 1 截 获 目标涵数前 .
l 2

目 标 函 数
2 鼠 标 屏 幕 取 词 实 现 原 理
进 程 A( 词 的 主 应 用 程 序 ) 了取 得 屏 幕 上某 取 为

鼠标取词

鼠标取词

鼠标取词原理初探其实这是个老话题了,自从这项技术面世以来就已经被讨论了无数遍。

事实上,这个看起来很牛逼的东西其实不是想象中的那么难,方法也有多种多样,而且,有了先前各位大牛的研究成果,实现这项技术变得相对容易很多。

最主要的是,编写的过程中能让人学到很多知识。

好了,话不多说,直接进入主题。

在Windows平台下,输出文字基本上都是靠TextOut,ExtTextOut这两个API实现。

也有DrawText这样的函数,但最终也是调用了ExtTextOut(TextOut其实就是ExtTextOut的特殊版本)。

在Windows 9x下是如此,Windows NT下也是,不过就是有了ANSI和Unicode两个版本的区别。

若能截获这些API,转到自己的函数里,便能得到输出的字符串,实现取词功能。

______________________________________________________________BOOL WINAPI MyExtTextOutA( HDC hdc, int x, int y, UINT options, CONST RECT * lprect, LPCSTR lpString, UINT c, CONST INT * lpDx){// lpString便是所要的字符串(ANSI),在此进行处理// 然后调用正版的API输出字符return ::ExtTextOutA(hdc,x,y,options,lprect,lpString,c,lpDx);}看到这里,聪明的你肯定已经想到了,这不就是要实现一个API钩子么。

确实是这样,鼠标取词的核心技术就是API钩子。

事实上,有了API钩子,你可以干很多事情(比如拦截WinSock的sendto / recvfrom函数来实现数据包的截取等)。

实现API钩子主要有两种方法,一种是修改exe文件在内存中各个模块的导入函数表,另一种则是经典的内嵌汇编代码,采用JMP XXXX跳转到你自己的函数。

鼠标什么原理

鼠标什么原理

鼠标什么原理
鼠标是一种用于操作计算机的输入设备。

它的原理是利用感光器或感应器来追踪用户在平面上移动时所产生的输入信号。

一种常见的鼠标原理是光学原理。

这种鼠标内部有一个光电传感器,当鼠标在表面上移动时,传感器会捕捉到由光源反射回来的光线。

根据这些光线的变化,鼠标可以计算出用户的移动方向和速度。

具体来说,传感器会在鼠标底部投射出红光或红光激光,并通过计算机处理这个光线的变化来确定鼠标的位置。

另一种常见的鼠标原理是机械原理。

这种鼠标内部有一个小球,当鼠标在表面上移动时,球会滚动并改变鼠标内部的位置。

然后,通过计算机内部的编码器来测量小球的滚动方向和速度。

这种原理的鼠标需要定期清洁小球以确保准确性。

还有一种较新的鼠标原理是激光原理。

这种鼠标使用激光来追踪用户在表面上的移动。

激光鼠标通常比光学鼠标更准确,因为它使用更高分辨率的光电传感器来捕捉细微的移动。

无论鼠标使用哪种原理,它们都能够通过与计算机连接,将用户在平面上的移动转化为相应的光标或指针的移动。

这种输入设备在现代计算机使用中起到非常重要的作用,使用户能够方便地进行各种操作。

鼠标的组成及工作原理

鼠标的组成及工作原理

鼠标的组成及工作原理鼠标,作为一种常见的计算机外部设备,广泛应用于个人电脑、笔记本电脑及其他智能设备中,为用户提供了方便快捷的操控方式。

鼠标不仅具有小巧精致的外观设计,而且背后隐藏着复杂的内部构造和工作原理。

本文将详细介绍鼠标的组成和工作原理,帮助读者深入了解这个常见而重要的外设。

一、组成部分1.外壳:鼠标的外壳通常由塑料或金属材料制成,具有光滑的表面和人体工学的设计,以提供舒适的手感和操控。

2.按键:鼠标有多个按键,常见的有左键、右键和滚轮。

左右按键用于基础的点击操作,而滚轮则用于上下滚动页面或调整音量等功能。

3.感应器:鼠标的感应器通常位于底部,用于感知鼠标在平面上的移动。

常见的感应器有光学感应器和激光感应器,可以根据不同的表面材质提供精确的跟踪。

4.连接线:鼠标通过连接线与计算机或其他设备连接,传输信号和电力。

连接线通常由塑料或铜制成,具有一定的柔韧性和抗拉性。

5.电路板:鼠标的电路板包含了多个电子元件,如芯片、电容、电阻等,用于控制鼠标的操作和发送信号。

二、工作原理鼠标的工作原理可以分为两种常见的类型:机械式和光电式。

1.机械式鼠标:机械式鼠标通常使用滚球和滚轮来感知鼠标的移动和操作。

滚球位于鼠标底部,当用户移动鼠标时,滚球会滚动并转动两个与滚球相连的轴,通过这种转动将鼠标的移动转化为电信号传输给计算机。

同时,滚轮上下滚动的动作也会发送相应的信号给计算机,实现页面的滚动和音量的调整。

2.光电式鼠标:光电式鼠标利用光学感应技术实现鼠标的移动和操作。

底部感应器通过射出红外线或激光并感应反射光线的变化,来判断鼠标在平面上的移动方向和速度。

感应器会将光线信号转化为数字信号后发送给控制芯片,芯片会处理这些信号并将其转化为计算机可以识别的代码和指令。

光电式鼠标的优势在于精确度高,适用于多种平面表面。

无论是机械式鼠标还是光电式鼠标,鼠标的工作都离不开计算机的支持。

计算机通过鼠标驱动程序来解读接收到的信号,并根据用户的操作来实现相应的功能。

金山词霸的使用

金山词霸的使用



选择取词语言 ,选取词霸翻译的语言
固定取词条,锁定窗口在当前位置,避免浮动窗口因鼠标的移 动而消失
二.词典查询
1.查词典:即打开金山词霸的主界面,在输入框中输入单词 (如develop),按Enter即可进行查询。
输入框
2.模糊查询:当您忘记单词的完整拼写时,可采用 “*”、 “?”等通配符进行模糊查词。 (1) 如果你忘记一个单词中的某个字母可以用?来代替进行 查询,此时目录栏会列出所有符合条件的单词,如图:
五.全文检索
在浩如烟海的词库内容中可以飞速查找要检索的单词的位 置,便于找到相关内容(支持输入多个单词组合进行检索)。点 击图中标记的按钮,在出现的图标 中选择即可。
目录栏将显示 解释、例句等 涉及到 “develop”的单 词列表,右边 显示区会显示 列表中单词的 详细解释。
六.工具的使用
打开生词本
Ctrl + Alt + F1 Ctrl + Alt + A 打开或关闭屏幕取词开关 将当前所取的词加进用户词典。
Ctrl + Alt + S
Ctrl + Alt + C Ctrl + F12
跳转到当前所取的词的解释窗口。
将当前取词窗口的文本拷贝到剪贴板。 朗读选中的文字。
Ctrl + Tab 切换词霸左侧“索引”“向导”“全文检 索”“附录”标签的内容。
双击“学”后
4.生词本与词霸的灵活切换
词霸取词可以放入生词本中,点击取词条上的加入生词本按
钮,可将所取单词加入到生词本中,便于今后的学习。同时 在生词本中也可以快速切换到词霸的查询界面。方法很简单, 在生词本的浏览窗口中双击列表中要查询单词即可快速打开 词霸解释该单词。

操作系统中鼠标操作原理

操作系统中鼠标操作原理

操作系统HID接口
而在创建具体的设备节点之前,Event Handler层需要先注册一类设备的输入事件处理函数及相关 接口 static int __init mousedev_init(void) { //注册输入事件处理、连接、断开、设备(文件)操作函数 input_register_handler(&mousedev_handler); //创建输入设备节点 devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), S_IFCHR|S_IRUGO|S_IWUSR, "input/mice"); } static struct input_handler mousedev_handler = { .event = mousedev_event,//REL(相对坐标)、按键、ABS(绝对坐标)、SYNC等事件处 理 .connect = mousedev_connect, .disconnect = mousedev_disconnect, .fops = &mousedev_fops,//鼠标打开、poll、读写等操作 .minor = MOUSEDEV_MINOR_BASE, .name = "mousedeቤተ መጻሕፍቲ ባይዱ", .id_table = mousedev_ids, };
HID协议简介
下面仅对这3个HID设备类特定描述符中的HID描 述符进行说明。 HID描述符关联于接口描述符,因而如果一个设 备只有一个接口描述符,则无论它有几个端点描 述符,HID设备只有一个HID描述符。HID设备描 述符主要描述HID规范的版本号、HID通信所使 用的额外描述B HID类可采用的通信管道 所有的HID设备通过USB的控制管道(默认管道 ,即端点0)和中断管道与主机通信。 USB HID规范定义的HID设备可用端点包含三种 管道: 1、控制(端点0)( 必选) 传输USB描述符、类请求 代码以及供查询的消息数据等 2、中断输入 (必选) 传输从设备到主机的输入数 据 3、中断输出 (可选 )传输从主机到设备的输出数 据

双击选中单词 原理

双击选中单词 原理

"双击选中单词"是计算机用户界面中的一个常见功能,它允许用户通过快速连续的双击来选中屏幕上的一个单词。

这个功能的原理基于以下几个方面:
1. 鼠标或触摸板输入:
当用户第一次点击鼠标或触摸板时,计算机理解为此用户想选择单词的一部分。

第二次点击发生在第一次点击之后不久,且位置大致相同,计算机将其解释为用户想要选中整个单词。

2. 点击间隔时间:
双击通常要求两次点击之间有一定的时间间隔,以确保用户不是偶然的双击。

这个时间间隔是程序预设的,如果两次点击太快,计算机可能只会将其识别为一次单击。

3. 点击位置的检测:
计算机还会检测两次点击的位置是否接近,如果是,则认为是选中单词的行为;如果位置相差较大,则可能不会被识别为双击选中单词。

4. 操作系统和应用软件的协同工作:
操作系统和应用软件共同定义了双击选中单词的行为和规则。

例如,在文本编辑器中,双击选中单词是一个系统级的或应用程序级的特性。

5. 用户界面规范:
不同操作系统和应用程序可能会有不同的双击行为,但是通常都遵循一定的用户界面规范,以保持用户的操作习惯和一致性。

实现双击选中单词的功能,需要在操作系统或应用程序的编程接口中实现相应的监听器和事件处理逻辑。

在不同的编程环境中,这可能涉及到不同的编程语言和框架。

例如,在Windows操作系统中,可以使用Windows API来检测鼠标事件并实现双击选中单词的功能。

Lingoes使用教程

Lingoes使用教程

开始使用Lingoes 是一款专业的词典与文本翻译工具,但同时也是非常简明易用,将复杂的功能包含在简洁的用户界面设计中,用户只要打开Lingoes窗口,输入单词,然后按下“Enter”键,软件就会自动地帮你进行查找,并返回正确的翻译结果。

Lingoes另一项创新的技术就是“屏幕取词”功能,用户只需将鼠标移动到屏幕中的任何有单词的位置,按下“Ctrl + 鼠标右键”,Lingoes就能智能地识别出该单词,即时弹出迷你窗口显示翻译结果,你甚至还可以听到单词的读音。

这一切都是自动的,也不会干扰到你当前正在进行的工作。

对于普通的用户,无需任何学习,就可以凭直观的操作来使用Lingoes,如果你希望更进一步地了解Lingoes的工作原理,对软件进行更高级的个性化设定,请继续阅读下面对各个功能的详细使用说明。

词典Lingoes采用了软件与词典分离的开放式架构,软件本身作为一个提供查询本地或联机词典的功能平台,由用户根据自已的需要下载词典安装使用。

Lingoes有二种类型的词典, 为Lingoes提供了丰富的内容l 本地词典:词典数据安装在本地硬盘上,可以随时使用。

l 联机词典:是由在线词典服务商提供的查询服务,需要连接网络才能使用。

Lingoes所有的功能都是围绕着词典来进行,在“词典管理”窗口中,用户可以查看词典的属性,安装、删除词典,调整词典的排列顺序,启用或禁用词典等。

用户还可以根据不同的用途,分将词典加入到“索引组”、“取词组”中,为索引提示和取词功能提供支持。

1. 词典安装列表:所有已安装的词典都会显示在词典安装列表中,并且在Lingoes主窗口中查询单词的详细解释时,将会对词典安装列表中的词典进行查询。

2. 索引组:其中的词典用于输入单词时,提供索引提示功能。

3. 取词组:其中的词典用于在取词时查询单词的解释,在迷你窗口中查询单词时亦使用该组中的词典。

查询单词词典查询功能作为Lingoes最核心的功能,具有索引提示、查找词条和词组、单词变形识别、相关词匹配等专业查询技能。

钩子原理

钩子原理

[转]钩子原理钩子原理Windows系统是建立在事件驱动的机制上的,说穿了就是整个系统都是通过消息的传递来实现的。

而钩子是Windows系统中非常重要的系统接口,用它可以截获并处理送给其他应用程序的消息,来完成普通应用程序难以实现的功能。

钩子可以监视系统或进程中的各种事件消息,截获发往目标窗口的消息并进行处理。

这样,我们就可以在系统中安装自定义的钩子,监视系统中特定事件的发生,完成特定的功能,比如截获键盘、鼠标的输入,屏幕取词,日志监视等等。

可见,利用钩子可以实现许多特殊而有用的功能。

因此,对于高级编程人员来说,掌握钩子的编程方法是很有必要的。

钩子的本质是一段用以处理系统消息的程序,通过系统调用,将其挂入系统。

钩子的种类有很多,每种钩子可以截获并处理相应的消息,每当特定的消息发出,在到达目的窗口之前,钩子程序先行截获该消息、得到对此消息的控制权。

此时在钩子函数中就可以对截获的消息进行加工处理,甚至可以强制结束消息的传递。

在本程序中我们需要捕获在任意窗口上的键盘输入,这就需要采用全局钩子以便拦截整个系统的消息,而全局钩子函数必须以DLL(动态连接库)为载体进行封装,VC6中有三种形式的MFC DLL可供选择,即Regular statically linked to MFC DLL(标准静态链接MFC DLL)、Regular using the shared MFC DLL(标准动态链接MFC DLL)以及Extension MFC DLL(扩展MFC DLL)。

在本程序中为方便起见采用了标准静态连接MFC DLL。

钩子的类型一.按事件分类,有如下的几种常用类型(1)键盘钩子和低级键盘钩子可以监视各种键盘消息。

(2)鼠标钩子和低级鼠标钩子可以监视各种鼠标消息。

(3)外壳钩子可以监视各种Shell事件消息。

比如启动和关闭应用程序。

(4)日志钩子可以记录从系统消息队列中取出的各种事件消息。

(5)窗口过程钩子监视所有从系统消息队列发往目标窗口的消息。

Mouse工作原理介绍

Mouse工作原理介绍

信号处理
信号处理 System Block Diagram
信号传输(1)
2.4G与Bluethooth对比: 优点:
Bluetooth为一短距离无线传输的通信界面,适应性广,基本型通 讯距离约10米,支援一对多资料传输及语音通讯等.
2.4GHz无线技术是一种短距离无线传输技术,双向传播,抗干扰性 强,传输距离远(短距离无线技术范围),耗电少的优点.
➢ RF : Radio Frequency
➢ DPI : Dots Per Inch.
--每英寸的面积上,点的个数;俗称图元;是衡量照片质量的参 数.
➢ CPI : Counts Per Inch
--鼠标移动每英寸的距离,产生的报告数量;是衡量鼠标灵敏度 的参数.
注:CPI(DPI)的规定如下: 鼠标在桌面移动1英寸(2.54cm),鼠标向计算机传输的报告数(反应
光学跟踪引擎部分横界面示意图
光学部分(3)
当鼠标移动的时候,成像传感器录得连续的图案,然后通过“数位讯号 处理器”(DSP)对每张图片的前后对比分析处理,以判断鼠标移动的方向 以及位移,从而得出鼠标x, y方向的移动数值。再通过SPI传给鼠标的微 型控制单元(MCU Unit)。鼠标的处理器对这些数值处理之后,传给计 算机主机。
成光标在荧幕移动的距离).
1.电源管理 --为整机提供稳定的动力
2.光学成像 --鼠标的眼睛
3.信号处理 --鼠标的大脑
4.信号传输 --计算机与鼠标沟通的桥梁
电源管理(1)
电源管理(2)
Vin1.5V
BlueTrack Mouse power management circuit BlueTrack Mouse Management Circuit

鼠标的工作原理

鼠标的工作原理

计算机鼠标工作原理鼠标的发展简介鼠标的内部结构鼠标的诞生鼠标接口光电鼠标光电鼠标的精度无线鼠标配对和安全性蓝牙鼠标为什么叫蓝牙?射频鼠标多媒体鼠标和遥控器鼠标游戏鼠标鼠标的横纵滚轮鼠标的发展简介1984年,随着Apple Macintosh的推出,鼠标也一同跃上舞台。

从此在它们的帮助下,计算机的使用方法得以彻底重新定义。

在您计算机使用生涯的每一天,只要想移动光标或者激活某些内容,您都会伸出手使用鼠标。

鼠标感知您的手部移动和单击并将它们发送给计算机,使计算机能够做出相应的响应。

这款微软智能鼠标利用了光学技术。

在本文中,我们将揭开人机界面这一重要部分的神秘面纱并了解它的工作原理。

鼠标的诞生鼠标的简单与高效令人赞叹。

同样令人吃惊的是鼠标变成日常生活的一部分经历了漫长的时间。

考虑到人们在讲述之前会自然而然地先指向相关物体,一种出色的指针设备经历了如此漫长的发展过程真是令人惊讶。

尽管在上世纪60年代就已经存在对鼠标的初步构思,但直到过了几十年之后鼠标才成为主流。

在初期,由于计算机使用类似于电传打字机或穿孔卡的粗糙界面进行数据输入,因而不需要进行指向。

早期的文本终端只是在模仿电传打字机(将屏幕替换为纸),因此经过许多年(上世纪整个60年代到70年代)箭头键才出现在多数终端上。

全屏幕编辑器首次真正地利用光标键,它们为人类提供了第一种指向方法。

光笔很多年来在各种机器上作为指针设备。

图形输入板、操纵杆及其他各种设备也在上世纪70年代大行其道。

然而,这些设备实际上都没有作为选择的指针设备受到普遍欢迎。

当鼠标连接到Mac计算机并登上舞台时便一举成功。

鼠标的某些方面是非常自然的。

与绘图式屏幕相比,鼠标非常便宜并且仅占用一点儿桌面空间。

在PC世界中,由于缺乏操作系统的支持,鼠标用了较长的时间才得以普及。

在 Windows 3.1使图形用户界面(GUI)成为标准后,鼠标很快成为了所选的人机接口方式。

鼠标的内部结构所有鼠标的主要目的都是将手部运动转换为计算机可以读取的信号。

屏幕抓词原理及其实现方法

屏幕抓词原理及其实现方法

第26卷 第4期2008年12月 贵 州 科 学GU IZHO U SC IENC E Vol.26,No .4Dec .2008收稿日期作者简介冀肖榆(%),男,5级研究生李丹宁,贵州科学院副院长,硕士生导师屏幕抓词原理及其实现方法冀肖榆1,赵廷义2,李丹宁2(1.贵州大学 电子技术与信息技术学院,贵州 贵阳 550025;2.贵州科学院,贵州 贵阳 550001)摘 要 本文介绍了W indo ws 2000/XP 下屏幕抓词的原理,对其如何获得鼠标位置的字符串,从代码拦截、鼠标HOOK 、屏幕刷新等方面进行了讨论.最后分析了通过本方法取词的局限性.关键词:屏幕取词;Hook;代码拦截中图分类号 TP391.1 文献标识码 A 文章编号 1003-6563(2008)04-0045-04THE P R INC IPL E AN D I M PL E M ENTAT I O N O F GRASP INGWO RDSJI Xiao -yu 1,ZHAO Ting -yi 2,L I D an -ning 2(1.College of Electroni c Sc ience and Infor m ati on T echn ology,Guizhou U nive rsity,Guiyang 550025;2.GuizhouAcademy of Sc iences,G uiyang 50001)ABSTRAC T This article intr oduced the princ i p l e of gras p ing words in W indo ws 2000/XP 1W e discussed theaspects of code intercepti on,mouse HOOK,and screen refurbis hing on h ow t o ge t charac ter a round t he mouse .F i nall y,we analyzed the li m itations of the gra s p i ng word based on the me th od .KEY W O RD S gras p ing word;H OOK ;AP I interception1 概述屏幕抓词的关键是如何获得鼠标位置的字符串,W indow s 的动态链接和消息响应机制为之提供了实现途径[3].概括地说,主要通过下面的几个步骤来取得屏幕上鼠标位置的字符串:代码拦截:W indows 以DLL 方式提供系统服务,可以方便地获取W indows 字符输出A P I 的地址,修改其入口代码,拦截应用程序对它们的调用.鼠标HOOK :安装WH _MOUSE 类型的全局鼠标HO O K 过程,监视鼠标在整个屏幕上的移动.屏幕刷新:使鼠标周围一块区域无效,并强制鼠标位置的窗口刷新屏幕输出.窗口过程响应WM_P A I N T 消息,调用ExtText Out 等字符输出AP I 更新无效区域里面的字符串.这些调用被我们截获,从堆栈里取得窗口过程传给字符I 的参数,如字符串地址、长度、输出坐标、D 、裁剪区等信息:2008-04-22:1982200..AP H C .2 原理分析在W indows2000/XP 系统中,屏幕上的大多数文字都是由gdi32.dll 和user32.dll 中的几个函数[1]显示的:Text O ut A ,Text Out W ,ExtText Out A ,ExtText Out W ,D ra wText W ,D ra wText A.其调用关系如图1所示.图1 字符输出F i g .1 C ha ra c te r o ut p ut 从上图可以看出,无论是通过那个字符输出函数,最终应用程序都会通过G D I 32.dll 的ExtText Out A 和ExtText O ut W 把字符输出到屏幕上.其中ExtText O ut A 输出ANS I 格式的字符,ExtText O ut W 输出U N I CODE 格式的字符;因此,只要拦截2个函数:ExtText Out A 和ExtText Out W ,就能截获应用程序的所有字符串输出.3 实现本文将用Delphi 实现在W indows2000/XP 系统下的屏幕抓词,以下是实现步骤及关键的伪码.图2 屏幕抓词实现F i g .2 R ea li z i ng t he g ra sp i ng wo rd s3.1 拦截字符输出AP I3 代码拦截的基本思路为了实现对x T xO x T xO W 等I 的拦截,需要在函数入口放入一条动态生成的“M <替代函数>”指令,M 的操作数是我们提供的一个拦截替代函数的地址[]当该I 被调用时,M 指令首64贵 州 科 学 26卷 .1.1E t e t ut A /E t e t ut A P J P J P 2.AP J P先执行,跳转到替代函数.替代函数负责从堆栈中获取参数,计算字符串坐标,分出鼠标位置的单词等工作.执行完成后,替代函数再调用原来的被拦截函数,完成正常的字符输出,然后返回.图2(a )表明了应用程序对Text Out 的正常调用流程,图2(b )是系统Text Out 被拦截后的流程.3.1.2 构造拦截替代函数拦截替代函数插入被拦截AP I 的流程中执行,需要有相同的参数和返回值原型.以对Text O utExt A 的拦截为例,下面是替代函数myText O utExt A 的D el phi 关键代码:Boolean m yExtText Out (H DC hdc,integer x,y,LPSTR l p str,integer cbstr ){ DoS py (hDC ,x ,y,lpstr,cbstr ); //保存参数,作抓词的所有工作 Restor eCode ();//恢复Text Out 入口原来的指令 Text Out (hDC ,x,y,l p str,cbstr );//调用原来的AP I SpyCode ();//再次放入JMP 指令 return TRUE;}函数首先调用DoSpy ()来作抓词的具体工作,然后R est oreCode ()函数恢复被拦截函数入口的代码,再调用Text O ut ()执行正常的字符输出,接下来S pyCode ()在被拦截函数入口再次放入JMP 指令,最后返回调用进程.3.1.3 获取被拦截AP I 的动态链接地址ExtText O ut W /ExtText Out A 的地址可以通过G e tPr oc Addr e ss 取得,以myExtText Out 为例的De l phi 伪码如下:Va r pSysFunc:Pointer; //系统函数的地址pSysFunc :=G e tPr ocAddr e ss (Get M oduleHandle (’gdi .dll ’),’ExtText O ut A ’);3.1.4 动态生成J MP 指令动态生成的J MP 指令占用5个字节,保存在一个TCode5记录内.以生成跳转到m yExtText Out A 的替代函数m yExtText Out 的JMP 指令为例的De l phi 关键代码如下:Va r pThunkFunc: Pointer ; //替换函数的地址 code B ak: TCode5;//系统函数的代码的前5个字节 codeThunk: T Code5;//替换函数的代码的5个字节pT hunkFunc :=GetP r oc Address (hI nstance,’m yExtText Out A ’);c ode B ak.siJmp :=P B yte (pSysFunc)^;c ode B ak.dw Addr :=P D WORD (D WORD (pSysFunc)+1)^;c odeThunk.si Jmp :=ShortInt (S _E9);c odeThunk.dw Addr :=D WORD (pThunkFunc )-D WORD (pSysFunc )-5;3.1.5 修改被拦截函数的入口修改ExtText Out W /ExtText Out A 的入口以便系统调用这两个函数的时候能重定向到自己的代码m yExt 2Text Out W /m yExtText Out A,可以通过W ritePr ocess Me mory 进行修改,该AP I 可以把指定长度的代码拷贝到指定进程地址空间中[2].关键代码如下:W ritePr oce ss Memor y (hPr oc,pSysFunc,@codeThunk,5);上面的语句表示把codeThunk 中前五位代码(即替换函数m yExtText Out 的入口地址)拷贝到pSysFunc 进程空间(即系统函数x T xO 的入口地址)中,即完成对x T xO 等I 的拦截修改3 使用OO K 监视鼠标移动安装一个W _MOUS 类型的全局OOK,就可以截获所有的鼠标消息[]每当有鼠标事件产生,OOK74 4期 冀肖榆,等:屏幕抓词原理及其实现方法E t e t ut E t e t ut AP ..2H H E H 4.H84贵 州 科 学 26卷 过程被调用,它判断出鼠标移动了后,就向主窗口发送消息,通知主窗口鼠标位置发生了变化.该全局H OOK 过程需要放入DLL里面.只要装入一个WH_MOUSE类型的系统钩子,关键代码如下:Set W indow s HookEx( W H_MOUSE, //钩子类型 (HOOK PROC)MouseP r oc,//回调函数 Get ModuleHandle("hookdll.dll"),//我的动态库0);//标明是系统钩子,即拦截所有消息在回调函数里:if(wPara m=WM_MOUSE MOVE)then beginl pMouseHookStruct:=(LP MO USEHOOKSTRUCT)lPara m;MousePoint:=l pMouseHookStruct->p t; //这就是鼠标的当前位置End;3.3 刷新屏幕输出根据鼠标位置(更确切说是需求取词的位置)构造一个矩形区域,然后调用I nva lidateR ect使得该区域无效,强制目标窗口刷新屏幕输出.在响应WM_P A I N T系统消息中,目标窗口对字符输出A PI(ExtText Out W/ ExtText O ut A)的调用将被我们截获和处理,完成一次抓词过程.如下是关键代码:Va r r ect:TR ECT; //使之无效的矩形区域ScreenToC lient(hwnd,&MousePoint);//转换坐标rec t.left:=MousePoint.x;//根据要取词的位置构造无效矩形区域rec t.t op:=MousePoint.y;rec t.right:=MousePoint.x+1;rec t.bott om:=MousePoint.y+1;I nvalidateR ect(hwnd,@r ect,F ALSE);//使之无效4 局限性分析安装钩子的抓词方式是目前最流行的方式,这种技术是基于应用程序调用W indows系统ExtText Out输出字符的原理,若是应用程序有自己特定的字符输出机制,不通过ExtText Out输出,则钩子方式是无法截获缓冲区的字符的.典型的应用就是Acr obat R eader.由于上述的局限性,可以考虑把OCR技术应用到屏幕抓词中,即直接读取屏幕一块区域为图片并进行文字识别,但效率问题一直未能得到比较好的解决.参考文献[1] John Ayres.Del p hi W in32核心AP I参考[M].北京:中国电力出版社,2004.[2] R I CHT ER J.W indo w s核心编程[M].北京:北京机械工业出版社,2000,299~309.[3] 陈小辉.钩子技术在信息窥探中的使用[J].计算机与现代化,2006,9:97~99.[4] 熊志勇.利用Hook技术实现屏幕热区[J].电脑编程技巧与维护,2002,12:17~18.。

鼠标的报告速率

鼠标的报告速率

鼠标的报告速率1. 介绍鼠标的报告速率是指鼠标向计算机发送数据的频率。

它表示鼠标在单位时间内向计算机发送的数据包数量。

常见的鼠标报告速率有125Hz、250Hz、500Hz和1000Hz等。

较高的报告速率意味着更频繁地向计算机发送数据,从而提高鼠标的响应速度和准确性。

2. 鼠标的工作原理为了理解鼠标的报告速率,我们首先需要了解鼠标的工作原理。

现代鼠标通常使用光学传感器或激光传感器来检测其移动。

当我们移动鼠标时,传感器会捕捉到光线的变化,并将其转化为电信号。

这些电信号被发送到计算机,计算机通过解读这些信号来确定鼠标的位置和移动方向。

3. 什么是鼠标的报告速率?鼠标的报告速率是鼠标每秒向计算机发送的数据包数量。

一个数据包可以包含鼠标的位置、移动速度、按键状态等信息。

较高的报告速率意味着鼠标会更频繁地向计算机发送这些信息,从而使鼠标的响应速度更快。

4. 鼠标报告速率的影响鼠标报告速率对于游戏玩家和专业设计师来说尤为重要。

较高的报告速率可以使鼠标的响应速度更快,提高游戏的精准度和反应时间。

此外,对于专业设计师来说,更高的报告速率可以提供更流畅的操作和绘制体验。

然而,较高的报告速率也会消耗更多的计算机资源。

更高的报告速率意味着计算机需要更频繁地接收和处理鼠标数据,因此可能会导致计算机的负载增加。

对于一些普通用户来说,较低的报告速率已经足够满足日常使用需求。

5. 如何调整鼠标的报告速率?调整鼠标的报告速率通常需要通过操作系统或鼠标驱动程序来完成。

以下是一些常见的调整方法:•在Windows操作系统中:打开控制面板,选择“鼠标”,然后选择“指针选项”选项卡。

在这里,您可以找到鼠标的报告速率设置,并进行相应的调整。

•在Mac操作系统中:打开“系统偏好设置”,然后选择“鼠标”或“触控板”。

在这里,您可以找到鼠标的报告速率设置,并进行调整。

•对于游戏鼠标或专业外设:通常配备了相应的驱动程序或软件,您可以使用这些软件来调整鼠标的报告速率以满足特定的需求。

mouse的名词解释

mouse的名词解释

mouse的名词解释Mouse(鼠标)是一种常见的计算机输入设备,用于控制光标在电脑屏幕上的移动,以及执行各种操作和指令。

它是计算机领域的重要发明之一,极大地提高了人机交互的便捷性和效率。

1. 鼠标的起源与发展鼠标这一概念最早由道格拉斯·恩格尔巴特(Douglas Engelbart)提出,并被他的团队发明和开发。

1964年,他们设计了一个原型,用木头和金属制成,形状类似于现在的鼠标,但使用的还是机械式技术。

这个原型被称为“鼠标”,因为连接在电脑上的线看起来像老鼠的尾巴。

然而,直到1980年代初,鼠标才得以商业化生产和广泛运用。

由于苹果公司于1984年发布的Macintosh计算机使用了鼠标,为鼠标的流行铺平了道路。

此后,鼠标逐渐取代了键盘作为主要的计算机输入设备,成为现代计算机不可或缺的部分。

2. 鼠标的构造和工作原理鼠标通常由一个外壳、左键、右键、滚轮和一个连接电脑的线缆组成。

最初的鼠标使用机械式结构,通过球和滚轮来感应手的移动,并将移动转化为光标在屏幕上的变化。

这种机械结构逐渐被光学式鼠标所取代,光学传感器通过感应台面上的细微纹理和模式,来追踪和捕捉手的移动。

现在,还有许多其他类型的鼠标可供选择,包括无线鼠标、蓝牙鼠标和触控板。

无线鼠标通过无线信号与电脑通信,使用户摆脱有线的限制。

蓝牙鼠标则使用蓝牙技术进行无线传输。

触控板则利用手指的触摸和手势来替代传统的鼠标点击和滚轮操作。

3. 鼠标的功能与应用鼠标最基础的功能是控制光标在屏幕上的移动。

通过鼠标滑动和滚轮旋转操作,用户可以方便地选择、点击、拖拽、放大、缩小和滚动屏幕上的内容。

鼠标还可以与操作系统和软件应用程序进行交互,例如右键点击可以打开上下文菜单,滚轮可以在网页或文档中上下滚动。

除了基本的移动和点击功能外,鼠标还可以进行定位、拖拽、快捷键切换、手势识别等高级操作。

例如,在图形设计软件中,通过将鼠标悬停在某个工具上,可以获得关于该工具的快捷键提示。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

鼠标屏幕取词原理“鼠标屏幕取词”技术是在电子字典中得到广泛地应用的,如四通利方和金山词霸等软件,这个技术看似简单,其实在windows系统中实现却是非常复杂的,总的来说有两种实现方式:第一种:采用截获对部分gdi的api调用来实现,如textout,textouta等。

第二种:对每个设备上下文(dc)做一分copy,并跟踪所有修改上下文(dc)的操作。

第二种方法更强大,但兼容性不好,而第一种方法使用的截获windowsapi的调用,这项技术的强大可能远远超出了您的想象,毫不夸张的说,利用windowsapi拦截技术,你可以改造整个操作系统,事实上很多外挂式windows中文平台就是这么实现的!而这项技术也正是这篇文章的主题。

截windowsapi的调用,具体的说来也可以分为两种方法:第一种方法通过直接改写winapi 在内存中的映像,嵌入汇编代码,使之被调用时跳转到指定的地址运行来截获;第二种方法则改写iat(import address table 输入地址表),重定向winapi函数的调用来实现对winapi的截获。

第一种方法的实现较为繁琐,而且在win95、98下面更有难度,这是因为虽然微软说win16的api只是为了兼容性才保留下来,程序员应该尽可能地调用32位的api,实际上根本就不是这样!win 9x内部的大部分32位api经过变换调用了同名的16位api,也就是说我们需要在拦截的函数中嵌入16位汇编代码!我们将要介绍的是第二种拦截方法,这种方法在win95、98和nt下面运行都比较稳定,兼容性较好。

由于需要用到关于windows虚拟内存的管理、打破进程边界墙、向应用程序的进程空间中注入代码、pe(portable executable)文件格式和iat(输入地址表)等较底层的知识,所以我们先对涉及到的这些知识大概地做一个介绍,最后会给出拦截部分的关键代码。

先说windows虚拟内存的管理。

windows9x给每一个进程分配了4gb的地址空间,对于nt 来说,这个数字是2gb,系统保留了2gb到4gb之间的地址空间禁止进程访问,而在win9x 中,2gb到4gb这部分虚拟地址空间实际上是由所有的win32进程所共享的,这部分地址空间加载了共享win32 dll、内存映射文件和vxd、内存管理器和文件系统码,win9x中这部分对于每一个进程都是可见的,这也是win9x操作系统不够健壮的原因。

win9x中为16位操作系统保留了0到4mb的地址空间,而在4mb到2gb之间也就是win32进程私有的地址空间,由于每个进程的地址空间都是相对独立的,也就是说,如果程序想截获其它进程中的api调用,就必须打破进程边界墙,向其它的进程中注入截获api调用的代码,这项工作我们交给钩子函数(setwindowshookex)来完成,关于如何创建一个包含系统钩子的动态链接库,《电脑高手杂志》在第?期已经有过专题介绍了,这里就不赘述了。

所有系统钩子的函数必须要在动态库里,这样的话,当进程隐式或显式调用一个动态库里的函数时,系统会把这个动态库映射到这个进程的虚拟地址空间里,这使得dll成为进程的一部分,以这个进程的身份执行,使用这个进程的堆栈,也就是说动态链接库中的代码被钩子函数注入了其它gui进程的地址空间(非gui进程,钩子函数就无能为力了),当包含钩子的dll注入其它进程后,就可以取得映射到这个进程虚拟内存里的各个模块(exe 和dll)的基地址,如:hmodule hmodule=getmodulehandle(“mypro.exe”);在mfc程序中,我们可以用afxgetinstancehandle()函数来得到模块的基地址。

exe和dll被映射到虚拟内存空间的什么地方是由它们的基地址决定的。

它们的基地址是在链接时由链接器决定的。

当你新建一个win32工程时,vc++链接器使用缺省的基地址0x00400000。

可以通过链接器的base选项改变模块的基地址。

exe通常被映射到虚拟内存的0x00400000处,dll也随之有不同的基地址,通常被映射到不同进程的相同的虚拟地址空间处。

系统将exe和dll原封不动映射到虚拟内存空间中,它们在内存中的结构与磁盘上的静态文件结构是一样的。

即pe (portable executable) 文件格式。

我们得到了进程模块的基地址以后,就可以根据pe文件的格式穷举这个模块的image_import_descriptor数组,看看进程空间中是否引入了我们需要截获的函数所在的动态链接库,比如需要截获“textouta”,就必须检查“gdi32.dll”是否被引入了。

说到这里,我们有必要介绍一下pe文件的格式,如右图,这是pe文件格式的大致框图,最前面是文件头,我们不必理会,从pe file optional header 后面开始,就是文件中各个段的说明,说明后面才是真正的段数据,而实际上我们关心的只有一个段,那就是“.idata”段,这个段中包含了所有的引入函数信息,还有iat(import address table)的rva(relative virtual address)地址。

说到这里,截获windowsapi的整个原理就要真相大白了。

实际上所有进程对给定的api函数的调用总是通过pe文件的一个地方来转移的,这就是一个该模块(可以是exe或dll)的“.idata”段中的iat输入地址表(import address table)。

在那里有所有本模块调用的其它dll 的函数名及地址。

对其它dll的函数调用实际上只是跳转到输入地址表,由输入地址表再跳转到dll真正的函数入口。

具体来说,我们将通过image_import_descriptor数组来访问“.idata”段中引入的dll的信息,然后通过image_thunk_data数组来针对一个被引入的dll访问该dll中被引入的每个函数的信息,找到我们需要截获的函数的跳转地址,然后改成我们自己的函数的地址……具体的做法在后面的关键代码中会有详细的讲解。

讲了这么多原理,现在让我们回到“鼠标屏幕取词”的专题上来。

除了api函数的截获,要实现“鼠标屏幕取词”,还需要做一些其它的工作,简单的说来,可以把一个完整的取词过程归纳成以下几个步骤:1.安装鼠标钩子,通过钩子函数获得鼠标消息。

使用到的api函数:setwindowshookex2.得到鼠标的当前位置,向鼠标下的窗口发重画消息,让它调用系统函数重画窗口。

使用到的api函数:windowfrompoint,screentoclient,invalidaterect3.截获对系统函数的调用,取得参数,也就是我们要取的词。

对于大多数的windows应用程序来说,如果要取词,我们需要截获的是“gdi32.dll”中的“textouta”函数。

我们先仿照textouta函数写一个自己的mytextouta函数,如:bool winapi mytextouta(hdc hdc, int nxstart, int nystart, lpcstr lpszstring,int cbstring){// 这里进行输出lpszstring的处理// 然后调用正版的textouta函数}把这个函数放在安装了钩子的动态连接库中,然后调用我们最后给出的hookimportfunction 函数来截获进程对textouta函数的调用,跳转到我们的mytextouta函数,完成对输出字符串的捕捉。

hookimportfunction的用法:hookfuncdesc hd;proc porigfuns;hd.szfunc="textouta";hd.pproc=(proc)mytextouta;hookimportfunction (afxgetinstancehandle(),"gdi32.dll",&hd,porigfuns);下面给出了hookimportfunction的源代码,相信详尽的注释一定不会让您觉得理解截获到底是怎么实现的很难,ok,let’s go:///////////////////////////////////////////// begin ///////////////////////////////////////////////////////////////#include <crtdbg.h>// 这里定义了一个产生指针的宏#define makeptr(cast, ptr, addvalue) (cast)((dword)(ptr)+(dword)(addvalue))// 定义了hookfuncdesc结构,我们用这个结构作为参数传给hookimportfunction函数typedef struct tag_hookfuncdesc{lpcstr szfunc; // the name of the function to hook.proc pproc; // the procedure to blast in.} hookfuncdesc , * lphookfuncdesc;// 这个函数监测当前系统是否是windowntbool isnt();// 这个函数得到hmodule -- 即我们需要截获的函数所在的dll模块的引入描述符(import descriptor)pimage_import_descriptor getnamedimportdescriptor(hmodule hmodule, lpcstr szimportmodule);// 我们的主函数bool hookimportfunction(hmodule hmodule, lpcstr szimportmodule,lphookfuncdesc pahookfunc, proc* paorigfuncs){/////////////////////// 下面的代码检测参数的有效性////////////////////////////_assert(szimportmodule);_assert(!isbadreadptr(pahookfunc, sizeof(hookfuncdesc)));#ifdef _debugif (paorigfuncs) _assert(!isbadwriteptr(paorigfuncs, sizeof(proc)));_assert(pahookfunc.szfunc);_assert(*pahookfunc.szfunc != '\0');_assert(!isbadcodeptr(pahookfunc.pproc));#endifif ((szimportmodule == null) || (isbadreadptr(pahookfunc, sizeof(hookfuncdesc)))){_assert(false);setlasterrorex(error_invalid_parameter, sle_error);return false;}//////////////////////////////////////////////////////////////////////////////// 监测当前模块是否是在2gb虚拟内存空间之上// 这部分的地址内存是属于win32进程共享的if (!isnt() && ((dword)hmodule >= 0x80000000)){_assert(false);setlasterrorex(error_invalid_handle, sle_error);return false;}// 清零if (paorigfuncs) memset(paorigfuncs, null, sizeof(proc));// 调用getnamedimportdescriptor()函数,来得到hmodule -- 即我们需要// 截获的函数所在的dll模块的引入描述符(import descriptor)pimage_import_descriptor pimportdesc = getnamedimportdescriptor(hmodule, szimportmodule);if (pimportdesc == null)return false; // 若为空,则模块未被当前进程所引入// 从dll模块中得到原始的thunk信息,因为pimportdesc->firstthunk数组中的原始信息已经// 在应用程序引入该dll时覆盖上了所有的引入信息,所以我们需要通过取得pimportdesc->originalfirstthunk// 指针来访问引入函数名等信息pimage_thunk_data porigthunk = makeptr(pimage_thunk_data, hmodule,pimportdesc->originalfirstthunk);// 从pimportdesc->firstthunk得到image_thunk_data数组的指针,由于这里在dll被引入时已经填充了// 所有的引入信息,所以真正的截获实际上正是在这里进行的pimage_thunk_data prealthunk = makeptr(pimage_thunk_data, hmodule,pimportdesc->firstthunk);// 穷举image_thunk_data数组,寻找我们需要截获的函数,这是最关键的部分!while (porigthunk->u1.function){// 只寻找那些按函数名而不是序号引入的函数if (image_ordinal_flag != (porigthunk->u1.ordinal & image_ordinal_flag)){// 得到引入函数的函数名pimage_import_by_name pbyname = makeptr(pimage_import_by_name, hmodule, porigthunk->u1.addressofdata);// 如果函数名以null开始,跳过,继续下一个函数if ('\0' == pbyname->name[0])continue;// bdohook用来检查是否截获成功bool bdohook = false;// 检查是否当前函数是我们需要截获的函数if ((pahookfunc.szfunc[0] == pbyname->name[0]) &&(strcmpi(pahookfunc.szfunc, (char*)pbyname->name) == 0)){// 找到了!if (pahookfunc.pproc)bdohook = true;}if (bdohook){// 我们已经找到了所要截获的函数,那么就开始动手吧// 首先要做的是改变这一块虚拟内存的内存保护状态,让我们可以自由存取memory_basic_information mbi_thunk;virtualquery(prealthunk, &mbi_thunk, sizeof(memory_basic_information));_assert(virtualprotect(mbi_thunk.baseaddress, mbi_thunk.regionsize,page_readwrite, &mbi_thunk.protect));// 保存我们所要截获的函数的正确跳转地址if (paorigfuncs)paorigfuncs = (proc)prealthunk->u1.function;// 将image_thunk_data数组中的函数跳转地址改写为我们自己的函数地址!// 以后所有进程对这个系统函数的所有调用都将成为对我们自己编写的函数的调用prealthunk->u1.function = (pdword)pahookfunc.pproc;// 操作完毕!将这一块虚拟内存改回原来的保护状态dword dwoldprotect;_assert(virtualprotect(mbi_thunk.baseaddress, mbi_thunk.regionsize,mbi_thunk.protect, &dwoldprotect));setlasterror(error_success);return true;}}// 访问image_thunk_data数组中的下一个元素porigthunk++;prealthunk++;}return true;}// getnamedimportdescriptor函数的实现pimage_import_descriptor getnamedimportdescriptor(hmodule hmodule, lpcstr szimportmodule){// 检测参数_assert(szimportmodule);_assert(hmodule);if ((szimportmodule == null) || (hmodule == null)){_assert(false);setlasterrorex(error_invalid_parameter, sle_error);return null;}// 得到dos文件头pimage_dos_header pdosheader = (pimage_dos_header) hmodule;// 检测是否mz文件头if (isbadreadptr(pdosheader, sizeof(image_dos_header)) ||(pdosheader->e_magic != image_dos_signature)){_assert(false);setlasterrorex(error_invalid_parameter, sle_error);return null;}// 取得pe文件头pimage_nt_headers pntheader = makeptr(pimage_nt_headers, pdosheader, pdosheader->e_lfanew);// 检测是否pe映像文件if (isbadreadptr(pntheader, sizeof(image_nt_headers)) ||(pntheader->signature != image_nt_signature)){_assert(false);setlasterrorex(error_invalid_parameter, sle_error);return null;}// 检查pe文件的引入段(即 .idata section)if (pntheader->optionalheader.datadirectory[image_directory_entry_import].virtualaddress == 0)return null;// 得到引入段(即 .idata section)的指针pimage_import_descriptor pimportdesc = makeptr(pimage_import_descriptor, pdosheader,pntheader->optionalheader.datadirectory[image_directory_entry_import].virtualaddress);// 穷举pimage_import_descriptor数组寻找我们需要截获的函数所在的模块while (pimportdesc->name){pstr szcurrmod = makeptr(pstr, pdosheader, pimportdesc->name);if (stricmp(szcurrmod, szimportmodule) == 0)break; // 找到!中断循环// 下一个元素pimportdesc++;}// 如果没有找到,说明我们寻找的模块没有被当前的进程所引入!if (pimportdesc->name == null)return null;// 返回函数所找到的模块描述符(import descriptor)return pimportdesc;}// isnt()函数的实现bool isnt(){osversioninfo stosvi;memset(&stosvi, null, sizeof(osversioninfo));stosvi.dwosversioninfosize = sizeof(osversioninfo);bool bret = getversionex(&stosvi);_assert(true == bret);if (false == bret) return false;return (ver_platform_win32_nt == stosvi.dwplatformid);}/////////////////////////////////////////////// end //////////////////////////////////////////////////////////////////////。

相关文档
最新文档