编写自己的驱动加载程序
最近想自己写个驱动加载程序。(平常用的加载程序不能拖动选择文件)
于是梳理一下驱动加载的两种方法
代码和程序也贴在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,//TagIdNULL,//依存关系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,//TagIdNULL,//依存关系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加载的效果是一样的。
编外:
在写MFC的时候,为了实现拖放文件来获取文件路径的功能,众所周知添加AcceptFile等属性即可,但是我在vs2017&win10的开发环境下却没有效果,后来查询得知,可能是被win10的安全措施屏蔽了。需要在初始化的时候加上如下代码
复制代码 隐藏代码
ChangeWindowMessageFilter(WM_DROPFILES, MSGFLT_ADD);//解决Win10下的拖放文件问题
ChangeWindowMessageFilter(0x0049, MSGFLT_ADD);
由于打开服务管理器需要特权,我们在vs的配置调试->属性->链接器->清单文件中
把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.lanzous.com/i3a4yhi 密码:happy
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
