打造自己的程序行为监视器.doc
- 格式:doc
- 大小:290.50 KB
- 文档页数:10
打造自己的程序行为监视器张东辉[shineast][/shineastdh] 袁野1. 为什么要写程序行为监视器目前是一个杀毒软件急需大革命的时代,网络上的病毒、木马、蠕虫、恶意软件不断的肆虐,尤其是各种木马、后门软件已经成灾。
虽然传统的杀毒软件还在奋力的抵挡病毒的入侵,但是这种带有滞后性的杀毒思想已经难以满足保证用户安全的要求,很多未知的病毒,甚至0day攻击经常出现,导致传统的杀毒手段很被动。
从原理上讲,病毒特征码的杀毒方法是不能抵御这些未知病毒的和0day的,因为这些写未知病毒和0day的朋友在暗处,而杀毒软件在明处,把这些未知病毒和0day攻击放出来前,当然是通过大量的测试的,中率是相当高的,过常用杀毒软件是这些病毒的重要指标。
能过、能免杀才是王道!——病毒的变形技术、免杀技术给传统的杀毒软件带来很大的压力。
在这样的大局面下,当然目前涌现了很多基于行为特征来杀毒的杀毒软件,还有一些主动防御杀毒软件,稍微使得局面有些好转。
因此,笔者认为通过程序行为来查毒、杀毒的理念是今后安全领域研究的热点、重点。
通俗的说,要判断一个人是好人还是坏人,看他的长相不顶用,听他说的话也没用,看他做的事情才行。
仔细想想在现实生活中,确实如此啊,俗话说,“人不可貌相”、“路遥知马力,日久见人心”很多话都暗示了这个道理。
因此我的硕士毕设题目也选定了这样一个方向,研究基于行为特征的攻防技术。
那么完整的、准确的得到任何一个程序在任何一个时刻的行为是我迈出的第一步,这应该说是最基础的,否则得不到程序的行为,任何后续的算法都是徒劳的。
经过近一个月的时间,从零开始,学习驱动,解读sysinternal的诸多软件,不断遇到问题、遇到困难,不断的做实验,不断的解决问题,终于打造出了自己的程序行为监视器1.0版——BehaviorMon 1.0。
本文将我在这个过程中遇到的问题,使用的主要技术、代码详细整理出来,供读者参考。
2. 基于行为特征的杀毒逻辑上面已经提到,基于行为特征来杀毒已经不同于传统的杀毒思想,化病毒文件特征码为行为特征。
可能有的朋友会认为行为特征最后也会和文件特征码一样,带有先天的滞后性,而且误杀率会很高。
——这个问题在网上争论很高,一直没有统一的观点,仁者见仁、智者见智。
而我不否认确实有些问题的存在,但是事实上,仔细想想很多病毒,甚至是未知病毒,在行为方面都有很多相似,相同之处,这样一来,借助行为特征杀毒从原理上就可以很好的抵御未知病毒,并且同样一条特征,也许能够查杀更多的病毒。
于是变形技术将被淘汰,与之而来的将是绕过技术的威胁,这就是目前涌现了很多针对主动防御软件的各种绕过技术出现的原因。
这一点也说明了行为杀毒确实有一定程度的滞后性,不过绕过无非也是一种行为,提取其行为特征即可,与病毒文件的变形,绕过能有那么大的变化空间吗?!这样就可以一步步将病毒逼向绝路。
总的来说我觉得行为杀毒一定会很有前景的。
关于行为特征的杀毒逻辑,仔细想想,其实很简单的,我设计了一种基于行为特征的杀毒逻辑,虽然不知道杀毒软件公司是怎么做的,不过估计原理思想应该差不多吧。
Ring3Ring0BehaviorMonProcess/Thread SensorRegistry SensorFile SensorNetwork SensorOther SensorDynamic Behavior ListMalicious Behavior CharacteristicRULEBASENormal code Malicious codeRedo Behaviors (Shadow or SandBox)图1 基于行为特征的杀毒逻辑本系统分为四大模块:程序行为提取模块、恶意行为特征库模块、规则匹配模块、恶意行为回滚/恢复模块;模块介绍如下:程序行为提取模块——通过SSDT HOOK的方式,编写一个Native API拦截的驱动程序,能够实时的知道任何一个程序,在任何一个时刻的调用了什么原生API函数,进而以此作为一个行为,在一段时间内该程序调用的这些函数组成的序列就作为这个程序的行为或行为序列。
该模块的主要作用就在于高效的、稳定的工作于Ring0上,从而提取所有程序的行为;恶意行为特征库模块——该模块主要作用在于,通过大量的恶意程序、病毒、木马来训练并构建一个合理的恶意行为特征知识库,有了这个库就可以形成一些规则,只要一个程序的行为和某条规则匹配,就认定该程序是某种恶意程序;规则匹配模块——该模块用于在模块1实时的得到一个程序的动态行为序列后,高效的、准确的和上述的行为特征规则库匹配出是否是恶意程序;恶意行为回滚/恢复模块——该模块用于在检测出是某个程序是恶意程序后,将其在检测之前所作的恶意行为进行回滚,或恢复对操作系统的各项更改。
当然,本文仅介绍程序行为提取部分内容,其他模块还在实现中,在后续的研究过程中将和读者见面。
3. 程序行为监视器(BehaviorMon)的实现BehaviorMon由两部分组成,一是后台驱动程序BehaviorMon.sys;二是前台应用程序BehaviorMon.exe。
这里先把前台程序界面展示一下:图2 程序行为监视器(BehaviorMon)前台程序界面其中蓝色的是注册表操作行为;紫色的是文件操作行为;红色的是内存操作行为;黑色的是其他操作行为。
其实应该还有网络操作行为,但是目前还未实现,将在下一个版中中完善。
另外本程序主要参考了sysinternal公司的RegMon和FileMon,因此界面上有很多相似之处,同时在功能方面有所加强,例如前台能够控制后台驱动动态的hook哪些Native API,也可以动态的unhook;可以针对一个特定的程序进行行为监视。
前台程序运行起来后,要做的第一件事就是安装我们的驱动程序,而由驱动程序内部来创建一个虚拟设备("\\Device\\BehaviorMon")。
这里安装驱动是通过服务来安装驱动的,注意在创建服务behaviormonservice时要声明服务类型为内核驱动类型。
具体看下面的代码和注释吧://安装设备驱动//安装了设备驱动后,设备驱动程序中负责创建一个新的虚拟设备void CBehaviorMonView::setup(){char namebuff[256];//get path to ths .sys.fileGetModuleFileName(0,namebuff,256);DWORD a=strlen(namebuff);while(1){if(namebuff[a]=='\\')break;a--;}a++;strcpy(&namebuff[a], "BehaviorMon.sys");/*安装驱动程序流程:1,调用OpenSCManager()打开服务控制管理器2,调用CreateService()创建一个服务,服务类型为内核驱动3,调用OpenService()取得服务句柄,启动服务4,调用StartService()启动服务,停止服务4,调用ControlService()停止服务,删除服务4,调用DeleteService()删除服务5,调用CloseServiceHandle()关闭服务句柄*///create service//system("msiexec /unregserver");SC_HANDLE t;SERVICE_STA TUS stat;SC_HANDLE man=OpenSCManager(0,0,SC_MANAGER_ALL_ACCESS);t=OpenService(man,"behaviormonservice",SERVICE_ALL_ACCESS);ControlService(t,SERVICE_CONTROL_STOP,&stat);DeleteService(t);CloseServiceHandle(t);if(man==NULL){displayError("打开服务管理器失败!");}t=CreateService(man,"behaviormonservice","behaviormonservice",SERVICE_START|SERVICE_STOP,SERVICE_KERNEL_DRIVER,SERVICE_DEMAND_START,SERVI CE_ERROR_NORMAL,namebuff,0,0,0,0,0);if(t==NULL){displayError("创建服务失败!");}if(0==StartService(t,0,0)){displayError("启动服务失败!");}}驱动加载到内核空间后,驱动开始执行入口函数——DriverEntry函数,该函数相当于c 语言的main函数,它在驱动程序被加载进内存的时候调用,在该函数中第一个任务就是要创建设备和创建符号链接;第二个任务就是要设定驱动程序对象的几个函数指针。
const WCHAR devicename[]=L"\\Device\\BehaviorMon";const WCHAR devicelink[]=L"\\DosDevices\\BEHA VIORMON";PDEVICE_OBJECT devobject=0;//设备对象UNICODE_STRING devlink,devname;//设备链接,设备名称RtlInitUnicodeString(&devname,devicename);RtlInitUnicodeString(&devlink,devicelink);//创建设备+创建符号链接IoCreateDevice(driver,2048,&devname,FILE_DEVICE_UNKNOWN,0,TRUE,&devobject);IoCreateSymbolicLink(&devlink,&devname);//设定驱动程序对象的几个函数指针driver->MajorFunction[IRP_MJ_DEVICE_CONTROL]=DrvDispatch;//派遣函数driver->MajorFunction[IRP_MJ_CREATE]=DrvCreateClose;driver->MajorFunction[IRP_MJ_CLOSE]=DrvCreateClose;driver->DriverUnload=DrvUnload;//卸载函数有了"\\DosDevices\\BEHA VIORMON"这个设备符号连接后,我们就可以在前台使用CreateFile函数来访问我们的虚拟设备"\\Device\\BehaviorMon"了,下面是前台访问该设备,并通过DeviceIoControl函数控制驱动来hook Native API函数的代码://让驱动hook SSDT中指定的Native APIvoid CBehaviorMonView::hook(){int i;hook_num=0;hook_API_info[hook_num++].nativeAPIname="NtRestoreKey";hook_API_info[hook_num++].nativeAPIname="NtOpenKey";hook_API_info[hook_num++].nativeAPIname="NtCreateKey";hook_API_info[hook_num++].nativeAPIname="NtQueryValueKey";hook_API_info[hook_num++].nativeAPIname="NtQueryKey";hook_API_info[hook_num++].nativeAPIname="NtDeleteKey";hook_API_info[hook_num++].nativeAPIname="NtDeleteValueKey";hook_API_info[hook_num++].nativeAPIname="NtSetValueKey";hook_API_info[hook_num++].nativeAPIname="NtEnumerateKey";hook_API_info[hook_num++].nativeAPIname="NtEnumerateValueKey";hook_API_info[hook_num++].nativeAPIname="NtOpenFile";hook_API_info[hook_num++].nativeAPIname="NtWriteFile";hook_API_info[hook_num++].nativeAPIname="NtCreateFile";hook_API_info[hook_num++].nativeAPIname="NtCreateProcess";hook_API_info[hook_num++].nativeAPIname="NtCreateProcessEx";hook_API_info[hook_num++].nativeAPIname="NtCreateSection";hook_API_info[hook_num++].nativeAPIname="NtOpenThread";hook_API_info[hook_num++].nativeAPIname="NtCreateThread";hook_API_info[hook_num++].nativeAPIname="NtOpenProcess";hook_API_info[hook_num++].nativeAPIname="NtOpenSection";hook_API_info[hook_num++].nativeAPIname="NtCreateSymbolicLinkObject";hook_API_info[hook_num++].nativeAPIname="NtSetSystemTime";//安装设备驱动//setup();//MessageBox("设备驱动安装成功!","提示",MB_OK);DWORD controlbuff[2048];DWORD dw;//打开设备if(!device)device=CreateFile("\\\\.\\BEHA VIORMON",GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING, FILE_A TTRIBUTE_SYSTEM,0);// Have driver zero informationif ( ! DeviceIoControl( device, IOCTL_BEHA VIORMON_ZEROSTATS,NULL, 0, NULL, 0, &dw, NULL ) ){return;}//告诉后台驱动hook上面的函数char * pcontrolbuff=(char *)controlbuff;int offsetcontrolbuff=0;//填写交换缓冲区的地址controlbuff[0]=(DWORD)&log_behavior[0];offsetcontrolbuff+=4;//填写LOG_BEHA VIOR数组的大小controlbuff[1]=LOG_BEHA VIOR_NUM;offsetcontrolbuff+=4;//被Hook的NativeAPI的总个数controlbuff[2]=hook_num;offsetcontrolbuff+=4;//把前面要Hook的Native API函数的基本信息(name,index)写入controlbufffor(i=0;i<hook_num;i++){DWORD * addr=(DWORD *)(1+(DWORD)GetProcAddress(GetModuleHandle("ntdll.dll"),hook_API_info[i].nativeAPIname));//被Hook的NativeAPI的名称strcpy(pcontrolbuff+offsetcontrolbuff,hook_API_info[i].nativeAPIname);offsetcontrolbuff+=strlen(hook_API_info[i].nativeAPIname);offsetcontrolbuff+=1;//被Hook的NativeAPI的Index//controlbuff[2]=addr[0];//函数调用地址的地址memmove(pcontrolbuff+offsetcontrolbuff,&addr[0],4);offsetcontrolbuff+=4;}DeviceIoControl(device,IOCTL_BEHA VIORMON_HOOK,controlbuff,2048,controlbuff,2048,&dw,0);//控制定时器程序开始按时向驱动请求输出拦截到的行为数据Capture=TRUE;}注意上面向驱动输入的是Native API函数在SSDT表中的服务序号,即Service Index。