吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8377|回复: 5
收起左侧

[其他转载] 编写自己的驱动加载程序

  [复制链接]
pcy190 发表于 2019-2-27 23:30
本帖最后由 pcy190 于 2019-3-1 16:18 编辑

最近想自己写个驱动加载程序。(平常用的加载程序不能拖动选择文件)
于是梳理一下驱动加载的两种方法
代码和程序也贴在github一份。

一般加载驱动的步骤为

  • 打开服务控制器
  • 根据任务条件创建服务
  • 打开设备或服务
  • 设置设备或者服务的状态.
  • 清理工作(关闭服务或者设备的句柄)

需要的函数:
通过OpenSCManager函数打开SCM,获取其句柄
通过CreateService函数利用SCM句柄创建一个服务
通过ControlService传入的标志位安装启动服务等等。

两步安装驱动:

SC_HANDLE sh = OpenSCManager(
  NULL,   // 机器名称,NULL表示本机.
NULL,     // 设备管理器数据库,NULL表示默认值
  SC_MANAGER_ALL_ACCESS    // 打开的权限
);
SC_HANDLE m_hServiceDDK = CreateService(
                sh,//SCManager句柄
                DriverName.c_str(),//驱动服务名称
                DriverName.c_str(),//驱动服务显示名称
                SERVICE_ALL_ACCESS,//访问权限
                SERVICE_KERNEL_DRIVER,//服务类型(驱动程序)
                SERVICE_DEMAND_START,//启动方式(需要时启动,注册表驱动程序的Start值)
                SERVICE_ERROR_IGNORE,//错误忽略
                szFilePath,//驱动程序文件路径
                NULL,//加载组命令
                NULL,//TagId
                NULL,//依存关系
                NULL,//服务启动名
                NULL);//密码

这两个函数做完后,核心的安装就完成了。
启动驱动

BOOL WINAPI StartService(
      _In_     SC_HANDLE hService,
      _In_     DWORD     dwNumServiceArgs,
      _In_opt_ LPCTSTR   *lpServiceArgVectors
);

控制状态,停止驱动

m_hServiceDDK = OpenService(sh, DriverName.c_str(), SERVICE_STOP);
        SERVICE_STATUS svcsta = { 0 };
        BOOL bRet = ControlService(m_hServiceDDK, SERVICE_CONTROL_STOP, &svcsta);

卸载驱动

m_hServiceDDK = OpenService(sh, DriverName.c_str(), SERVICE_STOP | DELETE);
DeleteService(m_hServiceDDK);

在返回结果异常的判断GetLastError()中,加入了几个常见的判断

ERROR_SERVICE_ALREADY_RUNNING
ERROR_SERVICE_NOT_FOUND
ERROR_SERVICE_NEVER_STARTED
ERROR_SERVICE_NOT_ACTIVE
ERROR_SERVICE_DOES_NOT_EXIST
  • 代码比较长,先贴一下安装代码,其余的可以在附件查看

    void CDriverLoaderDlg::OnBnClickedButtonInstall()
    {
    
        if (wcslen(szFilePath)==0)
        {
                Msg(_T("请选择文件"));
                return;
        }
        size_t pos = wstring(szFilePath).find_last_of('\\');
        DriverName.assign(wstring(szFilePath).substr(pos + 1));
    
        sh = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
        if (!sh)
        {
                Msg(_T("打开服务控制器失败,请检查是否以管理员权限运行"));
                CloseServiceHandle(sh);
                return;
        }
        Msg(CString(DriverName.c_str()));
        SC_HANDLE m_hServiceDDK = CreateService(
                sh,//SMC句柄
                DriverName.c_str(),//驱动服务名称(驱动程序的在注册表中的名字)
                DriverName.c_str(),//驱动服务显示名称(注册表驱动程序的DisplayName值)
                SERVICE_ALL_ACCESS,//权限(所有访问权限)
                SERVICE_KERNEL_DRIVER,//服务类型(驱动程序)
                SERVICE_DEMAND_START,//启动方式(需要时启动,注册表驱动程序的Start值)
                SERVICE_ERROR_IGNORE,//错误控制(忽略,注册表驱动程序的ErrorControl值)
                szFilePath,//服务的二进制文件路径(驱动程序文件路径, 注册表驱动程序的ImagePath值)
                NULL,//加载组命令
                NULL,//TagId
                NULL,//依存关系
                NULL,//服务启动名
                NULL);//密码
        if (!m_hServiceDDK)
        {
                if (GetLastError() == ERROR_SERVICE_EXISTS)
                {
                        Msg(_T("驱动已经存在"));
                        if(!m_hServiceDDK)m_hServiceDDK = OpenService(sh, DriverName.c_str(), SERVICE_ALL_ACCESS);
                }
                else {
                        TCHAR msg[100];
                        wprintf_s(msg, "安装失败,错误码 %p", GetLastError());
                        Msg(msg);
    
                        Msg(_T("Error while Install ,error code:" + GetLastError()));
                        MessageBox(NULL, DriverName.c_str(),  MB_OK);
                }
    
        }
        else {
                Msg(_T("驱动安装成功!"));
        }
        CloseServiceHandle(sh);
        CloseServiceHandle(m_hServiceDDK);
    }
  • 效果(目标平台win10)
    最后和普通的monitor加载的效果是一样的。
    https://upload-images.jianshu.io/upload_images/13348817-1cffcb454efc67b5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240

编外:
  • 在写MFC的时候,为了实现拖放文件来获取文件路径的功能,众所周知添加AcceptFile等属性即可,但是我在vs2017&win10的开发环境下却没有效果,后来查询得知,可能是被win10的安全措施屏蔽了。需要在初始化的时候加上如下代码
    ChangeWindowMessageFilter(WM_DROPFILES, MSGFLT_ADD);//解决Win10下的拖放文件问题
        ChangeWindowMessageFilter(0x0049, MSGFLT_ADD);
  • 由于打开服务管理器需要特权,我们在vs的配置调试->属性->链接器->清单文件
    https://upload-images.jianshu.io/upload_images/13348817-c7290ffbada536c3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240
    UAC执行级别改成如图所示即可。

通过ZwSetSystemInformation加载驱动

这个是RootKits的技术。
ZwSetSystemInformation函数是个未公开的函数,调用38号则会加载驱动。
原型如下

typedef NTSTATUS(__stdcall *ZwSetSystemInformation)(
        IN DWORD SystemInformationClass,
        IN OUT PVOID SystemInformation,
        IN ULONG SystemInformationLength
        );

我们需要手动获取函数的地址
RtlInitUnicodeString,ZwSetSystemInformation

这种方法的特性是比较简便隐秘,相比上一个方法不会在进程中主动查找服务管理器等敏感API。但是,这种方法没有提供卸载的特性,驱动加载后,只能通过重启系统来卸载。

const INT SystemLoadAndCallImage = 38;
typedef struct  _UNICODE_STRING {

        USHORT Length;
        USHORT MaximumLength;
        PWCH   Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

typedef struct _SYSTEM_LOAD_AND_CALL_IMAGE {
        UNICODE_STRING ModuleName;
} SYSTEM_LOAD_AND_CALL_IMAGE, *PSYSTEM_LOAD_AND_CALL_IMAGE;

typedef void(*RTLINITUNICODESTRING)(
        PUNICODE_STRING DestinationString,
        PCWSTR          SourceString
        );

typedef NTSTATUS(__stdcall *ZwSetSystemInformation)(
        IN DWORD SystemInformationClass,
        IN OUT PVOID SystemInformation,
        IN ULONG SystemInformationLength
        );

bool load(PWCHAR path) {
        SYSTEM_LOAD_AND_CALL_IMAGE Images;
        RTLINITUNICODESTRING RtlInitUnicodeString;
        ZwSetSystemInformation fZwSetSystemInformation;
        if (!(RtlInitUnicodeString = (RTLINITUNICODESTRING)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "RtlInitUnicodeString")))
                return false;
        if (!(fZwSetSystemInformation = (ZwSetSystemInformation)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "ZwSetSystemInformation")))
                return false;
        RtlInitUnicodeString(&(Images.ModuleName), path);
        if (!NT_SUCCESS(fZwSetSystemInformation(SystemLoadAndCallImage, &Images, sizeof(SYSTEM_LOAD_AND_CALL_IMAGE))))
                return false;
        return true;
}
//注意path的格式,和普通的ring0读设备的路径一个问号不同的是
//这里有两个问号,以\\??\\开头,后面是驱动路径。例如\\??\\C:\\YOURDRIVERPATH.sys


最后,virscan安全检测一下


源代码和二进制文件
https://github.com/pcy190/DriverKit/tree/master/DriverLoader

网盘链接
下载: https://www.lanzouj.com/i3a4yhi 密码:happy

免费评分

参与人数 3吾爱币 +7 热心值 +2 收起 理由
yaoshan + 1 谢谢@Thanks!
xindelangmaney + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
苏紫方璇 + 5 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

wozzi 发表于 2019-2-28 23:15
感谢分享,收藏
mashan2014 发表于 2019-3-2 13:55
独霸首席 发表于 2019-7-22 10:27
M60 发表于 2019-7-22 11:17
感谢分享!
_退隐帆海 发表于 2019-8-8 12:04
感谢分享,学习到了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-16 14:40

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表