• 1618阅读
  • 3回复

教你在64位Win7系统下使用ObRegisterCallbacks内核函数来实现进程保护 [复制链接]

上一主题 下一主题
离线啊冲
 

只看楼主 倒序阅读 使用道具 楼主  发表于: 2016-02-03
我平时工作很忙,也很少有空闲时间上看雪论坛。我在看雪论坛里面文章发表的很少,几只有几篇,我也很少回答别人的问题。我的很多朋友都这样问我问题:我整理了一下,无非就以下几种问题:
(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函数
你只要在百度或Google上,搜索关键字-----绕过MmVerifyCallbackFunction。这会出来很多的文章供你参考。

  NTSTATUS status = STATUS_SUCCESS;
  PLDR_DATA ldr;

  // 绕过MmVerifyCallbackFunction。
  ldr = (PLDR_DATA)DriverObject->DriverSection;
  ldr->Flags |= 0x20;*转载请注明来自看雪论坛@PEdiy.com  
善者 慈悲心常在 无怨无恨 以苦为乐
默认压缩密码www.hifyl.com
文件分享密码问题:http://www.hifyl.com/read-htm-tid-4444.html
离线啊冲

只看该作者 沙发  发表于: 2016-02-03
最近写驱动,发现ObRegisterCallbacks这个总是函数调用不成功,在网上查了一下,发现使用这个函数对驱动有特殊的要求,必须使用特殊的签名才行!否则这个函数会返回0xC0000022(拒绝访问),逆向此函数可以看到以下是有关是否加签名的判断,

PAGE:00000001404AA75D                 call    MmVerifyCallbackFunction
PAGE:00000001404AA762                 cmp     eax, ebx
PAGE:00000001404AA764                 jz      short loc_1404AA7E1
PAGE:00000001404AA766
PAGE:00000001404AA766 loc_1404AA766:                          ; CODE XREF: ObRegisterCallbacks+11Bj
PAGE:00000001404AA766                 mov     rcx, [rsi+rbp+18h]
PAGE:00000001404AA76B                 cmp     rcx, rbx
PAGE:00000001404AA76E                 jz      short loc_1404AA779
PAGE:00000001404AA770                 call    MmVerifyCallbackFunction
PAGE:00000001404AA775                 cmp     eax, ebx
PAGE:00000001404AA777                 jz      short loc_1404AA7E1

开发调试时可以将
PAGE:00000001404AA764                 jz      short loc_1404AA7E1
PAGE:00000001404AA76E                 jz      short loc_1404AA779
这两行改为nop暂时使ObRegisterCallbacks调用成功,方便开发调试和暂时没签名的朋友

ObRegisterCallbacks这个函数是在Vista sp1之后的版本中添加的,可用来监控系统中对进线程句柄的操作,如打开进程、复制线程句柄等。


来自 bbs.pediy.com/showthread.php?t=140891



[公告]如果你觉得有人语言挑衅,请点每帖右上角的“举报”按钮!
回复时引用此帖 返回顶端  

学雄
查看公开信息
查找 学雄 发表的帖子
查找 学雄 发表的所有主题
查看 学雄 发表的精华帖  

tianhz
级别:8 | 在线时长:100小时 | 升级还需:17小时级别:8 | 在线时长:100小时 | 升级还需:17小时


普通会员
普通会员


资 料:
注册日期: Jan 2009
帖子: 117 tianhz 品行端正
精华: 2
现金: 320 Kx
致谢数: 0
获感谢文章数:12
获会员感谢数:101   7 旧 2013-04-11, 12:28:23 默认  tianhz 当前离线  

--------------------------------------------------------------------------------

学雄, 我告诉你,绕过MmVerifyCallbackFunction函数其实很容易的。

其实只要定义一个LDR_DATA的结构体。

typedef struct _LDR_DATA                         // 24 elements, 0xE0 bytes (sizeof)
{
   struct _LIST_ENTRY InLoadOrderLinks;                     // 2 elements, 0x10 bytes (sizeof)
   struct _LIST_ENTRY InMemoryOrderLinks;                   // 2 elements, 0x10 bytes (sizeof)
   struct _LIST_ENTRY InInitializationOrderLinks;           // 2 elements, 0x10 bytes (sizeof)
   VOID*        DllBase;
   VOID*        EntryPoint;
   ULONG32      SizeOfImage;
   UINT8        _PADDING0_[0x4];
   struct _UNICODE_STRING FullDllName;                      // 3 elements, 0x10 bytes (sizeof)
   struct _UNICODE_STRING BaseDllName;                      // 3 elements, 0x10 bytes (sizeof)
   ULONG32      Flags;
   UINT16       LoadCount;
   UINT16       TlsIndex;
        union                                                  
        {
           struct _LIST_ENTRY HashLinks;                        
                  struct                                              
                  {
                     VOID*        SectionPointer;
                     ULONG32      CheckSum;
                     UINT8        _PADDING1_[0x4];
                  };
         };

         union                                                  
          {
             ULONG32      TimeDateStamp;
             VOID*        LoadedImports;
          };
     struct _ACTIVATION_CONTEXT* EntryPointActivationContext;
    VOID*        PatchInformation;
    struct _LIST_ENTRY ForwarderLinks;                  
    struct _LIST_ENTRY ServiceTagLinks;                  
    struct _LIST_ENTRY StaticLinks;                        
    VOID*        ContextInformation;
    UINT64       OriginalBase;
    union _LARGE_INTEGER LoadTime;                      
}LDR_DATA, *PLDR_DATA;

善者 慈悲心常在 无怨无恨 以苦为乐
默认压缩密码www.hifyl.com
文件分享密码问题:http://www.hifyl.com/read-htm-tid-4444.html
离线啊冲

只看该作者 板凳  发表于: 2016-02-03
我这里要告诉大家的是: 如何在 64位的Windows系统上保护进程,使得进程不被Windows自带的任务管理器给结束掉。

至于绕过那些专业的进程管理工具,比如:PC Hunter、Win64AST等这些64位的工具, 那还需要继续讨论和研究。

360安全卫士在Win7 x64系统下,使用的也是 ObRegisterCallbacks内核函数。

我只是告诉你方法,至于更深入细至的,比如软件之间的对抗,恶意竞争,某款软件结束其它软件的进程,这里不做讨论。
善者 慈悲心常在 无怨无恨 以苦为乐
默认压缩密码www.hifyl.com
文件分享密码问题:http://www.hifyl.com/read-htm-tid-4444.html
离线v2680267313

只看该作者 地板  发表于: 2016-04-30
用户被禁言,该主题自动屏蔽!
快速回复
限100 字节
如果您在写长篇帖子又不马上发表,建议存为草稿
 
上一个 下一个