ssdt-hook 进程隐藏与保护

摘要:
如果要实现在Ring3中对进程进行隐藏的话,只需要Hook掉NtQuerySystemInformationAPI即可。而第二种情况的话,就是进程被别的进程杀掉,比如在任务管理器中就可以杀掉绝大部分的应用程序进程,而这里的进程保护就是要实现进程不能够被任务管理器或者其他的进程管理工具杀掉。

在 Ring3 下获取到当前 Windows 操作系统下的所有的进程无外乎以下的几种方法:

第一种:使用 ToolHelp 遍历获取到所有进程,关于这种方式的话,笔者以前写过一篇博文的,

《列举 Windows 所有进程(ToolHelp)》博文地址如下:

http://www.cnblogs.com/BoyXiao/archive/2011/02/27/1966383.html

第二种:使用 PSAPI 下的 EnumProcesses 获取到所有进程的 PID,然后提升进程权限为 SE_DEBUG 权限,

再调用 OpenProcess 即可打开进程,从而获取到进程的基本信息(可以查看 MSDN 的 PSAPI 专题)。

第三种:使用未公开的本地 API 即位于 Ntdll.dll 中的未文档化的 API – NtQuerySystemInformation,

而 Windows 任务管理器就是通过这种方式来获取到所有的进程信息的 ~

而事实上的是,ToolHelp 和 PSAPI 只不过是对 Ntdll.dll 中 NtQuerySystemInformation API 的一个封装,

所以在 Ring3 下获取系统中所有进程信息最终都会回到 Ndll.dll 中 NtQuerySystemInformation API 的调用上。

如果要实现在 Ring3 中对进程进行隐藏的话,只需要 Hook 掉 NtQuerySystemInformation API 即可。

而至于进程保护的话,我们需要考虑到两种情况,第一种则是该进程自行终止,第二种情况则是该进程被其他进程给杀掉,

第一种情况基本上对于窗口应用程序来说,一般都是用户点击了右上角的 x 按钮,然后产生 WM_CLOSE 消息,

最后由窗口过程退出进程,这种情况下,我们应该是需要允许退出的,也就是进程是可以正常退出的。

而第二种情况的话,就是进程被别的进程杀掉,比如在任务管理器中就可以杀掉绝大部分的应用程序进程,

而这里的进程保护就是要实现进程不能够被任务管理器或者其他的进程管理工具杀掉。

在 Ring3 中,由一个进程结束其他进程,调用的 API 为 Kernel32.dll 中的 TerminateProcess,

如果追溯这个 TerminateProcess,可以发现,其调用了 Ntdll.dll 中的 NtTerminateProcess API,

然后再追溯下去就可以到 ntoskrnl.exe 中的 ZwTerminateProcess 和系统服务 NtTerminateProcess 了。

而这和我的上一篇博文中介绍 NtQuerySystemInformation 就是一致的了,

所以如果我们要实现进程保护,需要 Hook 的系统服务就是 NtTerminateProcess ~

进程保护效果:

进程保护(保护自身进程 SSDTProcess.exe):

image

取消进程保护(这里还是以 SSDTProcess.exe 为例):

下面的截图表示 SSDTProcess.exe 已经被取消了保护,

此时再到任务管理器中结束 SSDTProcess.exe 时,你可以发现是可以正常结束这个进程的 ~

image

Ring0 实现进程隐藏:

有了 SSDT Hook 框架后,其实要实现进程的隐藏是很简单的了,

根据前面的介绍,要想实现进程隐藏,你可以通过 Hook NtQuerySystemInformation 来实现,

所以剩下的任务就只需要在我们自己的 Hook 处理函数中来将进程隐藏掉就 OK 了 ~

由于 NtQuerySystemInformation 这个系统服务在 ntddk.h 中并没有被声明,

虽然这个系统服务在 ntoskrnl.exe 中被导出了,但是没有它的声明,我们仍然是无法使用的,

所以我们就需要手动的声明一下这个函数 ~

还有需要注意的是,我们在前面知道,在 ntoskrnl.exe 中实质上是存在 ZwQuerySystemInformation

以及 NtQuerySystemInformation 这两个 API 的,

而在 SSDT Hook 中我们是根据 ZwQuerySystemInformation

来推算出在 SSDT 中保存有 NtQuerySystemInformation 的地址所在的索引号的 ~

关于这个,你可以查看 SYSCALL_INDEX 这个宏来再次确认一下 ~

然后有了这个索引号,我们才可以进行对 NtQuerySystemInformation 系统服务的 Hook,

所以在声明时,我们需要声明两个 API,当然如果这些 API 在 ntddk.h 中声明了就不需要了,

但是由于 ZwQuerySystemInformation 和 NtQuerySystemInformation 在 ntddk.h 中都没有声明,

所以需要在我们自己的代码中手动声明 ~

NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation (
         __in SYSTEM_INFORMATION_CLASS SystemInformationClass,
         __out_bcount_opt(SystemInformationLength) PVOID SystemInformation,
       __in ULONG SystemInformationLength,
        __out_opt PULONG ReturnLength
        );
     
    typedef NTSTATUS (*NTQUERYSYSTEMINFORMATION)(
         __in SYSTEM_INFORMATION_CLASS SystemInformationClass,
       __out_bcount_opt(SystemInformationLength) PVOID SystemInformation,
        __in ULONG SystemInformationLength,
        __out_opt PULONG ReturnLength
       );

完成了这些声明后,我们就可以来实现自己的 NtQuerySystemInformation Hook 函数了,

在这个 Hook 函数中,我们需要对我们感兴趣的进程进行隐藏 ~

然后这里需要注意的是,我是如何来实现对进程隐藏的,

首先我是判断这个进程的 ID 是否是需要隐藏的进程 ID,

这是通过 ValidateProcessNeedHide 函数来判断的 ~ 这个函数会在后面给出 ~

注意结合代码中的注释来看(虽然注释比较少 ~ 嘿嘿 ~ )

 NTSTATUS HookNtQuerySystemInformation (
   2:      __in SYSTEM_INFORMATION_CLASS SystemInformationClass,
   3:      __out_bcount_opt(SystemInformationLength) PVOID SystemInformation,
   4:      __in ULONG SystemInformationLength,
   5:      __out_opt PULONG ReturnLength
   6:      );
     
   1:  //=====================================================================================//
   2:  //Name: NTSTATUS HookNtQuerySystemInformation()                                        //
   3:  //                                                                                     //
   4:  //Descripion: 自定义的 NtQuerySystemInformation,用来实现 Hook Kernel API              //
   5:  //                                                                                     //
   6:  //=====================================================================================//
   7:  NTSTATUS HookNtQuerySystemInformation (
   8:      __in SYSTEM_INFORMATION_CLASS SystemInformationClass,
   9:      __out_bcount_opt(SystemInformationLength) PVOID SystemInformation,
  10:      __in ULONG SystemInformationLength,
  11:      __out_opt PULONG ReturnLength
  12:      )
  13:  {
  14:      NTSTATUS rtStatus;
  15:   
  16:      pOldNtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION)
  17:          oldSysServiceAddr[SYSCALL_INDEX(ZwQuerySystemInformation)];
  18:   
  19:      rtStatus = pOldNtQuerySystemInformation(SystemInformationClass, SystemInformation, 
  20:          SystemInformationLength, ReturnLength);
  21:      if(NT_SUCCESS(rtStatus))
  22:      {
  23:          if(SystemProcessInformation == SystemInformationClass)
  24:          {
  25:              PSYSTEM_PROCESS_INFORMATION pPrevProcessInfo = NULL;
  26:              PSYSTEM_PROCESS_INFORMATION pCurrProcessInfo = 
  27:                  (PSYSTEM_PROCESS_INFORMATION)SystemInformation; 
  28:   
  29:              while(pCurrProcessInfo != NULL)
  30:              {
  31:                  //获取当前遍历的 SYSTEM_PROCESS_INFORMATION 节点的进程名称和进程 ID
  32:                  ULONG uPID = (ULONG)pCurrProcessInfo->UniqueProcessId;
  33:                  UNICODE_STRING strTmpProcessName = pCurrProcessInfo->ImageName;
  34:   
  35:                  //判断当前遍历的这个进程是否为需要隐藏的进程
  36:                  if(ValidateProcessNeedHide(uPID) != -1)
  37:                  {
  38:                      if(pPrevProcessInfo)
  39:                      {
  40:                          if(pCurrProcessInfo->NextEntryOffset)
  41:                          {
  42:                              //将当前这个进程(即要隐藏的进程)从 SystemInformation 中摘除(更改链表偏移指针实现)
  43:                              pPrevProcessInfo->NextEntryOffset += pCurrProcessInfo->NextEntryOffset;
  44:                          }
  45:                          else
  46:                          {
  47:                              //说明当前要隐藏的这个进程是进程链表中的最后一个
  48:                              pPrevProcessInfo->NextEntryOffset = 0;
  49:                          }
  50:                      }
  51:                      else
  52:                      {
  53:                          //第一个遍历到得进程就是需要隐藏的进程
  54:                          if(pCurrProcessInfo->NextEntryOffset)
  55:                          {
  56:                              (PCHAR)SystemInformation += pCurrProcessInfo->NextEntryOffset;
  57:                          }
  58:                          else
  59:                          {
  60:                              SystemInformation = NULL;
  61:                          }
  62:                      }
  63:                  }
  64:   
  65:                  //遍历下一个 SYSTEM_PROCESS_INFORMATION 节点
  66:                  pPrevProcessInfo = pCurrProcessInfo;
  67:   
  68:                  //遍历结束
  69:                  if(pCurrProcessInfo->NextEntryOffset)
  70:                  {
  71:                      pCurrProcessInfo = (PSYSTEM_PROCESS_INFORMATION)
  72:                          (((PCHAR)pCurrProcessInfo) + pCurrProcessInfo->NextEntryOffset);
  73:                  }
  74:                  else
  75:                  {
  76:                      pCurrProcessInfo = NULL;
  77:                  }
  78:              }
  79:          }
  80:      }
  81:      return rtStatus;
  82:  }

免责声明:文章转载自《ssdt-hook 进程隐藏与保护》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇MySQL分区myeclipse10.7安装git插件(myeclipse2014也适用)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

react 中echarts-for-react使用 自适应div

import*asReactfrom'react'importReactEchartsfrom'charts-for-ract'导出接口IProps{}接口IState{}classCapitalBudgetsextendsReact.Component<IProps,IState>{constructor(props:IProps){super(props...

自定义样式滚动条

自定义IE浏览器滚动条样式追溯浏览器对滚动条的自定义,恐怕最早的就是IE浏览器了。感觉IE浏览器滚动条自定制功能并不是很强,只能控制一样显示各个部分的颜色而已,像宽度,结构等都无法控制,要靠出个性点的滚动条,很难!自定义FireFox浏览器滚动条在网上找了很多关于Firfox自定义浏览器滚动条的方法,发现firefox中却实是不支持的。...

Linux(debian7)操作基础(四)之CPU频率调整 Linux系统CPU频率调整工具使用

在Linux中,内核的开发人员定义了一组框架模型,以实现动态调整CPU频率的目的,这就是CPUFreq系统。交互式:交互式模式,直接连接到最高频率,然后CPU负载缓慢降低,导致相对较高的功耗。Interactive根据计划的CPU数量来调整频率,以节省电力。InteractiveX根据CPU负载调整CPU频率,而不会过度降低频率。用户空间:用户定义的模式。该...

TensorRT在ubuntu18.04的安装

安装TensorRT前需要安装Cuda和cudnn,安装步骤可以参考ubuntu安装cuda和cudnn。...

Linux下PHP的完全卸载

如果要完全卸载PHP,则不能直接使用yum remove命令。相反,您需要检查有多少rpm数据包可用,然后按依赖顺序逐个卸载它们。许多在线查询都是关于“rpm-qa|grepphp”的,它用于检查哪些rpm数据包可用,然后按依赖顺序卸载它们。按命令查看[root@localhosttest]#rpm qa|grepphpphp-cli-5.3.3-22.el...

EasyPoi导入验证功能

1准备好要导入的Excel,注意Excel的标题要和domain中的@Excel一样1导入验证包支持˂!...