首页>
技术资讯>
详情

先进的反病毒引擎设计之实时监控篇

2016-06-21 来源:CloudBest 阅读量: 628
关键词:


  3.病毒实时监控
  3.1实时监控概论
  
  实时监控技术其实并非什么新技术,早在DOS编程时代就有之。只不过那时人们没有给这项技术冠以这样专业的名字而已。早期在各大专院校机房中普遍使用的硬盘写保护软件正是利用了实时监控技术。硬盘写保护软件一般会将自身写入硬盘零磁头开始的几个扇区(由0磁头0柱面1扇最开始的64个扇区是保留的,DOS访问不到)并修改原来的主引导记录以使启动时硬盘写保护程序可以取得控制权。引导时取得控制权的硬盘写保护程序会修改INT13H的中断向量指向自身已驻留于内存中的钩子代码以便随时拦截所有对磁盘的操作。钩子代码的作用当然是很明显的,它主要负责由判断中断入口参数,包括功能号,磁盘目标地址等来决定该类型操作是否被允许,这样就可以实现对某一特定区域的写操作保护。后来又诞生了在此基础之上进行改进了的磁盘恢复卡之类的产品,其利用将写操作重定向至目标区域外的临时分区并保存磁盘先前状态等技术来实现允许写入并可随时恢复之功能。不管怎么改进,这类产品的核心技术还是对磁盘操作的实时监控。对此有兴趣的朋友可参看高云庆著《硬盘保护技术手册》。DOS下还有许多通过驻留并截获一些有用的中断来实现某种特定目的的程序,我们通常称之为TSR(终止并等待驻留terminate-and-stay-resident,此种程序不容易编好,需要大量的关于硬件和Dos中断的知识,还要解决Dos重入,tsr程序重入等问题,搞不好就会当机)。在WINDOWS下要实现实时监控决非易事,普通用户态程序是不可能监控系统的活动的,这也是出于系统安全的考虑。HPS病毒能在用户态下直接监控系统中的文件操作其实是由于WIN9X在设计上存在漏洞。而我们下面要讨论的两个病毒实时监控(For WIN9X&WINNT/2000)都使用了驱动编程技术,让工作于系统核心态的驱动程序去拦截所有的文件访问。当然由于工作系统的不同,这两个驱动程序无论从结构还是工作原理都不尽相同的,当然程序写法和编译环境更是千差万别了,所以我们决定将其各自分成独立的一节来详细地加以讨论。上面提到的病毒实时监控其实就是对文件的监控,说成是文件监控应该更为合理一些。除了文件监控外,还有各种各样的实时监控工具,它们也都具有各自不同的特点和功用。这里向大家推荐一个关于WINDOWS系统内核编程的站点:www.sysinternals.com。在其上可以找到很多实时监控小工具,比如能够监视注册表访问的Regmon(通过修改系统调用表中注册表相关服务入口),可以实时地观察TCP和UDP活动的Tdimon(通过hook系统协议驱动Tcpip.sys中的dispatch函数来截获tdi clinet向其发送的请求),这些工具对于了解系统内部运作细节是很有裨益的。介绍完有关的背景情况后,我们来看看关于病毒 实时监控的具体实现技术的情况。
  
  3.2病毒实时监控实现技术概论
  
  正如上面提到的病毒实时监控其实就是一个文件监视器,它会在文件打开,关闭,清除,写入等操作时检查文件是否是病毒携带者,如果是则根据用户的决定选择不同的处理方案,如清除病毒,禁止访问该文件,删除该文件或简单地忽略。这样就可以有效地避免病毒在本地机器上的感染传播,因为可执行文件装入器在装入一个文件执行时首先会要求打开该文件,而这个请求又一定会被实时监控在第一时间截获到,它确保了每次执行的都是干净的不带毒的文件从而不给病毒以任何执行和发作的机会。以上说的仅是病毒实时监控一个粗略的工作过程,详细的说明将留到后面相应的章节中。病毒实时监控的设计主要存在以下几个难点:
  
  其一是驱动程序的编写不同于普通用户态程序的写作,其难度很大。写用户态程序时你需要的仅仅就是调用一些熟知的API函数来完成特定的目的,比如打开文件你只需调用CreateFile就可以了;但在驱动程序中你将无法使用熟悉的CreateFile。在NT/2000下你可以使用ZwCreateFile或NtCreateFile(native API),但这些函数通常会要求运行在某个IRQL(中断请求级)上,如果你对如中断请求级,延迟/异步过程调用,非分页/分页内存等概念不是特别清楚,那么你写的驱动将很容易导致蓝屏死机(BSOD),Ring0下的异常将往往导致系统崩溃,因为它对于系统总是被信任的,所以没有相应处理代码去捕获这个异常。在NT下对KeBugCheckEx的调用将导致蓝屏的出现,接着系统将进行转储并随后重启。另外驱动程序的调试不如用户态程序那样方便,用象VC++那样的调试器是不行的,你必须使用系统级调试器,如softice,kd,trw等。
  
  其二是驱动程序与ring3下客户程序的通信问题。这个问题的提出是很自然的,试想当驱动程序截获到某个文件打开请求时,它必须通知位于ring3下的查毒模块检查被打开的文件,随后查毒模块还需将查毒的结果通过某种方式传给ring0下的监控程序,最后驱动程序根据返回的结果决定请求是否被允许。这里面显然存在一个双向的通信过程。写过驱动程序的人都知道一个可以用来向驱动程序发送设备I/O控制信息的API调用DeviceIoControl,它的接口在MSDN中可以找到,但它是单向的,即ring3下客户程序可以通过调用DeviceIoControl将某些信息传给ring0下的监控程序但反过来不行。既然无法找到一个现成的函数实现从ring0下的监控程序到ring3下客户程序的通信,则我们必须采用迂回的办法来间接做到这一点。为此我们必须引入异步过程调用(APC)和事件对象的概念,它们就是实现特权级间唤醒的关键所在。现在先简单介绍一下这两个概念,具体的用法请参看后面的每子章中的技术实现细节。异步过程调用是一种系统用来当条件合适时在某个特定线程的上下文中执行一个过程的机制。当向一个线程的APC队列排队一个APC时,系统将发出一个软件中断,当下一次线程被调度时,APC函数将得以运行。APC分成两种:系统创建的APC称为内核模式APC,由应用程序创建的APC称为用户模式APC。另外只有当线程处于可报警(alertable)状态时才能运行一个APC。比如调用一个异步模式的ReadFileEx时可以指定一个用户自定义的回调函数FileIOCompletionRoutine,当异步的I/O操作完成或被取消并且线程处于可报警状态时函数被调用,这就是APC的典型用法。Kernel32.dll中导出的QueueUserAPC函数可以向指定线程的队列中增加一个APC对象,

热门推荐 查看更多