1、引言
上世纪90年纪使用过windows3.x的人可能很少有人了解这类操作系统中存在着密码保护的漏洞,如果选择密码控件中的“****”文本然后复制到剪贴板上,那么看到的将不是“****”而是密码的原始文本。微软发现了windows3.x这个问题并在新的版本window95中修改了这个漏洞。但是windows95存在着新的漏洞,可以设计出间谍程序从当前运行的程序中得到密码控件中的密码,这些间谍程序并非是如同softice一样的破解程序。然而,微软在window2000中又修补了这个问题,如何通过MMF与HOOK技术获取任何版本windows 密码控件的内容,这正是本文讨论的重点问题。
图1 2K/XP密码校验
获取密码技术主要是利用了windows的漏洞。在Windows NT/95/98/ME等操作系统下,如果在间谍程序中发送WM_GETTEXT消息到密码控件,返回的文本将不再是“****”而是实际的文本内容,而在windows2K/XP系统中微软加了安全控制,如果发送WM_GETTEXT到密码控件,系统将校验请求的进程判断该进程是否有许可权,如图1所示:如果请求进程与密码控件所在进程是同一进程,那么WM_GETTEXT消息将仍旧返回密码的真实文本。如果两个进程不一样,就返回一个ERROR_Access_DENIED的错误。所以获取windows2K/XP密码的关键技术在于:从密码控件所在的进程中获取WM_GETTEXT消息,而不是在渗透进程中得到。而这种在其它进程中运行用户代码的技术完全可以利用windows 钩子(hook)技术来实现。首先我们需要了解一下什么是钩子。
2、Windows钩子
Windows系统是建立在事件驱动的机制上的,即整个系统都是通过消息的传递来实现的。钩子(hook)是一种特殊的消息处理机制,钩子可以监视系统或进程中的各种事件消息,截获发往目标窗口的消息并进行处理。这样,我们就可以在系统中安装自定义的钩子,监视系统中特定事件的发生,完成特定的功能,比如截获键盘、鼠标的输入,屏幕取词,日志监视等等。钩子的种类很多,每种钩子可以截获并处理相应的消息,如键盘钩子可以截获键盘消息,外壳钩子可以截取、启动和关闭应用程序的消息等。如图2是一全局钩子示意图。
在实例程序中运用WH_GETMESSAGE钩子,这个钩子监视投递到消息队列中的Windows消息。
图2 全局钩子的原理图
3、Windows钩子在此处的应用
安装钩子的函数为SetWindowsHookEx,利用这个函数可以为整个系统或为某一特定进程安装钩子,不同的钩子监视特定钩子事件的发生,当某一事件触发后,与之对应的代码就会被系统调用。
运用windows钩子的一个难点是如何妥善保存钩子的句柄。在设置钩子前需要解决两件事:
1) 一个包括了钩子函数的动态链接库;
2) 要注入钩子的进程ID。
现在假设进程A为进程B注入了一个钩子。钩子注入后,钩子的句柄返回给了进程A并且动态链接库映射到了进程B的地址空间。当进程B中触发了一个钩子事件,钩子代码被进程B调用(需要特别指出的是,钩子代码被一个远程进程所调用,被调用的钩子代码中如果调用GetCurrentProcessId这个函数,得到的是被注入了钩子进程的进程ID,而不是注入进程)。在钩子代码中通过发消息获取密码真实文本,在钩子代码结束前需调用CallNextHookEx函数,如果这个函数调用失败,安装的其它钩子将得不到消息。现在出现的问题是CallNextHookEx需要一个钩子的句柄,但那个所需的句柄已返回给了进程A而钩子程序目前运行在进程B的代码段内。这样就需要用到进程间通信IPC(Inter Process Communication)来传递钩子句柄。
4、进程间通信的一般方法
解决以上问题的一般方法是在动态链接库中创建一个“共享”部分,写入如下代码:
#pragma data_seg(“Shared”) HHOOK g_hHook = NULL; #pragma data_seg() #pragma comment(linker, “/section:Shared,rws”) |
简单地说这几行代码创建了一个共享的变量,如果5个进程载入这个动态链接库,5个进程都有访问的权限。但这个方法有一些问题:一是一些编译器可能并不支持这种方法。二是如果未来的windows版本发生了改变,这种方法就行不通。三是这个方法没有规定线程同步,如果有多线程访问这个变量,线程同步是非常重要的,没有线程间的同步可能会触发诸如冲突等一些问题。解决这个问题的方法是利用内存映像文件(MMF)。
5、内存映像文件(MMF)
在WIN32中,通过使用映像文件在进程间实现共享文件或内存共享,如果利用相同的映像名字或文件句柄,则不同的进程可以通过一个指针来读写同一个文件或者同一内存数据块,并把他们当成该进程内存空间的一部分。内存映像文件可以映射一个文件、一个文件中的指定区域或者指定的内存块,其中的数据就可以用内存读取指令来直接访问,而不用频繁的使用操作文件的I/O系统函数,从而提高文件的存取速度和效率。
映像文件的另一个重要作用就是用来支持永久命名的共享内存。要在两个应用程序之间共享内存,可以在一个应用程序中创建一个文件并映射,然后另外一个程序通过打开和映射此文件,并把它当作自己进程的内存来使用。
6、建立基于MMF的类CIPC
[1]
【责编:Luzi】
--------------------next---------------------
阅读(318) | 评论(0) | 转发(0) |