From 49dc598a81b59fd6132e1c6e59160b27eb176d1c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Pali=20Roh=C3=A1r?= Date: Sat, 16 Aug 2025 03:17:25 +0200 Subject: [PATCH] windows: Improve version detection Move version detection code into helper functions, which can be reused. For 32-bit x86 builds use GetVersion() which is available in all Windows versions instead of GetVersionEx(). --- lib/physmem-windows.c | 30 +++++------ lib/win32-helpers.c | 112 +++++++++++++++++++++++++++++++----------- lib/win32-helpers.h | 1 + lib/win32-kldbg.c | 7 +-- 4 files changed, 98 insertions(+), 52 deletions(-) diff --git a/lib/physmem-windows.c b/lib/physmem-windows.c index ed827ba..6263d28 100644 --- a/lib/physmem-windows.c +++ b/lib/physmem-windows.c @@ -524,8 +524,10 @@ init_physmem_w32skrnl(struct physmem *physmem, struct pci_access *a) { HMODULE w32skrnl; LPVOID (WINAPI *GetThunkBuff)(VOID); - OSVERSIONINFOA version; LPVOID buf_ptr; + DWORD raw_version; + USHORT build_num; + BOOL build_num_valid; a->debug("resolving DPMI function via GetThunkBuff() function from w32skrnl.dll..."); w32skrnl = GetModuleHandleA("w32skrnl.dll"); @@ -544,16 +546,12 @@ init_physmem_w32skrnl(struct physmem *physmem, struct pci_access *a) return 0; } - version.dwOSVersionInfoSize = sizeof(version); - if (!GetVersionExA(&version)) - { - a->debug("failed: cannot detect version."); - errno = EINVAL; - return 0; - } + raw_version = GetVersion(); + build_num = (raw_version >> 16) & 0x3FFF; + build_num_valid = ((raw_version & 0xC0000000) == 0x80000000 && (raw_version & 0xff) < 4); - /* Versions before 1.1 (1.1.88) are not supported. */ - if (version.dwMajorVersion < 1 || (version.dwMajorVersion == 1 && version.dwMinorVersion < 1)) + /* Builds older than 88 (match version 1.1) are not supported. */ + if (build_num_valid && build_num < 88) { a->debug("failed: found old incompatible version."); errno = ENOENT; @@ -576,15 +574,11 @@ init_physmem_w32skrnl(struct physmem *physmem, struct pci_access *a) } /* - * Versions 1.1 (1.1.88) - 1.15 (1.15.103) have DPMI function at offset 0xa0. - * Versions 1.15a (1.15.111) - 1.30c (1.30.172) have DPMI function at offset 0xa4. + * Builds 88-103 (match versions 1.1-1.15) have DPMI function at offset 0xa0. + * Builds 111-172 (match versions 1.15a-1.30c) have DPMI function at offset 0xa4. + * If build number is unavailable then expects the latest version. */ - if (version.dwMajorVersion > 1 || - (version.dwMajorVersion == 1 && version.dwMinorVersion > 15) || - (version.dwMajorVersion == 1 && version.dwMinorVersion == 15 && version.dwBuildNumber >= 111)) - physmem->w32skrnl_dpmi_lcall_ptr = (LPVOID)((BYTE *)buf_ptr + 0xa4); - else - physmem->w32skrnl_dpmi_lcall_ptr = (LPVOID)((BYTE *)buf_ptr + 0xa0); + physmem->w32skrnl_dpmi_lcall_ptr = (LPVOID)((BYTE *)buf_ptr + ((build_num_valid && build_num < 111) ? 0xa0 : 0xa4)); a->debug("success."); return 1; diff --git a/lib/win32-helpers.c b/lib/win32-helpers.c index 3b182aa..df09d64 100644 --- a/lib/win32-helpers.c +++ b/lib/win32-helpers.c @@ -177,11 +177,89 @@ win32_get_process_machine(void) BOOL win32_is_non_nt_system(void) { - OSVERSIONINFOA version; +#if defined(_M_IX86) || defined(__i386__) + /* Highest bit set indicates the non-NT system. */ + return GetVersion() >> 31; +#else + /* Non-i386 systems are not pre-NT compatible. */ + return FALSE; +#endif +} + +static BOOL +win32_is_nt40_system(void) +{ +#if defined(_M_IX86) || defined(__i386__) + /* Check for Windows NT 4.0. Highest two bits are zero for NT and in lowest 8 bits is major os version. */ + DWORD raw_version = GetVersion(); + return (raw_version >> 30) == 0 && (raw_version & 0xff) >= 4; +#else + /* Modern non-i386 systems have at least version 5.2 (XP x64). */ + return TRUE; +#endif +} + +static BOOL +win32_is_win2k_system(void) +{ +#if defined(_M_IX86) || defined(__i386__) + /* Check for Windows 2000 (NT 5.0). Highest two bits are zero for NT and in lowest 8 bits is major os version. */ + DWORD raw_version = GetVersion(); + return (raw_version >> 30) == 0 && (raw_version & 0xff) >= 5; +#else + /* Modern non-i386 systems have at least version 5.2 (XP x64). */ + return TRUE; +#endif +} + +BOOL +win32_is_vista_system(void) +{ +#if defined(_M_IX86) || defined(__i386__) + /* Check for Windows Vista (NT 6.0). Highest two bits are zero for NT and in lowest 8 bits is major os version. */ + DWORD raw_version = GetVersion(); + return (raw_version >> 30) == 0 && (raw_version & 0xff) >= 6; +#else + /* Check for Windows Vista (NT 6.0). */ + OSVERSIONINFO version; version.dwOSVersionInfoSize = sizeof(version); - return GetVersionExA(&version) && version.dwPlatformId < VER_PLATFORM_WIN32_NT; + if (!GetVersionEx(&version) || + version.dwPlatformId != VER_PLATFORM_WIN32_NT || + version.dwMajorVersion >= 6) + return FALSE; + else + return TRUE; +#endif } +#ifndef _WIN64 +static BOOL +win32_is_win8_system(void) +{ +#if defined(_M_IX86) || defined(__i386__) + /* Check for Windows 8 (NT 6.2). Highest two bits are zero for NT and in lowest 16 bits are minor<<8 + major os version. */ + DWORD raw_version = GetVersion(); + if ((raw_version >> 30) != 0 || + (raw_version & 0xff) < 6 || + ((raw_version & 0xff) == 6 && ((raw_version >> 8) & 0xff) < 2)) + return FALSE; + else + return TRUE; +#else + /* Check for Windows 8 (NT 6.2). */ + OSVERSIONINFO version; + version.dwOSVersionInfoSize = sizeof(version); + if (!GetVersionEx(&version) || + version.dwPlatformId != VER_PLATFORM_WIN32_NT || + version.dwMajorVersion < 6 || + (version.dwMajorVersion == 6 && version.dwMinorVersion < 2)) + return FALSE; + else + return TRUE; +#endif +} +#endif + BOOL win32_is_32bit_on_64bit_system(void) { @@ -223,17 +301,7 @@ win32_is_32bit_on_win8_64bit_system(void) #ifdef _WIN64 return FALSE; #else - OSVERSIONINFOA version; - - /* Check for Windows 8 (NT 6.2). */ - version.dwOSVersionInfoSize = sizeof(version); - if (!GetVersionExA(&version) || - version.dwPlatformId != VER_PLATFORM_WIN32_NT || - version.dwMajorVersion < 6 || - (version.dwMajorVersion == 6 && version.dwMinorVersion < 2)) - return FALSE; - - return win32_is_32bit_on_64bit_system(); + return win32_is_win8_system() && win32_is_32bit_on_64bit_system(); #endif } @@ -350,7 +418,6 @@ UINT win32_change_error_mode(UINT new_mode) { SetThreadErrorModeProt MySetThreadErrorMode = NULL; - OSVERSIONINFOA version; HMODULE kernel32; HMODULE ntdll; DWORD old_mode; @@ -383,10 +450,7 @@ win32_change_error_mode(UINT new_mode) * On Windows NT 4.0+ systems fallback to thread HardErrorMode API. * It depends on architecture specific offset for HardErrorMode field in TEB. */ - version.dwOSVersionInfoSize = sizeof(version); - if (GetVersionExA(&version) && - version.dwPlatformId == VER_PLATFORM_WIN32_NT && - version.dwMajorVersion >= 4) + if (win32_is_nt40_system()) { ULONG *hard_error_mode_ptr = (ULONG *)((BYTE *)NtCurrentTeb() + TEB_HARD_ERROR_MODE_OFFSET); old_mode = *hard_error_mode_ptr; @@ -748,7 +812,6 @@ prepare_security_descriptor_for_set_operation(PSECURITY_DESCRIPTOR security_desc SECURITY_DESCRIPTOR_CONTROL bits_mask; SECURITY_DESCRIPTOR_CONTROL bits_set; SECURITY_DESCRIPTOR_CONTROL control; - OSVERSIONINFO version; HMODULE advapi32; DWORD revision; @@ -778,10 +841,7 @@ prepare_security_descriptor_for_set_operation(PSECURITY_DESCRIPTOR security_desc * older versions of advapi32.dll library, so resolve it at runtime. */ - version.dwOSVersionInfoSize = sizeof(version); - if (!GetVersionEx(&version) || - version.dwPlatformId != VER_PLATFORM_WIN32_NT || - version.dwMajorVersion < 5) + if (!win32_is_win2k_system()) return TRUE; if (!GetSecurityDescriptorControl(security_descriptor, &control, &revision)) @@ -1024,7 +1084,6 @@ open_process_for_query(DWORD pid, BOOL with_vm_read) { BOOL revert_only_privilege; LUID luid_debug_privilege; - OSVERSIONINFO version; DWORD process_right; HANDLE revert_token; HANDLE process; @@ -1044,10 +1103,7 @@ open_process_for_query(DWORD pid, BOOL with_vm_read) * PROCESS_QUERY_LIMITED_INFORMATION right on older systems than * Windows Vista (NT 6.0). */ - version.dwOSVersionInfoSize = sizeof(version); - if (GetVersionEx(&version) && - version.dwPlatformId == VER_PLATFORM_WIN32_NT && - version.dwMajorVersion >= 6) + if (win32_is_vista_system()) process_right = PROCESS_QUERY_LIMITED_INFORMATION; else process_right = PROCESS_QUERY_INFORMATION; diff --git a/lib/win32-helpers.h b/lib/win32-helpers.h index 93f2a4b..87843d7 100644 --- a/lib/win32-helpers.h +++ b/lib/win32-helpers.h @@ -1,6 +1,7 @@ const char *win32_strerror(DWORD win32_error_id); USHORT win32_get_process_machine(void); BOOL win32_is_non_nt_system(void); +BOOL win32_is_vista_system(void); BOOL win32_is_32bit_on_64bit_system(void); BOOL win32_is_32bit_on_win8_64bit_system(void); BOOL win32_is_not_native_process(USHORT *native_machine); diff --git a/lib/win32-kldbg.c b/lib/win32-kldbg.c index 089fbe0..9624239 100644 --- a/lib/win32-kldbg.c +++ b/lib/win32-kldbg.c @@ -467,7 +467,6 @@ out: static int win32_kldbg_setup(struct pci_access *a) { - OSVERSIONINFO version; DWORD ret_len; DWORD error; DWORD id; @@ -475,11 +474,7 @@ win32_kldbg_setup(struct pci_access *a) if (kldbg_dev != INVALID_HANDLE_VALUE) return 1; - /* Check for Windows Vista (NT 6.0). */ - version.dwOSVersionInfoSize = sizeof(version); - if (!GetVersionEx(&version) || - version.dwPlatformId != VER_PLATFORM_WIN32_NT || - version.dwMajorVersion < 6) + if (!win32_is_vista_system()) { a->debug("Accessing PCI config space via Kernel Local Debugging Driver requires Windows Vista or higher version."); return 0; -- 2.47.3