内核编程之SSDTHook(2)Hook NtOpenProcess实现进程保护

来源:互联网 发布:淘宝网天猫塑料凉鞋 编辑:程序博客网 时间:2024/06/05 07:04
本博文由CSDN博主zuishikonghuan所作,版权归zuishikonghuan所有,转载请注明出处:http://blog.csdn.net/zuishikonghuan/article/details/50765464

上一篇博文“内核编程之SSDTHook(1)原理(地址:http://blog.csdn.net/zuishikonghuan/article/details/50717936)”中,介绍了SSDTHook的原理,这一篇博文,我们来写一个实例,通过Hook NtOpenProcess来的实现进程保护。

我之前写过两篇Ring3下的API Inline Hook的博文,这两篇博文通过Inline Hook OpenProcess 实现对指定进程的保护,从而保护进程不能被其他进程打开、结束、写内存等等。可以先去看看:http://blog.csdn.net/zuishikonghuan/article/details/47976067

原理什么的上一篇也说的差不多了,还有一点就是,要修改SSDT,需要关闭页面保护,在80x86的CPU上,cr0寄存器中的WP位是“写保护”位,我们要想修改SSDT,就要先干掉WP位,我们可以编写这样的两个函数(内联汇编)用于开关cr0的WP位:

//关闭页面保护void PageProtectClose(){__asm{climov eax, cr0and eax, not 10000hmov cr0, eax}}//启用页面保护void PageProtectOpen(){__asm{mov eax, cr0or eax, 10000hmov cr0, eaxsti}}

cli和sti分别表示“不允许中断”和“允许中断”(只有Ring0级别的程序能够使用)

我们需要实现的效果是:

OK,闲话少说,原理上一篇都说完了,直接上代码:

用户模式程序代码:

#include "stdafx.h"#include<Windows.h>#define IOCTL1 CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)int _tmain(int argc, _TCHAR* argv[]){HANDLE handle = CreateFileA("\\\\.\\MySSDTHookDevice_link", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (handle == INVALID_HANDLE_VALUE){MessageBoxA(0, "打开设备失败", "错误", 0);return 0;}unsigned char buffer[50] = { 0 };DWORD len;DWORD MyProcessID = GetCurrentProcessId();_itow(MyProcessID, (wchar_t*)buffer, 10);if (DeviceIoControl(handle, IOCTL1, buffer, sizeof(wchar_t)*(wcslen((wchar_t*)buffer)+1), buffer, 49, &len, NULL)){printf("OK! Process is Protect");}CloseHandle(handle);getchar();return 0;}

驱动代码:

#include <ntddk.h>extern "C" VOID DriverUnload(PDRIVER_OBJECT pDriverObject);extern "C" NTSTATUS DefDispatchRoutine(PDEVICE_OBJECT pDevObj, PIRP pIrp);extern "C" NTSTATUS IoctlDispatchRoutine(PDEVICE_OBJECT pDevObj, PIRP pIrp);//定义的ioctl控制码#define IOCTL1 CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)typedef struct _DEVICE_EXTENSION {UNICODE_STRING SymLinkName;//我们定义的设备扩展里只有一个符号链接名成员} DEVICE_EXTENSION, *PDEVICE_EXTENSION;//我们将 NtOpenProcess hook 到自己的函数NTSTATUS NTAPI MyNtOpenProcess(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID ClientId);//KeServiceDescriptorTable 中我们感兴趣的结构typedef struct _KESERVICE_DESCRIPTOR_TABLE{PULONG ServiceTableBase;PULONG ServiceCounterTableBase;ULONG NumberOfServices;PUCHAR ParamTableBase;}KESERVICE_DESCRIPTOR_TABLE, *PKESERVICE_DESCRIPTOR_TABLE;//ntoskrnl.exe (ntoskrnl.lib) 导出的 KeServiceDescriptorTableextern "C" extern PKESERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable;//关闭页面保护void PageProtectClose(){__asm{climov eax, cr0and eax, not 10000hmov cr0, eax}}//启用页面保护void PageProtectOpen(){__asm{mov eax, cr0or eax, 10000hmov cr0, eaxsti}}//根据 ZwXXXX的地址 获取服务函数在 SSDT 中所对应的服务的索引号#define SYSTEMCALL_INDEX(ServiceFunction) (*(PULONG)((PUCHAR)ServiceFunction + 1))ULONG oldNtOpenProcess;//之前的NtOpenProcessULONG ProtectProcessID = 0;//要保护的进程ID#pragma code_seg("INIT")extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath){DbgPrint("DriverEntry\r\n");pDriverObject->DriverUnload = DriverUnload;//注册驱动卸载函数//注册派遣函数pDriverObject->MajorFunction[IRP_MJ_CREATE] = DefDispatchRoutine;pDriverObject->MajorFunction[IRP_MJ_CLOSE] = DefDispatchRoutine;pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IoctlDispatchRoutine;NTSTATUS status;PDEVICE_OBJECT pDevObj;PDEVICE_EXTENSION pDevExt;//创建设备名称的字符串UNICODE_STRING devName;RtlInitUnicodeString(&devName, L"\\Device\\MySSDTHookDevice");//创建设备status = IoCreateDevice(pDriverObject, sizeof(DEVICE_EXTENSION), &devName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevObj);if (!NT_SUCCESS(status))return status;pDevObj->Flags |= DO_BUFFERED_IO;//将设备设置为缓冲设备pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;//得到设备扩展//创建符号链接UNICODE_STRING symLinkName;RtlInitUnicodeString(&symLinkName, L"\\??\\MySSDTHookDevice_link");pDevExt->SymLinkName = symLinkName;status = IoCreateSymbolicLink(&symLinkName, &devName);if (!NT_SUCCESS(status)){IoDeleteDevice(pDevObj);return status;}//Hook SSDTPageProtectClose();//得到原来的地址,记录在 oldNtOpenProcessoldNtOpenProcess = KeServiceDescriptorTable->ServiceTableBase[SYSTEMCALL_INDEX(ZwOpenProcess)];//修改SSDT中 NtOpenProcess 的地址,使其指向 MyNtOpenProcessKeServiceDescriptorTable->ServiceTableBase[SYSTEMCALL_INDEX(ZwOpenProcess)] = (ULONG)&MyNtOpenProcess;DbgPrint("Old Addr:0x%X\r\n", oldNtOpenProcess);PageProtectOpen();return STATUS_SUCCESS;}DRIVER_UNLOAD DriverUnload;extern "C" VOID DriverUnload(PDRIVER_OBJECT pDriverObject){PageProtectClose();//修改SSDT中 NtOpenProcess 的地址,使其指向 oldNtOpenProcess//也就是在驱动卸载时恢复原来的地址KeServiceDescriptorTable->ServiceTableBase[SYSTEMCALL_INDEX(ZwOpenProcess)] = oldNtOpenProcess;PageProtectOpen();PDEVICE_OBJECT pDevObj;pDevObj = pDriverObject->DeviceObject;PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;//得到设备扩展//删除符号链接UNICODE_STRING pLinkName = pDevExt->SymLinkName;IoDeleteSymbolicLink(&pLinkName);//删除设备IoDeleteDevice(pDevObj);}extern "C" NTSTATUS DefDispatchRoutine(PDEVICE_OBJECT pDevObj, PIRP pIrp){pIrp->IoStatus.Status = STATUS_SUCCESS;pIrp->IoStatus.Information = 0;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return STATUS_SUCCESS;}extern "C" NTSTATUS IoctlDispatchRoutine(PDEVICE_OBJECT pDevObj, PIRP pIrp){NTSTATUS status = STATUS_SUCCESS;//得到I/O堆栈的当前这一层,也就是IO_STACK_LOCATION结构的指针PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);ULONG in_size = stack->Parameters.DeviceIoControl.InputBufferLength;//得到输入缓冲区的大小ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;//得到控制码PVOID buffer = pIrp->AssociatedIrp.SystemBuffer;//得到缓冲区指针switch (code){case IOCTL1:DbgPrint("Get ioctl code 1\r\n");//用 RtlInitUnicodeString 将用户发送的 wchar_t* 封装成 UNICODE_STRINGUNICODE_STRING temp;RtlInitUnicodeString(&temp, (PWSTR)buffer);//转换成 Unsigned Long 类型,这就是我们要保护的进程RtlUnicodeStringToInteger(&temp, 0, &ProtectProcessID);DbgPrint("ProtectProcessID: %u\r\n", ProtectProcessID);break;default:status = STATUS_INVALID_VARIANT;//如果是没有处理的IRP,则返回STATUS_INVALID_VARIANT,这意味着用户模式的I/O函数失败,但并不会设置GetLastError}// 完成IRPpIrp->IoStatus.Status = status;//设置IRP完成状态,会设置用户模式下的GetLastErrorpIrp->IoStatus.Information = 0;//设置操作的字节IoCompleteRequest(pIrp, IO_NO_INCREMENT);//完成IRP,不增加优先级return status;}NTSTATUS NTAPI MyNtOpenProcess(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID ClientId){//判断要打开的进程ID是不是我们要保护的进程if (ClientId->UniqueProcess == (HANDLE)ProtectProcessID)return (NTSTATUS)-1073741790;//返回“拒绝访问”错误//不是我们要保护的进程,定义一个函数指针 _NtOpenProcess ,根据 oldNtOpenProcess 记录的真实函数的地址进行 Call//也就是说其他进程直接交还给系统的 NtOpenProcess 处理typedef NTSTATUS(NTAPI * _NtOpenProcess)(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID ClientId);_NtOpenProcess _oldNtOpenProcess = (_NtOpenProcess)oldNtOpenProcess;return _oldNtOpenProcess(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);}

和在Ring3下做的效果差不多,不过用驱动更强大,因为hook的是SSDT,可以拦截ZwOpenProcess的所有调用。但Ring3下做Hook,有很多进程注入不了,而且还有session各隔离的问题。当然64位还是在R3下做hook吧,原因上一篇已经说了。如何在R3下做hook:http://blog.csdn.net/zuishikonghuan/article/details/47976067 和http://blog.csdn.net/zuishikonghuan/article/details/47979603

0 0
原创粉丝点击