/* * PROJECT: ReactOS Setup Library * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) * PURPOSE: NT Version Resource Management API * COPYRIGHT: Copyright 2017-2018 Hermes Belusca-Maito * * NOTE 1: Adapted from Wine-synced dll/win32/version DLL. * NOTE 2: We only deal with 32-bit PE executables. */ /* INCLUDES *****************************************************************/ #include "precomp.h" #include #include #include "ntverrsrc.h" #define NDEBUG #include /* FUNCTIONS ****************************************************************/ NTSTATUS NtGetVersionResource( IN PVOID BaseAddress, OUT PVOID* Resource, OUT PULONG ResourceSize OPTIONAL) { // #define RT_VERSION MAKEINTRESOURCE(16) // See winuser.h #define VS_VERSION_INFO 1 // See psdk/verrsrc.h #define VS_FILE_INFO RT_VERSION NTSTATUS Status; LDR_RESOURCE_INFO ResourceInfo; PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry; PVOID Data = NULL; ULONG Size = 0; /* Try to find the resource */ ResourceInfo.Type = 16; // RT_VERSION; ResourceInfo.Name = VS_VERSION_INFO; // MAKEINTRESOURCEW(VS_VERSION_INFO); ResourceInfo.Language = 0; // Don't care about the language Status = LdrFindResource_U(BaseAddress, &ResourceInfo, RESOURCE_DATA_LEVEL, &ResourceDataEntry); if (!NT_SUCCESS(Status)) { DPRINT1("NtGetVersionResource: Version resource not found, Status 0x%08lx\n", Status); return Status; } /* Access the resource */ Status = LdrAccessResource(BaseAddress, ResourceDataEntry, &Data, &Size); if (!NT_SUCCESS(Status)) { DPRINT1("NtGetVersionResource: Cannot access Version resource, Status 0x%08lx\n", Status); return Status; } *Resource = Data; if (ResourceSize) *ResourceSize = Size; return STATUS_SUCCESS; } /* NOTE: the xxx_STRUCT16 version differs by storing strings in ANSI, not in UNICODE */ typedef struct _VS_VERSION_INFO_STRUCT32 { WORD wLength; WORD wValueLength; WORD wType; /* 1:Text, 0:Binary */ WCHAR szKey[1]; #if 0 /* variable length structure */ /* DWORD aligned */ BYTE Value[]; /* DWORD aligned */ VS_VERSION_INFO_STRUCT32 Children[]; #endif } VS_VERSION_INFO_STRUCT32, *PVS_VERSION_INFO_STRUCT32; typedef const VS_VERSION_INFO_STRUCT32 *PCVS_VERSION_INFO_STRUCT32; #define DWORD_ALIGN( base, ptr ) \ ( (ULONG_PTR)(base) + ((((ULONG_PTR)(ptr) - (ULONG_PTR)(base)) + 3) & ~3) ) #define VersionInfo32_Value( ver ) \ DWORD_ALIGN( (ver), (ver)->szKey + wcslen((ver)->szKey) + 1 ) #define VersionInfo32_Children( ver ) \ (PCVS_VERSION_INFO_STRUCT32)( VersionInfo32_Value( ver ) + \ ( ( (ver)->wValueLength * \ ((ver)->wType? 2 : 1) + 3 ) & ~3 ) ) #define VersionInfo32_Next( ver ) \ (PVS_VERSION_INFO_STRUCT32)( (ULONG_PTR)ver + (((ver)->wLength + 3) & ~3) ) static PCVS_VERSION_INFO_STRUCT32 VersionInfo32_FindChild( IN PCVS_VERSION_INFO_STRUCT32 info, IN PCWSTR szKey, IN UINT cchKey) { PCVS_VERSION_INFO_STRUCT32 child = VersionInfo32_Children(info); while ((ULONG_PTR)child < (ULONG_PTR)info + info->wLength) { if (!_wcsnicmp(child->szKey, szKey, cchKey) && !child->szKey[cchKey]) return child; if (child->wLength == 0) return NULL; child = VersionInfo32_Next(child); } return NULL; } static NTSTATUS VersionInfo32_QueryValue( IN PCVS_VERSION_INFO_STRUCT32 info, IN PCWSTR lpSubBlock, OUT PVOID* lplpBuffer, OUT PUINT puLen OPTIONAL, OUT BOOL* pbText OPTIONAL) { PCWSTR lpNextSlash; DPRINT("lpSubBlock : (%S)\n", lpSubBlock); while (*lpSubBlock) { /* Find next path component */ for (lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++) { if (*lpNextSlash == '\\') break; } /* Skip empty components */ if (lpNextSlash == lpSubBlock) { lpSubBlock++; continue; } /* We have a non-empty component: search info for key */ info = VersionInfo32_FindChild(info, lpSubBlock, lpNextSlash - lpSubBlock); if (!info) { if (puLen) *puLen = 0; return STATUS_RESOURCE_TYPE_NOT_FOUND; } /* Skip path component */ lpSubBlock = lpNextSlash; } /* Return value */ *lplpBuffer = (PVOID)VersionInfo32_Value(info); if (puLen) *puLen = info->wValueLength; if (pbText) *pbText = info->wType; return STATUS_SUCCESS; } NTSTATUS NtVerQueryValue( IN const VOID* pBlock, IN PCWSTR lpSubBlock, OUT PVOID* lplpBuffer, OUT PUINT puLen) { PCVS_VERSION_INFO_STRUCT32 info = pBlock; DPRINT("%s (%p, %S, %p, %p)\n", __FUNCTION__, pBlock, lpSubBlock, lplpBuffer, puLen); if (!pBlock) return FALSE; if (!lpSubBlock || !*lpSubBlock) lpSubBlock = L"\\"; return VersionInfo32_QueryValue(info, lpSubBlock, lplpBuffer, puLen, NULL); } /* EOF */