基于API HOOK的剪切板监控



 



    摘  要  本文通过对剪切板机制的研究,采用API HOOK技术对剪切板的系统调用函数拦截,实现了对剪切板的监控,防止敏感信息通过剪切板泄露。



    关键词  剪切板;API HOOK;信息保密



 


 


1  引言



    计算机的普及带来了信息交流的便利,同时也造成了信息泄露问题的日趋严重。剪切板是信息泄露的一个主要途径,对剪切板的监控是防止信息泄密的不可或缺的一环。本文通过对剪切板机制和API HOOK技术的研究,通过远程线程注入的方式替换剪切板的系统调用函数,实现对剪切板的监控。



2  剪切板机制



    Windows剪切板是一种简单而且开销较小的IPC(InterProcess Communication,进程间通讯)机制,方便用户在不同程序间拷贝数据。在Windows操作系统中存在两种剪切板机制,即标准剪切板机制和OLE剪切板机制。



    标准剪切板的基本机制是 【1】:Windows系统预留一块全局共享内存,提供数据的进程创建一个全局内存块,并将要传送的数据拷贝到内存中,接受数据的进程获取此内存块的句柄,并拷贝其中的数据。进程使用剪切板的一般步骤为:调用OpenClipboard()函数打开剪切板,调用GetClipboard Data()函数获取剪切板的内容,如果是设置剪切板内容,则调用EmptyClipboard()函数清空剪切板,然后调用SetCipboard Data()设置剪切板内容,调用CloseClipboard()关闭剪切板。因此,防泄密系统可以通过截获进程对USER32.dll中Open Clipboard、GetClipboardData、EmptyClipboard、SetClipboardData API函数的调用,实现对剪切板的控制。



    自从OLE(Object Linking and Embedding,对象链接和嵌入)出现后,Windows操作系统出现了另一种剪切板机制――OLE剪切板机制。OLE剪切板使用IDataObject接口,相关的API函数和标准剪切板类似,主要有以下几个:



    OleSetClipboard():在剪切板上放置一个IDataObject接口指针;



    OleGetClipboard():从剪切板获取一个IDataObject接口指针;



    OleFlushClipboard():清除剪切板中的内容,并释放IDataObject接口指针;



    OleIsCurrentClipboard():判断剪切板上是否存在指定对象。



3  API HOOK



    Windows API是Windows提供给应用程序的接口,通过这个接口,应用程序可以使用操作系统的所有资源。大多数应用程序都要使用很多API函数,在应用程序没有提供编程接口,也不知道源代码的情况下,API HOOK技术是控制应用程序的一种有效途径。通过API HOOK,可以实现对Win32 API函数的拦截,从而改变函数甚至应用程序的行为。



3.1  API HOOK途径



    通常API HOOK的实现有以下两种途径 【2】【3】



    1)导入地址表(Import Address Table, IAT)补丁



    Windows 32位操作系统中,所有可执行文件或动态链接库都是基于PE(Portable Executable)格式构建。PE文件的结构由多个成为“节”块组成,每个节中都包含了特定的内容,而且加载入内存中的PE文件的结构与磁盘上的静态文件结构完全一样。在PE文件的.idata节中包含一个IAT,它保存着所有与可执行代码应用的导入函数名称的偏移量。当调用某一导入函数时,可执行程序从IAT中找到该导入函数的入口地址,然后再跳转到执行函数代码。用户可以用自己函数的入口地址覆盖IAT中相对应的导入函数地址,实现API函数拦截。



     2)修改应用程序



    该方式主要通过替换函数实现的前几个字节。通过调用GetProcAddress函数得到被拦截API函数的入口地址,保存入口地址前几个字节的内容,并用一个JMP或INT指令替换。当API函数被调用时,应用程序就会直接跳转或通过中断的方式跳转到拦截函数。



3.2  API HOOK的实现步骤



    API HOOK的实现一般包括两个步骤:



    1) 代码注入



    在Windows操作系统中,所有32位应用程序都运行在一个相对独立的私有地址空间中。API HOOK的第一步就是把自己的拦截函数做成动态链接库,注入到目标进程的地址空间中,然后再实现函数跳转。通常代码注入采用创建远程线程的方法。



    创建远程线程实现代码注入的主要思想是用Virtual AllocEx函数在远程进程中申请空间,调用WriteProcess Memory将拦截函数动态链接库的名字和路径写入申请的空间,调用CreateRemoteThread和LoadLibrary函数将动态链接库映射到远程进程,等待映射完毕后,调用GetExitCodeThread获得返回码,即得到映射的动态链接库的加载基地址。至此,拦截代码已经加载到远程进程的地址空间中。



    2) 挂接API



    得到拦截代码加载到远程进程的地址后,就可以采用IAT补丁或应用程序修改的方法,将目标API函数的调用修改为拦截函数的调用。



4  剪切板监控的实现



    本文将两种剪切板所用API函数的替代函数(如表1所示)存储到ClipboardControl.dll中,供剪切板监控程序拦截API时调用。


 


表1  剪切板API替换函数表



函数名

替换函数名

替换函数功能

SetClipboardData

MySetClipboardData

获取数据来源,收集数据源信息,对

OleSetClipboard

MyOleSetClipboard

GetClipboardData

MyGetClipboardData

收集数据目的地信息,根据防泄密规则决定该操作是否放行

OleGetClipboard

MyOleGetClipboard

SetClipboardViewer

MySetClipboardViewer

保证监控程序观察窗口始终处于链首,站取优先权


 


    剪切板监控程序调用CreateRemoteThread函数在阅读器进程中创建远程线程,把监控代码ClipboardControl.dll注入到目标进程中,并调用ImageDirectoryEntryToData函数获取目标进程模块的输入表地址,通过遍历输入表找到USER32.dll模块对应的IMAGE_IMPORT_DESCRIPTOR,然后遍历其IAT,找到目标API在IAT中相应的表项,通过VirtualQuery获取内存信息,调用VirtualProtectEx修改内存为可读写,再调用WriteProcessMemory修改内存,使表项中API函数的地址变为系统监控代码的地址,修改完毕后调用VirtualProtectEx将内存属性改回来。当用户使用剪切板时,监控程序就能根据替换函数的代码进行相应的操作,从而达到对剪切板进行监控的目的。


5  总结


    本文通过创建远程线程的方式,将API替代函数注入目标进程,通过修改IAT,对目标API函数进行替换,达到对其拦截的目的,从而实现了剪切板的监控,防止信息通过剪切板泄露。