内容简介:配置好驱动测试环境后,就可以正式编写驱动了。市面上讲解驱动开发的书籍汗牛充栋,但讲得较为太复杂,让初学者不好理解。本文从一个简单的本文主角:(不得不说,此人长得帅,编程技术又牛,让多少男人羡慕妒忌,让多少女人一见倾心)。
配置好驱动测试环境后,就可以正式编写驱动了。市面上讲解驱动开发的书籍汗牛充栋,但讲得较为太复杂,让初学者不好理解。本文从一个简单的 hello,world 驱动(驱动模板)讲起,力求讲解得简单明了,让大家好理解。
本文主角:
Mark
Russinovich
编写(不得不说,此人长得帅,编程技术又牛,让多少男人羡慕妒忌,让多少女人一见倾心)。
下载地址: http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx
2.KmdMgr。 KmdMgr 是一个由俄国人编写的驱动加载工具。比起国内那些乱七八糟的驱动加载工具,它的特点是可以与驱动进行通信(虽然无法设置 I/O 缓冲区)。下载地址:
https://www.assembla.com/code/L2h/subversion/nodes/LowLevel/KmdManager.exe?_for mat=raw&rev=1
3. WIN64AST。作者自行开发的 64 位 ARK 类工具。在本章中用来查看驱动是否加载成功。在后续章节还有其他的用途。下载地址: www.win64ast.com 。
4.WIN64UDL。作者自行开发的驱动加载工具,能在正常模式下加载没有签名的驱动。
编写驱动: 以下是一个我写的 WIN64 驱动模板
//【0】包含的头文件,可以加入系统或自己定义的头文件
#include <ntddk.h>
#include <windef.h>
#include <stdlib.h>
//【1】定义符号链接,一般来说修改为驱动的名字即可
#define DEVICE_NAME L"\\Device\\KrnlHW64"
#define LINK_NAME L"\\DosDevices\\KrnlHW64"
#define LINK_GLOBAL_NAME L"\\DosDevices\\Global\\KrnlHW64"
//【2】定义驱动功能号和名字,提供接口给应用程序调用
#define IOCTL_IO_TEST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800,
METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SAY_HELLO CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801,
METHOD_BUFFERED, FILE_ANY_ACCESS)
//【3】驱动卸载的处理例程
VOID DriverUnload(PDRIVER_OBJECT pDriverObj)
{
UNICODE_STRING strLink;
DbgPrint("[KrnlHW64]DriverUnload\n");
RtlInitUnicodeString(&strLink, LINK_NAME);
IoDeleteSymbolicLink(&strLink);
IoDeleteDevice(pDriverObj->DeviceObject);
}
//【4】 IRP_MJ_CREATE对应的处理例程,一般不用管它
NTSTATUS DispatchCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
DbgPrint("[KrnlHW64]DispatchCreate\n");
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
//【5】 IRP_MJ_CLOSE对应的处理例程,一般不用管它
NTSTATUS DispatchClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
DbgPrint("[KrnlHW64]DispatchClose\n");
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
//【6】 IRP_MJ_DEVICE_CONTROL对应的处理例程,驱动最重要的函数之一,一般走正常途径调用驱动功能的程序,都会经过这个函数
NTSTATUS DispatchIoctl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
PIO_STACK_LOCATION pIrpStack;
ULONG uIoControlCode;
PVOID pIoBuffer;
ULONG uInSize;
ULONG uOutSize;
DbgPrint("[KrnlHW64]DispatchIoctl\n");
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
//控制码
uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
//输入输出缓冲区
pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
//输入区域大小
uInSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
//输出区域大小
uOutSize = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
switch(uIoControlCode)
{
//在这里加入接口
case IOCTL_IO_TEST:
{
DWORD dw=0;
//获得输入的内容
memcpy(&dw,pIoBuffer,sizeof(DWORD));
//使用输入的内容
dw++;
//输出处理的结果
memcpy(pIoBuffer,&dw,sizeof(DWORD));
//处理成功,返回非STATUS_SUCCESS会让DeviveIoControl返回失败
status = STATUS_SUCCESS;
break;
}
case IOCTL_SAY_HELLO:
{
DbgPrint("[KrnlHW64]IOCTL_SAY_HELLO\n");
status = STATUS_SUCCESS;
break;
}
}
if(status == STATUS_SUCCESS)
pIrp->IoStatus.Information = uOutSize;
else
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return status;
}
//【7】驱动加载的处理例程,里面进行了驱动的初始化工作
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING
pRegistryString)
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING ustrLinkName;
UNICODE_STRING ustrDevName;
PDEVICE_OBJECT pDevObj;
//初始化驱动例程
pDriverObj->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
pDriverObj->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
pDriverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctl;
pDriverObj->DriverUnload = DriverUnload;
RtlInitUnicodeString(&ustrDevName, DEVICE_NAME);
status = IoCreateDevice(pDriverObj, 0, &ustrDevName, FILE_DEVICE_UNKNOWN,
0, FALSE, &pDevObj);
if(!NT_SUCCESS(status)) return status;
if(IoIsWdmVersionAvailable(1, 0x10))
RtlInitUnicodeString(&ustrLinkName, LINK_GLOBAL_NAME);
else
RtlInitUnicodeString(&ustrLinkName, LINK_NAME);
//创建符号链接
status = IoCreateSymbolicLink(&ustrLinkName, &ustrDevName);
if(!NT_SUCCESS(status))
{
IoDeleteDevice(pDevObj);
return status;
}
//走到这里驱动实际上已经初始化完成,下面添加的是功能初始化的代码
DbgPrint("[KrnlHW64]DriverEntry\n");
return STATUS_SUCCESS;
}
编译驱动:
1.打开『 x64 Free Build Environment 』:
2.切换到源码目录(假设源码目录是: z:\sys ),并输入 BUILD 编译:
3.如果看到『 1 executable built 』字眼,则证明编译成功。
4.驱动的编译跟目录下的 source 文件有关系,比如本例中,它的内容如下(注意不要手贱把空行去掉了,否则可能会导致无法编译):
TARGETNAME=KrnlHW64 <-驱动的文件的名称,一般来说修改这个就行了 TARGETTYPE=DRIVER <-编译的类型 TARGETPATH=obj INCLUDES=.\ SOURCES = MyDriver.c <-多个C文件时,把所有C文件的名称分成多行写
测试驱动前的准备:
1.以管理员权限运行 DBGVIEW 。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session
Manager\Debug
Print Filter的 Default 值修改为 ffffffff
3.打开 DBGVIEW 并把以下选项全部勾上:
标准的驱动测试方法:
1.打开虚拟机,进入双机调试的环境(忘记了就参考上节课的内容)。
2.运行 KmdMgr.exe ,把 SYS 拖动到文本框里。
3.点击 “Register” 和 “Run” 按钮,看看输出是否提示成功。如果成功会有类似的输出:
4.运行 WIN64AST ,点击内核模块,查看驱动是否已经存在于内核里了:
“I/O
Control”
按钮,如果成功会有类似的输出:
6. 点击 “Unregister” 和 “Stop” 按钮,如果成功会有类似的输出:
很显然,用标准方法测试一个驱动是很麻烦且很耗时的。双机调试非常占用系统资源,虽然我的电脑配置较好( 2600K+16GB 内存),但是在操作虚拟机时,仍然感到了明显的卡顿。下面介绍一种用特殊 工具 测试驱动的方法,无需双机调试,甚至无需使用虚拟机。
用 WIN64UDL 测试驱动:
1.运行 WIN64UDL 。
2.把驱动文件拖进 WIN64UDL 里,然后按下 ENTER 加载。
3.再按一次 ENTER 卸载驱动。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
An Introduction to the Analysis of Algorithms
Robert Sedgewick、Philippe Flajolet / Addison-Wesley Professional / 1995-12-10 / CAD 67.99
This book is a thorough overview of the primary techniques and models used in the mathematical analysis of algorithms. The first half of the book draws upon classical mathematical material from discre......一起来看看 《An Introduction to the Analysis of Algorithms》 这本书的介绍吧!