内容简介:配置好驱动测试环境后,就可以正式编写驱动了。市面上讲解驱动开发的书籍汗牛充栋,但讲得较为太复杂,让初学者不好理解。本文从一个简单的本文主角:(不得不说,此人长得帅,编程技术又牛,让多少男人羡慕妒忌,让多少女人一见倾心)。
配置好驱动测试环境后,就可以正式编写驱动了。市面上讲解驱动开发的书籍汗牛充栋,但讲得较为太复杂,让初学者不好理解。本文从一个简单的 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 卸载驱动。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
应用Rails进行敏捷Web开发
Dave Thomas, David Hansson等 / 林芷薰 / 电子工业出版社 / 2006-7 / 65.00元
这是第一本关于Ruby on Rails的著作。 全书主要内容分为两大部分。在“构建应用程序”部分中,读者将看到一个完整的“在线购书网站” 示例。在演示的过程中,作者真实地再现了一个完整的迭代式开发过程,让读者亲身体验实际应用开发中遇到的各种问题、以及Rails如何有效解决这些问题。在随后的“Rails框架”部分中,作者深入介绍了Rails框架的各个组成部分。尤为值得一提的是本部分的后几章......一起来看看 《应用Rails进行敏捷Web开发》 这本书的介绍吧!