[1]编程实现加载驱动

  • 加载驱动的  标准方法 只有一种,就是利用服务管理器函数加载----SCM 加载法。

 

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
"); 
    RtlInitUnicodeString(&strLink, LINK_NAME);  IoDeleteSymbolicLink(&strLink);
    IoDeleteDevice(pDriverObj->DeviceObject);
}

//【4】IRP_MJ_CREATE对应的处理例程,一般不用管它 
NTSTATUS DispatchCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{ 
    DbgPrint("[KrnlHW64]DispatchCreate
");  
    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
");
    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
");
    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
");   
            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
"); 
    return STATUS_SUCCESS; 
}

使用SCM 系列函数加载卸载驱动的过程并不复杂,总体流程是:打开SCM 管理器(获得SCM 句柄)->创建驱动服务(获得服务句柄,如果服务已经存在,此步则变成打开服务)->启动服务->停止服务->移除服务->关闭服务句柄->关闭SCM 句柄。如果要与驱动通信,则用CreateFile 打开驱动的符号链接(可以理解成获得一个“通信句柄”),然后使DeviceIoControl 与驱动进行信息交互。如果曾经打开过驱动的符号链接,则必须在卸载驱动前关闭“通信句柄”,否则再次加载相同的驱动时会有一些麻烦。

 DeviceIoControl 的参数也很好理解,只有5 个重要参数:控制码,输入缓冲区,输入长度,输出缓冲区,输出长度

 

原文地址:https://www.cnblogs.com/hanhandaren/p/11351711.html