驱动保护一般是基于注册表保护,文件保护。在开机中抢占优先加载顺序。都会在注册关机回调。写注册表,释放文件。修改 ServiceGroupOrder GroupOrderList 达到优先启动。但是有些会做注册表隐藏(HHIVE),这种需要自己恢复钩子,还有一些会做注册表还原。删除注册表禁止启动,基本所用病毒,劫持都能绕过。
文件保护,360强力模式 火绒都打不开,删除不了 ,系统重启后 ,文件依然存在,这种文件。
删除后文件依然存在,
火绒也扫不到
在加上注册表保护,基本是杀不死的。在对抗过程中,都是考虑关机前或者在关机回调中,如何删除文件,删除注册表。 但是面对这种驱动,也是毫无办法。
本人想到的方法,在关机前把一些系统目录下的打不开的文件和打不开的注册表CurrentControlSet\Services,名字记录下来(排除微软自己的文件和注册表),或者直接提取特征码(对于部分可以),注册关机回调,可以把自己关机回调的执行顺序,调整到最后一个回调执行,尽量抢占开机优先加载顺序,但是面对一下厉害的病毒,劫持,还是抢占不了。然后重启系统,系统在boot 启动的时候,会把所有的驱动加载到内存,然后逐一执行,在boot启动时 文件,网络 ,都是无效的。当执行到自己的驱动时,优先查看自己驱动顺序,把所有驱动遍历出来,匹配一下,关机前保存的文件名字 注册表下的imagepath,特征码。如果加载顺序在自己驱动后面,如果匹配上特征码直接hook ,oep,返回,如果只匹配上文件和注册表名,还不能确定是病毒,那么这时需要hooK oep,把可疑驱动的DriverEntry 延期执行(不能把系统驱动hook,最好有个白名单库,反正系统目录下文件打不开 注册表打不开的基本都有问题)
//hook 模块入口
NTSTATUS HOOKDriverOep(PUCHAR moudle,PWCHAR ServiceNameKey)
{
static BOOLEAN isinit = FALSE;
if (!isinit)
{
InitializeListHead(&g_DriverEntryList);
isinit = TRUE;
}
#ifdef _WIN64
1 | CHAR buff[] = { 0xFF , 0x25 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
|
#else
CHAR buff[] = { 0xE9,0,0,0,0,0 };
#endif
PHOOK_DRIVER_ENTRY hkdr = ExAllocatePoolWithTag(NonPagedPool,sizeof(HOOK_DRIVER_ENTRY),'xxxx');
if (!hkdr)
{
return 0;
}
RtlZeroMemory(hkdr, sizeof(HOOK_DRIVER_ENTRY));
1 2 3 4 5 6 7 8 9 10 11 | ULONG_PTR poep = GETOpe(moudle);
if (!MmIsAddressValid((PVOID)poep))
{
if (hkdr) ExFreePool(hkdr);
return 0 ;
}
/ / 判断
hkdr - >oldFuncAddress = (DriverEntryProc)poep; / / 原始oep
RtlCopyMemory(hkdr - >oldShellCode, (PVOID)poep,sizeof(buff)); / / 保存原始字节
|
#ifdef _WIN64
PULONG64 addressLocal = (PULONG64)&buff[6];
addressLocal = (ULONG64)HOOKDriverEntry;//实际执行的函数
#else
(PULONG)(&buff[1]) = (ULONG_PTR)HOOKDriverEntry - (poep + 5);
#endif
if (RtlCompareMemory((const void)poep, ShellOepCodeRet, sizeof(ShellOepCodeRet)) == sizeof(ShellOepCodeRet) ||
RtlCompareMemory((const void)poep, buff, sizeof(buff)) == sizeof(buff))
{
if (hkdr)
{
ExFreePool(hkdr);
1 2 3 4 5 6 7 8 9 | }
return 0 ; / / 说明oep 早已经hook
}
WriteShellCode((PVOID)poep, buff, sizeof(buff));
RtlCopyMemory(hkdr - >serviceName, ServiceNameKey,wcslen(ServiceNameKey) * 2 );
InsertHeadList(&g_DriverEntryList,&hkdr - >EntryList);
return 0 ;
|
}执行自己构造的函数
//driverEntry 执行函数
NTSTATUS HOOKDriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
VMPSTART("HOOKDriverEntry");
#ifdef _WIN64
1 | CHAR buff[] = { 0xFF , 0x25 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
|
#else
CHAR buff[] = { 0xE9,0,0,0,0,0};
#endif
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | PLIST_ENTRY DriverEntryListNext = g_DriverEntryList.Blink;
PHOOK_DRIVER_ENTRY pHOOk = NULL;
UNICODE_STRING temp = { 0 };
while (DriverEntryListNext ! = &g_DriverEntryList) / / 找到对应的信息
{
pHOOk = (PHOOK_DRIVER_ENTRY)CONTAINING_RECORD(DriverEntryListNext, HOOK_DRIVER_ENTRY, EntryList);
RtlInitUnicodeString(&temp, pHOOk - >serviceName);
if (IsUnicodeTailstr(&temp, RegistryPath, TRUE))
{
RemoveEntryList(DriverEntryListNext);
break ;
}
DriverEntryListNext = DriverEntryListNext - >Blink;
pHOOk = NULL;
}
if (!pHOOk)
{
return STATUS_SUCCESS;
}
/ / 恢复hook 原始的driverEntey
WriteShellCode((PVOID)pHOOk - >oldFuncAddress, pHOOk - >oldShellCode, sizeof(buff));
if (!xxRtlCreateUnicodeString(&pHOOk - >DriverReg, RegistryPath - >Length)) / / 申请保存注册表键值
{
return pHOOk - >oldFuncAddress(DriverObject, RegistryPath);
}
RtlCopyUnicodeString(&pHOOk - >DriverReg, RegistryPath); / / 保存注册表键值
/ / 注册 HOOKBootReinitialize 在里面读取文件 判断文件MD5 签名 确定是否执行真正driverentry
IoRegisterBootDriverReinitialization(DriverObject, BootReinitializeCheckDriverEntry, pHOOk); / / 注册 BootDriverReinitialization
return STATUS_SUCCESS;
|
}
恢复hook,注册一个IoRegisterBootDriverReinitialization,(在boot 阶段文件系统没有启动,文件时打不开的,所有的文件保护都是在BootDriverReinitialization回调做的,或者之后做的)在回调中可以读取文件判断签名 MD5 ,如果匹配规则,直接返回,如果没有匹配执行原始的driverentry,
VOID BootReinitializeCheckDriverEntry(In struct _DRIVER_OBJECT *DriverObject,In_opt PVOID Context,In ULONG Count)
{
UNREFERENCED_PARAMETER(Count);
PHOOK_DRIVER_ENTRY pHOOk = Context;
NTSTATUS status = STATUS_SUCCESS;
PUCHAR FileBuf = NULL;
ULONG FileSize = 0;
UNICODE_STRING pUService = { 0 };
RtlInitUnicodeString(&pUService, pHOOk->serviceName);
status = xxntReadFile(&((PLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection)->FullDllName, &FileBuf, &FileSize);
if (!NT_SUCCESS(status))
{
status = pHOOk->oldFuncAddress(DriverObject, &pHOOk->DriverReg);
//释放内存
YLRtlFreeUnicodeString(&pHOOk->DriverReg);
ExFreePool(pHOOk);
//释放内存
return;
}
BOOLEAN RetBool = FALSE;
#ifndef _DEBUG
try
{
#endif
if (CheckDriverRule1(FileBuf, FileSize))
{
RetBool = TRUE; //匹配上
}
ExFreePool(FileBuf);
FileBuf = NULL;
#ifndef _DEBUG
}
except(EXCEPTION_EXECUTE_HANDLER)
{
if (FileBuf)
{
ExFreePool(FileBuf);
FileBuf = NULL;
}
}
#endif
if (!RetBool) //没有匹配上规则 执行原始driverentry
{
status = pHOOk->oldFuncAddress(DriverObject, &pHOOk->DriverReg);
}
else
{//把文件删除 或者覆盖成自己编译的空驱动
OverWriteFile(&((PLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection)->FullDllName, updatesys, sizeof(updatesys));
}
xxRtlFreeUnicodeString(&pHOOk->DriverReg);
ExFreePool(pHOOk);
return;
}
如果自己驱动启动顺序特别靠后,如果匹配上文件名字,或者注册表的imagepath,特征码,(boot启动时,病毒驱动的功能启动不了,文件系统 网络 注册表都操作不了,这些病毒也是注册BootDriverReinitialization,保护自己注册表 文件),把这些可疑驱动注册的回调替换成自己的函数,在自己的函数中读取文件,匹配规则。如果匹配上规则禁止执行原始驱动注册的回调函数,并且暂停这个驱动创建的线程,并且他的驱动文件删除或者替换成自己编译的空驱动,如果病毒驱动线程没有挂起成功,远程下发新的驱动文件,在自己注册的minifter,写关闭的时候,替换成自己编译的空驱动,给他一种写入成功的错觉,他才不会想办法绕文件过滤,再比如写注册表让他写入成功,在自己注册的注册表中修改写入的内容(Start 0 改1),最后把自己注册BootDriverReinitialization 执行顺序调整到第一位(注册回调就是挂在一个链表上,移除后挂在链表头),(回调之前的boot阶段文件系统没有启动,如果病毒驱动注册在boot最后一个,说明自己的驱动在他的前面,直接hook oep,走上面流程)由于是第一个执行,病毒驱动还没执行,还对文件没有保护,可以把所有病毒文件删除。
最后,各位大神有windows岗位 帮忙推荐一下,qq 2646800257
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)