標 題: 【原創(chuàng)】編寫軟件動態(tài)加載NT式驅動
作 者: epluguo
時 間: 2013-07-24,23:19:30
鏈 接: http://bbs.pediy.com/showthread.php?t=176028
NT式設備驅動程序的動態(tài)加載主要是由服務控制管理程序(Service Control Manager,即SCM)系統(tǒng)組件來完成的。
Windwos服務可以在系統(tǒng)啟動時加載,用戶也可以按需在服務控制平臺開啟或者關閉服務。程序員可以通過Windows提供的相關服務函數(shù)進行加載或者卸載該服務等。服務程序更是可以在用戶還沒有登錄系統(tǒng)的時候,就載入系統(tǒng)并且被執(zhí)行。
加載NT驅動一般分為4個步驟:1. 調用OpenSCManager打開SCM管理器;
2. 調用CreateService創(chuàng)建服務;如果存在則調用OpenService打開服務(可根據(jù)GetLastError判斷);
3. 調用StartService開啟服務;
4. 關閉句柄。
卸載NT驅動一般分為5個步驟:1. 調用OpenSCManager打開SCM管理器;
2. 調用OpenService打開此項服務;
3. 調用ControlService傳遞SERVICE_CONTROL_STOP來停止服務
4. 調用DeleteService卸載此項服務;
5. 關閉句柄。
注意:DeleteService只是標記一下該項服務需要刪除,只有停止了服務并且關閉了打開服務的句柄,改服務才會被正式卸載。
打開SCM管理器函數(shù)SC_HANDLE WINAPI OpenSCManager(
__in LPCTSTR lpMachineName, //計算機名稱
__in LPCTSTR lpDatabaseName, //SCM數(shù)據(jù)庫名稱
__in DWORD dwDesiredAccess //使用權限
);
說明
函數(shù)建立了一個連接到服務控制管理器,并打開指定的數(shù)據(jù)庫。
參數(shù)
lpMachineName
指向零終止字符串,命名為目標計算機。如果該指針為NULL ,或者如果它指向一個空字符串,函數(shù)連接到服務控制管理器在本地計算機上。
lpDatabaseName
指向零終止字符串,名稱的服務控制管理數(shù)據(jù)庫,以開放。此字符串應指定ServicesActive 。如果該指針為NULL ,該ServicesActive數(shù)據(jù)庫默認情況下打開。
dwDesiredAccess
指定服務的訪問控制管理。才準予進入的要求,系統(tǒng)會檢查訪問令牌的調用進程對任意訪問控制列表的安全描述符與服務控制管理器對象。訪問類型的SC_MANAGER_CONNECT是含蓄地指明調用這個函數(shù)。此外,任何或所有下列服務控制管理器對象的訪問類型可以指定:
SC_MANAGER_ALL_ACCESS
包括STANDARD_RIGHTS_REQUIRED ,除了所有類型的訪問此表中列出。
SC_MANAGER_CONNECT
可以連接到服務控制管理器。
SC_MANAGER_CREATE_SERVICE
使要求的CreateService函數(shù)創(chuàng)建一個服務對象,并將其添加到數(shù)據(jù)庫中。
SC_MANAGER_ENUMERATE_SERVICE
使要求的EnumServicesStatus功能清單的服務,這是在數(shù)據(jù)庫中。
SC_MANAGER_LOCK
使要求的LockServiceDatabase功能獲得鎖定數(shù)據(jù)庫。
SC_MANAGER_QUERY_LOCK_STATUS
使要求的QueryServiceLockStatus檢索功能鎖定狀態(tài)信息的數(shù)據(jù)庫。
返回值
如果函數(shù)成功,返回值是一個句柄指定的服務控制管理器數(shù)據(jù)庫。如果函數(shù)失敗,返回值為NULL 。要獲得擴展錯誤信息,請使用GetLastError 獲得錯誤代碼。
關閉服務句柄BOOL WINAPI CloseHandle(
__in HANDLE hObject //要關閉的句柄
);
hObjece
對象句柄,即使用OpenSCManager或者CreateService、OpenService返回的句柄。
創(chuàng)建服務創(chuàng)建一個服務對象并且把它加入到服務管理數(shù)據(jù)庫中。
[cpp] view plaincopy
SC_HANDLE WINAPI CreateService(
__in SC_HANDLE hSCManager, //SCM管理器的句柄
__in LPCTSTR lpServiceName, //服務名稱
__in LPCTSTR lpDisplayName, //服務顯示名稱
__in DWORD dwDesiredAccess, //訪問權限
__in DWORD dwServiceType, //服務類型
__in DWORD dwStartType, //啟動類型
__in DWORD dwErrorControl, //關于錯誤處理的代碼
__in LPCTSTR lpBinaryPathName, //二進制文件的代碼
__in LPCTSTR lpLoadOrderGroup, //在加載順序此服務所屬的組的名稱
__out LPDWORD lpdwTagId, //輸出驗證標簽
__in LPCTSTR lpDependencies, //所依賴的服務名稱
__in LPCTSTR lpServiceStartName, //用戶賬號名稱
__in LPCTSTR lpPassword //用戶口令
);
參數(shù)
hSCManager
服務控制管理器數(shù)據(jù)庫的句柄。 此句柄由OpenSCManager函數(shù)返回,并且必須具有SC_MANAGER_CREATE_SERVICE 的訪問權限。
lpServiceName
要安裝該服務的名稱。 最大字符串長度為 256 個字符。 服務控制管理器數(shù)據(jù)庫將保留字符的大小寫,但是服務名稱比較總是區(qū)分大小寫。 正斜杠和一個反斜線不是有效的服務名稱字符。
lpDisplayName
對被用戶界面程序用來識別服務的顯示名稱。 此字符串具有最大長度為 256 個字符。 服務控制管理器中的情況下保留名稱。 顯示名稱比較總是不區(qū)分大小寫。
dwDesiredAccess
對服務的訪問權限。請求的訪問之前,系統(tǒng)將檢查調用進程的訪問令牌。如果沒有特殊要求,一般設置為SERVICE_ALL_ACCESS (0xF01FF)
dwServiceType
服務類型。一般選擇以下兩種:
SERVICE_FILE_SYSTEM_DRIVER
0x00000002
文件系統(tǒng)的驅動
SERVICE_KERNEL_DRIVER
0x00000001
普通程序的驅動,一般使用此項。
dwStartType
服務啟動選項,亦即打開服務的時間,有以下幾種選擇:
SERVICE_AUTO_START
0x00000002
系統(tǒng)啟動時由服務控制管理器自動啟動該服務程序。
SERVICE_BOOT_START
0x00000000
用于由系統(tǒng)加載器創(chuàng)建的設備驅動程序。
只能用于驅動服務程序。
SERVICE_DEMAND_START
0x00000003
由服務控制管理器(SCM)啟動的服務,即手動啟動。
SERVICE_DISABLED
0x00000004
表示該服務不可啟動。
SERVICE_SYSTEM_START
0x00000001
用于由IoInitSystem函數(shù)創(chuàng)建的設備驅動程序。
dwErrorControl
當該啟動服務失敗時產(chǎn)生錯誤的嚴重程度以及采取的保護措施。此參數(shù)可以是下列值之一:
SERVICE_ERROR_CRITICAL
0x00000003
服務啟動程序將把該錯誤記錄到事件日志中
SERVICE_ERROR_IGNORE
0x00000000
服務啟動程序將忽略該錯誤并返回繼續(xù)執(zhí)行
SERVICE_ERROR_NORMAL
0x00000001
服務啟動程序將把該錯誤記錄到事件日志中并返回繼續(xù)執(zhí)行
SERVICE_ERROR_SEVERE
0x00000002
服務啟動程序將把該錯誤記錄到事件日志中。
否則將返回繼續(xù)執(zhí)行。
lpBinaryPathName
服務所用的二進制文件,也就是編譯后的驅動程序。 如果路徑中包含空格它必須被引用,以便它正確的解析。
例如"d:\myshare\myservice.exe"應指定為""d:\myshare\myservice.exe""。該路徑也可以包含一個自動啟動服務的參數(shù)。
例如"d:\myshare\myservice.exearg1 arg2"。 這些參數(shù)被傳遞給服務的入口點通常主要作用。
打開服務此函數(shù)針對已經(jīng)創(chuàng)建過的服務,再次打開此項服務。
SC_HANDLE WINAPI OpenService(
__in SC_HANDLE hSCManager, //SCM管理器的句柄
__in LPCTSTR lpServiceName, //服務名稱
__in DWORD dwDesiredAccess //訪問權限
hSCManager
SCM管理器的句柄,即OpenSCManager打開的句柄。
lpSeviceName
已經(jīng)創(chuàng)建的服務名稱。
dwDesiredAccess
訪問權限。如果沒有特殊情況,一般使用
SERVICE_ALL_ACCESS(0xF01FF) 控制服務發(fā)送一個控制碼去指定的服務,根據(jù)不同的控制碼操作服務。
BOOL WINAPI ControlService(
__in SC_HANDLE hService, //服務的句柄
__in DWORD dwControl, //發(fā)送的控制碼
__out LPSERVICE_STATUS lpServiceStatus //接收之前的服務狀態(tài)信息
);
hService
服務的句柄,即用CreateService創(chuàng)建或者使用OpenService打開的句柄。
dwControl
發(fā)送給服務的控制碼,常用的有以下幾種:
SERVICE_CONTROL_CONTINUE
0x00000003
針對暫停的服務發(fā)出繼續(xù)運行的指令。
SERVICE_CONTROL_PAUSE
0x00000002
暫停正在運行中的服務。
SERVICE_CONTROL_STOP
0x00000001
停止正在運行的服務。
lpServiceStatus
用于接收之前的服務狀態(tài)信息。
刪除服務標記刪除一個指定的服務。
BOOL WINAPI DeleteService(
__in SC_HANDLE hService //服務句柄
);
注意:必須停止服務并且關閉服務句柄后,服務才會被刪除。
完整代碼// LoadNtDriver.cpp : 定義控制臺應用程序的入口點。
//
#include "stdafx.h"
#include <Windows.h>
#include "string.h"
#include "locale.h"
BOOL LoadNTDriver(TCHAR * lpszDriverName,TCHAR * lpszDriverPath)
{
TCHAR szDriverPath[256] = {0};
_tprintf(_T("加載驅動...\n"));
//獲取完整的驅動路徑
GetFullPathName(lpszDriverPath,sizeof(szDriverPath)/sizeof(szDriverPath[0]),szDriverPath,NULL);
// _tprintf(szDriverPath);
SC_HANDLE hSCM = NULL;
SC_HANDLE hServie = NULL;
hSCM = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if (!hSCM)
{
_tprintf(_T("OpenSCManger 失敗!,錯誤代碼:%d\n"),GetLastError());
return FALSE;
}
else
{
_tprintf(_T("OpenSCManger 成功!\n"));
hServie = CreateService(hSCM,
lpszDriverName, //服務的名稱
lpszDriverName, //顯示的名稱DisplayName
SERVICE_ALL_ACCESS, //訪問所有權
SERVICE_KERNEL_DRIVER, //表示加載的服務是驅動程序
SERVICE_DEMAND_START, //啟動類型為手動啟動
SERVICE_ERROR_IGNORE, //忽略錯誤
szDriverPath, //驅動文件名(保護路徑),注冊表中的ImagePath值
NULL,
NULL,
NULL,
NULL,
NULL);
if (!hServie)
{
_tprintf(_T("CreateService 失敗!,錯誤代碼:%d,嘗試使用OpenService\n"),GetLastError());
hServie = OpenService(hSCM,lpszDriverName,SERVICE_ALL_ACCESS);
if (!hServie)
{
_tprintf(_T("OpenService 失敗!,錯誤代碼:%d\n"),GetLastError());
//清理
CloseServiceHandle(hSCM);
return FALSE;
}
else
{
_tprintf(_T("OpenService 成功!\n"));
}
}
else
_tprintf(_T("CreateService 成功!\n"));
//打開或創(chuàng)建服務成功后,開啟服務
BOOL bRet = StartService(hServie,NULL,NULL);
if (!bRet)
{
_tprintf(_T("StartService 失敗!,錯誤代碼:%d\n"),GetLastError());
bRet = FALSE;
}
else
{
bRet = TRUE;
_tprintf(_T("加載驅動...成功!\n"));
}
//先關掉服務句柄,再關掉服務管理器句柄
if (hServie)
{
CloseServiceHandle(hServie);
}
if (hSCM)
{
CloseServiceHandle(hSCM);
}
return bRet;
} // hSCM
}
BOOL UnloadNTDriver(TCHAR * szSvrName)
{
SC_HANDLE hSCM = NULL; //SCManger
SC_HANDLE hService = NULL;
_tprintf(_T("卸載驅動...\n"));
hSCM = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if (!hSCM) //打開失敗
{
_tprintf(_T("OpenSCManger 失敗!,錯誤代碼:%d\n"),GetLastError());
return FALSE;
}
else
{
_tprintf(_T("OpenSCManager 成功!\n"));
hService = OpenService(hSCM,szSvrName,SERVICE_ALL_ACCESS);
if (!hService) //打開服務失敗
{
_tprintf(_T("OpenService 失敗,錯誤代碼:%d\n"),GetLastError());
CloseServiceHandle(hSCM);
return FALSE;
}
else
{
_tprintf(_T("OpenService 成功!\n"));
SERVICE_STATUS SvrSta = {0};
//停止服務。停止服務后,服務才能完成卸載。
if (!ControlService(hService,SERVICE_CONTROL_STOP,&SvrSta))
{
_tprintf(_T("停止服務 失敗,錯誤代碼:%d\n"),GetLastError());
}
else
{
_tprintf(_T("停止服務 成功!\n"));
}
BOOL bRet = FALSE;
//動態(tài)卸載服務
bRet = DeleteService(hService);
if (!bRet)
{
//卸載失敗
_tprintf(_T("DeleteService 失敗,錯誤代碼:%d\n"),GetLastError());
}
else
{
//卸載成功
_tprintf(_T("DeleteService 成功!\n"));
_tprintf(_T("卸載驅動...成功!\n"));
}
//清理
if (hService)
{
CloseServiceHandle(hService);
}
if (hSCM)
{
CloseServiceHandle(hSCM);
}
return bRet;
} // hService
}
}
int _tmain(int argc, _TCHAR* argv[])
{
TCHAR szDriverPath[256];
TCHAR szDriverName[25];
setlocale(LC_ALL, "chs");//需要實現(xiàn)本地化,以實現(xiàn)中文正常輸出
_tcscpy_s(szDriverPath,sizeof(szDriverPath)/sizeof(szDriverPath[0]),_T("Driver.sys"));
_tcscpy_s(szDriverName,sizeof(szDriverPath)/sizeof(szDriverPath[0]),_T("TestDDK"));
BOOL bRet = LoadNTDriver(szDriverName,szDriverPath);
if (bRet)
{
printf("輸入任意鍵來卸載驅動程序.\n");
getchar();
UnloadNTDriver(szDriverName);
}
else
_tprintf(_T("加載驅動...失敗!\n"));
getchar();
return 0;
}
【結果】
加載:
卸載: