zoukankan      html  css  js  c++  java
  • Win64 驱动内核编程-2.基本框架(安装.通讯.HelloWorld)

    驱动安装,通讯,Hello World

    开发驱动的简单流程是这样,开发驱动安装程序,开发驱动程序,然后安装程序(或者其他程序)通过通讯给驱动传命令,驱动接到之后进行解析并且执行,然后把执行结果返回。

    驱动程序Hello World

    之前总结了驱动环境的搭建,这里就直接继续之前搭建好的环境创建项目,打开vs2015创建一个驱动项目:



    写代码之前先配置下编译选项:


    然后添加一个项目文件main.c(注意后缀是.c,前面名字无所谓可以不叫main),里面的内容如下(下面模板代码来源于网络,作者:胡文亮,我是在看他的资料学习,感谢这位前辈。)

    /*
    WIN64驱动开发模板
    作者:Tesla.Angela
    */
     
    //【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
    ");
    //获得IRP里的关键数据
    pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
    //这个就是传说中的控制码
    uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
    //输入和输出的缓冲区(DeviceIoControl的InBuffer和OutBuffer都是它)
    pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
    //EXE发送传入数据的BUFFER长度(DeviceIoControl的nInBufferSize)
    uInSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
    //EXE接收传出数据的BUFFER长度(DeviceIoControl的nOutBufferSize)
    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 = STATUS_SUCCESS;
    break;
    }
    case IOCTL_SAY_HELLO:
    {
    DbgPrint("[KrnlHW64]IOCTL_SAY_HELLO
    ");
    status = STATUS_SUCCESS;
    break;
    }
    }
    //这里设定DeviceIoControl的*lpBytesReturned的值(如果通信失败则返回0长度)
    if(status == STATUS_SUCCESS)
    pIrp->IoStatus.Information = uOutSize;
    else
    pIrp->IoStatus.Information = 0;
    //这里设定DeviceIoControl的返回值是成功还是失败
    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;
    //判断支持的WDM版本,其实这个已经不需要了,纯属WIN9X和WINNT并存时代的残留物
    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安装。具体流程是:


    然后这个函数要仔细看定义:


    更详细的细节之前看MSDN吧。

    然后还是把资料上的模板代码直接拿过来,注意目前先用这个模板,因为这个安装模板是和上面的那个Hello World对应的,等看懂之后了,在自己定义相关驱动安装和驱动程序的代码,也可以自己写个模板,这里先不自己随便定义,可能会导致链接名字,驱动名字,还有驱动通讯的那个地方的细节自己弄乱了。这个博客看完了再回头定义自己的就行。

    创建C++工程,然后直接添加安装代码和安装测试代码:

    功能代码:

    /*============================
    Drvier Control Class (SCM way)
    ============================*/
     
    #pragma comment(lib,"advapi32.lib")
     
    class cDrvCtrl
    {
    public:
    cDrvCtrl()
    {
    m_pSysPath = NULL;
    m_pServiceName = NULL;
    m_pDisplayName = NULL;
    m_hSCManager = NULL;
    m_hService = NULL;
    m_hDriver = INVALID_HANDLE_VALUE;
    }
    ~cDrvCtrl()
    {
    CloseServiceHandle(m_hService);
    CloseServiceHandle(m_hSCManager);
    CloseHandle(m_hDriver);
    }
    public:
    DWORD m_dwLastError;
    PCHAR m_pSysPath;
    PCHAR m_pServiceName;
    PCHAR m_pDisplayName;
    HANDLE m_hDriver;
    SC_HANDLE m_hSCManager;
    SC_HANDLE m_hService;
    public:
    BOOL Install(PCHAR pSysPath,PCHAR pServiceName,PCHAR pDisplayName);
    BOOL Start();
    BOOL Stop();
    BOOL Remove();
    BOOL Open(PCHAR pLinkName);
    BOOL IoControl(DWORD dwIoCode, PVOID InBuff, DWORD InBuffLen, PVOID OutBuff, DWORD OutBuffLen, DWORD *RealRetBytes);
    private:
    BOOL GetSvcHandle(PCHAR pServiceName);
    DWORD CTL_CODE_GEN(DWORD lngFunction);
    protected:
    //null
    };
     
    BOOL cDrvCtrl::GetSvcHandle(PCHAR pServiceName)
    {
    m_pServiceName = pServiceName;
    m_hSCManager = OpenSCManagerA(NULL,NULL,SC_MANAGER_ALL_ACCESS);
    if (NULL == m_hSCManager)
    {
    m_dwLastError = GetLastError();
    return FALSE;
    }
    m_hService = OpenServiceA(m_hSCManager,m_pServiceName,SERVICE_ALL_ACCESS);
    if (NULL == m_hService)
    {
    CloseServiceHandle(m_hSCManager);
    return FALSE;
    }
    else
    {
    return TRUE;
    }
    }
     
    BOOL cDrvCtrl::Install(PCHAR pSysPath,PCHAR pServiceName,PCHAR pDisplayName)
    {
    m_pSysPath = pSysPath;
    m_pServiceName = pServiceName;
    m_pDisplayName = pDisplayName;
    m_hSCManager = OpenSCManagerA(NULL,NULL,SC_MANAGER_ALL_ACCESS);
    if (NULL == m_hSCManager)
    {
    m_dwLastError = GetLastError();
    return FALSE;
    }
    m_hService = CreateServiceA(m_hSCManager,m_pServiceName,m_pDisplayName,
                                SERVICE_ALL_ACCESS,SERVICE_KERNEL_DRIVER,SERVICE_DEMAND_START,SERVICE_ERROR_NORMAL,
                                m_pSysPath,NULL,NULL,NULL,NULL,NULL);
    if (NULL == m_hService)
    {
    m_dwLastError = GetLastError();
    if (ERROR_SERVICE_EXISTS == m_dwLastError)
    {
    m_hService = OpenServiceA(m_hSCManager,m_pServiceName,SERVICE_ALL_ACCESS);
    if (NULL == m_hService)
    {
    CloseServiceHandle(m_hSCManager);
    return FALSE;
    }
    }
    else
    {
    CloseServiceHandle(m_hSCManager);
    return FALSE;
    }
    }
    return TRUE;
    }
     
    BOOL cDrvCtrl::Start()
    {
    if (!StartServiceA(m_hService,NULL,NULL))
    {
    m_dwLastError = GetLastError();
    return FALSE;
    }
    return TRUE;
    }
     
    BOOL cDrvCtrl::Stop()
    {
    SERVICE_STATUS ss;
    GetSvcHandle(m_pServiceName);
    if (!ControlService(m_hService,SERVICE_CONTROL_STOP,&ss))
    {
    m_dwLastError = GetLastError();
    return FALSE;
    }
    return TRUE;
     
    }
     
    BOOL cDrvCtrl::Remove()
    {
    GetSvcHandle(m_pServiceName);
    if (!DeleteService(m_hService))
    {
    m_dwLastError = GetLastError();
    return FALSE;
    }
    return TRUE;
    }
     
    BOOL cDrvCtrl::Open(PCHAR pLinkName)//example: \\.\xxoo
    {
    if (m_hDriver != INVALID_HANDLE_VALUE)
    return TRUE;
    m_hDriver = CreateFileA(pLinkName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    if(m_hDriver != INVALID_HANDLE_VALUE)
    return TRUE;
    else
    return FALSE;
    }
     
    BOOL cDrvCtrl::IoControl(DWORD dwIoCode, PVOID InBuff, DWORD InBuffLen, PVOID OutBuff, DWORD OutBuffLen, DWORD *RealRetBytes)
    {
    DWORD dw;
    BOOL b=DeviceIoControl(m_hDriver,CTL_CODE_GEN(dwIoCode),InBuff,InBuffLen,OutBuff,OutBuffLen,&dw,NULL);
    if(RealRetBytes)
    *RealRetBytes=dw;
    return b;
    }
     
    DWORD cDrvCtrl::CTL_CODE_GEN(DWORD lngFunction)
    {
    return (FILE_DEVICE_UNKNOWN * 65536) | (FILE_ANY_ACCESS * 16384) | (lngFunction * 4) | METHOD_BUFFERED;
    }
     

    测试代码:

    // DriverInstall.cpp : 定义控制台应用程序的入口点。
    //
     
    #include "stdafx.h"
    #include <string>
    #include <windows.h>
    #include "ScmDrvCtrl.h"
     
    #pragma warning(disable:4996)
     
    #pragma comment(lib,"user32.lib")
     
    using namespace std;
     
     
    void GetAppPath(char *szCurFile) //最后带斜杠
    {
    GetModuleFileNameA(0, szCurFile, MAX_PATH);
    for (SIZE_T i = strlen(szCurFile) - 1; i >= 0; i--)
    {
    if (szCurFile[i] == '\')
    {
    szCurFile[i + 1] = '';
    break;
    }
    }
    }
     
    int main()
    {
    BOOL b;
    cDrvCtrl dc;
    //设置驱动名称
    char szSysFile[MAX_PATH] = { 0 };
    char szSvcLnkName[] = "KrnlHW64";;
    GetAppPath(szSysFile);
    strcat(szSysFile, "KrnlHW64.sys");
    //安装并启动驱动
    b = dc.Install(szSysFile, szSvcLnkName, szSvcLnkName);
    b = dc.Start();
    printf("LoadDriver=%d
    ", b);
    //“打开”驱动的符号链接
    dc.Open("\\.\KrnlHW64");
    //使用控制码控制驱动(0x800:传入一个数字并返回一个数字)
    DWORD x = 100, y = 0, z = 0;
    dc.IoControl(0x800, &x, sizeof(x), &y, sizeof(y), &z);
    printf("INPUT=%ld
    OUTPUT=%ld
    ReturnBytesLength=%ld
    ", x, y, z);
    //使用控制码控制驱动(0x801:在DBGVIEW里显示HELLOWORLD)
    dc.IoControl(0x801, 0, 0, 0, 0, 0);
    //关闭符号链接句柄
    CloseHandle(dc.m_hDriver);
    //停止并卸载驱动
    b = dc.Stop();
    b = dc.Remove();
    printf("UnloadDriver=%d
    ", b);
    getchar();
    return 0;
    }

    然后就直接本地尝试调试安装一次,结果先是这个:


    不用管它,点击全部允许,但是还是会发现

     

    还是装不上,其实是肯定装不上的。原因是64位机器需要的强制签名加载驱动:


    注意最后面那句,各种系统的防护已经被攻克,他没有说win10,不过目前已经亲测win10也已经攻克,之后有机会再说这些东西,这里只讨论正常安装。想在win64上安装无签名驱动也可以,如果是win7,直接cmd 输入  bcdedit /set testsigning on ,然后重启电脑(win7是这样,win10貌似是前面要多输入一条命令,如果是要win10的话自己搜下吧,同时还有其他改设置关掉无签名驱动提示等的设置,加载测试驱动程序,需要的也可以找找,网上很多)。设置后上面的配置之后,重启电脑:

     

    有的时候会有测试模式水印,有的时候没有,可能提示不是正版的话会没这个水印,不过这不重要,只要相面的那个cmd命令执行成功,重启电脑就可以加载无签名64位驱动了。

    接下来测试下我们上面的那一套代码(所有程序都右键管理员启动):

    先打开dbgview全都选上:


    然后启动安装程序:


    OK驱动加载成功,并且通讯测试成功。这里基本模板就算完事了,之后就是一些常用的驱动开发,后续再整理。

  • 相关阅读:
    Algorithm Gossip (48) 上三角、下三角、对称矩阵
    .Algorithm Gossip (47) 多维矩阵转一维矩阵
    Algorithm Gossip (46) 稀疏矩阵存储
    Algorithm Gossip (45) 费氏搜寻法
    Algorithm Gossip (44) 插补搜寻法
    Algorithm Gossip (43) 二分搜寻法
    Algorithm Gossip (42) 循序搜寻法(使用卫兵)
    Algorithm Gossip (41) 基数排序法
    Algorithm Gossip (40) 合并排序法
    AlgorithmGossip (39) 快速排序法 ( 三 )
  • 原文地址:https://www.cnblogs.com/csnd/p/12062052.html
Copyright © 2011-2022 走看看