教你在64位Win7系统下使用ObRegisterCallbacks内核函数来实现进程保护

原文链接:https://bbs.pediy.com/thread-168023.htm

我平时工作很忙,也很少有空闲时间上看雪论坛。我在看雪论坛里面文章发表的很少,几只有几篇,我也很少回答别人的问题。我的很多朋友都这样问我问题:我整理了一下,无非就以下几种问题:

(1)怎么样在64位的Windows7操作系统下实现进程保护? 
(2)我在网络上搜索了很多天,我根本就找不到64位进程保护的文章啊!
(3)公司的项目很急,领导让我实现64位系统下的进程保护,这要怎么做啊?
(4)为什么网络上给的文章都是32位的啊?
(5)为什么64位的Windows系统不能Hook SSDT啊?

  本文是在Windows 7的64位操作系统下来实现进程保护。 这里只给出核心代码的实现方式,用来保护Calc.exe(计算器)程序,不能够被任务管理器来结束。

  很多时候,网络上的进程保护例子都是针对Windows 的32位操作系统的, 基本上也都是告诉你如何Hook SSDT。 进程保护的实现,快而有效的方法基本上都是去Hook ZwTerminateProcess或者ZwOpenProcess等。 而这些技术都被人用烂了。你知道的,在百度或Google上随便一搜索Hook SSDT这样的关键字,就会出来非常多的文章告诉你怎样做。

  我这里要告诉大家的是: 如何在 64位的Windows系统上保护进程,使得进程不被Windows自带的任务管理器给结束掉。

  我们知道,在64位的Windows7系统下,驱动程序要有数字证书必须要签名, 并且驱动程序不能够去Hoook SSDT、GDT等等 ,因为这会引发BSOD, 其根本原因就是PatchGuard组件在保护着64位操作系统的内核。

  首先,我们一起来看一看WDK文档里面对ObRegisterCallbacks()的主要描述:

The ObRegisterCallbacks routine registers a list of callback routines for thread and process handle operations.

NTSTATUS 
  ObRegisterCallbacks(
    IN POB_CALLBACK_REGISTRATION  CallBackRegistration,
    OUT PVOID  *RegistrationHandle
    );

CallBackRegistration 
A pointer to an OB_CALLBACK_REGISTRATION structure that specifies the list of callback routines and other registration information. 

RegistrationHandle 
A pointer to a variable that receives a value that identifies the set of registered callback routines. The caller passes this value to the ObUnRegisterCallbacks routine to unregister the set of callbacks. 

我们可以看见,有一个对应的ObUnRegisterCallbacks函数,以及其他的说明。

其实保护进程,也就是修改结构体POB_PRE_OPERATION_INFORMATION里面对应的成员值了。

在代码中一般都是:

PVOID obHandle;//定义一个void*类型的变量,它将会作为ObRegisterCallbacks函数的第2个参数。 

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)&preCall; //在这里注册一个回调函数指针

obReg.OperationRegistration = &opReg; //注意这一条语句

return ObRegisterCallbacks(&obReg, &obHandle); //在这里注册回调函数
}

现在好了,到这里为止,我们已经用上了ObRegisterCallbacks函数了。事情有了一个好的开始,接着马上就要讲实现了。 在这里,我希望你再次打开WDK帮助文档,当然还是有关ObRegisterCallbacks函数的帮助。
我们首先注意上面代码的一条语句:
opReg.PreOperation = (POB_PRE_OPERATION_CALLBACK)&preCall; //在这里注册一个回调函数指针

我们在WDK帮助文档里面找到有关结构体OB_OPERATION_REGISTRATION的说明。我们在这个结构体里面找到 PreOperation结构体成员变量的帮助说明:

PreOperation 
A pointer to an ObjectPreCallback routine. The system calls this routine before the requested operation occurs. 

我们不需要使用另外一个 成员变量--PostOperation 
PostOperation 
A pointer to an ObjectPostCallback routine. The system calls this routine after the requested operation occurs.

PostOperation成员不是我们关心的,我们不去讨论它。

好了,这下,你找到了 PreOperation的用法说明了。我们知道了PreOperation是一个函数指针,我们的进程保护程序就在这个函数指针里面进行。
我们再回过头来看上面的程序代码,ProtectProcess函数的实现。 我们刚才就注意到了opReg.PreOperation = (POB_PRE_OPERATION_CALLBACK)&preCall;
现在,我们来实现 preCall函数,代码如下:

OB_PREOP_CALLBACK_STATUS 
preCall(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,"calc.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函数。像这样:
VOID 
Unload(IN PDRIVER_OBJECT DriverObject)
{
  UNREFERENCED_PARAMETER(DriverObject);
  DbgPrint("driver unloading...\n");

  ObUnRegisterCallbacks(obHandle); //obHandle是上面定义的 PVOID obHandle;
}

代码就这样吗? 是的,这样就可以实现进程保护了。

另外,还需要注意绕过MmVerifyCallbackFunction函数。

在Windows Vista 及之后版本的 Windows 操作系统在驱动程序加载完成后,驱动中调用的一些系统回调函数(如 ObRegisterCallbacks,可用来监控系统中对进线程句柄的操作,如打开进程、复制线程句柄等)等 API 中会通过 MmVerifyCallbackFunction 函数对该驱动程序进行完整性检查,检测未通过则会返回 0xC0000022 拒绝访问的返回值。

你只要在百度或Google上,搜索关键字-----绕过MmVerifyCallbackFunction。这会出来很多的文章供你参考。



  NTSTATUS status = STATUS_SUCCESS;
  PLDR_DATA ldr;

  // 绕过MmVerifyCallbackFunction。
  ldr = (PLDR_DATA)DriverObject->DriverSection;
  ldr->Flags |= 0x20;

你可能感兴趣的:(Windows,系统安全,进程保护)