다양한 버전의 Windows를 위한 드라이버 작성
Writing drivers for different versions of Windows(원본 Microsoft Learn 링크)
아래는 위 문서의 번역이다.
드라이버 프로젝트를 생성할 때, 드라이버가 실행될 Windows의 최소 버전인 최소 대상 운영체제(minimum target operating system) 를 지정한다. 예를 들어 Windows 7을 최소 대상 운영체제로 지정할 수 있으며, 이 경우 드라이버는 Windows 7 및 그 이후 버전에서 실행된다.
Note
특정 최소 Windows 버전을 위한 드라이버를 개발하면서 이후 Windows 버전에서도 동작시키고자 한다면, 문서화되지 않은 함수를 사용해서는 안 되며, 문서화된 함수도 문서에 설명된 방식 외의 방법으로 사용해서는 안 된다. 그렇지 않으면 드라이버가 이후 Windows 버전에서 실행되지 않을 수 있다. 문서화된 함수만 사용하도록 주의했더라도, 새로운 Windows 버전이 출시될 때마다 그 버전에서 드라이버를 테스트해야 한다.
공통 기능만 사용하여 멀티 버전 드라이버 작성하기
여러 Windows 버전에서 실행될 드라이버를 설계할 때 가장 단순한 접근법은, 드라이버가 실행될 모든 Windows 버전에 공통적으로 존재하는 DDI 함수와 구조체만 사용하도록 허용하는 것이다. 이 경우 최소 대상 운영체제를 드라이버가 지원할 가장 오래된 Windows 버전으로 설정한다.
예를 들어 Windows 7부터 시작하여 모든 Windows 버전을 지원하려면 다음과 같이 한다.
- Windows 7에 존재하는 기능만 사용하도록 드라이버를 설계하고 구현한다.
- 드라이버를 빌드할 때 Windows 7을 최소 대상 운영체제로 지정한다.
이 과정은 단순하지만, 드라이버가 이후 Windows 버전에서 사용 가능한 기능 중 일부분만 사용하도록 제한될 수 있다. 많은 경우 보안 향상, 안정성 향상, 또는 새로운 기능 활성화를 위해 사용 가능한 새로운 운영체제 기능을 활용하고자 할 것이다.
버전 종속적인 기능을 사용하는 멀티 버전 드라이버 작성하기
커널 모드 드라이버는 운영체제가 제공하는 API가 사용 가능한지 또는 드라이버가 어떤 Windows 버전에서 실행 중인지를 동적으로 판단하여, 해당 런타임 환경에서 사용 가능한 기능을 선택적으로 사용할 수 있다. 예를 들어 Windows 7부터 모든 Windows 버전을 지원해야 하는 드라이버는 런타임에 자신이 실행 중인 Windows 버전을 판단할 수 있다. 드라이버가 Windows 7에서 실행 중이라면 Windows 7이 지원하는 DDI 함수만 사용해야 한다. 그러나 동일한 드라이버가, 예를 들어 런타임 검사를 통해 Windows 8에 고유한 추가 DDI 함수가 현재 존재하거나 자신이 Windows 8에서 실행 중임을 판단하면, 그 함수들을 사용할 수 있다.
Note
드라이버가 특정 운영체제 버전 이상에서 실행 중인지 확인하는 대신, 가능하면 기능이나 API의 가용성을 확인하는 것이 권장된다.
Windows 버전 종속적인 함수를 조건부로 호출하기
커널 모드 드라이버는 MmGetSystemRoutineAddress 또는 MmGetSystemRoutineAddressEx 함수를 사용하여, 사용하고자 하는 특정 API가 현재 런타임 환경에서 사용 가능한지 동적으로 확인하고, 해당 API를 호출할 때 사용할 함수 포인터를 얻을 수 있다.
Note
타입 검사를 유지하고 의도하지 않은 오류를 방지하기 위해, 원본 함수 타입을 그대로 반영하는 typedef를 만드는 것이 좋다.
예시: API 가용성 판단 및 조건부 API 호출
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
typedef
NTSTATUS
(*PFN_IoOpenDriverRegistryKey)(
PDRIVER_OBJECT DriverObject,
DRIVER_REGKEY_TYPE RegKeyType,
ACCESS_MASK DesiredAccess,
ULONG Flags,
PHANDLE DriverRegKey
);
VOID ExampleFunction(VOID) {
NTSTATUS status = STATUS_UNSUCCESSFUL;
HANDLE persistentStateKey = NULL;
PFN_IoOpenDriverRegistryKey pfnIoOpenDriverRegistryKey = NULL;
UNICODE_STRING functionName = {0};
RtlInitUnicodeString(&functionName, L"IoOpenDriverRegistryKey");
pfnIoOpenDriverRegistryKey = (PFN_IoOpenDriverRegistryKey)MmGetSystemRoutineAddress(&functionName);
if (pfnIoOpenDriverRegistryKey != NULL) {
// Open a key to where state can be stored under the driver service
status = pfnIoOpenDriverRegistryKey(g_GlobalStructure.DriverObject,
DriverRegKeyPersistentState,
KEY_WRITE,
0,
&persistentStateKey);
} else {
// Fall back to opening up a different location to store state in
}
// Use the opened registry key
}
Windows 버전 판단하기
커널 모드 드라이버는 RtlVerifyVersionInfo 함수를 사용하여 현재 실행 중인 Windows 버전을 동적으로 확인할 수 있다.
Note
드라이버가 특정 운영체제 버전 이상에서 실행 중인지 확인하는 대신, 가능하면 기능이나 API의 가용성을 확인하는 것이 권장된다.
예시: Windows 버전 판단하기
다음 예시는 현재 실행 중인 운영체제 버전이 10.0 이상인지, 그리고 빌드 번호가 22000(Windows 11, 버전 21H2) 이상인지를 감지한다.
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
...
NTSTATUS Status = STATUS_SUCCESS;
RTL_OSVERSIONINFOEXW VersionInfo = {0};
ULONG TypeMask = 0;
ULONGLONG ConditionMask = 0;
VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo);
VersionInfo.dwMajorVersion = 10;
VersionInfo.dwMinorVersion = 0;
VersionInfo.dwBuildNumber = 22000;
TypeMask = VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER;
VER_SET_CONDITION(ConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION(ConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION(ConditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL);
Status = RtlVerifyVersionInfo(&VersionInfo,
TypeMask,
ConditionMask);
if (NT_SUCCESS(Status)) {
//
// The call to RtlVerifyVersionInfo succeeded, so the running OS
// version and build number is greater than or equal to the value
// specified. Do appropriate action for newer OS versions.
//
} else if (Status == STATUS_REVISION_MISMATCH) {
//
// The running OS version is less than the value specified. Do
// appropriate action for older OS versions.
//
} else {
//
// There was an error comparing to the running OS version. Do
// appropriate action for when the OS version is not known.
//
}
...