用Detours截取Windows程序密码
一、引言
随着信息技术的快速发展,人们会越来越重视信息的安全性,信息数据的安全保密已经成为研究计算机发展的一个重要课题。在其它识别技术尚不能普及情况下,密码常常被用户用作保护他们宝贵数据的最后一道屏障,然而有了密码,用户也不能高枕无忧,因为现在有很多的工具可以穷举和窃取用户密码,下面通过Detours简单介绍一下截取密码的基本原理,以此提醒用户密码要定期更换,而且其它相关的安全保卫措施同样不可忽视。
二、基本原理
在Windows编程中,人们普遍使用密码编辑框,来提示用户使用密码,密码编辑框除了回显字符之外,与一般的编辑框框控件并没有任何区别。通过调用GetWindowText和GetDlgItemText函数,或者向该密码编辑框窗口发送WM_GETTEXT消息,用户很容易获得这些输入的密码字符,这可以通过Visual Studio提供的SPY++工具来验证。如果用户为了图省事,让系统记住这些密码,免去每次登录时密码输入,这将会使他们陷入更加危险的境地,因为现在有许多类似于Reveal的小程序,可以获得鼠标所指之处的密码,它们基本上都是通过向密码编辑框发送WM_GETTEXT消息实现的。即便不让系统保存密码,用户也不能大意,因为就在你输入程序的背后,可能隐藏着 这么一个恶意的程序,它会记录你输入的任何字符,并神不知鬼不觉地把它记录到一个文件中。
这样的程序一般都是通过钩子函数或者API HOOK实现的。因为用户输入完密码之后,还要提交给应用程序来验证,并以此确定他们是否为合法用户。这时候,应用程序往往会调用上述函数或者发送WM_GETTEXT消息,获得用户输入的密码文本。如果有这么一个程序,能够截获这些API函数调用或者截获这些窗口消息,那么它就会在密码到达应用程序之前先期截获这些密码。
这些程序一般都会在系统启动时,自动运行,然后安装系统钩子,截获GetWindowText或GetDlgItemText函数,或者截获Windows消息(如WM_DESTROY),并向密码及其兄弟窗口发送WM_GETTEXT消息,即可获得包括用户名在内的全部文本,保存到文件之后,然后把控制权交给系统。这样的程序一般都有 局限性,因为它必须开机自动运行后,才会起作用,因此通过修改注册编辑表,很容易发现它们的踪迹,并把它们清除到系统之外。而且在安全模式下,这些程序除非你主动运行它,否则它永远不会被激活。 注意这里的运行并非一定要你用鼠标去双击一个应用程序,如果你双击的文件是一个TXT文本文件(或者BMP、HTML等文件),而这些文件默认打开程序已被修改为黑客程序,这种情况下数据文件成了导火索,它们同样也会激活黑客程序。
还有一种程序是以DLL形式寄生在可执行文件之上(譬如记事本Notepad、画笔Mspaint)_),这往往需要一个安装程序,负责修改可执行文件,使得可执行文件运行时能够自动加载这些(木马程序)动态链接库,删除这些动态链接库,则会导致可执行文件无法运行。这种情况下,除非你重新安装应用程序, 否则你无法甩掉跟在你程序背后的鬼影。
三、具体实现
1.动态链接库的注入
动态链接库是WIN32系统的一个重要组成部分,它能够动态地装入到进程的地址空间, 动态链接库一旦注入到应用程序的进程空间,就会成为应用程序的运行中的一部分,和应用程序代码一起运行。由于有些进程压根就没有用到某些动态链接库,包括它的输出数据和输出函数。可以说这些应用程序和动态链接库之间没有任何“血缘关系”,应用程序也从来不会去主动地加载这些动态链接库,因此,我们必须编写代码实现DLL库的注入。把动态链接库注入到另外一个进程。最经典的做法是,在DLL中安装一个钩子函数,这样系统会帮我们把它注入到每一个受该钩子函数影响的进程之中。
钩子函数的安装往往需要一个安装程序,负责调用SetWindowsHookEx函数,然而如果我们每次使用钩子函数时都运行安装程序,那将是非常麻烦,对于一个木马程序来说,很容易暴露自己,因此我们希望我们的动态连接库能够寄生在一个可执行文件之上,一旦这个应用程序执行时,它就会在进程初始化阶段(DLL_PROCESS_ATTACH),安装钩子函数,这样应用程序甚至系统的窗口消息都会处于钩子函数的监控之下,钩子函数的钩子过程会负责截获有用的消息,并作相应的处理。
微软公司提供的Detours工具包(http://www.research.microsoft.com/sn/detours),刚好能够满足我们这个要求。Detours除了提供了一组API拦截的函数之外,还提供了一组函数能够很容易地实现DLL的注入,利用这组函数,我们既可以创建一个注入了DLL的新进程,也可以把DLL注入到一个已经运行的进程,更重要的是,它还能够修改应用程序的文件头,在文件头中加入DLL的信息,这样应用程序修改后不用任何干预,它自身就能负责完成动态链接库的加载。
2.Detours注入动态链接库
我们知道win32应用程序都采用win 32二进制PE格式存储,PE是一个COFF扩展(Common Object File Format)。一个win32二进制文件是由下面几部分组成的,一个DOS 兼容头、一个PE头、 一个包含程序代码的文本段、一个包含初始化数据的数据段、一个列举引用DLL 和函数名的引入表、一个列举代码和输出符号的输出表,除了两个头结构之外,其余部分都是可选的,在某些win32文件中可能某些部分不存在。
为了修改win 32 二进制代码,Detours 又在输出表和调试符号部分中间创建了一个新的.Detours段(如上图所示)(注:调试符号部分必须位于win32 二进值文件的最后),这个新的.Detours段包含了一个Detours头记录和一个原来PE头的副本。如果要修改输入表的话,Detours就会创建一个新的输入表,并把它添加到复制的PE 头中,然后修改原始的PE头结构,使其指向新的输入表。最后,Detours把用户的Payloads(负载)追加到. Detours段的尾部,然后在文件尾部添加调试符号信息。由于Detours备份了原始的PE头,所以这个过程完全可逆,以便能够去除.Detours段,恢复exe文件到未注入前的样子。
创建一个新的输入表有两个目的,一个目的是它能够保存原来的输入表,以便需要时恢复对原来文件的修改;另一个目的是,新的输入表可以包含重命名的动态连接库和函数,还可以包含新的动态连接库和函数.
Detours既提供了一组编辑输入表,添加、枚举、去除Payloads(负载),再绑定二进制的函数,也提供了一组枚举映射地址空间的二进制文件、定位映射文件Payloads(负载)的函数。每一个Payload(负载)均由一个GUID (a 128- bit globally unque identifier全球唯一标识符)标识。
这些函数的使用读者可以参考Detours提供的例子程序SetDll.cpp文件。
3.消息拦截
一旦动态链接库注入到应用程序后,它就会在进程初始化阶段完成钩子函数的安装,这里我们安装了两种钩子类型,WH_GETMESSAGE和WH_CALLWNDPROC,钩子函数的处理过程主要对WM_SETFOCUS和WM_DESTROY消息进行拦截,对前一个消息,先通过获得其类名(GetClassName函数)和窗口风格(GetWindowLong函数),判断它是否是一个密码编辑框(注意VisualC++、Delphi、Visual Basic编辑框的类名都不一样)。如果是,则把它本身窗口及其兄弟窗口、父窗口的窗口句柄保存到一个数组中,一旦系统向窗口WM_DESTROY消息时,消息被钩子函数截获,钩子处理过程会向保存到数组中的每一个窗口句柄发送WM_GETTEXT,获得对话框标题或各个编辑框的文本。
四、程序的使用
本程序是在Windows 2000环境下用Visual C++ 6.0调试通过的,在Windows98环境下也可以运行。使用时,先运行DllPatch.Exe程序,然后浏览到有密码的应用程序,确认后,DllPath程序会给目标应用程序创建一个备份文件,然后修改应用程序,并把InetPub.Dll文件拷贝到目标应用程序目录和Windows系统目录。这时你可以利用View Dependency 工具打开应用程序文件,你会发现它里面又多引用了一个名叫InetPub.Dll的动态链接库.密码截获后,木马程序会把密码文件存放在临时文件目录下的一个扩展名为tmp的文件中,为了便于说明,该文件的内容没有加密,同时Windows系统目录的Kernel32.ini文件也保存了有关密码的一些信息。真正的黑客程序可能就不会这么做,因为这很容易暴露自己,而且它还会修改InetPub.dll文件的日期与应用程序一致。也许你会说,我马上更改密码,你截获的密码照样进不去,殊不知就在你更改密码的同时,更改后的新密码也被记录下来。
通过这个程序,我们可以看到仅仅依靠密码来保证系统的安全是远远不够的。
点击这里下载源程序和演示程序。
DETOURS 下载地址:
http://www.research.microsoft.com/sn/detours
http://research.microsoft.com/sn/detours