1.Ring0驱动层代码的编写:
//codemsg.h 通信控制码的定义
#ifndef _DEFINE_H_
#define _DEFINE_H_
// _number: 0 -> 2047 : reserved for Microsoft 微软保留
// 2047 -> 4095 : reserved for OEMs 用户自定义
#define CODEMSG(_number) CTL_CODE(FILE_DEVICE_UNKNOWN, _number , METHOD_BUFFERED,
FILE_READ_DATA | FILE_WRITE_DATA)
//定义控制码
#define INIT_FILE_NAME 2047
#endif
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//Ring0.h
#ifndef _KERNEL_MODULE_H_
#define _KERNEL_MODULE_H_
#include <ntifs.h>
#include "codemsg.h"
//设备对象的名称
#define DEVICE L"\Device\www.AntiGameProtect.com"
//链接符号的名称
#define DOSDEVICE L"\DosDevices\www.AntiGameProtect.com"
PDEVICE_OBJECT DriverDeviceObject;
#endif
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//Ring0.c
#include "Ring0.h"
//驱动卸载例程函数,在这里释放一些资源。
VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING DeviceName;
UNICODE_STRING DosDeviceName;
//删除符号链接
RtlInitUnicodeString(&DosDeviceName, DOSDEVICE);
IoDeleteSymbolicLink(&DosDeviceName );
//删除驱动对象
if(DriverDeviceObject != NULL)
IoDeleteDevice(DriverDeviceObject);
DbgPrint("驱动卸载成功!
");
}
//默认的例程处理函数
NTSTATUS IODispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
//验证一个WCHAR内容的指针是否可以访问
BOOLEAN ValidateWCHARString(WCHAR *pwzStr, ULONG_PTR Length)
{
ULONG i;
__try
{
//第一步判断指针和大小是否为NULL,是的话就没必要验证了
if (*pwzStr == NULL || Length == 0)
{
return FALSE;
}
//以length长度循环检查指针pwzStr里面的值
for (i = 0; i < Length; i++)
{
//检查内存是否可以访问。
if (!MmIsAddressValid((PUCHAR)pwzStr + i))
{
//只要有一个字节是不可读取,就失败
return FALSE;
}
}
}__except(EXCEPTION_EXECUTE_HANDLER)
{
//触发了异常
return FALSE;
}
return TRUE;
}
//IRP通信例程处理函数
NTSTATUS IOManager(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
//获取当前IrpStack,通过读取其结构成员,取出我们需要的控制码IRPcode
PIO_STACK_LOCATION StackLocation = IoGetCurrentIrpStackLocation(Irp);
//获取控制码IRPcode
ULONG IRPcode = StackLocation->Parameters.DeviceIoControl.IoControlCode;
WCHAR *buf;
SIZE_T size;
WCHAR *pwzCopyBuf = NULL;
//获取应用层传进来的内存缓冲区
buf = (WCHAR*)Irp->AssociatedIrp.SystemBuffer;
//内存缓冲区的字节长度
size = (SIZE_T)Irp->Size;
//设置Irp的状态
Irp->IoStatus.Status = STATUS_SUCCESS;
switch(IRPcode)
{
case CODEMSG(INIT_FILE_NAME):
//从应用层传进来的buf,你无法预知这个值是否可以访问,所以,这里要验证我们传递进来的buf的有效性,才可以在驱动层访问buf
//所以,这里我写了一个ValidateWCHARString来验证这个变量
__try{
//判断Buffer的有效性
if (ValidateWCHARString(buf, size))
{
//提示-应用层数据传到了驱动层
DbgPrint("Buf ==> %ws:%d
", buf, size);
//申请内存,类似应用层的new,并给于标识'fp'
pwzCopyBuf = (WCHAR*)ExAllocatePoolWithTag(NonPagedPool, size, 'fp');
//如果申请内存成功
if (pwzCopyBuf)
{
//内存初始化
memset(pwzCopyBuf, 0, size);
//copy到我们新申请的内存
memcpy(pwzCopyBuf,buf,size);
//显示从应用层获取到的字符串信息
DbgPrint("CopyBuf ==> %ws
", pwzCopyBuf);
//在驱动下面用C语言来写,就要遵守windows的规则。申请的内存,必须要释放。
//要记得释放内存
ExFreePool(pwzCopyBuf);
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
//获取异常的状态码
Irp->IoStatus.Status = GetExceptionCode();
}
break;
default:
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
}
//设置Irp的返回码
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Irp->IoStatus.Status;
}
//驱动的入口函数DriverEntry
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING theRegistryPath)
{
UNICODE_STRING DeviceName;
UNICODE_STRING DosDeviceName;
NTSTATUS status;
//初始化驱动符号名
//UNICODE_STRING是一个结构体,类似win32里面的结构体,比如SYSTEMTIME
//在Win系统下,内核的结构体都是可以通过windbg或者wrk获得
/*
lkd> dt_unicode_string
nt!_UNICODE_STRING
+0x000 Length : Uint2B //文本长度
+0x002 MaximumLength : Uint2B //最大长度
+0x004 Buffer : Ptr32 Uint2B //文本内容,是unicode类型,即WCHAR
*/
//设备名称字符串
RtlInitUnicodeString(&DeviceName, DEVICE);
//符号链接字符串
RtlInitUnicodeString(&DosDeviceName, DOSDEVICE);
//创建设备对象
status = IoCreateDevice(
DriverObject, // ptr to caller object
0, // extension device allocated byte number
&DeviceName, // device name
FILE_DEVICE_UNKNOWN,
0, // no special caracteristics
FALSE, // we can open many handles in same time
&DeviceObject); // [OUT] ptr to the created object
if (!NT_SUCCESS(status))
{
return STATUS_NO_SUCH_DEVICE;
}
//同样也需要一个符号链接,不然会影响到驱动和应用层的通信
status = IoCreateSymbolicLink(&DosDeviceName,&DeviceName);
if(!NT_SUCCESS(status))
{
IoDeleteDevice(DriverDeviceObject);
return STATUS_NO_SUCH_DEVICE;
}
//设置驱动卸载例程函数
DriverObject->DriverUnload = DriverUnload;
//IRP_MJ_CREATE,响应的是应用层函数CreateFile,应用层调用这个函数就会进入这个例程
DriverObject->MajorFunction[IRP_MJ_CREATE] = IODispatch;
//下面的分别对应应用层CloseHandle、ReadFile、WriteFile函数
DriverObject->MajorFunction[IRP_MJ_CLOSE] = IODispatch;
DriverObject->MajorFunction[IRP_MJ_READ] = IODispatch;
DriverObject->MajorFunction[IRP_MJ_WRITE] = IODispatch;
//一般我们跟应用层通信,都是通过IRP_MJ_DEVICE_CONTROL例程,这个例程对应的是应用层下的DeviceIoControl
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IOManager; //DeviceIoControl()
//设置通信方式--直接方式I/O
DeviceObject->Flags |= DO_BUFFERED_IO;
//设置文件字对齐
DeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
//设备初始化完毕可以工作了
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
//提示驱动加载成功
DbgPrint("Hello Driver !
");
return STATUS_SUCCESS;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//Ring3.cpp
#include <windows.h>
#include <stdio.h>
//包含控制码的头文件
#include "..Ring0codemsg.h"
//向驱动发送请求
BOOL CallDriver(char *ID,char *lpBuffer)
{
HANDLE service = 0;
HANDLE device = 0;
char ret[1024];
WCHAR ToSend[512];
DWORD code = -1;
DWORD bytes;
//通过符号连接打开设备对象
device = CreateFile("\\.\www.AntiGameProtect.com", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if( !device || device==INVALID_HANDLE_VALUE )
{
printf("打开驱动失败,驱动加载不成功. %d
",GetLastError());
return FALSE;
}
//判断输入的命令是否是"-file"
if(!strcmp(ID,"-file"))
{
//对应我们驱动下面的控制码。
code = INIT_FILE_NAME;
}
//判断驱动的控制码是否有效
if (code == -1)
{
printf("无效的ID
");
return FALSE;
}
//将ascii码lpBuffer字符串转unicode码字符串ToSend
MultiByteToWideChar(CP_ACP, 0, lpBuffer, -1, ToSend, sizeof(ToSend));
DeviceIoControl(device,
CODEMSG(code), //驱动的控制码
ToSend, //输入缓冲区
(wcslen(ToSend)+1)*2, //输入缓冲区的大小
&ret, //输出缓冲区
sizeof(ret), //输出缓冲区的大小
&bytes, //返回的字节数
NULL);
//关闭驱动文件
CloseHandle(device);
printf("完成!
");
return TRUE;
}
//main函数
void main(int argc,char *argv[])
{
//判断用户输入的合法性
if (argc != 3)
{
printf("Example:%s ID CommandLine
",argv[0]);
return;
}
//调用驱动的代码
CallDriver(argv[1], argv[2]);
return;
}