• 编写简单的 NT 式驱动程序的加载与卸载工具


    写驱动的加载需要用到五个函数:

    OpenSCManager()

    CreateService()

    OpenService()

    StartService()

    CloseServiceHandle()

    这五个函数的作用和用法,我在代码中会进行说明。

    正常加载驱动的步骤如下:

    1、调用 OpenSCManager 这个 Win32 API 函数来打开 SCM 服务管理器,如果返回值为:NULL,则表示打开失败,否则表示打开成功并继续下一步执行。

    2、调用 CreateService 这个 Win32 API 函数来创建服务,然后用 GetLastError 函数获取返回值,如果返回值为:ERROR_IO_PENDING,则说明服务已经创建过。

    3、然后,此时用 OpenService 这个 Win32 API 函数打开此服务。

    4、调用 StartService 这个 Win32 API 函数来开启此服务。

    5、最后调用 CloseServiceHandle() 对错误信息进行一个简单的处理。

    当我点击加载驱动按钮后,弹出打开文件对话框,然后选择驱动文件,进行加载这个过程我写在 Load Driver 按钮的单击事件中。

    下面看代码:

    static CStringW DriverName;  //保存驱动名称的全局变量
    CEdit * pEditA;
    CString CirLf,AddEditSrt;

    BOOL LoadNTDriver(WCHAR* pDriverName, WCHAR* pDriverPathName);
    void CLoadDriverToolsDlg::On_btnLoadD_Clicked()
    {        
        CEdit * pEdit =(CEdit*)GetDlgItem(IDC_txtGetSysName); //获取 EDIT 控件的句柄,并转换成 CEdit 控件类指针
        pEditA = pEdit;    
        CirLf = ".
    ";  // 
    表示换行
    
        WCHAR *Filters = L"All File(*.*)|*.*|Driver File(*.sys)|*.sys|";
        WCHAR *DefaultFileter = L"All File(*.*)|*.*|";
        WCHAR *DefaultFileName = L"请选择驱动文件";
    
        /*CFileDialog 类封装了Windows常用的文件对话框。常用的文件对话框提供了文件打开和文件存盘对话框功能。
        DoModal 代表这个窗口变成当前窗口,而且此函数一直阻塞知道你点OK或者Cancel退出,如果点的时候OK,该函数返回值为IDOK。
        IDOK 按钮默认响应CDialog::OnOK();这个虚函数。这个函数调用EndDialog(IDOK);EndDialog设置对话框返回值,IDOK就是返回值。*/
        CFileDialog FileDlg(true, DefaultFileter, DefaultFileName, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, Filters, NULL);
        if (FileDlg.DoModal() == IDOK){
            DriverName =  FileDlg.GetFileName();
            pEditA->SetWindowTextW(AddEditSrt += L"打开的驱动名称为:" + DriverName + CirLf);
            
        }    
        
        /*能GetBuffer函数,说明这个函数是为一个CString对象,可重新获取其内部字符缓冲区的指针,
        返回的LPTSTR为非const的,从而允许直接修改CString中的内容,里面的参数表示缓冲区的大小*/
        WCHAR *DriverNameBuffer = DriverName.GetBuffer(DriverName.GetLength());
        BOOL Status =LoadNTDriver(DriverNameBuffer, FileDlg.GetPathName().GetBuffer(256));
        if (Status == false){    
            printf("服务启动失败!!错误代码为:%d 
    ", GetLastError());
            MessageBox(L"服务启动失败!!", L"消息框", MB_OK);
        }
        else{
            printf("服务启动成功! 
    ");
            MessageBox(L"服务启动成功!", L"消息框", MB_OK);
            Status = true;
        }
    
    }
     

    这里有个自定义的驱动加载函数,并传递了两个参数,一个驱动名称,一个驱动路径。而整个加载的过程,可以写在头文件里面,我这里就直接写在源文件中,

    下面看代码:

    BOOL LoadNTDriver(WCHAR* pDriverName, WCHAR* pDriverPathName){
        BOOL Status = false;
        SC_HANDLE hServiceManager = NULL;
        SC_HANDLE hServiceDriver = NULL;
    
        //打开服务管理器
        hServiceManager = OpenSCManager(
            NULL,                    //指定目标计算机的名称。如果该指针为NULL ,就连接到本地主机的服务控制器。
            SERVICES_ACTIVE_DATABASE, //指定将要打开的服务控制管理数据库的名称。
            SC_MANAGER_CREATE_SERVICE  //如果该指针为NULL ,则打开默认的 SERVICES_ACTIVE_DATABASE
            ); //返回值为服务管理器的句柄
        if (hServiceManager != NULL){
    
            /*TRACE 宏有点象C语言中用的Printf函数,使程序在运行中输出一些调试信息。
            但有一点不同的是:TRACE 宏只有在调试状态下才有所输出,而以前用的Printf 函数在任何情况下都有输出。*/
            printf("打开服务管理器成功! 
    ");
            pEditA->SetWindowTextW(AddEditSrt += L"打开服务管理器成功!" + CirLf);
    
    
            //创建服务
            hServiceDriver = CreateService(
                hServiceManager,        //服务管理器的句柄,由系统函数OpenSCManager 返回
                pDriverName,            //驱动程序在注册表中的名称,最大字符串长度为 256 个字符
                pDriverName,            //被用户界面程序用来识别服务的显示名称。此字符串具有最大长度为 256 个字符。 
                SERVICE_ALL_ACCESS,     //加载驱动程序时所具备的访问权限
                SERVICE_KERNEL_DRIVER,  //服务类型,此枚举表示加载的服务是驱动程序
                SERVICE_DEMAND_START,   //服务启动选项,此枚举表示由服务控制管理器(SCM)启动的服务,也就是需手动启动。
                SERVICE_ERROR_IGNORE,   //当该启动服务失败时产生错误及采取的保护措施, 此枚举表示服务启动程序将忽略该错误并返回继续执行。
                pDriverPathName,        //注册表中驱动程序所在的路径
                NULL,
                NULL,
                NULL,
                NULL,
                NULL
                );   //返回值为服务的句柄    
            if (hServiceDriver != NULL){
                printf("创建服务成功! 
    ");
                pEditA->SetWindowTextW(AddEditSrt += L"创建服务成功!" + CirLf);
    
                //打开创建的服务
                hServiceDriver = OpenService(
                    hServiceManager,     //服务管理器的句柄
                    pDriverName,         //服务的名称
                    SERVICE_ALL_ACCESS   //打开服务所需的访问权限,此枚举为完全权限
                    );   //返回值为服务的句柄
                if (hServiceDriver != NULL){
                    printf("打开服务成功! 
    ");
                    pEditA->SetWindowTextW(AddEditSrt += L"打开服务成功!" + CirLf);
    
                    //启动创建的服务
                    INT reValue = StartService(
                        hServiceDriver,  //要打开的服务的服务句柄
                        NULL,  //服务向量数组中的字符串数量,如果字符串数量为空,该参数可以是零。
                        NULL   //字符串被传递给服务的ServiceMain函数作为参数。如果没有参数,可以为空。
                        );   //如果启动成功返回非零的数,否则返回零                
                    if (reValue != 0){
                        TRACE("启动服务成功! 
    ");
                        pEditA->SetWindowTextW(AddEditSrt += L"启动服务成功!" + CirLf);
                        Status = true;
                        return Status;
                    }
                    else{
                        printf("StartService() Fild %d ! 
    ", GetLastError());
                        pEditA->SetWindowTextW(AddEditSrt += L"启动服务失败!!错误代码为:" + GetLastError() + CirLf);
                        goto a;   //出现错误后,调到a处,进行处理
                    }
                }
                else{
                    printf("OpenService() Fild %d ! 
    ", GetLastError());
                    pEditA->SetWindowTextW(AddEditSrt += L"打开服务失败!!错误代码为:" + GetLastError() + CirLf);
                    goto a;
                }
            }
            else{
                printf("CreateService() Fild %d ! 
    ", GetLastError());
                pEditA->SetWindowTextW(AddEditSrt += L"创建服务失败!!错误代码为:" + GetLastError() + CirLf);
                goto a;
            }
        }
        else{
            printf("OpenSCManager() Fild %d ! 
    ", GetLastError());
            pEditA->SetWindowTextW(AddEditSrt += L"打开服务管理器失败!!错误代码为:" + GetLastError() + CirLf);
            goto a;
        }
    
        //用 CloseServiceHandle 函数来关闭服务管理器或服务
    a:    if (hServiceManager){    //如果打开了服务管理器,就关闭服务管理器
        CloseServiceHandle(hServiceManager);
    }
        if (hServiceDriver){     //如果打开了服务,就关闭服务
            CloseServiceHandle(hServiceDriver);
        }
        return Status;
    }

    好了,加载驱动的过程以编写完毕,下面看下效果:

    新建位图图像

    2

    3

    驱动加载并成功启动!!

    下面我们写一个卸载驱动的过来,让这个工具能加载也能卸载!

    卸载驱动的过程需要用到四个函数:

    OpenSCManager()     //打开服务管理器

    OpenService()             //打开要卸载的服务

    ControlService()        //发送控制命令来停止要卸载的服务

    DeleteService()        //删除要卸载的服务

    同样,当我点击卸载驱动按钮后,就进行卸载,这个过程我写在 Unload Driver 按钮的单击事件中。

    下面看代码:

    BOOL UnloadNTDriver(WCHAR* lpDriverName);
    void CLoadDriverToolsDlg::On_btnUnloadD_Clicked()
    {
        
        BOOL Status = UnloadNTDriver(DriverName.GetBuffer(DriverName.GetLength()));
        if (Status = true){
            printf("服务卸载成功!
    ");
            MessageBox(L"服务卸载成功!", L"消息框", MB_OK);
        }
        else{
            printf("服务卸载失败!!错误代码为:%d 
    ",GetLastError());
            MessageBox(L"服务卸载失败!!", L"消息框", MB_OK);
        }
    }

    这里有个自定义的驱动卸载函数,并传递了一个参数,一个驱动名称的缓冲区指针。而整个卸载过程,可以写在头文件里面,我这里就直接写在源文件中,

    下面看代码:

    BOOL UnloadNTDriver(WCHAR* lpDriverName){
        BOOL Status = false;
        SC_HANDLE hServiceManager = NULL;
        SC_HANDLE hServiceDriver = NULL;
        SERVICE_STATUS SaveValue;      // SERVICE_STATUS 显示了服务器上运行的服务状态信息。
    
    
        //打开服务管理器
        hServiceManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CREATE_SERVICE);
        if (hServiceManager != NULL){
            printf("服务管理器打开成功!
    ");
            pEditA->SetWindowTextW(AddEditSrt += L"服务管理器打开成功!" + CirLf);
    
            //打开服务
            hServiceDriver = OpenService(hServiceManager, lpDriverName, SERVICE_ALL_ACCESS);
            if (hServiceDriver != NULL){
                printf("服务打开成功!
    ");
                pEditA->SetWindowTextW(AddEditSrt += L"服务打开成功!" + CirLf);
                int StatusValue;
    
                //想要顺利卸载驱动,必先停止驱动,所以用ControlService函数发送控制命令.
                StatusValue = ControlService(hServiceDriver, SERVICE_CONTROL_STOP, &SaveValue);
                if (StatusValue > 0){
                    printf("服务停止成功!
    ");
                    pEditA->SetWindowTextW(AddEditSrt += L"服务停止成功!" + CirLf);
                    /*我们把 ControlService 函数读出的 SERVICE_STATUS 服务状态信息打印出来看看,
                    上面,我们以保存在 SaveValue 这个变量中了,所以现在只需读取这个变量就行。*/
                    printf("停止服务的过程已经执行了,那现在的状态是:=%d 
    ", &SaveValue);
    
                    //卸载驱动,此函数从服务控制管理器数据库删除指定的服务
                    StatusValue = DeleteService(hServiceDriver);
                    if (StatusValue > 0){
                        printf("服务卸载成功!
    ");
                        pEditA->SetWindowTextW(AddEditSrt += L"服务卸载成功!" + CirLf);
                        Status = true;
                        return Status;
                    }
                    else{
                        printf("服务卸载失败!!错误代码为:=%d 
    ", GetLastError());
                        pEditA->SetWindowTextW(AddEditSrt += L"服务卸载失败!!错误代码为:" + GetLastError() + CirLf);
                        goto b;
                    }
                }
                else{
                    printf("服务停止失败!!错误代码为:=%d 
    ", GetLastError());
                    pEditA->SetWindowTextW(AddEditSrt += L"服务停止失败!!错误代码为:" + GetLastError() + CirLf);
                    goto b;
                }
            }
            else{
                printf("服务打开失败!!错误代码为:=%d 
    ", GetLastError());
                pEditA->SetWindowTextW(AddEditSrt += L"服务打开失败!!错误代码为:" + GetLastError() + CirLf);
                goto b;
            }
        }
        else{
            printf("服务管理器打开失败!!错误代码为:=%d 
    ", GetLastError());
            pEditA->SetWindowTextW(AddEditSrt += L"服务管理器打开失败!!错误代码为:" + GetLastError() + CirLf);
            goto b;
        }
    
        //如果出现错误,就对句柄进行处理
    b:  if (hServiceManager){
        CloseServiceHandle(hServiceManager);
    }
        if (hServiceDriver){
            CloseServiceHandle(hServiceDriver);
        }
        return Status;
    }

    大功告成!!验证结果见下图:

    2

  • 相关阅读:
    Yaf 在 Nginx 中的配置
    关于 GPG 用这个 就够 了
    PHP 服务器端处理跨域问题
    Linux 终端代理方式
    【转载】Oracle数据字典详解
    【转载】Oracle之内存结构(SGA、PGA)
    【转载】 使用rman进行坏块修复(ORA-01578、ORA-01110)
    【转载】使用Exp和Expdp导出数据的性能对比与优化
    【转载】oracle dbms_metadata.get_ddl的使用方法总结
    ORACLE执行详解
  • 原文地址:https://www.cnblogs.com/lfls128/p/4998549.html
Copyright © 2020-2023  润新知