1 /* 2 * PROJECT: ReactOS Setup Library 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: NT Version Resource Management API 5 * COPYRIGHT: Copyright 2017-2018 Hermes Belusca-Maito 6 * 7 * NOTE 1: Adapted from Wine-synced dll/win32/version DLL. 8 * NOTE 2: We only deal with 32-bit PE executables. 9 */ 10 11 /* INCLUDES *****************************************************************/ 12 13 #include "precomp.h" 14 #include <ndk/ldrtypes.h> 15 #include <ndk/ldrfuncs.h> 16 17 #include "ntverrsrc.h" 18 19 #define NDEBUG 20 #include <debug.h> 21 22 23 /* FUNCTIONS ****************************************************************/ 24 25 NTSTATUS 26 NtGetVersionResource( 27 IN PVOID BaseAddress, 28 OUT PVOID* Resource, 29 OUT PULONG ResourceSize OPTIONAL) 30 { 31 // #define RT_VERSION MAKEINTRESOURCE(16) // See winuser.h 32 #define VS_VERSION_INFO 1 // See psdk/verrsrc.h 33 #define VS_FILE_INFO RT_VERSION 34 35 NTSTATUS Status; 36 LDR_RESOURCE_INFO ResourceInfo; 37 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry; 38 PVOID Data = NULL; 39 ULONG Size = 0; 40 41 /* Try to find the resource */ 42 ResourceInfo.Type = 16; // RT_VERSION; 43 ResourceInfo.Name = VS_VERSION_INFO; // MAKEINTRESOURCEW(VS_VERSION_INFO); 44 ResourceInfo.Language = 0; // Don't care about the language 45 46 Status = LdrFindResource_U(BaseAddress, 47 &ResourceInfo, 48 RESOURCE_DATA_LEVEL, 49 &ResourceDataEntry); 50 if (!NT_SUCCESS(Status)) 51 { 52 DPRINT1("NtGetVersionResource: Version resource not found, Status 0x%08lx\n", Status); 53 return Status; 54 } 55 56 /* Access the resource */ 57 Status = LdrAccessResource(BaseAddress, 58 ResourceDataEntry, 59 &Data, 60 &Size); 61 if (!NT_SUCCESS(Status)) 62 { 63 DPRINT1("NtGetVersionResource: Cannot access Version resource, Status 0x%08lx\n", Status); 64 return Status; 65 } 66 67 *Resource = Data; 68 if (ResourceSize) *ResourceSize = Size; 69 70 return STATUS_SUCCESS; 71 } 72 73 /* NOTE: the xxx_STRUCT16 version differs by storing strings in ANSI, not in UNICODE */ 74 typedef struct _VS_VERSION_INFO_STRUCT32 75 { 76 WORD wLength; 77 WORD wValueLength; 78 WORD wType; /* 1:Text, 0:Binary */ 79 WCHAR szKey[1]; 80 #if 0 /* variable length structure */ 81 /* DWORD aligned */ 82 BYTE Value[]; 83 /* DWORD aligned */ 84 VS_VERSION_INFO_STRUCT32 Children[]; 85 #endif 86 } VS_VERSION_INFO_STRUCT32, *PVS_VERSION_INFO_STRUCT32; 87 typedef const VS_VERSION_INFO_STRUCT32 *PCVS_VERSION_INFO_STRUCT32; 88 89 #define DWORD_ALIGN( base, ptr ) \ 90 ( (ULONG_PTR)(base) + ((((ULONG_PTR)(ptr) - (ULONG_PTR)(base)) + 3) & ~3) ) 91 92 #define VersionInfo32_Value( ver ) \ 93 DWORD_ALIGN( (ver), (ver)->szKey + wcslen((ver)->szKey) + 1 ) 94 95 #define VersionInfo32_Children( ver ) \ 96 (PCVS_VERSION_INFO_STRUCT32)( VersionInfo32_Value( ver ) + \ 97 ( ( (ver)->wValueLength * \ 98 ((ver)->wType? 2 : 1) + 3 ) & ~3 ) ) 99 100 #define VersionInfo32_Next( ver ) \ 101 (PVS_VERSION_INFO_STRUCT32)( (ULONG_PTR)ver + (((ver)->wLength + 3) & ~3) ) 102 103 static PCVS_VERSION_INFO_STRUCT32 104 VersionInfo32_FindChild( 105 IN PCVS_VERSION_INFO_STRUCT32 info, 106 IN PCWSTR szKey, 107 IN UINT cchKey) 108 { 109 PCVS_VERSION_INFO_STRUCT32 child = VersionInfo32_Children(info); 110 111 while ((ULONG_PTR)child < (ULONG_PTR)info + info->wLength) 112 { 113 if (!_wcsnicmp(child->szKey, szKey, cchKey) && !child->szKey[cchKey]) 114 return child; 115 116 if (child->wLength == 0) return NULL; 117 child = VersionInfo32_Next(child); 118 } 119 120 return NULL; 121 } 122 123 static NTSTATUS 124 VersionInfo32_QueryValue( 125 IN PCVS_VERSION_INFO_STRUCT32 info, 126 IN PCWSTR lpSubBlock, 127 OUT PVOID* lplpBuffer, 128 OUT PUINT puLen OPTIONAL, 129 OUT BOOL* pbText OPTIONAL) 130 { 131 PCWSTR lpNextSlash; 132 133 DPRINT("lpSubBlock : (%S)\n", lpSubBlock); 134 135 while (*lpSubBlock) 136 { 137 /* Find next path component */ 138 for (lpNextSlash = lpSubBlock; *lpNextSlash; lpNextSlash++) 139 { 140 if (*lpNextSlash == '\\') 141 break; 142 } 143 144 /* Skip empty components */ 145 if (lpNextSlash == lpSubBlock) 146 { 147 lpSubBlock++; 148 continue; 149 } 150 151 /* We have a non-empty component: search info for key */ 152 info = VersionInfo32_FindChild(info, lpSubBlock, lpNextSlash - lpSubBlock); 153 if (!info) 154 { 155 if (puLen) *puLen = 0; 156 return STATUS_RESOURCE_TYPE_NOT_FOUND; 157 } 158 159 /* Skip path component */ 160 lpSubBlock = lpNextSlash; 161 } 162 163 /* Return value */ 164 *lplpBuffer = (PVOID)VersionInfo32_Value(info); 165 if (puLen) 166 *puLen = info->wValueLength; 167 if (pbText) 168 *pbText = info->wType; 169 170 return STATUS_SUCCESS; 171 } 172 173 NTSTATUS 174 NtVerQueryValue( 175 IN const VOID* pBlock, 176 IN PCWSTR lpSubBlock, 177 OUT PVOID* lplpBuffer, 178 OUT PUINT puLen) 179 { 180 PCVS_VERSION_INFO_STRUCT32 info = pBlock; 181 182 DPRINT("%s (%p, %S, %p, %p)\n", __FUNCTION__, pBlock, lpSubBlock, lplpBuffer, puLen); 183 184 if (!pBlock) 185 return FALSE; 186 187 if (!lpSubBlock || !*lpSubBlock) 188 lpSubBlock = L"\\"; 189 190 return VersionInfo32_QueryValue(info, lpSubBlock, lplpBuffer, puLen, NULL); 191 } 192 193 /* EOF */ 194