关于进程保护,在 64 位版的 Windows7 操作系统中不能通过 HOOK SSDT 等方式来实现,因为会触发 PatchGuard 保护造成蓝屏。在本文中通过内核函数 ObRegisterCallbacks 来实现对一般进程的保护。
函数 ObRegisterCallbacks 的定义如下:
NTSTATUS ObRegisterCallbacks (
_In_ POB_CALLBACK_REGISTRATION CallBackRegistration,
_Out_ PVOID *RegistrationHandle
);
首先需要看的是在微软 MSDN 中的 WDK 文档对 ObRegisterCallbacks 函数的解释。
The ObRegisterCallbacks routine registers a list of callback routines for thread, process, and desktop handle operations.
“ObRegisterCallbacks 例程为线程、进程和桌面句柄操作注册一个回调例程列表。”通过这个函数注册一个回调函数,在回调处理函数中执行我们需要执行的保护操作。
再来看看 ObRegisterCallbacks 的两个参数,第二个参数是指向注册句柄的指针,通过这个句柄对注册回调进行卸载,目前先不讨论。第一个参数 CallBackRegistration 是个指向 OB_CALLBACK_REGISTRATION 类型的结构体的指针。当 ObRegisterCallbacks 例程注册 ObjectPreCallback 或 ObjectPostCallback 回调例程时这个结构体指定回调例程和其他注册信息的的列表。其结构如下:
typedef struct _OB_CALLBACK_REGISTRATION {
USHORT Version;
USHORT OperationRegistrationCount;
UNICODE_STRING Altitude;
PVOID RegistrationContext;
OB_OPERATION_REGISTRATION *OperationRegistration;
} OB_CALLBACK_REGISTRATION, *POB_CALLBACK_REGISTRATION;
其中第五个成员 OperationRegistration 是关键部分。这是个指向 OB_OPERATION_REGISTRATION 类型结构体数组的指针。每个 OB_OPERATION_REGISTRATION 结构体指定 ObjectPreCallback 和 ObjectPostCallback 回调例程以及那些例程被调用的操作类型。其结构如下:
typedef struct _OB_OPERATION_REGISTRATION {
POBJECT_TYPE *ObjectType;
OB_OPERATION Operations;
POB_PRE_OPERATION_CALLBACK PreOperation;
POB_POST_OPERATION_CALLBACK PostOperation;
} OB_OPERATION_REGISTRATION, *POB_OPERATION_REGISTRATION;
在这里需要注意的是第三个成员 PreOperation。这是个指向 ObjectPreCallback 例程的指针,系统会在请求的操作发生之前调用这个例程,通过这个 ObjectPreCallback 例程来达到我们的目的。现在来看看 ObjectPreCallback 的具体定义:
OB_PREOP_CALLBACK_STATUS ObjectPreCallback (
_In_ PVOID RegistrationContext,
_In_ POB_PRE_OPERATION_INFORMATION OperationInformation
);
我们在后面实现的回调处理函数也必须以这样的格式来定义。接下来就需要实现注册这个例程的代码实现部分。
PVOID obCallbackHandle = NULL; // void* variable, the second perameter of ObRegisterCallbacks
NTSTATUS PreventKillingProcess (void)
{
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)); // init structure viriable
opReg.ObjectType = PsProcessType;
opReg.Operations = OB_OPERATION_HANDLE_CREATE|OB_OPERATION_HANDLE_DUPLICATE;
opReg.PreOperation = (POB_PRE_OPERATION_CALLBACK)&fnPreCallbackRoutine; //set the callback routine pointer
obReg.OperationRegistration = &opReg; // bind
return ObRegisterCallbacks(&obReg, &obCallbackHandle); // register the callback routine
}
以上是注册回调的函数代码。这时候会发现最关键的回调处理函数 fnPreCallbackRoutine 并没有实现,那么接下来就需要实现这部分的代码了。
fnPreCallbackRoutine 是个返回值为 OB_PRE_OPERATION_CALLBACK 的函数,也就是我们要实现的回调处理函数。在这个函数中,通过判断进程名确定是否为指定的目标进程,并将访问权限成员 pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess 中的进程关闭、操作、读写等权限标志位全部去掉。DesiredAccess 是一个 ACCESS_MASK 类型的结构体成员,它的值指定授予给句柄的访问权限,这个成员默认情况下和 OriginalDesiredAccess 相同,但是 ObjectPreCallback 例程可以修改这个值来限制授权的访问。其实现代码如下:
OB_PREOP_CALLBACK_STATUS
fnPreCallbackRoutine (
PVOID RegistrationContext,
POB_PRE_OPERATION_INFORMATION pOperationInformation
)
{
HANDLE pid = PsGetProcessId((PEPROCESS)pOperationInformation->Object);
char szProcName[16] = {0};
UNREFERENCED_PARAMETER(RegistrationContext);
strcpy(szProcName,GetProcessNameByProcessId(pid));
if ( !_stricmp(szProcName,"notepad.exe") )
{
if (pOperationInformation->Operation == OB_OPERATION_HANDLE_CREATE)
{
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE) == PROCESS_TERMINATE)
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE;
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_VM_OPERATION) == PROCESS_VM_OPERATION)
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_VM_OPERATION;
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_VM_READ) == PROCESS_VM_READ)
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_VM_READ;
if ((pOperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_VM_WRITE) == PROCESS_VM_WRITE)
pOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_VM_WRITE;
}
}
return OB_PREOP_SUCCESS;
}
为了保证程序的稳定,需要在驱动程序卸载例程中对注册回调进行卸载。
ObUnRegisterCallbacks(obCallbackHandle);
另外需要注意的是,在使用 ObCallBackxx 函数和 PsxxEx 函数的时候,在这些函数的内部实现中都会去调用 MmVerifyCallbackFunction() 来进行校验,所以需要对其进行绕过。绕过的代码如下:
PLDR_DATA ldr;
ldr = (PLDR_DATA)DriverObject->DriverSection;
ldr->Flags |= 0x20;
微软在 MmVerifyCallbackFunction 函数中是通过检测驱动对象的 ((PLDR_DATA_TABLE_ENTRY)pDriverObj->DriverSection)->Flags 的 0x20 标志位来进行校验的,所以只需要修改 Flags 的这个标志位即可。
可能这种方法并不是一个十分稳固和可靠的方法,仍旧可以被一些更加高深和先进的方式破解和绕过。当然,更加牛逼的技术等以后掌握了再去讨论,哈哈。
MSDN 中的相关文档:http://msdn.microsoft.com/en-us/library/ff558692(v=vs.85).aspx(http://msdn.microsoft.com/en-us/library/ff558692(v=vs.85%29.aspx)