上面的3篇文章已经大概的讲述了HOOK API的编写方法,可是如何让它们真正的运行起来呢?
这就需要搭建环境,而这个环境你必须使用DDK。我在这里假设你已经安装了DDK,并且会使用DDK来编译一个
WDM驱动程序。这里我要说的是如何在代码中将我上面的3篇文章中讲到的功能串在一起,以及编写WDM驱动程序所需要的Sources文件。
我的Sources文件是这样写的:
TARGETNAME=TestDriver
TARGETTYPE=DRIVER
TARGETPATH=obj
BROWSER_INFO=1
C_DEFINES=-DDRIVER
INCLUDES=c:\ntddk\inc;
USER_C_FLAGS=/FAcs
SOURCES=My.c
这就需要搭建环境,而这个环境你必须使用DDK。我在这里假设你已经安装了DDK,并且会使用DDK来编译一个
WDM驱动程序。这里我要说的是如何在代码中将我上面的3篇文章中讲到的功能串在一起,以及编写WDM驱动程序所需要的Sources文件。
我的Sources文件是这样写的:
TARGETNAME=TestDriver
TARGETTYPE=DRIVER
TARGETPATH=obj
BROWSER_INFO=1
C_DEFINES=-DDRIVER
INCLUDES=c:\ntddk\inc;
USER_C_FLAGS=/FAcs
SOURCES=My.c
其中TARGETNAME=TestDriver指明编译出来的文件名称叫做TestDriver。
TARGETTYPE=DRIVER指明生成的文件类型是*.sys。
SOURCES=My.c指明需要编译的源代码文件。
TARGETTYPE=DRIVER指明生成的文件类型是*.sys。
SOURCES=My.c指明需要编译的源代码文件。
下面来看看My.c文件内容。
作为一个WDM驱动,首先运行的应该是DriverEntry例程。该例程类似于C语言中的Main函数。
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
UNICODE_STRING nameString, linkString;
UNICODE_STRING *InstallDir=NULL;
PDEVICE_OBJECT deviceObject;
NTSTATUS status;
WCHAR wBuffer[200];
nameString.Buffer = wBuffer;
nameString.MaximumLength = 200;
//DriverUnload例程用来处理驱动卸载时所做的恢复工作.
DriverObject->DriverUnload = DriverUnload;
RtlInitUnicodeString(&nameString, L" \\Device\\MyDriver");
status = IoCreateDevice(DriverObject, 0,&nameString, FILE_DEVICE_UNKNOWN, 0, TRUE, &deviceObject );
if (!NT_SUCCESS( status ))
{
return status;
}
deviceObject->Flags |= DO_BUFFERED_IO;
RtlInitUnicodeString(&linkString, L" \\??\\MyDriver");
status = IoCreateSymbolicLink (&linkString, &nameString);
if (!NT_SUCCESS( status ))
{
IoDeleteDevice (DriverObject->DeviceObject);
return status;
}
//MydrvDispatch例程是一个IRP的分发例程(在我的代码中没有怎么用到它)
DriverObject->MajorFunction[IRP_MJ_CREATE] = MydrvDispatch;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = MydrvDispatch;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = MydrvDispatch;
//MydrvDispatchIoctl例程比较重要,该例程可以接受来自外界EXE程序发送给它的参数。例如在我的项目中,由一个外界exe程序
//发送过来需要保护的文件名称、注册表键值等数据,都是使用这个例程来接收的。
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MydrvDispatchIoctl;
__asm{
mov eax, cr0
mov CR0VALUE, eax
and eax, 0fffeffffh
mov cr0, eax
}
作为一个WDM驱动,首先运行的应该是DriverEntry例程。该例程类似于C语言中的Main函数。
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
UNICODE_STRING nameString, linkString;
UNICODE_STRING *InstallDir=NULL;
PDEVICE_OBJECT deviceObject;
NTSTATUS status;
WCHAR wBuffer[200];
nameString.Buffer = wBuffer;
nameString.MaximumLength = 200;
//DriverUnload例程用来处理驱动卸载时所做的恢复工作.
DriverObject->DriverUnload = DriverUnload;
RtlInitUnicodeString(&nameString, L" \\Device\\MyDriver");
status = IoCreateDevice(DriverObject, 0,&nameString, FILE_DEVICE_UNKNOWN, 0, TRUE, &deviceObject );
if (!NT_SUCCESS( status ))
{
return status;
}
deviceObject->Flags |= DO_BUFFERED_IO;
RtlInitUnicodeString(&linkString, L" \\??\\MyDriver");
status = IoCreateSymbolicLink (&linkString, &nameString);
if (!NT_SUCCESS( status ))
{
IoDeleteDevice (DriverObject->DeviceObject);
return status;
}
//MydrvDispatch例程是一个IRP的分发例程(在我的代码中没有怎么用到它)
DriverObject->MajorFunction[IRP_MJ_CREATE] = MydrvDispatch;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = MydrvDispatch;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = MydrvDispatch;
//MydrvDispatchIoctl例程比较重要,该例程可以接受来自外界EXE程序发送给它的参数。例如在我的项目中,由一个外界exe程序
//发送过来需要保护的文件名称、注册表键值等数据,都是使用这个例程来接收的。
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MydrvDispatchIoctl;
__asm{
mov eax, cr0
mov CR0VALUE, eax
and eax, 0fffeffffh
mov cr0, eax
}
看过我文章的朋友一定不会对下面的代码陌生。
//文件删除
RealZwSetInformationFile=(ZWSETINFORMATIONFILE)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwSetInformationFile")]);
(ZWSETINFORMATIONFILE)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwSetInformationFile")])=HookZwSetInformationFile;
//注册表删除
RealZwDeleteKey=(REALZWDELETEKEY)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwDeleteKey")]);
(REALZWDELETEKEY)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwDeleteKey")])=HookZwDeleteKey;
//删除注册表内容
RealZwDeleteValueKey=(REALZWDELETEVALUEKEY)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwDeleteValueKey")]);
(REALZWDELETEVALUEKEY)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwDeleteValueKey")])=HookZwDeleteValueKey;
//设置注册表键值
RealZwSetValueKey=(REALZWSETVALUEKEY)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwSetValueKey")]);
(REALZWSETVALUEKEY)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwSetValueKey")])=HookZwSetValueKey;
//创建文件
RealZwCreateFile=(REALZWCREATEFILE)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwCreateFile")]);
(REALZWCREATEFILE)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwCreateFile")])=HookZwCreateFile;
__asm{
mov eax, CR0VALUE
mov cr0, eax
}
return STATUS_SUCCESS;
}
//文件删除
RealZwSetInformationFile=(ZWSETINFORMATIONFILE)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwSetInformationFile")]);
(ZWSETINFORMATIONFILE)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwSetInformationFile")])=HookZwSetInformationFile;
//注册表删除
RealZwDeleteKey=(REALZWDELETEKEY)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwDeleteKey")]);
(REALZWDELETEKEY)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwDeleteKey")])=HookZwDeleteKey;
//删除注册表内容
RealZwDeleteValueKey=(REALZWDELETEVALUEKEY)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwDeleteValueKey")]);
(REALZWDELETEVALUEKEY)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwDeleteValueKey")])=HookZwDeleteValueKey;
//设置注册表键值
RealZwSetValueKey=(REALZWSETVALUEKEY)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwSetValueKey")]);
(REALZWSETVALUEKEY)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwSetValueKey")])=HookZwSetValueKey;
//创建文件
RealZwCreateFile=(REALZWCREATEFILE)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwCreateFile")]);
(REALZWCREATEFILE)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwCreateFile")])=HookZwCreateFile;
__asm{
mov eax, CR0VALUE
mov cr0, eax
}
return STATUS_SUCCESS;
}
在卸载驱动的时候使用的DriverUnload例程代码如下:
VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject)
{
UNICODE_STRING nameString;
RtlInitUnicodeString(&nameString, L" \\??\\MyDriver");
IoDeleteSymbolicLink(&nameString);
IoDeleteDevice(pDriverObject->DeviceObject);
//卸载设置文件属性
(ZWSETINFORMATIONFILE)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwSetInformationFile")])=RealZwSetInformationFile;
//删除注册表键值
(REALZWDELETEKEY)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwDeleteKey")])=RealZwDeleteKey;
//删除注册表内容
(REALZWDELETEVALUEKEY)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwDeleteValueKey")])=RealZwDeleteValueKey;
//设置注册表键值
(REALZWSETVALUEKEY)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwSetValueKey")])=RealZwSetValueKey;
//创建文件
(REALZWCREATEFILE)(KeServiceDescriptorTable->ServiceTableBase[SYSTEMSERVICE("ZwCreateFile")])=RealZwCreateFile;
return;
}
这样就搭建出了一个完整的WDM驱动框架。编译后可以生成一个具有一定功能的驱动程序。
下次我将会写如何将我们编写好的驱动进行安装,并通过外界的EXE程序和这个驱动程序进行通信。
下次我将会写如何将我们编写好的驱动进行安装,并通过外界的EXE程序和这个驱动程序进行通信。