Since Windows 8.1, these functions have been deprecated and run in a sort of compatibility mode, reporting Windows 8 unless the application supplies a manifest that specifies compatibility with newer Windows versions explicitly (by listing their GUIDs).
Some applications have bad non-forward-compatible checks based on GetVersionEx, and depend on this behavior (they do not supply a manifest). Currently, they break on Wine if we use a Windows 10 prefix for example, since we always report the real version. One example is the game Rock of Ages.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
I'm introducing an exported internal ntdll function, since I didn't want to duplicate the table for kernelbase. I don't know if this is the best way, so let me know if I should proceed differently.
dlls/kernelbase/version.c | 54 +++++++++++++++++++------ dlls/ntdll/ntdll.spec | 1 + dlls/ntdll/version.c | 85 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+), 13 deletions(-)
diff --git a/dlls/kernelbase/version.c b/dlls/kernelbase/version.c index cf46e9c..d07c1c9 100644 --- a/dlls/kernelbase/version.c +++ b/dlls/kernelbase/version.c @@ -43,6 +43,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(ver);
+extern CDECL const RTL_OSVERSIONINFOEXW *__wine_get_compat_win_version(void); + typedef struct { WORD offset; @@ -1317,7 +1319,7 @@ DWORD WINAPI GetVersion(void) */ BOOL WINAPI GetVersionExA( OSVERSIONINFOA *info ) { - RTL_OSVERSIONINFOEXW infoW; + const RTL_OSVERSIONINFOEXW *ver;
if (info->dwOSVersionInfoSize != sizeof(OSVERSIONINFOA) && info->dwOSVersionInfoSize != sizeof(OSVERSIONINFOEXA)) @@ -1327,23 +1329,26 @@ BOOL WINAPI GetVersionExA( OSVERSIONINFOA *info ) return FALSE; }
- infoW.dwOSVersionInfoSize = sizeof(infoW); - if (!set_ntstatus( RtlGetVersion( &infoW ))) return FALSE; + if (!(ver = __wine_get_compat_win_version())) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + }
- info->dwMajorVersion = infoW.dwMajorVersion; - info->dwMinorVersion = infoW.dwMinorVersion; - info->dwBuildNumber = infoW.dwBuildNumber; - info->dwPlatformId = infoW.dwPlatformId; - WideCharToMultiByte( CP_ACP, 0, infoW.szCSDVersion, -1, + info->dwMajorVersion = ver->dwMajorVersion; + info->dwMinorVersion = ver->dwMinorVersion; + info->dwBuildNumber = ver->dwBuildNumber; + info->dwPlatformId = ver->dwPlatformId; + WideCharToMultiByte( CP_ACP, 0, ver->szCSDVersion, -1, info->szCSDVersion, sizeof(info->szCSDVersion), NULL, NULL );
if (info->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA)) { OSVERSIONINFOEXA *vex = (OSVERSIONINFOEXA *)info; - vex->wServicePackMajor = infoW.wServicePackMajor; - vex->wServicePackMinor = infoW.wServicePackMinor; - vex->wSuiteMask = infoW.wSuiteMask; - vex->wProductType = infoW.wProductType; + vex->wServicePackMajor = ver->wServicePackMajor; + vex->wServicePackMinor = ver->wServicePackMinor; + vex->wSuiteMask = ver->wSuiteMask; + vex->wProductType = ver->wProductType; } return TRUE; } @@ -1354,11 +1359,34 @@ BOOL WINAPI GetVersionExA( OSVERSIONINFOA *info ) */ BOOL WINAPI GetVersionExW( OSVERSIONINFOW *info ) { + const RTL_OSVERSIONINFOEXW *ver; + if (info->dwOSVersionInfoSize != sizeof(OSVERSIONINFOW) && info->dwOSVersionInfoSize != sizeof(OSVERSIONINFOEXW)) { WARN( "wrong OSVERSIONINFO size from app (got: %d)\n", info->dwOSVersionInfoSize ); return FALSE; } - return set_ntstatus( RtlGetVersion( (RTL_OSVERSIONINFOEXW *)info )); + + if (!(ver = __wine_get_compat_win_version())) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + + info->dwMajorVersion = ver->dwMajorVersion; + info->dwMinorVersion = ver->dwMinorVersion; + info->dwBuildNumber = ver->dwBuildNumber; + info->dwPlatformId = ver->dwPlatformId; + wcscpy( info->szCSDVersion, ver->szCSDVersion ); + + if(info->dwOSVersionInfoSize == sizeof(RTL_OSVERSIONINFOEXW)) + { + OSVERSIONINFOEXW *vex = (OSVERSIONINFOEXW *)info; + vex->wServicePackMajor = ver->wServicePackMajor; + vex->wServicePackMinor = ver->wServicePackMinor; + vex->wSuiteMask = ver->wSuiteMask; + vex->wProductType = ver->wProductType; + } + return TRUE; } diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 0ea72e3..5f58e4a 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -1572,6 +1572,7 @@ @ cdecl wine_get_version() NTDLL_wine_get_version @ cdecl wine_get_build_id() NTDLL_wine_get_build_id @ cdecl wine_get_host_version(ptr ptr) NTDLL_wine_get_host_version +@ cdecl __wine_get_compat_win_version()
# Codepages @ cdecl __wine_get_unix_codepage() diff --git a/dlls/ntdll/version.c b/dlls/ntdll/version.c index 61e48f6..f48f725 100644 --- a/dlls/ntdll/version.c +++ b/dlls/ntdll/version.c @@ -191,6 +191,13 @@ static const RTL_OSVERSIONINFOEXW VersionData[NB_WINDOWS_VERSIONS] =
};
+/* GUIDs for Windows versions WIN81 and later, needed for compatibility manifest check */ +static const GUID version_compat_guid[NB_WINDOWS_VERSIONS - WIN81] = +{ + {0x1f676c76,0x80e1,0x4239,{0x95,0xbb,0x83,0xd0,0xf6,0xd0,0xda,0x78}}, /* WIN81 */ + {0x8e0f7a12,0xbfb3,0x4fe8,{0xb9,0xa5,0x48,0xfd,0x50,0xa1,0x5a,0x9a}}, /* WIN10 */ +}; + static const struct { WCHAR name[12]; WINDOWS_VERSION ver; } version_names[] = { { {'w','i','n','2','0',0}, WIN20 }, @@ -781,3 +788,81 @@ NTSTATUS WINAPI RtlVerifyVersionInfo( const RTL_OSVERSIONINFOEXW *info,
return STATUS_SUCCESS; } + +/****************************************************************************** + * __wine_get_compat_win_version (NTDLL.@) + * + * Get a pointer to a RTL_OSVERSIONINFOEXW that matches the compatibility mode. + * + * For compatibility, Windows 8.1 and later report Win8 version unless the app + * has a manifest that confirms its compatibility with newer versions of Windows. + * + * RETURNS + * A pointer to a RTL_OSVERSIONINFOEXW containing the version in compatibility + * mode, or NULL if out of memory. + */ +CDECL const RTL_OSVERSIONINFOEXW *__wine_get_compat_win_version(void) +{ + static const RTL_OSVERSIONINFOEXW *compat_ver; + + if (!compat_ver) + { + /*ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION*/DWORD *acci; + const RTL_OSVERSIONINFOEXW *ver = current_version; + SIZE_T req; + int idx; + + for (idx = ARRAY_SIZE(version_compat_guid); idx--;) + { + const RTL_OSVERSIONINFOEXW *v = &VersionData[WIN81 + idx]; + + if ( current_version->dwMajorVersion > v->dwMajorVersion || + (current_version->dwMajorVersion == v->dwMajorVersion && + current_version->dwMinorVersion >= v->dwMinorVersion)) + break; + } + + if (idx >= 0) + { + ver = &VersionData[WIN8]; + + if (RtlQueryInformationActivationContext(0, NULL, NULL, + CompatibilityInformationInActivationContext, NULL, 0, &req) == STATUS_BUFFER_TOO_SMALL + && req) + { + if (!(acci = RtlAllocateHeap(GetProcessHeap(), 0, req))) + return NULL; + + if (RtlQueryInformationActivationContext(0, NULL, NULL, + CompatibilityInformationInActivationContext, acci, req, &req) == STATUS_SUCCESS) + { + do + { + COMPATIBILITY_CONTEXT_ELEMENT *elements = (COMPATIBILITY_CONTEXT_ELEMENT*)(acci + 1); + DWORD i, count = *acci; + + for (i = 0; i < count; i++) + { + if (elements[i].Type == ACTCX_COMPATIBILITY_ELEMENT_TYPE_OS && + IsEqualGUID(&elements[i].Id, &version_compat_guid[idx])) + { + ver = &VersionData[WIN81 + idx]; + + if (ver->dwMajorVersion == current_version->dwMajorVersion && + ver->dwMinorVersion == current_version->dwMinorVersion) + ver = current_version; + + idx = 0; /* break from outer loop */ + break; + } + } + } while(idx--); + } + RtlFreeHeap(GetProcessHeap(), 0, acci); + } + } + interlocked_cmpxchg_ptr((void**)&compat_ver, (void*)ver, NULL); + } + + return compat_ver; +}
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/kernelbase/version.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/dlls/kernelbase/version.c b/dlls/kernelbase/version.c index d07c1c9..d0c5186 100644 --- a/dlls/kernelbase/version.c +++ b/dlls/kernelbase/version.c @@ -1305,11 +1305,20 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetProductInfo( DWORD os_major, DWORD os_minor, */ DWORD WINAPI GetVersion(void) { - DWORD result = MAKELONG( MAKEWORD( NtCurrentTeb()->Peb->OSMajorVersion, - NtCurrentTeb()->Peb->OSMinorVersion ), - (NtCurrentTeb()->Peb->OSPlatformId ^ 2) << 14 ); - if (NtCurrentTeb()->Peb->OSPlatformId == VER_PLATFORM_WIN32_NT) - result |= LOWORD(NtCurrentTeb()->Peb->OSBuildNumber) << 16; + const RTL_OSVERSIONINFOEXW *ver; + DWORD result; + + if (!(ver = __wine_get_compat_win_version())) + { + ERR( "failed to get version (not enough memory)\n" ); + return 0; + } + + result = MAKELONG( MAKEWORD( ver->dwMajorVersion, ver->dwMinorVersion ), + (ver->dwPlatformId ^ 2) << 14 ); + + if (ver->dwPlatformId == VER_PLATFORM_WIN32_NT) + result |= LOWORD(ver->dwBuildNumber) << 16; return result; }
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/ntdll/version.c | 54 +++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 23 deletions(-)
diff --git a/dlls/ntdll/version.c b/dlls/ntdll/version.c index f48f725..60c4942 100644 --- a/dlls/ntdll/version.c +++ b/dlls/ntdll/version.c @@ -701,25 +701,16 @@ static inline NTSTATUS version_compare_values(ULONG left, ULONG right, UCHAR con return STATUS_SUCCESS; }
-/****************************************************************************** - * RtlVerifyVersionInfo (NTDLL.@) - */ -NTSTATUS WINAPI RtlVerifyVersionInfo( const RTL_OSVERSIONINFOEXW *info, - DWORD dwTypeMask, DWORDLONG dwlConditionMask ) +static NTSTATUS verify_version_info(const RTL_OSVERSIONINFOEXW *info, const RTL_OSVERSIONINFOEXW *ver, + DWORD dwTypeMask, DWORDLONG dwlConditionMask) { - RTL_OSVERSIONINFOEXW ver; NTSTATUS status;
- TRACE("(%p,0x%x,0x%s)\n", info, dwTypeMask, wine_dbgstr_longlong(dwlConditionMask)); - - ver.dwOSVersionInfoSize = sizeof(ver); - if ((status = RtlGetVersion( &ver )) != STATUS_SUCCESS) return status; - if(!(dwTypeMask && dwlConditionMask)) return STATUS_INVALID_PARAMETER;
if(dwTypeMask & VER_PRODUCT_TYPE) { - status = version_compare_values(ver.wProductType, info->wProductType, dwlConditionMask >> 7*3 & 0x07); + status = version_compare_values(ver->wProductType, info->wProductType, dwlConditionMask >> 7*3 & 0x07); if (status != STATUS_SUCCESS) return status; } @@ -727,11 +718,11 @@ NTSTATUS WINAPI RtlVerifyVersionInfo( const RTL_OSVERSIONINFOEXW *info, switch(dwlConditionMask >> 6*3 & 0x07) { case VER_AND: - if((info->wSuiteMask & ver.wSuiteMask) != info->wSuiteMask) + if((info->wSuiteMask & ver->wSuiteMask) != info->wSuiteMask) return STATUS_REVISION_MISMATCH; break; case VER_OR: - if(!(info->wSuiteMask & ver.wSuiteMask) && info->wSuiteMask) + if(!(info->wSuiteMask & ver->wSuiteMask) && info->wSuiteMask) return STATUS_REVISION_MISMATCH; break; default: @@ -739,13 +730,13 @@ NTSTATUS WINAPI RtlVerifyVersionInfo( const RTL_OSVERSIONINFOEXW *info, } if(dwTypeMask & VER_PLATFORMID) { - status = version_compare_values(ver.dwPlatformId, info->dwPlatformId, dwlConditionMask >> 3*3 & 0x07); + status = version_compare_values(ver->dwPlatformId, info->dwPlatformId, dwlConditionMask >> 3*3 & 0x07); if (status != STATUS_SUCCESS) return status; } if(dwTypeMask & VER_BUILDNUMBER) { - status = version_compare_values(ver.dwBuildNumber, info->dwBuildNumber, dwlConditionMask >> 2*3 & 0x07); + status = version_compare_values(ver->dwBuildNumber, info->dwBuildNumber, dwlConditionMask >> 2*3 & 0x07); if (status != STATUS_SUCCESS) return status; } @@ -758,28 +749,28 @@ NTSTATUS WINAPI RtlVerifyVersionInfo( const RTL_OSVERSIONINFOEXW *info, if(dwTypeMask & VER_MAJORVERSION) { condition = version_update_condition(&last_condition, dwlConditionMask >> 1*3 & 0x07); - status = version_compare_values(ver.dwMajorVersion, info->dwMajorVersion, condition); - do_next_check = (ver.dwMajorVersion == info->dwMajorVersion) && + status = version_compare_values(ver->dwMajorVersion, info->dwMajorVersion, condition); + do_next_check = (ver->dwMajorVersion == info->dwMajorVersion) && ((condition >= VER_EQUAL) && (condition <= VER_LESS_EQUAL)); } if((dwTypeMask & VER_MINORVERSION) && do_next_check) { condition = version_update_condition(&last_condition, dwlConditionMask >> 0*3 & 0x07); - status = version_compare_values(ver.dwMinorVersion, info->dwMinorVersion, condition); - do_next_check = (ver.dwMinorVersion == info->dwMinorVersion) && + status = version_compare_values(ver->dwMinorVersion, info->dwMinorVersion, condition); + do_next_check = (ver->dwMinorVersion == info->dwMinorVersion) && ((condition >= VER_EQUAL) && (condition <= VER_LESS_EQUAL)); } if((dwTypeMask & VER_SERVICEPACKMAJOR) && do_next_check) { condition = version_update_condition(&last_condition, dwlConditionMask >> 5*3 & 0x07); - status = version_compare_values(ver.wServicePackMajor, info->wServicePackMajor, condition); - do_next_check = (ver.wServicePackMajor == info->wServicePackMajor) && + status = version_compare_values(ver->wServicePackMajor, info->wServicePackMajor, condition); + do_next_check = (ver->wServicePackMajor == info->wServicePackMajor) && ((condition >= VER_EQUAL) && (condition <= VER_LESS_EQUAL)); } if((dwTypeMask & VER_SERVICEPACKMINOR) && do_next_check) { condition = version_update_condition(&last_condition, dwlConditionMask >> 4*3 & 0x07); - status = version_compare_values(ver.wServicePackMinor, info->wServicePackMinor, condition); + status = version_compare_values(ver->wServicePackMinor, info->wServicePackMinor, condition); }
if (status != STATUS_SUCCESS) @@ -789,6 +780,23 @@ NTSTATUS WINAPI RtlVerifyVersionInfo( const RTL_OSVERSIONINFOEXW *info, return STATUS_SUCCESS; }
+/****************************************************************************** + * RtlVerifyVersionInfo (NTDLL.@) + */ +NTSTATUS WINAPI RtlVerifyVersionInfo( const RTL_OSVERSIONINFOEXW *info, + DWORD dwTypeMask, DWORDLONG dwlConditionMask ) +{ + RTL_OSVERSIONINFOEXW ver; + NTSTATUS status; + + TRACE("(%p,0x%x,0x%s)\n", info, dwTypeMask, wine_dbgstr_longlong(dwlConditionMask)); + + ver.dwOSVersionInfoSize = sizeof(ver); + if ((status = RtlGetVersion( &ver )) != STATUS_SUCCESS) return status; + + return verify_version_info(info, &ver, dwTypeMask, dwlConditionMask); +} + /****************************************************************************** * __wine_get_compat_win_version (NTDLL.@) *
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/kernel32/version.c | 7 ++++++- dlls/ntdll/ntdll.spec | 1 + dlls/ntdll/version.c | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/version.c b/dlls/kernel32/version.c index 5f33847..d67bef5 100644 --- a/dlls/kernel32/version.c +++ b/dlls/kernel32/version.c @@ -41,6 +41,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(ver);
+extern NTSTATUS CDECL __wine_verify_compat_win_version(const RTL_OSVERSIONINFOEXW*,DWORD,DWORDLONG); +
/****************************************************************************** * VerifyVersionInfoA (KERNEL32.@) @@ -71,11 +73,14 @@ BOOL WINAPI VerifyVersionInfoA( LPOSVERSIONINFOEXA lpVersionInfo, DWORD dwTypeMa BOOL WINAPI VerifyVersionInfoW( LPOSVERSIONINFOEXW lpVersionInfo, DWORD dwTypeMask, DWORDLONG dwlConditionMask) { - switch(RtlVerifyVersionInfo( lpVersionInfo, dwTypeMask, dwlConditionMask )) + switch(__wine_verify_compat_win_version( lpVersionInfo, dwTypeMask, dwlConditionMask )) { case STATUS_INVALID_PARAMETER: SetLastError( ERROR_BAD_ARGUMENTS ); return FALSE; + case STATUS_NO_MEMORY: + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return FALSE; case STATUS_REVISION_MISMATCH: SetLastError( ERROR_OLD_WIN_VERSION ); return FALSE; diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 5f58e4a..5cc6d63 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -1573,6 +1573,7 @@ @ cdecl wine_get_build_id() NTDLL_wine_get_build_id @ cdecl wine_get_host_version(ptr ptr) NTDLL_wine_get_host_version @ cdecl __wine_get_compat_win_version() +@ cdecl __wine_verify_compat_win_version()
# Codepages @ cdecl __wine_get_unix_codepage() diff --git a/dlls/ntdll/version.c b/dlls/ntdll/version.c index 60c4942..76df243 100644 --- a/dlls/ntdll/version.c +++ b/dlls/ntdll/version.c @@ -874,3 +874,21 @@ CDECL const RTL_OSVERSIONINFOEXW *__wine_get_compat_win_version(void)
return compat_ver; } + +/****************************************************************************** + * __wine_verify_compat_win_version (NTDLL.@) + * + * Same as RtlVerifyVersionInfo, but uses compatibility mode. + * See __wine_get_compat_win_version for more information. + * + */ +NTSTATUS CDECL __wine_verify_compat_win_version( const RTL_OSVERSIONINFOEXW *info, + DWORD dwTypeMask, DWORDLONG dwlConditionMask ) +{ + const RTL_OSVERSIONINFOEXW *ver; + + if (!(ver = __wine_get_compat_win_version())) + return STATUS_NO_MEMORY; + + return verify_version_info(info, ver, dwTypeMask, dwlConditionMask); +}
On 3/16/20 4:05 PM, Gabriel Ivăncescu wrote:
I'm introducing an exported internal ntdll function, since I didn't want to duplicate the table for kernelbase. I don't know if this is the best way, so let me know if I should proceed differently.
I think custom export is unnecessary in this case. You only need a public ntdll call that returns unaltered version, that you can later clamp to Windows 8.1, unless manifest version is specified. Is RtlGetVersion() itself affected by manifest?
Same for patch 4/4.
P.S. another question is if PEB fields are left intact.
Hi Nikolay,
On 16/03/2020 15:21, Nikolay Sivov wrote:
On 3/16/20 4:05 PM, Gabriel Ivăncescu wrote:
I'm introducing an exported internal ntdll function, since I didn't want to duplicate the table for kernelbase. I don't know if this is the best way, so let me know if I should proceed differently.
I think custom export is unnecessary in this case. You only need a public ntdll call that returns unaltered version, that you can later clamp to Windows 8.1, unless manifest version is specified. Is RtlGetVersion() itself affected by manifest?
Only the functions changed by the patch series are affected. Just clamping to Windows 8 isn't going to work, consider the case where:
- We have Windows 10 prefix. - Application only specifies GUID for Windows 8.1, not Windows 10. - Returned Version must be Windows 8.1, not Windows 8 (no manifest).
The reason I exported it from ntdll was to have access to the version table there. Otherwise we'd have to duplicate the table from WIN8 and up.
It also makes it trivial to extend it, should Microsoft release new Windows versions: just add new GUIDs.
P.S. another question is if PEB fields are left intact.
Good question, I'll test it. Though of course it would be a separate patch if so.
Thanks, Gabriel
On 3/16/20 4:44 PM, Gabriel Ivăncescu wrote:
Hi Nikolay,
On 16/03/2020 15:21, Nikolay Sivov wrote:
On 3/16/20 4:05 PM, Gabriel Ivăncescu wrote:
I'm introducing an exported internal ntdll function, since I didn't want to duplicate the table for kernelbase. I don't know if this is the best way, so let me know if I should proceed differently.
I think custom export is unnecessary in this case. You only need a public ntdll call that returns unaltered version, that you can later clamp to Windows 8.1, unless manifest version is specified. Is RtlGetVersion() itself affected by manifest?
Only the functions changed by the patch series are affected. Just clamping to Windows 8 isn't going to work, consider the case where:
- We have Windows 10 prefix.
- Application only specifies GUID for Windows 8.1, not Windows 10.
- Returned Version must be Windows 8.1, not Windows 8 (no manifest).
The reason I exported it from ntdll was to have access to the version table there. Otherwise we'd have to duplicate the table from WIN8 and up.
It also makes it trivial to extend it, should Microsoft release new Windows versions: just add new GUIDs.
Guid/version mapping is not going to be used from ntdll, right? So far you'll only need to duplicate two 8.1 and 10, with a good chance that no version will follow as Windows continues to be 10. By the way if you set manifest entry to anything below Win 8.1 (Vista/7/8), does it affect reported version?
P.S. another question is if PEB fields are left intact.
Good question, I'll test it. Though of course it would be a separate patch if so.
Thanks, Gabriel
On 16/03/2020 15:52, Nikolay Sivov wrote:
On 3/16/20 4:44 PM, Gabriel Ivăncescu wrote:
Hi Nikolay,
On 16/03/2020 15:21, Nikolay Sivov wrote:
On 3/16/20 4:05 PM, Gabriel Ivăncescu wrote:
I'm introducing an exported internal ntdll function, since I didn't want to duplicate the table for kernelbase. I don't know if this is the best way, so let me know if I should proceed differently.
I think custom export is unnecessary in this case. You only need a public ntdll call that returns unaltered version, that you can later clamp to Windows 8.1, unless manifest version is specified. Is RtlGetVersion() itself affected by manifest?
Only the functions changed by the patch series are affected. Just clamping to Windows 8 isn't going to work, consider the case where:
- We have Windows 10 prefix.
- Application only specifies GUID for Windows 8.1, not Windows 10.
- Returned Version must be Windows 8.1, not Windows 8 (no manifest).
The reason I exported it from ntdll was to have access to the version table there. Otherwise we'd have to duplicate the table from WIN8 and up.
It also makes it trivial to extend it, should Microsoft release new Windows versions: just add new GUIDs.
Guid/version mapping is not going to be used from ntdll, right? So far you'll only need to duplicate two 8.1 and 10, with a good chance that no version will follow as Windows continues to be 10. By the way if you set manifest entry to anything below Win 8.1 (Vista/7/8), does it affect reported version?
Yeah, I'll have to duplicate everything from WIN8 and up, so that's 3 versions currently. Do you think that's better?
Another issue is VerifyVersionInfo. We'd have to duplicate the entire RtlVerifyVersionInfo function in kernel32 (but use GetVersionEx).
Also, setting it to anything below WIN8.1 has no effect as far as I'm aware, at least with respect to these APIs. It will still report WIN8.
On Mon, Mar 16, 2020 at 7:07 AM Gabriel Ivăncescu gabrielopcode@gmail.com wrote:
if (idx >= 0)
{
ver = &VersionData[WIN8];
if (RtlQueryInformationActivationContext(0, NULL, NULL,
CompatibilityInformationInActivationContext, NULL, 0, &req) == STATUS_BUFFER_TOO_SMALL
&& req)
{
if (!(acci = RtlAllocateHeap(GetProcessHeap(), 0, req)))
return NULL;
if (RtlQueryInformationActivationContext(0, NULL, NULL,
CompatibilityInformationInActivationContext, acci, req, &req) == STATUS_SUCCESS)
{
Please use the goto keyword to avoid nesting a lot of if statements. It'll make any future patches that modify this code much cleaner.
-Alex