0%

程序安装NDIS5.1的方法(2)

前言

测试NDIS驱动时,可以用 手动处理 的方法,但是在打包发布的时候,还得用 程序处理 的方法。
代码框架使用WDK源码中 src -> network -> config -> bindview 工程作为基础。

准备工作

这里我们主要使用 NetCfgAPI.hNetCfgAPI.cpp 两个文件,另外还需要我们从WDK源码中
复制 netcfgn.h netcfgn.idl netcfgx.h netcfgx.idl 这4个文件到工程目录中,并修改
NetCfgAPI.h 文件中包含的头文件为当前工程目录,即:

1
2
#include <netcfgx.h> // 改为 #include "netcfgx.h"
#include <netcfgn.h> // 改为 #include "netcfgx.h"

另外我们还需要在工程中配置包含库文件,或者在代码中声明包含库文件

1
2
3
#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "advapi32.lib")
#pragma comment(lib, "setupapi.lib")

关闭XP签名验证

在XP中的 硬件签名检测 的配置信息,在注册表中的位置为

1
2
3
4
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Driver Signing               Policy      BIN   0
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Non-Driver Signing Policy BIN 0
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Driver Signing Policy DWORD 0
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup PrivateHash BIN MD5

使用代码关闭 硬件签名检测 需要用到的头文件和结构体为

1
2
3
4
5
6
#include <wincrypt.h>

typedef struct _DRIVER_SIGNING {
BYTE Policy;
BYTE PrivateHash[16];
} DRIVER_SIGNING, *PDRIVER_SIGNING;

从注册表中读取到 硬件签名检测 配置信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
BOOL DriverSigningGet(OUT DRIVER_SIGNING &Info)
{
HKEY hKey = NULL;
DWORD dwType = 0;
DWORD dwCount = 16;
DRIVER_SIGNING Sign = { 0 };
// 读取HASH信息
LONG nRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup",
0, KEY_ALL_ACCESS, &hKey);
if (nRet != ERROR_SUCCESS) return FALSE;
nRet = RegQueryValueEx(
hKey, "PrivateHash", NULL, &dwType, Sign.PrivateHash, &dwCount);
RegCloseKey(hKey); // 先关闭句柄
if (nRet != ERROR_SUCCESS) return FALSE;
// 读取策略信息
nRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Driver Signing", 0, KEY_ALL_ACCESS, &hKey);
if (nRet != ERROR_SUCCESS) return FALSE;
dwCount = 1;
nRet = RegQueryValueEx(
hKey, "Policy", NULL, &dwType, &Sign.Policy, &dwCount);
RegCloseKey(hKey); // 先关闭句柄
if (nRet != ERROR_SUCCESS) return FALSE;
// 复制到输出中
memcpy(&Info, &Sign, sizeof(DRIVER_SIGNING));
return TRUE;
}

修改配置信息之前,需要先计算对应配置信息的HASH值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
BOOL DriverSigningHash(IN OUT DRIVER_SIGNING &Info)
{
HKEY hKey = NULL;
DWORD dwType = 0;
DWORD dwSeed = 0;
DWORD dwCount = sizeof(DWORD);
// 读取HASH需要的序列
LONG nRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
"SYSTEM\\WPA\\PnP", 0, KEY_ALL_ACCESS, &hKey);
if (nRet != ERROR_SUCCESS) return FALSE;
nRet = RegQueryValueEx(
hKey, "seed", NULL, &dwType, (PBYTE)&dwSeed, &dwCount);
RegCloseKey(hKey); // 先关闭句柄
if (nRet != ERROR_SUCCESS) return FALSE;
// 根据策略计算HASH值
HCRYPTHASH hProv = NULL;
if (!CryptAcquireContext(&hProv, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) return FALSE;
HCRYPTHASH hHash = NULL;
if (!CryptCreateHash(hProv, 0x8003, 0, 0, &hHash))
{
CryptReleaseContext(hProv, 0);
return FALSE;
}
DWORD dwData = Info.Policy;
if (!CryptHashData(hHash, (PBYTE)&dwData, sizeof(DWORD), 0))
{
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return FALSE;
}
if (!CryptHashData(hHash, (PBYTE)&dwSeed, sizeof(DWORD), 0))
{
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return FALSE;
}
DWORD dwLen = sizeof(Info.PrivateHash);
if (!CryptGetHashParam(hHash, HP_HASHVAL, Info.PrivateHash, &dwLen, 0))
{
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return FALSE;
}
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return TRUE;
}

计算完HASH值之后,就可以写入新的配置信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
BOOL DriverSigningSet(IN DRIVER_SIGNING &Info)
{
HKEY hKey = NULL;
// 写入HASH信息
LONG nRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup",
0, KEY_ALL_ACCESS, &hKey);
if (nRet != ERROR_SUCCESS) return FALSE;
nRet = RegSetValueEx(hKey, "PrivateHash",
0, REG_BINARY, Info.PrivateHash, sizeof(Info.PrivateHash));
RegCloseKey(hKey); // 先关闭句柄
if (nRet != ERROR_SUCCESS) return FALSE;
// 写入驱动策略信息
nRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Driver Signing", 0, KEY_ALL_ACCESS, &hKey);
if (nRet != ERROR_SUCCESS) return FALSE;
nRet = RegSetValueEx(
hKey, "Policy", 0, REG_BINARY, &Info.Policy, sizeof(BYTE));
RegCloseKey(hKey); // 先关闭句柄
if (nRet != ERROR_SUCCESS) return FALSE;
// 写入非驱动策略信息
nRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Non-Driver Signing",
0, KEY_ALL_ACCESS, &hKey);
if (nRet != ERROR_SUCCESS) return FALSE;
nRet = RegSetValueEx(
hKey, "Policy", 0, REG_BINARY, &Info.Policy, sizeof(BYTE));
RegCloseKey(hKey); // 先关闭句柄
if (nRet != ERROR_SUCCESS) return FALSE;
// 写入用户策略信息(可能不存在)
nRet = RegOpenKeyEx(HKEY_CURRENT_USER,
"SOFTWARE\\Microsoft\\Driver Signing", 0, KEY_ALL_ACCESS, &hKey);
if (nRet == ERROR_SUCCESS)
{
DWORD dwData = Info.Policy;
nRet = RegSetValueEx(
hKey, "Policy", 0, REG_BINARY, (PBYTE)&dwData, sizeof(DWORD));
RegCloseKey(hKey); // 先关闭句柄
if (nRet != ERROR_SUCCESS) return FALSE;
}
return TRUE;
}

安装网络组件

读取 inf 配置信息的函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
CStringW InfGetKeyValue(IN HINF hInf, IN PCWSTR pSection, IN PCWSTR pKey, IN DWORD dwIndex)
{
if (hInf == NULL) return L"";
if (hInf == INVALID_HANDLE_VALUE) return L"";
if (pSection == NULL) return L"";
INFCONTEXT infCtx = { 0 };
if (!SetupFindFirstLineW(hInf, pSection, pKey, &infCtx)) return L"";
DWORD dwSize = 0;
if (!SetupGetStringFieldW(&infCtx, dwIndex, NULL, 0, &dwSize)) return L"";
PWCHAR pValue = (PWCHAR)CoTaskMemAlloc(sizeof(WCHAR) * dwSize);
if (pValue == NULL) return L"";
memset(pValue, 0, sizeof(WCHAR) * dwSize);
if (!SetupGetStringFieldW(&infCtx, dwIndex, pValue, dwSize, &dwSize))
{
CoTaskMemFree(pValue);
return L"";
}
CStringW csValue = pValue;
CoTaskMemFree(pValue);
return csValue;
}

读取 设备实例ID 的函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CStringW InfGetPnpID(IN CStringW csInfPath)
{
if (csInfPath.IsEmpty()) return L"";
HINF hInf = SetupOpenInfFileW(
(PCWSTR)csInfPath, NULL, INF_STYLE_WIN4, NULL);
if (hInf == INVALID_HANDLE_VALUE) return L"";
CStringW csModel = InfGetKeyValue(hInf, L"Manufacturer", NULL, 1);
if (csModel.IsEmpty())
{
SetupCloseInfFile(hInf);
return L"";
}
CStringW csPnpID = InfGetKeyValue(hInf, (PCWSTR)csModel, NULL, 2);
SetupCloseInfFile(hInf);
return csPnpID;
}

由于XP下安装 NDIS5 驱动需要2个inf文件,所以我们需要主动复制第2个文件的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
BOOL InstallNetService(IN CStringW csInfPath, IN CStringW csInf2Path)
{
if (csInfPath.IsEmpty()) return FALSE;
if (csInf2Path.IsEmpty()) return FALSE;
// 备份原硬件签名检测配置
DRIVER_SIGNING Backup = { 0 };
if (!DriverSigningGet(Backup)) return FALSE;
// 计算忽略硬件签名检测配置的HASH
DRIVER_SIGNING Info = { 0 };
if (!DriverSigningHash(Info)) return FALSE;
// 读取NDIS设备实例ID
CStringW csPnpID = InfGetPnpID(csInfPath);
if (csPnpID.IsEmpty()) return FALSE;
// 开始安装网络组件
INetCfg *pnc = NULL;
HRESULT hr = HrGetINetCfg(TRUE, L"NdisSetup", &pnc, NULL);
if (hr == S_OK)
{
// 设置忽略硬件签名检测
if (!DriverSigningSet(Info))
{
HrReleaseINetCfg(pnc, TRUE);
return FALSE;
}
// 复制第2个inf文件的信息
if (!SetupCopyOEMInfW((PCWSTR)csInf2Path,
NULL, SPOST_NONE, 0, NULL, 0, NULL, NULL))
{
HrReleaseINetCfg(pnc, TRUE);
return FALSE;
}
// 把网络组件安装成服务
hr = HrInstallNetComponent(pnc, (PCWSTR)csPnpID,
&GUID_DEVCLASS_NETSERVICE, (PCWSTR)csInfPath);
HrReleaseINetCfg(pnc, TRUE);
// 恢复硬件签名检测配置
DriverSigningSet(Backup);
// 有时候提示需要重启才生效,也算安装成功
// if (hr == NETCFG_S_REBOOT) return TRUE;
if (SUCCEEDED(hr)) return TRUE;
}
return FALSE;
}

卸载时只需要第1个文件的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
BOOL UninstallNetService(IN CStringW csInfPath)
{
if (csInfPath.IsEmpty()) return FALSE;
// 读取NDIS设备实例ID
CStringW csPnpID = InfGetPnpID(csInfPath);
if (csPnpID.IsEmpty()) return FALSE;
// 开始卸载网络组件
INetCfg *pnc = NULL;
HRESULT hr = HrGetINetCfg(TRUE, L"NdisSetup", &pnc, NULL);
if (hr == S_OK)
{
// 根据设备实例ID进行卸载
hr = HrUninstallNetComponent(pnc, (PCWSTR)csPnpID);
HrReleaseINetCfg(pnc, TRUE);
// 有时候提示需要重启才生效,也算卸载成功
// if (hr == NETCFG_S_REBOOT) return TRUE;
if (SUCCEEDED(hr)) return TRUE;
}
return FALSE;
}