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 字段说明

字段类型说明
dwOSVersionInfoSizeULONG调用前必须设置为sizeof(RTL_OSVERSIONINFOW)sizeof(RTL_OSVERSIONINFOEXW)
dwMajorVersionULONGWindows NT 版本号:5=Windows 2000/XP/Server 2003,6=Vista/7/8/10,10=Windows 11
dwMinorVersionULONG子版本号:0=2000/Vista,1=XP/7,2=8,3=8.1
dwBuildNumberULONG操作系统构建号
dwPlatformIdULONG平台标识:VER_PLATFORM_WIN32_NT(2) = Windows NT
szCSDVersionWCHAR[128]服务包信息,如L"Service Pack 1"
wServicePackMajorUSHORT服务包主版本号
wServicePackMinorUSHORT服务包次版本号
wSuiteMaskUSHORT操作系统套件标识(如VER_SUITE_PERSONALVER_SUITE_ENTERPRISE
wProductTypeUCHAR产品类型: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_SUCCESS

3.3 版本欺骗机制

RosGetProcessEffectiveVersion()返回应用程序清单中声明的目标 Windows 版本:

  • 如果应用程序包含compatibility清单,声明支持特定 Windows 版本
  • RtlGetVersion会返回该版本号而非真实系统版本
  • 这是 Windows 应用程序兼容性机制的一部分

版本映射示例

EffectiveVersion对应 Windows 版本构建号
0x0500Windows 2000系统构建号
0x0501Windows XP系统构建号
0x0502Windows Server 2003系统构建号
0x0600Windows Vista系统构建号
0x0601Windows 77600
0x0602Windows 8系统构建号
0x0603Windows 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服务包版本(高字节=主版本,低字节=次版本)
CSDVersionCSD 版本字符串

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 └── NtProductType

9.3 关键设计决策

  1. 版本欺骗:为了兼容旧版应用程序,支持应用程序声明的目标版本
  2. PEB 缓存:用户态版本信息缓存到 PEB,避免每次调用都访问内核
  3. 扩展结构:通过dwOSVersionInfoSize区分基础和扩展版本信息
  4. ReactOS 扩展:产品类型覆盖机制解决特定兼容性问题