自学编程也有大半年了, 直到现在还是感觉自己没学到些什么. 这段时间在学习驱动, 整理了一下自己写的 Hook NtOpenProcess 来实现简单的进程保护, 希望能申请到邀请码.  

   都是利用前人的经验来实现的, 不过总算是自己写的. 过程偶也不说了, 看注释吧, 够详细的了.

   系统  Win7 SP1 专业版, 编译器 VS2010 +  WDK 7.1.0.7600  虚拟机环境 VM7.0 WinXP Sp3  项目设置属性在源代码中的  Driver_template.props

/*----------------------------------------------------------------------
 *  文件名:  Hook_NtOpenProces_Driver.h  
 *  文件描述: 演示应用程序通过驱动  Hook NtOpenProcess 的实现. 
 *            此文件用于定义必须的结构和函数声明
 *  ------------------------------------------------------------------*/


#pragma   once            // 保证头文件只被编译一次

#ifdef  __cplusplus      // __cplusplus 这个宏的含义是; 如果这是一段 CPP 的代码, 那么加入 
extern  "C"                  // "C" { 和 } 处理其中的代码.   
{
#endif
#include <ntddk.h>       // 包含着内核下数据结构的库文件
#ifdef  __cplusplus
}
#endif

#define   PAGECODE  code_seg("PAGE")    // 此宏后的代码放入页面文件 
#define   INITCODE  code_seg("INIT")      //  此宏后的代码放入初始化

#define   PAGEDATA  data_seg("PAGE")   // 将代码载入非分页文件的节中
#define   INITDATA  data_seg("INIT")     // 此宏后的代码放入初始化的节中


/*----------------------------------------------------------------------------------------------------
 * 下面定义的是方便在驱动程序中使用的各种数据结构或者宏定义
 * ----------------------------------------------------------------------------------------------------*/

#define  arraysize(p) (sizeof(p) / sizeof((p)[0]))    // 用于 DriverEntry() 中对 对应 IRP 类型的调用函数

// 设备扩展结构, 用于存放设备的相关信息, 以便在不同的函数中调用
typedef  struct   _DEVICE_EXTENSION {
  PDEVICE_OBJECT   pDevice;                     // 指向设备对象的指针, 
  UNICODE_STRING   ustrDeviceName;        // 设备的名称
  UNICODE_STRING   ustrSymLinkName;      // 设备的称号连接名称
} DEVICE_EXTENSION,  *PDEVICE_EXTENSION;


/*--------------------------------------------------------------------------------------
 *  下面声明的函数例程,  是驱动程序中所必需的函数例程
*---------------------------------------------------------------------------------------- */

// 创建设备的函数例程
NTSTATUS   CreateDevice (IN  PDRIVER_OBJECT  pDriverObject);

// 设备卸载例程
VOID   UnloadDevice (IN  PDRIVER_OBJECT  pDriverObject);

// 通用派遣函数例程, 此例程不实现任何的功能
NTSTATUS   IRP_Routine  (IN  PDEVICE_OBJECT  pDevObj, IN  PIRP  pIrp);


/*-----------------------------------------------------------------------------------------
 *  下面是派遣函数中所用到的宏定义和函数声明
 *-----------------------------------------------------------------------------------------*/
// 定义 CTL_CODE 控制码, 用于应用程序使用  DeviceIoControl 方式的与驱动程序交互
// 四个参数分别对应的是: 设备对象的类型,  IOCTL 控制码, 操作模式(读写), 访问权限
#define  IOCTL_BUFFER  CTL_CODE (FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)   //缓冲区模式

// [IRP_MJ_DEVICE_CONTROL] 的派遣函数例程
NTSTATUS  DeviceIoControl_Buffer (IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp);



/*------------------------------------------------------------------------------------------
 *   下面是对 SSDT 进行 Hook 所必须的宏定义, 结构, 及函数声明
 *------------------------------------------------------------------------------------------*/

// 定义 SSDT 导出表的结构体,  此结构和 ServiceDescriptorTable 的结构一致
#pragma  pack(1)    // 对齐单位, 以一个字节对齐
typedef  struct  _SystemServiceEntry {
  ULONG  *ServiceTableBase;          // 指向系统服务函数地址表的基地址的指针 (即 SSDT 的首地址)
  ULONG  *ServiceCounterTableBase;   // 包含着 SSDT 中每个服务被调用次数的计数器
  ULONG  NumberOfServices;           // SSDT 中描述的服务的总数, 每个服务的长度为 4 字节
  ULONG  *ParamTableBase;            // 包括每个系统服务参数字节数的基地址
} SSDT_Entry, *PSSDT_Entry;
#pragma   pack()

// 为了实现可以直接导出 SSDT 中对应函数的当前地址, 必须使用上面定义的结构以指针类型来导出表
extern  "C"  PSSDT_Entry  KeServiceDescriptorTable;


/* ---------------------------------------------------------------------------------------------------
 *   此区域为实现 HOOK 而定义的宏
 *---------------------------------------------------------------------------------------------------*/


// 获取 Zw 系列函数的当前地址的宏.  
// 参数 _FuncName: Zw系列的函数,  
// 注意这里必须使用 -> 的指向类型

#define   GetSystemService(_FuncName)\
  KeServiceDescriptorTable->ServiceTableBase[*(PULONG]((PUCHAR) _FuncName+1)]


// 查询 Zw 系列函数在 SSDT 中的索引号的宏. 
// 参数 _Function : Zw 系列的函数

#define   GetServiceIndex(_Function) (*(PULONG)((PUCHAR)_Function+1))


// 实现 Hook 的宏 通过 InterlockedExchange 来交换两个函数的地址.
//  _Function  :  Zw* 形式的函数.  此处是通过 NTSYSAPI 重定义一个 ZwOpenProcess   
//  _Hook      :  自己构造的 Hook 函数的地址    
//  _Orig      :  原 SSDT 表中被 Hook 的函数地址.
//  _OrigType  :  原始函数的类型.      
// _MappedSSDTBase:  MDL 映射后指向 SSDT 首地址的指针.

#define   HOOK_SSDT(_Function, _Hook, _Orig, _OrigType, _MappedSSDTBase)\
  _Orig = (_OrigType) InterlockedExchange ((PLONG)&_MappedSSDTBase [GetServiceIndex(_Function)], (LONG)_Hook)


// 用于解除 HOOK SSDT 的宏,  通过 InterlockedExchange 来交换两个函数的地址.
//  _Function  :  Zw* 形式的函数.  此处是通过 NTSYSAPI 重定义一个 ZwOpenProcess   
//  _Orig      :  原 SSDT 表中被 Hook 的函数地址.
// _MappedSSDTBase:  MDL 映射后指向 SSDT 首地址的指针.

#define  UNHOOK_SSDT(_Function, _Orig, _MappedSSDTBase)\
  InterlockedExchange((PLONG) &_MappedSSDTBase[GetServiceIndex(_Function)], (LONG)_Orig)


/*  ----------------------------------------------------------------------------------------------
 *    此区域为上面实现的宏, 而所必须定义的函数
 *-------------------------------------------------------------------------------------------------*/

// 重定义 ZwOpenProcess 函数, 用于保存 SSDT 中原来的 NtOpenProcess 函数的地址. 用于上面宏中参数 _Function 中调用
//  前缀使用 NTSYSAPI 宏.  NTSYSAPI 的定义:   __declspec(dllimport) 
NTSYSAPI  NTSTATUS  NTAPI  ZwOpenProcess ( __out PHANDLE ProcessHandle,
  __in ACCESS_MASK DesiredAccess, __in POBJECT_ATTRIBUTES ObjectAttributes, __in_opt PCLIENT_ID ClientId );


// 定义一个指向上面重定义的  ZwOpenProcess 函数 的函数指针,  用于上面宏中参数 _OrigType 中调用
typedef  NTSTATUS  (*_NtOpenProcess)( __out PHANDLE ProcessHandle,
  __in ACCESS_MASK DesiredAccess, __in POBJECT_ATTRIBUTES ObjectAttributes, __in_opt PCLIENT_ID ClientId );


// 定义一个 *_ZwOpenProcess 类型的对象 , 用于上面宏中参数  _Orig 中调用
_NtOpenProcess  Old_ZwOpenProcess;


// 定义一个用于 Hook  NtOpenProcess 的函数,   用于上面宏中参数  _Hook 中调用   此处函数的实现为保护指定进程
LONG  Pid = 0;  // 用于存储用户层应用程序传入的 Pid , 用于在 MyOpenProcess 函数中进行处理
NTSTATUS  MyOpenProcess (OUT PHANDLE ProcessHandle, 
  IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN PCLIENT_ID ClientId);


/*------------------------------------------------------------------------------------
 *  此区域实现二个函数, 一个用于 Hook SSDT , 一个用于恢复 Hook SSDT 
 *------------------------------------------------------------------------------------*/

// 用于解除 SSDT 的页面保护. 并对 SSDT 进行 Hook   
VOID  Hook_SSDT_MDL ();

// 用于解除 SSDT 的页面保护. 并恢复 被 Hook 的 SSDT
VOID  Resume_SSDT_MDL ();



/*----------------------------------------------------------------------------
 *  Hook_NtOpenProces_Driver.cpp   函数实现代码
 *----------------------------------------------------------------------------*/

#include "Hook_NtOpenProces_Driver.h"


/*----------------------------------------------------------------------------------------------
 * 函数名称: DriverEntry
 * 功能描述: 驱动程序的入口函数. 用于初始化驱动, 定位和申请硬件资源, 创建内核对象
 * 参数列表: IN 驱动对象指针         pDriverObject  从 I/O 管理器中传进来的驱动对象
 *           IN PUNICODE 字符串指针  pRegistryPath  驱动程序在注册表中的路径
 * 返回  值: 返回初始化驱动状态
 * --------------------------------------------------------------------------------------------*/

#pragma  INITCODE
extern  "C" NTSTATUS  DriverEntry (IN  PDRIVER_OBJECT  pDriverObject,  IN  PUNICODE_STRING  pRegistryPath)
{
  NTSTATUS  status;                         // 用于获取操作是否成功, 并作为函数的返回值使用
  KdPrint(("Enter  DriverEntry \n"));       // log

  // 注册卸载函数的地址.
  pDriverObject->DriverUnload = UnloadDevice;
                                
  // 注册对应 IRP 派遣函数的地址, 注意, 如果单独注册派遣函数, 记得要注册 IRP_MJ_CREATE 的例程, 
  for (int i = 0; i < arraysize(pDriverObject->MajorFunction); i++)
    pDriverObject->MajorFunction[i] = IRP_Routine;

  pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceIoControl_Buffer;

  // 创建设备对象
  status = CreateDevice (pDriverObject);

  // SSDT hook
  Hook_SSDT_MDL();

  return status;
}


/*------------------------------------------------------------------------------------------------
 * 函数名称: CreateDevice
 * 功能描述: 初始化设备对象 (即创建并初始化)
 * 参数列表: 驱动对象指针    pDriverObject : 从 I/O 管理器中传进来的驱动对象
 * 返回  值: 返回初始化状态
 * -----------------------------------------------------------------------------------------------*/

#pragma   INITCODE  
NTSTATUS  CreateDevice (IN PDRIVER_OBJECT pDriverObject)
{
  NTSTATUS  status;     // 用于获取操作是否成功, 并作为函数的返回值使用

  //------------------  1. 必须定义的类型对象,  创建设备名称并初始化该名称  -----------------

  PDEVICE_OBJECT     pDevObj;        // 创建的设备对象
  PDEVICE_EXTENSION  pDevExt;        // 定义一个设备扩展结构的对象, 用于保存设备的相关信息

  UNICODE_STRING  DevName;           // 创建的设备对象的名称
  RtlInitUnicodeString (&DevName, L"\\Device\\MyDevice");


  //------------------  2. 创建设备对象, 判断设备是否成功创建, 设置和保存设备的相关信息 -------

  status = IoCreateDevice (pDriverObject,               // 创建此设备对象的驱动对象
                         sizeof(DEVICE_CAPABILITIES), // 指定设备扩展的大小, I/O 管理器负责分配及关联   
               &(UNICODE_STRING)DevName,    // 设备对象的名称
               FILE_DEVICE_UNKNOWN,         // 生成的设备类型, 此处为未知设备
               0,                           // 设置设备对象的特征, 一般为 0
               TRUE,                        // 设置此设备对象是否为内核模式下使用, 一般为 TRUE
               &pDevObj);                   //  I/O 管理器负责创建这个设备对象, 并返回设备对象的地址

  // 判断设备是否成功创建
  if(!NT_SUCCESS(status))
  {
    KdPrint((" Error: 设备创建失败 \n"));
    return  status;
  }

  // 设置和保存设备的相关信息
  //pDevObj->Flags = DO_BUFFERED_IO;    // 设置此设备的读写方式, 此处为缓冲区方式
  
  pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;  // 将创建的设备的扩展子域映射到我们定义的扩展结构中
  pDevExt->pDevice = pDevObj;                             // 定义映射此设备的指针到自定义的扩展结构中
  pDevExt->ustrDeviceName = DevName;                      // 保存此设备的名称到自定义的扩展结构中


  //----------------------- 3. 创建设备的符号链接, 和设备进行绑定, 及判断绑定是否成功  -------------

  UNICODE_STRING  SymLinkName;                               // 设备的符号链接名称

  // 初始化此符号链接名称, 注意要和生成的驱动的名字一致, 否则将导致驱动无法卸载.
  RtlInitUnicodeString (&SymLinkName, L"\\??\\Hook_NtOpenProces_Driver");   

  pDevExt->ustrSymLinkName = SymLinkName;                    // 保存此设备链接符号名到自定义的扩展结构中

  status = IoCreateSymbolicLink (&SymLinkName, &DevName);    // 将创建的设备和此符号链接进行绑定

  // 判断符号链接和设备绑定是否成功
  if(!NT_SUCCESS(status))
  {
    KdPrint((" 设备和称号链接绑定失败 \n"));
    IoDeleteDevice (pDevObj);                              // 绑定失败则删除此设备对象
    return status;
  }

  KdPrint(("设备创建成功 \n"));                              // log 信息
  return STATUS_SUCCESS;
}

/*--------------------------------------------------------------------------------------------------------------
 * 函数名称: UnloadDevice
 * 功能描述: 负责驱动程序的卸载操作
 * 参数列表: IN 驱动对象指针      pDriverObject : 传递进来的驱动对象
 * 返回  值: 返回状态, 成功或失败
 * ------------------------------------------------------------------------------------------------------------*/

#pragma   PAGECODE
VOID  UnloadDevice (IN PDRIVER_OBJECT  pDriverObject)
{
   PDEVICE_OBJECT  pNextObj;    // 驱动对象的设备对象子域是一个链表, pNextObj 指向链表中的下一个设备对象

   // 解除 SSDT Hook
   Resume_SSDT_MDL();

   pNextObj = pDriverObject->DeviceObject;    // 由传入的驱动对象得到此对象的设备链表的首个设备对象.

   while (pNextObj != NULL)     // 遍历驱动对象中的设备链表
   {
     // 将设备对象的扩展结构映射到我们定义的扩展结构中, 以获取相关信息
     PDEVICE_EXTENSION  pDevExt = (PDEVICE_EXTENSION)pNextObj->DeviceExtension;

     UNICODE_STRING  SymLinkName = pDevExt->ustrSymLinkName;    // 获取将设备对象的符号链接并删除
     IoDeleteSymbolicLink(&SymLinkName);

     pNextObj = pNextObj->NextDevice;                          //  删除设备并从链表中获取下一个设备对象
     IoDeleteDevice(pDevExt->pDevice);
   }


   KdPrint(("设备卸载成功 \n"));
}

/*-----------------------------------------------------------------------------
 * 函数名称: IRP_Routine
 * 功能描述: 通用派遣函数例程, 此例程不实现任何的功能
 * 参数列表: IN 设备对象指针:   pDevObj :  传入的设备对象
 *           IN IRP 指针           pIrp :  从 I/O 管理器请求包, 以于判断 IRP 的类型
 * 返回  值: 返回操作状态
 * ----------------------------------------------------------------------------*/

#pragma  PAGECODE
NTSTATUS   IRP_Routine  (IN  PDEVICE_OBJECT  pDevObj, IN  PIRP  pIrp)
{
  NTSTATUS  status = STATUS_SUCCESS;    // 设置操作返回状态为成功

  pIrp->IoStatus.Status = status;       // 设置 IRP 完成状态

  pIrp->IoStatus.Information = 0;       // 此处不需要读写, 所以设置 IRP 操作字节数为 0

  IoCompleteRequest(pIrp, IO_NO_INCREMENT);  // 设置 IRP 请求成功

  return status;
}

/*---------------------------------------------------------------------------------------
 * 函数名称: DeviceIoControl_All
 * 功能描述:  应用程序以 IOCTL 方式的缓冲区模式来读写设备  对应 IRP [IRP_MJ_DEVICE_CONTROL]
 * 参数列表: IN 设备对象指针      pDriverObject : 传递进来的驱动对象
 *           IN  IRP 指针         pIrp: 指向 IRP 栈顶的指针
 * 返回  值: 返回状态, 成功或失败
 * -------------------------------------------------------------------------------------*/

#pragma PAGECODE 
NTSTATUS  DeviceIoControl_Buffer (IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
{
  NTSTATUS  status = STATUS_SUCCESS;    // 设置操作返回状态为成功 

  //-----------------  1. 获得必须的相关信息  ---------------------------------------------

  PIO_STACK_LOCATION  stack = IoGetCurrentIrpStackLocation(pIrp);      // 获得对应  IPR 的当前堆栈指针
  ULONG  CBIn = stack->Parameters.DeviceIoControl.InputBufferLength;   // 获得系统输入缓冲区的长度
  ULONG  CBOut = stack->Parameters.DeviceIoControl.OutputBufferLength; // 获得系统输出缓冲区的长度

  ULONG  IOCTL_Code = stack->Parameters.DeviceIoControl.IoControlCode; // 获得应用程序的 IOCTL 控制码

  //-----------------  2. 检测和处理过程  -----------------------------------------------------

  ULONG  info = 0;                       // 用于指示派遣函数需要实际操作的字节数

  if(IOCTL_Code == IOCTL_BUFFER)         // 如果获得的应用程序的控制码和驱动程序的控制码一致
  {
    ULONG *InputBuffer = (ULONG *)pIrp->AssociatedIrp.SystemBuffer;   // 指向系统缓冲区的指针

    // 获得系统缓冲区输入的数据, 即应用程序对驱动程序输入的数据
    Pid = (LONG)*InputBuffer;         // 此处是保存用户层应用程序传入的 Pid 值  Pid 为全局变量

    ULONG *OuputBuffer = (ULONG *)pIrp->AssociatedIrp.SystemBuffer;    // 指向系统缓冲区的指针

    // 向系统缓冲区输出数据, 即让应用程序从驱动程序中读取的数据

    info = CBOut;    // 指示派遣函数需要操作的字节数
  }

  /*-------------------  3. 设置 IRP 的完成及返回状态 ----------------------------------*/

  pIrp->IoStatus.Status = status;            //设置 IRP 的完成状态为成功
  pIrp->IoStatus.Information = info;         //设置 IRP 实际操作的字节数

  IoCompleteRequest(pIrp, IO_NO_INCREMENT);  // 指示 IRP 成功完成

  return status;
}

/*--------------------------------------------------------------------------------------------
 *    临时区域;  此驱动程序的应用函数
*---------------------------------------------------------------------------------------------- */

// 对 NtOpenProcess 进行 Hook 的实现函数 , 此处实现的功能是对指定 Pid 的进程进程进行保护
NTSTATUS  MyOpenProcess (OUT PHANDLE ProcessHandle, 
  IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN PCLIENT_ID ClientId)
{
  NTSTATUS  Status = STATUS_SUCCESS;      // 设置操作状态为成功

  // 根据全局变量 Pid 判断是否要实现此函数的功能, 即对此 Pid 的进程进行保护
  if(ClientId->UniqueProcess == (HANDLE)Pid)
  {
    // 可以显示是那个进程调用此 PID (不是必须的)
    // PEPROCESS   EP;
    // EP = PsGetCurrentProcess();                   // 0x174 为 _EPROCESS 结构中的偏移位置, 存储进程的名称
    // KdPrint((" 试图访问此进程的进程名称为 %s \n", (PTSTR)(ULONG)EP+0x174));

    ProcessHandle = NULL;            // 如果是传入的 PID  OUT 参数 ProcessHandle 为空, 便达到保护的目的
    return  STATUS_ACCESS_DENIED;    // 并返回状态为拒绝访问.
  }   

  // 如果 PID 不是所指定的, 便交还原函数进行处理
  Status = Old_ZwOpenProcess(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);

  return  STATUS_SUCCESS;
}

// 用于解除 SSDT 的页面保护. 并对 SSDT 进行 Hook   
#pragma  PAGECODE
VOID  Hook_SSDT_MDL ()
{
  PMDL   pMdlSSDT = NULL;      // 用来创建原始的 SSDT 地址, 映射到我们的域中, 来达到解除页面保护
  PVOID  *MappedSSDTBase = 0;  // 存放解除页面保护后指向的 SSDT 首地址的指针

  // 调用 MmCreateMdl 创建一个映射 SSDT 的 MDL 结构的虚拟内存空间
  pMdlSSDT = MmCreateMdl (NULL, KeServiceDescriptorTable->ServiceTableBase,
                        KeServiceDescriptorTable->NumberOfServices * 4);

  if(!pMdlSSDT)          // 检测创建是否成功
    KdPrint(("创建 MDL 失败 \n"));
  
  MmBuildMdlForNonPagedPool (pMdlSSDT);  // 将上面创建的 MDL 分配在非分页页面中, 因为 SSDT 在非分页页面中

  // 改变 MDL 的标记来实现可读写
  pMdlSSDT->MdlFlags = pMdlSSDT->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;

  // 锁定此 MDL 的虚拟内存空间, 以防止系统对其释放, 并返回指向此 MDL 首地址的指针
  MappedSSDTBase = (PVOID *) MmMapLockedPages (pMdlSSDT, KernelMode);

  // 检测返回首地址的指针是否成功, 成功便对 SSDT 进行 Hook
  if(MappedSSDTBase != 0)
  {
    HOOK_SSDT(ZwOpenProcess, MyOpenProcess, Old_ZwOpenProcess, _NtOpenProcess, MappedSSDTBase);
    KdPrint(("SSDT HOOK 成功 \n"));
  }


  // 对 MDL 分配的内存空间进行释放
  if(pMdlSSDT != NULL)
  {
    MmUnmapLockedPages (MappedSSDTBase, pMdlSSDT);
    IoFreeMdl(pMdlSSDT);
  }

}


// 用于解除 SSDT 的页面保护. 并恢复 被 Hook 的 SSDT
#pragma  PAGECODE
VOID  Resume_SSDT_MDL ()
{
  
  PMDL   pMdlSSDT = NULL;      // 用来创建原始的 SSDT 地址, 映射到我们的域中, 来达到解除页面保护
  PVOID  *MappedSSDTBase = 0;  // 存放解除页面保护后指向的 SSDT 首地址的指针

  // 调用 MmCreateMdl 创建一个映射 SSDT 的 MDL 结构的虚拟内存空间
  pMdlSSDT = MmCreateMdl (NULL, KeServiceDescriptorTable->ServiceTableBase,
    KeServiceDescriptorTable->NumberOfServices * 4);

  if(!pMdlSSDT)          // 检测创建是否成功
    KdPrint(("创建 MDL 失败 \n"));

  MmBuildMdlForNonPagedPool (pMdlSSDT);  // 将上面创建的 MDL 分配在非分页内存中, 因为 SSDT 在非分页内存中

  // 改变 MDL 的标记来实现可读写
  pMdlSSDT->MdlFlags = pMdlSSDT->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;


  // 锁定此 MDL 的虚拟内存空间, 以防止其他进程来访问, 并返回指向此 MDL 首地址的指针
  MappedSSDTBase = (PVOID *) MmMapLockedPages (pMdlSSDT, KernelMode);

  // 检测返回首地址的指针是否成功, 成功便对 SSDT 进行 Hook
  if(MappedSSDTBase != 0)
  {
    UNHOOK_SSDT(ZwOpenProcess, Old_ZwOpenProcess, MappedSSDTBase);
    KdPrint(("恢复 SSDT HOOK 成功 \n"));
  }


  // 对 MDL 分配的内存空间进行释放
  if(pMdlSSDT != NULL)
  {
    MmUnmapLockedPages (MappedSSDTBase, pMdlSSDT);
    IoFreeMdl(pMdlSSDT);
  }

}


// 用控制台实现对此驱动进行调用的源代码

// Hook_NtOpenProcess_Test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <windows.h>       // 为了返回错误信息
#include <winioctl.h>      // 使用 CTL_CODE 必须加入的头文件
#include <iostream>

using namespace std;


// 此定义是用于  DeviceIoControl 的第一种 (缓冲区模式读写方式)  
// 注意: 要和在驱动程序中的定义的 CTL_CODE 一致.
// 四个参数分别对应的是: 设备对象的类型, IOCTL 码, 操作模式(读写), 访问权限
#define  IOCTL_BUFFER  CTL_CODE (\
  FILE_DEVICE_UNKNOWN,\
  0x800,\
  METHOD_BUFFERED,\
  FILE_ANY_ACCESS)


int _tmain(int argc, _TCHAR* argv[])
{
  // 打开设备句柄, 
  HANDLE  hDevice = CreateFile (
    L"\\\\.\\Hook_NtOpenProces_Driver",  // 指向文件名的指针, 即驱动程序的设备符号链接名称
    GENERIC_WRITE | GENERIC_READ,       // 访问模式 (写/读)
    0,                                  // 共享方式,  0 代表不共享
    NULL,                               // 指向文件安全属性的指针, 此处为空
    OPEN_EXISTING,                      // 创建设置, 此处为打开现有的
    FILE_ATTRIBUTE_NORMAL,              // 文件属性, 此处为默认属性
    NULL );                             // 如果不为 NULL, 则指定一个文件句柄

  if (hDevice == INVALID_HANDLE_VALUE)    // 如果打开失败
  {
    printf("未能获得文件句柄, 打开 DispatchDemo 失败, 错误代码 %d \n ", GetLastError());
  }

  long Pid = 0;       //存储用户输入的 Pid  用于 DeviceIoControl 的输入缓冲区

  cout << "控制台版进程保护器\n" << "请输入需要保护的进程PID:";
    cin >> Pid;    


  UCHAR  OutputBuffer[20];                 //作为输出缓冲区 (即应用程序对设备的读取操作)
  DWORD  dwOutput;                         // 计数输出的字符数 (Read)

   DeviceIoControl( 
    hDevice,               // 已经打开的设备句柄
    IOCTL_BUFFER,          // 自定义的控制码    //*注意*: 此应该为定义的直接模式的 IOCTL
    &Pid,                  // 输入缓冲区
    sizeof(Pid),           // 输入缓冲区的大小
    OutputBuffer,          // 输出缓冲区
    sizeof(OutputBuffer),  // 输出缓冲区的大小
    &dwOutput,            // 实际返回的字节数
    NULL);

   // 关闭文件句柄
   CloseHandle(hDevice);

   system("PAUSE");
  return 0;
}

上传的附件 Hook_NtOpenProces_Driver.rar
Hook_NtOpenProcess_Test.rar