NT式驱动加载器

引言


设备驱动程序的动态加载主要是由服务控制管理程序(Service Control Manager,SCM)系统组件完成,SCM组件可以提供许多服务,如,启动、停止和控制服务。
编写加载驱动程序,主要是操作SCM组件。
一般,操作SCM组件的相关API函数有如下几个:
SC_HANDLE WINAPI OpenSCManager(
  __in_opt  LPCTSTR lpMachineName,//计算机名称
  __in_opt  LPCTSTR lpDatabaseName,//SCM数据库名称
  __in      DWORD dwDesiredAccess//使用权限
);

BOOL WINAPI CloseServiceHandle(
  __in  SC_HANDLE hSCObject //要关闭的SCM句柄
);

SC_HANDLE WINAPI CreateService(
  __in       SC_HANDLE hSCManager, //SCM管理器的句柄
  __in       LPCTSTR lpServiceName, //服务名称
  __in_opt   LPCTSTR lpDisplayName, //服务显示出的名称
  __in       DWORD dwDesiredAccess, //打开权限
  __in       DWORD dwServiceType, //服务类型
  __in       DWORD dwStartType, //打开服务的时间
  __in       DWORD dwErrorControl, //关于错误处理的代码
  __in_opt   LPCTSTR lpBinaryPathName, //二进制文件的代码
  __in_opt   LPCTSTR lpLoadOrderGroup, //用什么用户组开发服务
  __out_opt  LPDWORD lpdwTagId, //输出验证标签
  __in_opt   LPCTSTR lpDependencies, //所依赖的服务名称
  __in_opt   LPCTSTR lpServiceStartName,//用户账户名称
  __in_opt   LPCTSTR lpPassword //用户口令
);

SC_HANDLE WINAPI OpenService(
  __in  SC_HANDLE hSCManager, //SCM数据库的句柄
  __in  LPCTSTR lpServiceName, //服务名称
  __in  DWORD dwDesiredAccess //访问权限
);

BOOL WINAPI ControlService(
  __in   SC_HANDLE hService, //服务的句柄
  __in   DWORD dwControl, //控制码
  __out  LPSERVICE_STATUS lpServiceStatus//返回状态码
); 

文件拖拽

要使对话框支持文件拖拽功能,只需3步即可实现
1> 对话框模版的 Accept Files 属性设置成 True
2> 响应主对话框类的 WM_DROPFILES 消息

3> 添加如下示例代码:

	TCHAR szPath[MAX_PATH] = {0};
	UINT nCount = DragQueryFile(hDropInfo,0xFFFFFFFF, NULL, 0);//文件个数
	for(UINT idx = 0; idx < nCount; ++idx) {
		DragQueryFile(hDropInfo, idx, szPath, MAX_PATH);
		TCHAR * pFind = _tcschr((TCHAR *)szPath, '\\');
		m_strSysFileName=pFind+1;
		m_strSysFilePath=szPath;
	}
	SetDlgItemText(IDC_STATIC_DRIVERPATH,m_strSysFilePath);		
	DragFinish(hDropInfo);
	CDialog::OnDropFiles(hDropInfo);
其中,

CString m_strSysFileName;//驱动名
CString m_strSysFilePath;//驱动路径

均为类的私有成员变量

当API函数DragQueryFile的第二个参数设置为:0xFFFFFFFF时,则函数返回拖动文件的数量

通过DragQueryFile的第三个参数用于保存获取的文件名路径信息,如:C:\test.sys

为了截取文件名(test.sys),可以函数_tcschr进行字符串的截取。

_tcschr函数返回目标字符在指定的字符串中出现的地址(包括目标字符),因此为了去掉反斜杠'\',需要对返回的结果进行加1。

安装驱动

LoadNtSys函数的作用是安装驱动,该函数的执行步骤如下:
  1. 调用OpenSCManager,打开SCM管理器,如果返回NULL,则返回失败,否则继续
  2. 调用CreateService,创建服务
  3. 根据CreateService的返回结果,如果返回NULL,则调用GetLastError获取失败信息,否则创建服务成功
//安装驱动
void CLoadSYSDlg::LoadNtSys()
{
	SC_HANDLE schSCManager;	//SCM管理器的句柄
	SC_HANDLE schService;	//NT驱动程序的服务句柄
	TCHAR szPath[MAX_PATH]={0}; 
	//打开SCM管理器
	schSCManager = OpenSCManager(NULL,//计算机名称
								 NULL,//SCM数据块名称
								 SC_MANAGER_ALL_ACCESS);//使用权限
	if (NULL==schSCManager)
	{
		CString str;
		str.Format(TEXT("OpenSCManager时出错:(%d)"),GetLastError());
		MessageBox(str); 
		return;
	}
	//创建驱动所对应的服务
	schService = CreateService(
								schSCManager,				// SCM database 
								m_strSysFileName,			// 驱动程序的在注册表中的名字
								m_strSysFileName,			// 注册表驱动程序的 DisplayName 值  
								SERVICE_ALL_ACCESS,			// 加载驱动程序的访问权限  
								SERVICE_KERNEL_DRIVER,		// 表示加载的服务是驱动程序  
								SERVICE_DEMAND_START,		// 注册表驱动程序的 Start 值  
								SERVICE_ERROR_IGNORE,		// 注册表驱动程序的 ErrorControl 值  
								m_strSysFilePath,			// 注册表驱动程序的 ImagePath 值  
								NULL,						// no load ordering group 
								NULL,						// no tag identifier 
								NULL,						// no dependencies 
								NULL,						// LocalSystem account 
								NULL);						// no password 

	if (!schService)
	{
		if(ERROR_SERVICE_EXISTS == GetLastError()) //如果服务已经存在
		{
			SetDlgItemText(IDC_STATIC_STATE,TEXT("状态:指定的服务已经存在!"));
		}
		else
		{
			SetDlgItemText(IDC_STATIC_STATE, TEXT("状态:CreateService时出错!")) ;
		}
		return;
	}
	else
		SetDlgItemText(IDC_STATIC_STATE,TEXT("状态:安装服务成功!!"));

	if(schService)CloseServiceHandle(schService) ;
	if(schSCManager)CloseServiceHandle(schSCManager) ;
}

启动驱动

StartNTSys函数的作用是启动驱动,该函数的执行步骤如下:
  1. 调用OpenSCManager,打开SCM管理器,如果返回NULL,则返回失败,否则继续
  2. 调用OpenService,根据服务名和SCM管理器的句柄,打开一个服务。如果返回NULL,则输出失败信息,否则继续
  3. 调用StartService,让指定的服务处于运行状态
  4. 退出前,关闭服务句柄
//启动驱动
void CLoadSYSDlg::StartNTSys()
{
	SC_HANDLE schSCManager;	//SCM管理器的句柄
	SC_HANDLE schService;	//NT驱动程序的服务句柄
	//打开SCM管理器
	schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
	if (NULL==schSCManager)
	{
		CString str;
		str.Format(TEXT("OpenSCManager时出错:(%d)"),GetLastError());
		MessageBox(str); 
		return;
	}
	schService = OpenService(schSCManager, m_strSysFileName, SERVICE_ALL_ACCESS);	
	if(!schService)
	{
		DWORD dwErrorCode = GetLastError() ; //获取错误信息
		if(ERROR_INVALID_NAME == dwErrorCode)
		{
			SetDlgItemText(IDC_STATIC_STATE,_T("状态:服务名无效!"));
		}
		else if(ERROR_SERVICE_DOES_NOT_EXIST == dwErrorCode)
		{
			SetDlgItemText(IDC_STATIC_STATE,_T("状态:不存在此服务!"));
		}
		else
		{ 
			SetDlgItemText(IDC_STATIC_STATE,_T("状态:OpenService时出错!"));
		}
		CloseServiceHandle(schService); //关闭服务句柄
		schSCManager = NULL ;
		return;
	}

	if (StartService(schService, 0, NULL))
	{
		SetDlgItemText(IDC_STATIC_STATE,_T("状态:驱动服务启动成功!"));
	}
	else
	{
		DWORD dwRet = GetLastError();
		if (ERROR_SERVICE_ALREADY_RUNNING==dwRet)
			SetDlgItemText(IDC_STATIC_STATE,_T("状态:指定的服务已经运行!"));
		else
			SetDlgItemText(IDC_STATIC_STATE,_T("状态:运行指定服务出错!"));
	}
	if(schService)CloseServiceHandle(schService) ;
	if(schSCManager)CloseServiceHandle(schSCManager) ;
}

停止驱动

StopNTSys函数的作用是停止驱动,该函数的执行步骤如下:
  1. 调用OpenSCManager,打开SCM管理器,如果返回NULL,则返回失败,否则继续
  2. 调用OpenService,根据服务名和SCM管理器的句柄,打开一个服务。如果返回NULL,则输出失败信息,否则继续
  3. 调用ControlService对指定的服务发送控制码
  4. 关闭服务句柄
BOOL WINAPI ControlService(
__in SC_HANDLE hService, //服务的句柄
__in DWORD dwControl, //控制码
__out LPSERVICE_STATUS lpServiceStatus //返回状态码
);
ControlService函数的作用是对相应的服务,发送控制码,根据不同的控制码操作服务,比如:
SERVICE_CONTROL_CONTINUE:继续服务
SERVICE_CONTROL_PAUSE:暂停服务
SERVICE_CONTROL_STOP:停止服务
//停止驱动
void CLoadSYSDlg::StopNTSys()
{
	SC_HANDLE schSCManager;	//SCM管理器的句柄
	SC_HANDLE schService;	//NT驱动程序的服务句柄
	SERVICE_STATUS status;

	//打开SCM管理器
	schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
	if (NULL==schSCManager)
	{
		CString str;
		str.Format(TEXT("OpenSCManager时出错:(%d)"),GetLastError());
		MessageBox(str); 
		return;
	}
	schService = OpenService(schSCManager, m_strSysFileName, SERVICE_ALL_ACCESS);	
	if(!schService)
	{
		DWORD dwErrorCode = GetLastError() ; //获取错误信息
		if(ERROR_INVALID_NAME == dwErrorCode)
			SetDlgItemText(IDC_STATIC_STATE,_T("状态:服务名无效!"));
		else if(ERROR_SERVICE_DOES_NOT_EXIST == dwErrorCode)
			SetDlgItemText(IDC_STATIC_STATE,_T("状态:不存在此服务!"));
		else
			SetDlgItemText(IDC_STATIC_STATE,_T("状态:OpenService时出错!"));
		CloseServiceHandle(schService); //关闭服务句柄
		schSCManager = NULL ;
		return;
	}
	if(!ControlService(schService, SERVICE_CONTROL_STOP, &status))//停止服务
	{	
		DWORD dwRet = GetLastError();
		if (ERROR_SERVICE_NOT_ACTIVE==dwRet)
			SetDlgItemText(IDC_STATIC_STATE,_T("状态:指定的服务并未启动!"));			
		else
			SetDlgItemText(IDC_STATIC_STATE,_T("状态:不能停止服务!"));			
	}
	else
		SetDlgItemText(IDC_STATIC_STATE,_T("状态:成功停止服务!")); 
	if(schService)CloseServiceHandle(schService) ;
	if(schSCManager)CloseServiceHandle(schSCManager) ;
}

卸载驱动

UnLoadNtSys函数的作用是卸载驱动,该函数的执行步骤如下:
  1. 调用OpenSCManager,打开SCM管理器,如果返回NULL,则返回失败,否则继续
  2. 调用OpenService,根据服务名和SCM管理器的句柄,打开一个服务。如果返回NULL,则输出失败信息,否则继续
  3. 调用DeleteService卸载指定的服务
  4. 关闭服务句柄
//卸载驱动
void CLoadSYSDlg::UnLoadNtSys()
{
	SC_HANDLE schSCManager;	//SCM管理器的句柄
	SC_HANDLE schService;	//NT驱动程序的服务句柄
	//打开SCM管理器
	schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
	if (NULL==schSCManager)
	{
		CString str;
		str.Format(TEXT("OpenSCManager时出错:(%d)"),GetLastError());
		MessageBox(str); 
		return;
	}
	schService = OpenService(schSCManager, m_strSysFileName, SERVICE_ALL_ACCESS);	
	if(!schService)
	{
		DWORD dwErrorCode = GetLastError() ; //获取错误信息
		if(ERROR_INVALID_NAME == dwErrorCode)
		{ 
			SetDlgItemText(IDC_STATIC_STATE,_T("状态:服务名无效!"));
		}
		else if(ERROR_SERVICE_DOES_NOT_EXIST == dwErrorCode)
		{
			SetDlgItemText(IDC_STATIC_STATE,_T("状态:不存在此服务!"));
		}
		else
		{
			SetDlgItemText(IDC_STATIC_STATE,_T("状态:OpenService时出错!"));
		}
	}
	else
	{
		if (!DeleteService(schService))//移除服务
			SetDlgItemText(IDC_STATIC_STATE,_T("状态:驱动服务卸载失败!"));
		else	
			SetDlgItemText(IDC_STATIC_STATE,_T("状态:驱动服务卸载成功!"));
	}	 
	if(schService)CloseServiceHandle(schService) ;
	if(schSCManager)CloseServiceHandle(schSCManager) ;
} 

附件

NT式驱动加载器

版权所有,迎转载,但转载请注明: 转载自  曾是土木人

你可能感兴趣的:(驱动)