设为首页 加入收藏

TOP

鼠标屏幕取词技术的原理和实现(二)
2012-11-04 15:14:21 来源: 作者: 【 】 浏览:521
Tags:鼠标 屏幕 技术 原理 实现
  先说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中被引入的每个函数的信息,找到我们需要截获的函数的跳转地址,然后改成我们自己的函数的地址……具体的做法在后面的关键代码中会有详细的讲解。

首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇用Visual C++轻松实现报表处理 下一篇VC++实现对文件夹时间的修改

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: