自学编程也有大半年了, 直到现在还是感觉自己没学到些什么. 这段时间在学习驱动, 整理了一下自己写的 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;
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)