編寫軟體動態載入NT式驅動
NT式裝置驅動程式的動態載入主要是由服務控制管理程式(Service Control Manager,即SCM)系統元件來完成的。
Windwos服務可以在系統啟動時載入,使用者也可以按需在服務控制平臺開啟或者關閉服務。程式設計師可以通過Windows提供的相關服務函式進行載入或者解除安裝該服務等。服務程式更是可以在使用者還沒有登入系統的時候,就載入系統並且被執行。
載入NT驅動一般分為4個步驟:
1. 呼叫OpenSCManager開啟SCM管理器;
2. 呼叫CreateService建立服務;如果存在則呼叫OpenService開啟服務(可根據GetLastError判斷);
3. 呼叫StartService開啟服務;
4. 關閉控制程式碼。
解除安裝NT驅動一般分為5個步驟:
1. 呼叫OpenSCManager開啟SCM管理器;
2. 呼叫OpenService開啟此項服務;
3. 呼叫ControlService傳遞SERVICE_CONTROL_STOP來停止服務
4. 呼叫DeleteService解除安裝此項服務;
5. 關閉控制程式碼。
注意:DeleteService只是標記一下該項服務需要刪除,只有停止了服務並且關閉了開啟服務的控制程式碼,改服務才會被正式解除安裝。
開啟SCM管理器函式
SC_HANDLE WINAPI OpenSCManager(
__in LPCTSTR lpMachineName, //計算機名稱
__in LPCTSTR lpDatabaseName, //SCM資料庫名稱
__in DWORD dwDesiredAccess //使用許可權
);
說明
函式建立了一個連線到服務控制管理器,並開啟指定的資料庫。
引數
lpMachineName
指向零終止字串,命名為目標計算機。如果該指標為NULL ,或者如果它指向一個空字串,函式連線到服務控制管理器在本地計算機上。
lpDatabaseName
指向零終止字串,名稱的服務控制管理資料庫,以開放。此字串應指定ServicesActive 。如果該指標為NULL ,該ServicesActive資料庫預設情況下開啟。
dwDesiredAccess
指定服務的訪問控制管理。才准予進入的要求,系統會檢查訪問令牌的呼叫程式對任意訪問控制列表的安全描述符與服務控制管理器物件。訪問型別的SC_MANAGER_CONNECT是含蓄地指明呼叫這個函式。此外,任何或所有下列服務控制管理器物件的訪問型別可以指定:
SC_MANAGER_ALL_ACCESS
包括STANDARD_RIGHTS_REQUIRED ,除了所有型別的訪問此表中列出。
SC_MANAGER_CONNECT
可以連線到服務控制管理器。
SC_MANAGER_CREATE_SERVICE
使要求的CreateService函式建立一個服務物件,並將其新增到資料庫中。
SC_MANAGER_ENUMERATE_SERVICE
使要求的EnumServicesStatus功能清單的服務,這是在資料庫中。
SC_MANAGER_LOCK
使要求的LockServiceDatabase功能獲得鎖定資料庫。
SC_MANAGER_QUERY_LOCK_STATUS
使要求的QueryServiceLockStatus檢索功能鎖定狀態資訊的資料庫。
返回值
如果函式成功,返回值是一個控制程式碼指定的服務控制管理器資料庫。如果函式失敗,返回值為NULL 。要獲得擴充套件錯誤資訊,請使用GetLastError 獲得錯誤程式碼。
關閉服務控制程式碼
BOOL WINAPI CloseHandle(
__in HANDLE hObject //要關閉的控制程式碼
);
hObjece
物件控制程式碼,即使用OpenSCManager或者CreateService、OpenService返回的控制程式碼。
建立服務
建立一個服務物件並且把它加入到服務管理資料庫中。
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 //使用者口令
);
引數
hSCManager
服務控制管理器資料庫的控制程式碼。 此控制程式碼由OpenSCManager函式返回,並且必須具有SC_MANAGER_CREATE_SERVICE 的訪問許可權。
lpServiceName
要安裝該服務的名稱。 最大字串長度為 256 個字元。 服務控制管理器資料庫將保留字元的大小寫,但是服務名稱比較總是區分大小寫。 正斜槓和一個反斜線不是有效的服務名稱字元。
lpDisplayName
對被使用者介面程式用來識別服務的顯示名稱。 此字串具有最大長度為 256 個字元。 服務控制管理器中的情況下保留名稱。 顯示名稱比較總是不區分大小寫。
dwDesiredAccess
對服務的訪問許可權。請求的訪問之前,系統將檢查呼叫程式的訪問令牌。如果沒有特殊要求,一般設定為SERVICE_ALL_ACCESS (0xF01FF)
dwServiceType服務型別。一般選擇以下兩種:
Value |
Meaning |
SERVICE_FILE_SYSTEM_DRIVER |
檔案系統的驅動 |
SERVICE_KERNEL_DRIVER |
普通程式的驅動,一般使用此項。 |
dwStartType
服務啟動選項,亦即開啟服務的時間,有以下幾種選擇:
Value |
Meaning |
SERVICE_AUTO_START |
系統啟動時由服務控制管理器自動啟動該服務程式。 |
SERVICE_BOOT_START |
用於由系統載入器建立的裝置驅動程式。 只能用於驅動服務程式。 |
SERVICE_DEMAND_START |
由服務控制管理器(SCM)啟動的服務,即手動啟動。 |
SERVICE_DISABLED |
表示該服務不可啟動。 |
SERVICE_SYSTEM_START |
用於由IoInitSystem函式建立的裝置驅動程式。 |
dwErrorControl當該啟動服務失敗時產生錯誤的嚴重程度以及採取的保護措施。此引數可以是下列值之一:
Value |
Meaning |
SERVICE_ERROR_CRITICAL |
服務啟動程式將把該錯誤記錄到事件日誌中 |
SERVICE_ERROR_IGNORE |
服務啟動程式將忽略該錯誤並返回繼續執行 |
SERVICE_ERROR_NORMAL |
服務啟動程式將把該錯誤記錄到事件日誌中並返回繼續執行 |
SERVICE_ERROR_SEVERE |
服務啟動程式將把該錯誤記錄到事件日誌中。 否則將返回繼續執行。 |
lpBinaryPathName
服務所用的二進位制檔案,也就是編譯後的驅動程式。 如果路徑中包含空格它必須被引用,以便它正確的解析。
例如"d:\myshare\myservice.exe"應指定為""d:\myshare\myservice.exe""。該路徑也可以包含一個自動啟動服務的引數。
例如"d:\myshare\myservice.exearg1 arg2"。 這些引數被傳遞給服務的入口點通常主要作用。
開啟服務
此函式針對已經建立過的服務,再次開啟此項服務。
SC_HANDLE WINAPI OpenService(
__in SC_HANDLE hSCManager, //SCM管理器的控制程式碼
__in LPCTSTR lpServiceName, //服務名稱
__in DWORD dwDesiredAccess //訪問許可權
hSCManager
SCM管理器的控制程式碼,即OpenSCManager開啟的控制程式碼。
lpSeviceName
已經建立的服務名稱。
dwDesiredAccess
訪問許可權。如果沒有特殊情況,一般使用SERVICE_ALL_ACCESS(0xF01FF)
控制服務
傳送一個控制碼去指定的服務,根據不同的控制碼操作服務。
BOOL WINAPI ControlService(
__in SC_HANDLE hService, //服務的控制程式碼
__in DWORD dwControl, //傳送的控制碼
__out LPSERVICE_STATUS lpServiceStatus //接收之前的服務狀態資訊
);
hService
服務的控制程式碼,即用CreateService建立或者使用OpenService開啟的控制程式碼。
dwControl
傳送給服務的控制碼,常用的有以下幾種:
Control code |
Meaning |
SERVICE_CONTROL_CONTINUE |
針對暫停的服務發出繼續執行的指令。 |
SERVICE_CONTROL_PAUSE |
暫停正在執行中的服務。 |
SERVICE_CONTROL_STOP |
停止正在執行的服務。 |
lpServiceStatus
用於接收之前的服務狀態資訊。
刪除服務
標記刪除一個指定的服務。
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"));
//開啟或建立服務成功後,開啟服務
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;
//動態解除安裝服務
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");//需要實現本地化,以實現中文正常輸出
_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;
}
【結果】
載入:
解除安裝:
相關文章
- 載入NT驅動的類 C++C++
- linux裝置驅動編寫入門Linux
- linux 觸控式螢幕驅動編寫Linux
- Linux驅動開發筆記(一):helloworld驅動原始碼編寫、makefile編寫以及驅動編譯Linux筆記原始碼編譯
- 【系統安全003】NT驅動框架框架
- 載入驅動
- C# 編寫 Windows 動態桌面軟體實現(一)之桌面互動功能C#Windows
- C# 編寫一個小巧快速的 Windows 動態桌面軟體C#Windows
- Linux驅動開發筆記(三):基於ubuntu的驅動、makefile編寫以及編譯載入流程Linux筆記Ubuntu編譯
- DLL動態庫動態載入
- drozer模組的編寫及模組動態載入問題研究
- AntSK 0.2.1 版本揭秘:動態載入dll,驅動Function Call新境界!Function
- Linux RN6752 驅動編寫Linux
- Linux驅動開發: Ubuntu(PC機)系統上編譯驅動並載入測試LinuxUbuntu編譯
- Linux驅動實踐:如何編寫【 GPIO 】裝置的驅動程式?Linux
- 動態載入UserControl
- 如何編寫linux下nandflash驅動-4LinuxNaN
- Helloworld 驅動模組載入
- 載入驅動三種execute
- Linux驅動模組載入方法和如何判斷Linux驅動是否載入成功Linux
- Apache ShardingSphere:由開源驅動的分散式資料庫中介軟體生態Apache分散式資料庫
- 如何編寫一個簡單的Linux驅動(三)——完善裝置驅動Linux
- 動手編寫—動態陣列(Java實現)陣列Java
- 驅動總裁是流氓軟體嗎 驅動總裁有捆綁軟體嗎
- python動態載入(三)Python
- QLibrary 載入動態庫
- vue 動態載入元件Vue元件
- goloader - golang動態載入Golang
- Java動態載入類Java
- Dolphinscheduler不重啟載入Oracle驅動Oracle
- 惡意軟體開發——編寫第一個Loader載入器
- UEFI載入程式 & 驅動模組化
- 指令碼的動態載入指令碼
- 使用dlopen載入動態庫
- ListView動態載入資料View
- STC8A系列裝置驅動軟體函式庫開源函式
- 圖解韌體、驅動、軟體的區別圖解
- echarts遷移圖動態載入Echarts
- OrchardCore 如何動態載入模組?