首页
社区
课程
招聘
教你在64位Win7系统下使用ObRegisterCallbacks内核函数来实现进程保护
发表于: 2013-4-10 17:08 66781

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

2013-4-10 17:08
66781

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


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 13
支持
分享
最新回复 (60)
雪    币: 74
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
內核方面完全不懂,感謝LZ的分享精神!
2013-4-10 18:12
0
雪    币: 3836
活跃值: (4142)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
楼主写的很细心。。。。。。。。。
2013-4-11 08:59
0
雪    币: 243
活跃值: (209)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
楼主好像写了几篇介绍sfilter,win7下ndis filter的文章
2013-4-11 10:03
0
雪    币: 371
活跃值: (72)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
5
感谢楼主,写得很精练,都是一些核心代码,

不像那些人,写一堆的代码,但核心代码就那么几句的...
2013-4-11 10:39
0
雪    币: 371
活跃值: (72)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
6
最近写驱动,发现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
2013-4-11 10:42
0
雪    币: 557
活跃值: (449)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
7
学雄, 我告诉你,绕过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;
2013-4-11 12:28
0
雪    币: 194
活跃值: (246)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
楼主辛苦了,,顶楼主。
2013-4-27 10:52
0
雪    币: 557
活跃值: (449)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
9
这个代码可以立刻使用,在Win7X64系统上运行起来。
2013-5-9 14:17
0
雪    币: 14
活跃值: (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
这个方法是不是没有签名也可以?那怎么加载驱动呢???
2013-5-10 14:41
0
雪    币: 557
活跃值: (449)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
11
数字证书,签名工具,需要你自己去购买。  这个驱动程序经过正规的签名,是可以直接在64位的Win7系统上运行的。  我在帖子上,只是告诉大家怎么编写进程保护。 至于数字证书、签名工具等,你需要去购买。你如果要看实际运行的效果,可以在虚拟机系统里面,当系统一启动的时候,按F8键,进入DOS选项,然后取消数字签名。
2013-5-20 11:06
0
雪    币: 544
活跃值: (264)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
12
sources文件里面加入LINKER_FLAGS=/integritycheck才是王道
2013-5-20 16:45
0
雪    币: 247
活跃值: (112)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
WST
13
这个保护不了吧?  任务管理器 结束进程好像是不行 但是一结束任务 就秒杀了
2013-5-20 19:11
0
雪    币: 115
活跃值: (46)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
14
谢谢分享,这个函数一直都不会使用
另外问下有否函数是设置ObjectAccess的
我在EAT发现三个可能有关的,msdn没描述
ObSetHandleAttributes
ObSetSecurityDescriptorInfo
ObSetSecurityObjectByPointer

直接对EPROCESS操作,似乎是Read_Only的
2013-5-20 19:48
0
雪    币: 557
活跃值: (449)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
15
我这里要告诉大家的是: 如何在 64位的Windows系统上保护进程,使得进程不被Windows自带的任务管理器给结束掉。

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

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

我只是告诉你方法,至于更深入细至的,比如软件之间的对抗,恶意竞争,某款软件结束其它软件的进程,这里不做讨论。
2013-5-21 17:38
0
雪    币: 11
活跃值: (40)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
没意思……在64位win8下无法保护窗体……连任务管理器的结束任务也防不了……
2013-5-21 18:01
0
雪    币: 557
活跃值: (449)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
17
帮自己顶一下帖子。能够让更多人看见并学习。
2013-12-17 10:08
0
雪    币: 1785
活跃值: (3975)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
mark  ObRegisterCallbacks
微软这么做是对的,CallBack 要比hook优雅的多
2013-12-17 10:42
0
雪    币: 636
活跃值: (174)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
19
这个的话,可以参考msdn给的示例代码:http://code.msdn.microsoft.com/windowshardware/ObCallback-Sample-67a47841
2013-12-17 11:26
0
雪    币: 77
活跃值: (48)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
国标 到此一游
2014-1-16 15:09
0
雪    币: 79
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
MARK一下。。。
2014-3-17 10:18
0
雪    币: 341
活跃值: (85)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
22
能否ByPass  PatchGuard  ?
2014-3-17 10:29
0
雪    币: 37
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
LZ这个应该只是实现进程保护,不是ByPass  PatchGuard。

PatchGuard在不断升级,ByPass  PatchGuard应该有不同的方法。

建议你在GOOGLE搜索PatchGuard+系统名,比如PatchGuard WIN7、PatchGuard WIN8,应该能找到相关的资料。
2014-3-17 10:51
0
雪    币: 65
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
非常感谢楼主解决了我心中的关于64位下ssdt的疑问.    另外非常想问楼主有没有方法在win7 64位机中去隐藏进程?
2014-5-11 17:37
0
雪    币: 15
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
隐藏进程X死PG再说...
2014-5-17 18:17
0
游客
登录 | 注册 方可回帖
返回
//