经过N多辗转和持续验证,终于搞定了在驱动程序中同时保护进程和文件(经持久测试后,避免了导致系统蓝屏的情况),重点
1)拒绝通过进程管理器关闭进程,同时又允许某些进程可以管理
2)通过比较文件名,截获被保护的文件操作
完整代码,可从https://download.csdn.net/download/pony12/12149153下载
进程保护回调函数:
NTSTATUS ProtectProcess(BOOLEAN Enable)
{
OB_CALLBACK_REGISTRATION obReg;
OB_OPERATION_REGISTRATION opReg;
memset(&obReg, 0, sizeof(obReg));
obReg.Version = ObGetFilterVersion();
obReg.OperationRegistrationCount = 1;
obReg.RegistrationContext = NULL;
RtlInitUnicodeString(&obReg.Altitude, L"321000");
memset(&opReg, 0, sizeof(opReg)); //初始化结构体变量
//下面请注意这个结构体的成员字段的设置
opReg.ObjectType = PsProcessType;
opReg.Operations = OB_OPERATION_HANDLE_CREATE|OB_OPERATION_HANDLE_DUPLICATE;
opReg.PreOperation = (POB_PRE_OPERATION_CALLBACK)&processPreCall; //在这里注册一个回调函数指针
obReg.OperationRegistration = &opReg; //注意这一条语句
return ObRegisterCallbacks(&obReg, &processCallBackHandle); //在这里注册回调函数
}
OB_PREOP_CALLBACK_STATUS
processPreCall(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION pOperationInformation)
{
if(pOperationInformation->KernelHandle == TRUE)
{
//如果是KernelHandle则直接返回不做操作
return(OB_PREOP_SUCCESS);
}
if (pOperationInformation->ObjectType != *PsProcessType)
{
return(OB_PREOP_SUCCESS);
}
HANDLE pid = PsGetProcessId((PEPROCESS)pOperationInformation->Object);
char szProcName[512+1]={0};
UNREFERENCED_PARAMETER(RegistrationContext);
_snprintf(szProcName, sizeof(szProcName)-1, GetProcessImageNameByProcessID((ULONG)pid));
parentsProtectedProcess = PsGetCurrentProcess();
char szSvcProcName[512+1]={0};
HANDLE svc_pid = PsGetProcessId(parentsProtectedProcess);
_snprintf(szSvcProcName, sizeof(szSvcProcName)-1, GetProcessImageNameByProcessID((ULONG)svc_pid));
//如果是auditflow_svc.exe进程的操作,则放行
if( !_strnicmp(szSvcProcName,"auditflow_svc.", 14))
{
DbgPrint("PID : %ld CmdExe: %s\r\n", (ULONG64)svc_pid, szSvcProcName);
return(OB_PREOP_SUCCESS);
}
//保护auditflow_svc.exe,auditflow_svc_child.exe,auditflow_child.exe,auditflowAgent.exe等进程
//GetProcessImageNameByProcessID只能获得进程名字的前14位+\0,所以只能比较前几位
if( !_strnicmp(szProcName,"auditflow", 9))
{
if (pOperationInformation->Operation == OB_OPERATION_HANDLE_CREATE)
{
if(pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess == PROCESS_TERMINATE)
{
//拒绝PROCESS_TERMINATE处理
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE) == PROCESS_TERMINATE)
{
//Terminate the process, such as by calling the user-mode TerminateProcess routine..
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE;
}
/*
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_VM_OPERATION) == PROCESS_VM_OPERATION)
{
//Modify the address space of the process, such as by calling the user-mode WriteProcessMemory and VirtualProtectEx routines.
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_VM_OPERATION;
}
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_VM_READ) == PROCESS_VM_READ)
{
//Read to the address space of the process, such as by calling the user-mode ReadProcessMemory routine.
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_VM_READ;
}
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_VM_WRITE) == PROCESS_VM_WRITE)
{
//Write to the address space of the process, such as by calling the user-mode WriteProcessMemory routine.
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_VM_WRITE;
}
*/
}
}
}
return OB_PREOP_SUCCESS;
}
文件保护函数:
OB_PREOP_CALLBACK_STATUS FilePreCallBack(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION OperationInformation)
{
UNICODE_STRING uniDosName;
uniDosName.Length = 0;
ACCESS_MASK oldCreateDesiredAccess = 0;
ACCESS_MASK oldDuplicateDesiredAccess = 0;
//参数检查
if(NULL == OperationInformation)
return OB_PREOP_SUCCESS;
PFILE_OBJECT FileObject = (PFILE_OBJECT)OperationInformation->Object;
HANDLE CurrentProcessId = PsGetCurrentProcessId();
UNREFERENCED_PARAMETER(RegistrationContext);
//有效性检查
if(NULL == FileObject)
return OB_PREOP_SUCCESS;
//(1)屏蔽非IoFileObjectType类型的处理
if( OperationInformation->ObjectType!=*IoFileObjectType)
{
return OB_PREOP_SUCCESS;
}
//(2)过滤无效指针
if( FileObject->FileName.Buffer==NULL ||
!MmIsAddressValid(FileObject->FileName.Buffer) ||
FileObject->DeviceObject==NULL ||
!MmIsAddressValid(FileObject->DeviceObject) )
{
return OB_PREOP_SUCCESS;
}
//(3)过滤无效路径, 否则使用RtlVolumeDeviceToDosName获取盘符会蓝屏
/**/
if( !_wcsicmp(FileObject->FileName.Buffer,L"\\Endpoint") ||
!_wcsicmp(FileObject->FileName.Buffer,L"?") ||
!_wcsicmp(FileObject->FileName.Buffer,L"\\.\\.") ||
!_wcsicmp(FileObject->FileName.Buffer,L"\\"))
return OB_PREOP_SUCCESS;
//被保护的4个文件
UNICODE_STRING UnicodeString1;
RtlInitUnicodeString(&UnicodeString1, L"audit_auth.conf");
UNICODE_STRING UnicodeString2;
RtlInitUnicodeString(&UnicodeString2, L"ignsql.cfg");
UNICODE_STRING UnicodeString3;
RtlInitUnicodeString(&UnicodeString3, L"auditflow.ini");
UNICODE_STRING UnicodeString4;
RtlInitUnicodeString(&UnicodeString4, L"DBLocalInfo.ini");
//获取操作文件char*名称
char cbFileName[1024] = {0};
UnicodeStringToChar(cbFileName, &FileObject->FileName);
MyUpper(cbFileName);
//(4)禁止删除下列文件, 经验证到这一步是有效的(非长时间,但区分了大小写)
/* wcsstr容易造成蓝屏,应该使用RtlEqualUnicodeString
if(wcsstr(_wcslwr(FileObject->FileName.Buffer),L"audit_auth.conf") || wcsstr(_wcslwr(FileObject->FileName.Buffer),L"ignsql.cfg") ||
wcsstr(_wcslwr(FileObject->FileName.Buffer),L"auditflow.ini") || wcsstr(_wcslwr(FileObject->FileName.Buffer),L"DBLocalInfo.ini"))
*/
/* StrStrIW就是款字符的、StrStrIA是非宽字符的忽略大小写查找 不能用相等
if(RtlEqualUnicodeString(&FileObject->FileName, &UnicodeString1,1) || RtlEqualUnicodeString(&FileObject->FileName, &UnicodeString2, 1) ||
RtlEqualUnicodeString(&FileObject->FileName, &UnicodeString3,1) || RtlEqualUnicodeString(&FileObject->FileName, &UnicodeString4, 1))
*/
if(strstr(cbFileName, "AUDIT_AUTH.CONF") || strstr(cbFileName, "IGNSQL.CFG") ||
strstr(cbFileName, "AUDITFLOW.INI") || strstr(cbFileName, "DBLOCALINFO.INI"))
{
oldCreateDesiredAccess = OperationInformation->Parameters->CreateHandleInformation.DesiredAccess;
oldDuplicateDesiredAccess = OperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess;
if (FileObject->DeleteAccess==TRUE/*||FileObject->WriteAccess==TRUE*/)
{
if (OperationInformation->Operation == OB_OPERATION_HANDLE_CREATE)
{
OperationInformation->Parameters->CreateHandleInformation.DesiredAccess=0;
}
if(OperationInformation->Operation == OB_OPERATION_HANDLE_DUPLICATE)
{
//OperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess=0;
}
/*
RtlVolumeDeviceToDosName(FileObject->DeviceObject, &uniDosName);
DbgPrint("PID : %ld Drive: %wZ, Path: %wZ, fullPath: %wZ\r\n", (ULONG64)CurrentProcessId, &uniDosName, FileObject->FileName, &uniFilePath);
//PID : 996 Drive: C:, Path: \Windows\System32\net1.exe, fullPath: C:\Windows\System32\net1.exe
DbgPrint("Operation=%d, DeleteAccess=%d, WriteAccess=%d, oldCreateDesiredAccess=%d, newCreateDesiredAcces=%d, oldDuplicateDesiredAccess=%d, newDuplicateDesiredAcces=%d\r\n",
OperationInformation->Operation, FileObject->DeleteAccess, FileObject->WriteAccess,
oldCreateDesiredAccess, OperationInformation->Parameters->CreateHandleInformation.DesiredAccess,
oldDuplicateDesiredAccess, OperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess);
*/
}
}
return OB_PREOP_SUCCESS;
}