REACTOS RtlGetVersion 函数实现分析
RtlGetVersion 函数实现分析
1. 概述
RtlGetVersion是 Windows NT/ReactOS 操作系统中用于获取操作系统版本信息的核心函数。它是 Rtl(Run-Time Library)的一部分,提供用户态和内核态两种实现,用于查询当前运行的操作系统版本、构建号、平台标识等信息。
用途:
- 应用程序兼容性检测(如版本检查)
- 系统信息收集
- 条件性代码执行(根据不同 Windows 版本执行不同逻辑)
- 版本欺骗(用于应用程序兼容性)
调用路径:
应用程序 ├── GetVersion() / GetVersionEx() [kernel32.dll] └── RtlGetVersion() [ntdll.dll] └── NtQuerySystemInformation(SystemVersionInformation)2. 数据结构定义
2.1 RTL_OSVERSIONINFOW
标准版本信息结构([rtltypes.h:245-252](file:///d:/reactos/sdk/include/xdk/rtltypes.h#L245-L252)):
typedefstruct_OSVERSIONINFOW{ULONG dwOSVersionInfoSize;// 结构大小(必须初始化)ULONG dwMajorVersion;// 主版本号ULONG dwMinorVersion;// 次版本号ULONG dwBuildNumber;// 构建号ULONG dwPlatformId;// 平台标识WCHAR szCSDVersion[128];// CSD 版本字符串(如 "Service Pack 1")}OSVERSIONINFOW,*POSVERSIONINFOW,*LPOSVERSIONINFOW,RTL_OSVERSIONINFOW,*PRTL_OSVERSIONINFOW;2.2 RTL_OSVERSIONINFOEXW
扩展版本信息结构([rtltypes.h:268-279](file:///d:/reactos/sdk/include/xdk/rtltypes.h#L268-L279)):
typedefstruct_OSVERSIONINFOEXW{ULONG dwOSVersionInfoSize;// 结构大小(必须初始化)ULONG dwMajorVersion;// 主版本号ULONG dwMinorVersion;// 次版本号ULONG dwBuildNumber;// 构建号ULONG dwPlatformId;// 平台标识WCHAR szCSDVersion[128];// CSD 版本字符串USHORT wServicePackMajor;// 服务包主版本USHORT wServicePackMinor;// 服务包次版本USHORT wSuiteMask;// 套件掩码(如 VER_SUITE_ENTERPRISE)UCHAR wProductType;// 产品类型(工作站/服务器/域控制器)UCHAR wReserved;// 保留字段}OSVERSIONINFOEXW,*POSVERSIONINFOEXW,*LPOSVERSIONINFOEXW;2.3 字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
dwOSVersionInfoSize | ULONG | 调用前必须设置为sizeof(RTL_OSVERSIONINFOW)或sizeof(RTL_OSVERSIONINFOEXW) |
dwMajorVersion | ULONG | Windows NT 版本号:5=Windows 2000/XP/Server 2003,6=Vista/7/8/10,10=Windows 11 |
dwMinorVersion | ULONG | 子版本号:0=2000/Vista,1=XP/7,2=8,3=8.1 |
dwBuildNumber | ULONG | 操作系统构建号 |
dwPlatformId | ULONG | 平台标识:VER_PLATFORM_WIN32_NT(2) = Windows NT |
szCSDVersion | WCHAR[128] | 服务包信息,如L"Service Pack 1" |
wServicePackMajor | USHORT | 服务包主版本号 |
wServicePackMinor | USHORT | 服务包次版本号 |
wSuiteMask | USHORT | 操作系统套件标识(如VER_SUITE_PERSONAL、VER_SUITE_ENTERPRISE) |
wProductType | UCHAR | 产品类型:VER_NT_WORKSTATION(1)、VER_NT_SERVER(3)、VER_NT_DOMAIN_CONTROLLER(2) |
3. 用户态实现
3.1 核心代码
RtlGetVersion用户态实现([version.c:182-250](file:///d:/reactos/dll/ntdll/rtl/version.c#L182-L250)):
NTSTATUS NTAPIRtlGetVersion(IN OUT PRTL_OSVERSIONINFOW lpVersionInformation){SIZE_T Length;PPEB Peb=NtCurrentPeb();// 1. 参数验证:检查结构大小是否有效if(lpVersionInformation->dwOSVersionInfoSize!=sizeof(RTL_OSVERSIONINFOW)&&lpVersionInformation->dwOSVersionInfoSize!=sizeof(RTL_OSVERSIONINFOEXW)){returnSTATUS_INVALID_PARAMETER;}// 2. 检查应用程序兼容性的有效版本(版本欺骗){UINT EffectiveVersion=RosGetProcessEffectiveVersion();if(EffectiveVersion){// 使用欺骗的版本号UINT Major=(EffectiveVersion>>8)&0xFF;UINT Minor=EffectiveVersion&0xFF;lpVersionInformation->dwMajorVersion=Major;lpVersionInformation->dwMinorVersion=Minor;lpVersionInformation->dwBuildNumber=(EffectiveVersion==0x0601)?7600U:(ULONG)Peb->OSBuildNumber;lpVersionInformation->dwPlatformId=VER_PLATFORM_WIN32_NT;}else{// 使用真实版本号lpVersionInformation->dwMajorVersion=Peb->OSMajorVersion;lpVersionInformation->dwMinorVersion=Peb->OSMinorVersion;lpVersionInformation->dwBuildNumber=Peb->OSBuildNumber;lpVersionInformation->dwPlatformId=Peb->OSPlatformId;}}// 3. 处理 CSD 版本字符串RtlZeroMemory(lpVersionInformation->szCSDVersion,sizeof(lpVersionInformation->szCSDVersion));if(Peb->CSDVersion.Length&&Peb->CSDVersion.Buffer&&Peb->CSDVersion.Buffer[0]!=UNICODE_NULL){Length=min(wcslen(Peb->CSDVersion.Buffer),ARRAYSIZE(lpVersionInformation->szCSDVersion)-1);wcsncpy(lpVersionInformation->szCSDVersion,Peb->CSDVersion.Buffer,Length);}lpVersionInformation->szCSDVersion[Length]=UNICODE_NULL;// 4. 如果是扩展结构,填充额外字段if(lpVersionInformation->dwOSVersionInfoSize==sizeof(RTL_OSVERSIONINFOEXW)){PRTL_OSVERSIONINFOEXW InfoEx=(PRTL_OSVERSIONINFOEXW)lpVersionInformation;InfoEx->wServicePackMajor=(Peb->OSCSDVersion>>8)&0xFF;InfoEx->wServicePackMinor=Peb->OSCSDVersion&0xFF;InfoEx->wSuiteMask=SharedUserData->SuiteMask&0xFFFF;InfoEx->wProductType=SharedUserData->NtProductType;InfoEx->wReserved=0;// ReactOS 特有:产品类型覆盖SetRosSpecificInfo(InfoEx);}returnSTATUS_SUCCESS;}3.2 执行流程
RtlGetVersion() ├── 参数验证:检查 dwOSVersionInfoSize │ └── 无效则返回 STATUS_INVALID_PARAMETER │ ├── 版本欺骗检查 │ ├── RosGetProcessEffectiveVersion() != 0 │ │ └── 使用欺骗版本号(从 EffectiveVersion 提取) │ └── RosGetProcessEffectiveVersion() == 0 │ └── 使用 PEB 中的真实版本号 │ ├── CSD 版本处理 │ ├── 清零 szCSDVersion │ ├── 从 Peb->CSDVersion 复制(如果存在) │ └── 确保 NULL 终止 │ ├── 扩展结构处理(RTL_OSVERSIONINFOEXW) │ ├── 填充服务包信息(从 Peb->OSCSDVersion 提取) │ ├── 填充套件掩码(从 SharedUserData->SuiteMask) │ ├── 填充产品类型(从 SharedUserData->NtProductType) │ └── ReactOS 特有:SetRosSpecificInfo() 产品类型覆盖 │ └── 返回 STATUS_SUCCESS3.3 版本欺骗机制
RosGetProcessEffectiveVersion()返回应用程序清单中声明的目标 Windows 版本:
- 如果应用程序包含
compatibility清单,声明支持特定 Windows 版本 RtlGetVersion会返回该版本号而非真实系统版本- 这是 Windows 应用程序兼容性机制的一部分
版本映射示例:
| EffectiveVersion | 对应 Windows 版本 | 构建号 |
|---|---|---|
| 0x0500 | Windows 2000 | 系统构建号 |
| 0x0501 | Windows XP | 系统构建号 |
| 0x0502 | Windows Server 2003 | 系统构建号 |
| 0x0600 | Windows Vista | 系统构建号 |
| 0x0601 | Windows 7 | 7600 |
| 0x0602 | Windows 8 | 系统构建号 |
| 0x0603 | Windows 8.1 | 系统构建号 |
3.4 ReactOS 产品类型覆盖
SetRosSpecificInfo()([version.c:24-79](file:///d:/reactos/dll/ntdll/rtl/version.c#L24-L79)):
staticVOID NTAPISetRosSpecificInfo(IN OUT PRTL_OSVERSIONINFOEXW VersionInformation){// 读取注册表:HKLM\SYSTEM\CurrentControlSet\Control\ReactOS\Settings\Version\ReportAsWorkstation// 如果设置为非零值,强制将产品类型报告为工作站(VER_NT_WORKSTATION)// 否则保持原始值if(g_ReportProductType>0){VersionInformation->wProductType=g_ReportProductType;}}用途:解决兼容性问题(参见 bug-reports CORE-6611 和 CORE-4620),允许管理员强制将服务器版报告为工作站版。
4. 内核态实现
4.1 核心代码
RtlGetVersion内核态实现([misc.c:39-64](file:///d:/reactos/ntoskrnl/rtl/misc.c#L39-L64)):
NTSTATUS NTAPIRtlGetVersion(IN OUT PRTL_OSVERSIONINFOW lpVersionInformation){PAGED_CODE();// 1. 填充基本版本信息lpVersionInformation->dwMajorVersion=NtMajorVersion;lpVersionInformation->dwMinorVersion=NtMinorVersion;lpVersionInformation->dwBuildNumber=NtBuildNumber&0x3FFF;lpVersionInformation->dwPlatformId=VER_PLATFORM_WIN32_NT;// 2. 如果是扩展结构,填充额外字段if(lpVersionInformation->dwOSVersionInfoSize==sizeof(RTL_OSVERSIONINFOEXW)){PRTL_OSVERSIONINFOEXW InfoEx=(PRTL_OSVERSIONINFOEXW)lpVersionInformation;InfoEx->wServicePackMajor=(USHORT)(CmNtCSDVersion>>8)&0xFF;InfoEx->wServicePackMinor=(USHORT)(CmNtCSDVersion&0xFF);InfoEx->wSuiteMask=(USHORT)(SharedUserData->SuiteMask&0xFFFF);InfoEx->wProductType=SharedUserData->NtProductType;InfoEx->wReserved=0;}returnSTATUS_SUCCESS;}4.2 与用户态的差异
| 特性 | 用户态 | 内核态 |
|---|---|---|
| 版本来源 | PEB(进程环境块) | 全局变量(NtMajorVersion 等) |
| 版本欺骗 | 支持(EffectiveVersion) | 不支持 |
| CSD 版本 | 从 PEB->CSDVersion 读取 | 不处理 |
| ReactOS 产品类型覆盖 | 支持(SetRosSpecificInfo) | 不支持 |
| 参数验证 | 检查结构大小 | 无验证 |
| 构建号掩码 | 无 | & 0x3FFF |
4.3 内核版本来源
全局变量定义([misc.c:19-21](file:///d:/reactos/ntoskrnl/rtl/misc.c#L19-L21)):
externULONG NtMajorVersion;externULONG NtMinorVersion;externULONG NtOSCSDVersion;这些全局变量在内核初始化时设置,存储操作系统的实际版本号。
5. 相关函数
5.1 RtlGetNtProductType
获取产品类型([version.c:105-125](file:///d:/reactos/dll/ntdll/rtl/version.c#L105-L125)):
BOOLEAN NTAPIRtlGetNtProductType(_Out_ PNT_PRODUCT_TYPE ProductType){*ProductType=SharedUserData->NtProductType;// 支持 ReactOS 产品类型覆盖if(g_ReportProductType==0){RTL_OSVERSIONINFOEXW ovi;ovi.dwOSVersionInfoSize=sizeof(ovi);ovi.wProductType=*ProductType;SetRosSpecificInfo(&ovi);}if(g_ReportProductType>0){*ProductType=g_ReportProductType;}returnTRUE;}5.2 RtlGetNtVersionNumbers
获取版本号([version.c:150-176](file:///d:/reactos/dll/ntdll/rtl/version.c#L150-L176)):
VOID NTAPIRtlGetNtVersionNumbers(OUT PULONG pMajorVersion,OUT PULONG pMinorVersion,OUT PULONG pBuildNumber){PPEB pPeb=NtCurrentPeb();// 兼容性:确保至少返回 5.1(Windows XP)if(pMajorVersion)*pMajorVersion=pPeb->OSMajorVersion<5?5:pPeb->OSMajorVersion;if(pMinorVersion){if((pPeb->OSMajorVersion<5)||((pPeb->OSMajorVersion==5)&&(pPeb->OSMinorVersion<1)))*pMinorVersion=1;else*pMinorVersion=pPeb->OSMinorVersion;}// Windows 风格的构建号(高 4 位为 0xF)if(pBuildNumber)*pBuildNumber=(0xF0000000|pPeb->OSBuildNumber);}注意:此函数确保返回至少 Windows XP(5.1)版本,以兼容旧版 msvcrt.dll。
5.3 RtlVerifyVersionInfo
验证版本信息([sdk/lib/rtl/version.c:53-221](file:///d:/reactos/sdk/lib/rtl/version.c#L53-L221)):
NTSTATUS NTAPIRtlVerifyVersionInfo(IN PRTL_OSVERSIONINFOEXW VersionInfo,IN ULONG TypeMask,IN ULONGLONG ConditionMask)用于验证当前系统版本是否满足指定条件,常用于兼容性检查。
6. 数据来源
6.1 PEB(进程环境块)
用户态版本从 PEB 读取版本信息:
| PEB 字段 | 说明 |
|---|---|
OSMajorVersion | 主版本号 |
OSMinorVersion | 次版本号 |
OSBuildNumber | 构建号 |
OSPlatformId | 平台标识 |
OSCSDVersion | 服务包版本(高字节=主版本,低字节=次版本) |
CSDVersion | CSD 版本字符串 |
6.2 SharedUserData
用户态和内核态都从 SharedUserData 读取:
| SharedUserData 字段 | 说明 |
|---|---|
SuiteMask | 套件掩码 |
NtProductType | 产品类型 |
6.3 内核全局变量
内核态从全局变量读取:
| 全局变量 | 说明 |
|---|---|
NtMajorVersion | 主版本号 |
NtMinorVersion | 次版本号 |
NtBuildNumber | 构建号 |
CmNtCSDVersion | 服务包版本 |
7. 调用示例
7.1 用户态调用
#include<ntdll.h>RTL_OSVERSIONINFOEXW osvi;ZeroMemory(&osvi,sizeof(osvi));osvi.dwOSVersionInfoSize=sizeof(osvi);NTSTATUS status=RtlGetVersion((PRTL_OSVERSIONINFOW)&osvi);if(NT_SUCCESS(status)){printf("Windows Version: %lu.%lu.%lu\n",osvi.dwMajorVersion,osvi.dwMinorVersion,osvi.dwBuildNumber);printf("Platform ID: %lu\n",osvi.dwPlatformId);printf("Product Type: %u\n",osvi.wProductType);printf("Suite Mask: 0x%04X\n",osvi.wSuiteMask);}7.2 内核态调用
#include<ntoskrnl.h>RTL_OSVERSIONINFOEXW osvi;ZeroMemory(&osvi,sizeof(osvi));osvi.dwOSVersionInfoSize=sizeof(osvi);NTSTATUS status=RtlGetVersion((PRTL_OSVERSIONINFOW)&osvi);if(NT_SUCCESS(status)){DbgPrint("Kernel Version: %lu.%lu.%lu\n",osvi.dwMajorVersion,osvi.dwMinorVersion,osvi.dwBuildNumber);}8. 设计特点
8.1 版本欺骗机制
- 支持应用程序兼容性清单声明的目标版本
- 通过
RosGetProcessEffectiveVersion()实现 - 兼容 Windows 的
GetVersion()行为
8.2 ReactOS 特有扩展
- 产品类型覆盖:通过注册表键
ReportAsWorkstation控制 - 解决特定应用程序兼容性问题
8.3 双模式支持
- 用户态:从 PEB 读取,支持版本欺骗
- 内核态:从全局变量读取,无欺骗
8.4 向后兼容性
RtlGetNtVersionNumbers确保至少返回 5.1(Windows XP)- 支持旧版应用程序对版本号的依赖
9. 总结
9.1 函数架构
┌─────────────────────────────────────────────────────────────┐ │ 用户态调用 │ │ RtlGetVersion() [ntdll.dll] │ │ ├── 参数验证 │ │ ├── 版本欺骗检查 (RosGetProcessEffectiveVersion) │ │ ├── 从 PEB 读取版本信息 │ │ ├── CSD 版本处理 │ │ ├── 扩展结构处理 │ │ └── ReactOS 产品类型覆盖 │ ├─────────────────────────────────────────────────────────────┤ │ 内核态调用 │ │ RtlGetVersion() [ntoskrnl.exe] │ │ ├── PAGED_CODE() │ │ ├── 从全局变量读取版本信息 │ │ └── 扩展结构处理 │ └─────────────────────────────────────────────────────────────┘9.2 核心数据流
版本信息来源 ├── 用户态:PEB(进程环境块) │ ├── OSMajorVersion │ ├── OSMinorVersion │ ├── OSBuildNumber │ ├── OSPlatformId │ ├── OSCSDVersion │ └── CSDVersion └── 内核态:全局变量 ├── NtMajorVersion ├── NtMinorVersion ├── NtBuildNumber └── CmNtCSDVersion 共同来源:SharedUserData ├── SuiteMask └── NtProductType9.3 关键设计决策
- 版本欺骗:为了兼容旧版应用程序,支持应用程序声明的目标版本
- PEB 缓存:用户态版本信息缓存到 PEB,避免每次调用都访问内核
- 扩展结构:通过
dwOSVersionInfoSize区分基础和扩展版本信息 - ReactOS 扩展:产品类型覆盖机制解决特定兼容性问题