Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

497 lines
12 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. version.h
  5. Abstract:
  6. Implementation of file version checking.
  7. Author:
  8. Wesley Witt (wesw) 18-Dec-1998
  9. Revision History:
  10. Andrew Ritz (andrewr) 6-Jul-1999
  11. --*/
  12. #include "sfcp.h"
  13. #pragma hdrstop
  14. //
  15. // Resource type information block
  16. //
  17. typedef struct rsrc_typeinfo RSRC_TYPEINFO, *LPRESTYPEINFO;
  18. //
  19. // Resource name information block
  20. //
  21. typedef struct rsrc_nameinfo RSRC_NAMEINFO, *PRSRC_NAMEINFO;
  22. #define RSORDID 0x8000 // if high bit of ID set then integer id
  23. // otherwise ID is offset of string from
  24. // the beginning of the resource table
  25. // Ideally these are the same as the
  26. // corresponding segment flags
  27. typedef struct _RESOURCE_DATAW {
  28. USHORT TotalSize;
  29. USHORT DataSize;
  30. USHORT Type;
  31. WCHAR Name[16]; // L"VS_VERSION_INFO" + unicode nul
  32. VS_FIXEDFILEINFO FixedFileInfo;
  33. } RESOURCE_DATAW, *PRESOURCE_DATAW;
  34. typedef struct _RESOURCE_DATAA {
  35. USHORT TotalSize;
  36. USHORT DataSize;
  37. USHORT Type;
  38. CHAR Name[16]; // L"VS_VERSION_INFO" + unicode nul
  39. VS_FIXEDFILEINFO FixedFileInfo;
  40. } RESOURCE_DATAA, *PRESOURCE_DATAA;
  41. LPBYTE
  42. FindResWithIndex(
  43. LPBYTE lpResTable,
  44. INT iResIndex,
  45. LPBYTE lpResType
  46. )
  47. /*++
  48. Routine Description:
  49. Routine searches for a resource in a resource table at the specified index.
  50. The routine works by walking the resource table until we hit the specified
  51. resource.
  52. Arguments:
  53. lpResTable - pointer to the resource table
  54. iResIndex - integer indicating the index of the resource to be retreived
  55. lpResType - pointer to data indicating the type of resource we're
  56. manipulating
  57. Return Value:
  58. a pointer to the specified resource or NULL on failure.
  59. --*/
  60. {
  61. LPRESTYPEINFO lpResTypeInfo;
  62. ASSERT((lpResTable != NULL) && (iResIndex >= 0));
  63. try {
  64. lpResTypeInfo = (LPRESTYPEINFO)(lpResTable + sizeof(WORD));
  65. while (lpResTypeInfo->rt_id) {
  66. if ((lpResTypeInfo->rt_id & RSORDID) &&
  67. (MAKEINTRESOURCE(lpResTypeInfo->rt_id & ~RSORDID) == (LPTSTR)lpResType)) {
  68. if (lpResTypeInfo->rt_nres > (WORD)iResIndex) {
  69. return (LPBYTE)(lpResTypeInfo+1) + iResIndex * sizeof(RSRC_NAMEINFO);
  70. } else {
  71. return NULL;
  72. }
  73. }
  74. //
  75. // point to the next resource
  76. //
  77. lpResTypeInfo = (LPRESTYPEINFO)((LPBYTE)(lpResTypeInfo+1) + lpResTypeInfo->rt_nres * sizeof(RSRC_NAMEINFO));
  78. }
  79. DebugPrint( LVL_VERBOSE, L"FindResWithIndex didn't find resource\n" );
  80. return(NULL);
  81. } except (EXCEPTION_EXECUTE_HANDLER) {
  82. DebugPrint( LVL_VERBOSE, L"FindResWithIndex hit an exception\n" );
  83. }
  84. return (NULL);
  85. }
  86. ULONGLONG
  87. GetFileVersion16(
  88. PVOID ImageBase,
  89. PIMAGE_OS2_HEADER NewImageHeader
  90. )
  91. /*++
  92. Routine Description:
  93. Routine retreives the version for a downlevel image file.
  94. Arguments:
  95. ImageBase - base pointer to the image
  96. NewImageHeader - pointer to the image's new header
  97. Return Value:
  98. a number indicating the version of the image or 0 if the version is
  99. unavailable
  100. --*/
  101. {
  102. PBYTE ResTable;
  103. PRSRC_NAMEINFO ResPtr;
  104. PRESOURCE_DATAA ResourceDataA;
  105. ULONG iShiftCount;
  106. ULONG Offset;
  107. ULONGLONG Version = 0;
  108. ASSERT(ImageBase != NULL && NewImageHeader != NULL && IMAGE_OS2_SIGNATURE == NewImageHeader->ne_magic);
  109. if (NewImageHeader->ne_rsrctab != NewImageHeader->ne_restab) {
  110. ResTable = (PBYTE) NewImageHeader + NewImageHeader->ne_rsrctab;
  111. ResPtr = (PRSRC_NAMEINFO) FindResWithIndex( ResTable, 0, (LPBYTE)RT_VERSION );
  112. if (ResPtr) {
  113. iShiftCount = *((WORD *)ResTable);
  114. Offset = MAKELONG(ResPtr->rn_offset << iShiftCount, (ResPtr->rn_offset) >> (16 - iShiftCount));
  115. ResourceDataA = (PRESOURCE_DATAA)((PBYTE)ImageBase + Offset);
  116. Version = ((ULONGLONG)ResourceDataA->FixedFileInfo.dwFileVersionMS << 32)
  117. | (ULONGLONG)ResourceDataA->FixedFileInfo.dwFileVersionLS;
  118. }
  119. }
  120. return Version;
  121. }
  122. ULONGLONG
  123. GetFileVersion32(
  124. IN PVOID ImageBase
  125. )
  126. /*++
  127. Routine Description:
  128. Routine retreives the version for a 32 bit image file.
  129. Arguments:
  130. ImageBase - base pointer to the image resource
  131. Return Value:
  132. a number indicating the version of the image or 0 if the version is
  133. unavailable
  134. --*/
  135. {
  136. NTSTATUS Status;
  137. ULONG_PTR IdPath[3];
  138. ULONG ResourceSize;
  139. ULONGLONG Version = 0;
  140. PIMAGE_RESOURCE_DATA_ENTRY DataEntry;
  141. PRESOURCE_DATAW ResourceDataW;
  142. ASSERT(ImageBase != NULL);
  143. //
  144. // Do this to prevent the Ldr routines from faulting.
  145. //
  146. ImageBase = (PVOID)((ULONG_PTR)ImageBase | 1);
  147. IdPath[0] = PtrToUlong(RT_VERSION);
  148. IdPath[1] = PtrToUlong(MAKEINTRESOURCE(VS_VERSION_INFO));
  149. IdPath[2] = 0;
  150. //
  151. // find the resource data entry
  152. //
  153. try {
  154. Status = LdrFindResource_U(ImageBase,IdPath,3,&DataEntry);
  155. } except(EXCEPTION_EXECUTE_HANDLER) {
  156. Status = STATUS_UNSUCCESSFUL;
  157. }
  158. if(!NT_SUCCESS(Status)) {
  159. return 0;
  160. }
  161. //
  162. // now get the data out of the entry
  163. //
  164. try {
  165. Status = LdrAccessResource(ImageBase,DataEntry,&ResourceDataW,&ResourceSize);
  166. } except(EXCEPTION_EXECUTE_HANDLER) {
  167. Status = STATUS_UNSUCCESSFUL;
  168. }
  169. if(!NT_SUCCESS(Status)) {
  170. return 0;
  171. }
  172. try {
  173. if((ResourceSize >= sizeof(*ResourceDataW)) && !_wcsicmp(ResourceDataW->Name,L"VS_VERSION_INFO")) {
  174. Version = ((ULONGLONG)ResourceDataW->FixedFileInfo.dwFileVersionMS << 32)
  175. | (ULONGLONG)ResourceDataW->FixedFileInfo.dwFileVersionLS;
  176. } else {
  177. DebugPrint( LVL_MINIMAL, L"GetFileVersion32 warning: invalid version resource" );
  178. }
  179. } except(EXCEPTION_EXECUTE_HANDLER) {
  180. DebugPrint( LVL_MINIMAL, L"GetFileVersion32 Exception encountered processing bogus version resource" );
  181. }
  182. return Version;
  183. }
  184. BOOL
  185. SfcGetVersionFileName(
  186. IN PVOID ImageBase,
  187. IN PWSTR FileName
  188. )
  189. /*++
  190. Routine Description:
  191. Routine retreives the original filename for an image. can be used to
  192. determine the actual source name of the hal that is installed on the
  193. system, for example
  194. Arguments:
  195. ImageBase - base pointer to the image resource
  196. FileName - pointer to unicode string buffer which receives the filename.
  197. There is an assumption that the original file name can never
  198. exceed 32 characters.
  199. Return Value:
  200. TRUE indicates no problems retrieving version, FALSE indicates failure.
  201. --*/
  202. {
  203. NTSTATUS Status;
  204. ULONG_PTR IdPath[3];
  205. ULONG ResourceSize;
  206. ULONGLONG Version = 0;
  207. PIMAGE_RESOURCE_DATA_ENTRY DataEntry;
  208. PRESOURCE_DATAW ResourceDataW;
  209. LPVOID lpInfo;
  210. LPVOID lpvData = NULL;
  211. DWORD *pdwTranslation;
  212. UINT uLen;
  213. UINT cch;
  214. DWORD dwDefLang = 0x409;
  215. WCHAR key[80];
  216. PWSTR s = NULL;
  217. ASSERT((ImageBase != NULL) && (FileName != NULL));
  218. //
  219. // Do this to prevent the Ldr routines from faulting.
  220. //
  221. ImageBase = (PVOID)((ULONG_PTR)ImageBase | 1);
  222. IdPath[0] = PtrToUlong(RT_VERSION);
  223. IdPath[1] = PtrToUlong(MAKEINTRESOURCE(VS_VERSION_INFO));
  224. IdPath[2] = 0;
  225. //
  226. // find the version resource
  227. //
  228. try {
  229. Status = LdrFindResource_U(ImageBase,IdPath,3,&DataEntry);
  230. } except(EXCEPTION_EXECUTE_HANDLER) {
  231. Status = STATUS_UNSUCCESSFUL;
  232. }
  233. if(!NT_SUCCESS(Status)) {
  234. return(FALSE);
  235. }
  236. //
  237. // access the version resource
  238. //
  239. try {
  240. Status = LdrAccessResource(ImageBase,DataEntry,&ResourceDataW,&ResourceSize);
  241. } except(EXCEPTION_EXECUTE_HANDLER) {
  242. Status = STATUS_UNSUCCESSFUL;
  243. }
  244. if(!NT_SUCCESS(Status)) {
  245. return(FALSE);
  246. }
  247. lpvData = ResourceDataW;
  248. //
  249. // get the default language
  250. //
  251. if (!VerQueryValue( lpvData, L"\\VarFileInfo\\Translation", &pdwTranslation, &uLen )) {
  252. pdwTranslation = &dwDefLang;
  253. uLen = sizeof(DWORD);
  254. }
  255. //
  256. // get the original file name
  257. //
  258. swprintf( key, L"\\StringFileInfo\\%04x%04x\\OriginalFilename", LOWORD(*pdwTranslation), HIWORD(*pdwTranslation) );
  259. if (VerQueryValue( lpvData, key, &lpInfo, &cch )) {
  260. ASSERT(UnicodeChars(lpInfo) < 32);
  261. wcsncpy( FileName, lpInfo, 32 );
  262. } else {
  263. DebugPrint( LVL_MINIMAL, L"VerQueryValue for OriginalFileName failed." );
  264. return(FALSE);
  265. }
  266. return(TRUE);
  267. }
  268. BOOL
  269. SfcGetFileVersion(
  270. IN HANDLE FileHandle,
  271. OUT PULONGLONG Version,
  272. OUT PULONG Checksum,
  273. OUT PWSTR FileName
  274. )
  275. /*++
  276. Routine Description:
  277. Routine retreives the file version for an image, the checksum and the original
  278. filename resource from the image.
  279. Arguments:
  280. FileHandle - handle to the file to retrieve an image for
  281. Version - ULONGLONG that receives the file version (can be NULL)
  282. Checksum - DWORD which receives the file checksum (can be NULL)
  283. FileName - pointer to unicode string buffer which receives the original
  284. filename. There is an assumption that the original file name
  285. can never exceed 32 characters (can be NULL)
  286. Return Value:
  287. TRUE if successful: Version receives the major version in the high DWORD and the minor version in the low DWORD.
  288. --*/
  289. {
  290. NTSTATUS Status;
  291. HANDLE SectionHandle;
  292. PVOID ImageBase;
  293. SIZE_T ViewSize;
  294. DWORD dwFileSize;
  295. ASSERT(FileHandle != INVALID_HANDLE_VALUE);
  296. ASSERT(Version != NULL || Checksum != NULL || FileName != NULL);
  297. if(Version != NULL)
  298. *Version = 0;
  299. if(Checksum != NULL)
  300. *Checksum = 0;
  301. if(FileName != NULL)
  302. *FileName = L'\0';
  303. dwFileSize = GetFileSize(FileHandle, NULL);
  304. if(-1 == dwFileSize)
  305. return FALSE;
  306. Status = SfcMapEntireFile(FileHandle, &SectionHandle, &ImageBase, &ViewSize);
  307. if(!NT_SUCCESS(Status))
  308. return FALSE;
  309. try {
  310. //
  311. // There are three sorts of files that can be replaced:
  312. //
  313. // 32-bit images. Extract the 32 bit version, checksum and filename
  314. // 16-bit images. Extract the 16 bit version and checksum
  315. // other. The version is 1 and we compute the checksum
  316. //
  317. if(dwFileSize > sizeof(IMAGE_DOS_HEADER))
  318. {
  319. PIMAGE_DOS_HEADER DosHdr = (PIMAGE_DOS_HEADER) ImageBase;
  320. //
  321. // this code will break if we ever protect files > 2^32. not to mention
  322. // being very slow.
  323. //
  324. if (IMAGE_DOS_SIGNATURE == DosHdr->e_magic && DosHdr->e_lfanew > 0)
  325. {
  326. // assume 32bit
  327. PIMAGE_NT_HEADERS NtHdrs = (PIMAGE_NT_HEADERS) ((PBYTE)ImageBase + DosHdr->e_lfanew);
  328. if(dwFileSize > (DWORD) (DosHdr->e_lfanew + sizeof(PIMAGE_NT_HEADERS)) &&
  329. IMAGE_NT_SIGNATURE == NtHdrs->Signature)
  330. {
  331. if(Version !=NULL)
  332. *Version = GetFileVersion32( ImageBase );
  333. if(Checksum != NULL)
  334. *Checksum = NtHdrs->OptionalHeader.CheckSum;
  335. if(FileName != NULL)
  336. SfcGetVersionFileName( ImageBase, FileName );
  337. goto lExit;
  338. }
  339. else
  340. {
  341. // assume 16bit
  342. PIMAGE_OS2_HEADER NeHdr = (PIMAGE_OS2_HEADER) NtHdrs;
  343. if(dwFileSize > (DWORD) (DosHdr->e_lfanew + sizeof(PIMAGE_OS2_HEADER)) &&
  344. IMAGE_OS2_SIGNATURE == NeHdr->ne_magic)
  345. {
  346. if(Version !=NULL)
  347. *Version = GetFileVersion16( ImageBase, NeHdr );
  348. if(Checksum != NULL)
  349. *Checksum = NeHdr->ne_crc;
  350. goto lExit; // no filename
  351. }
  352. }
  353. }
  354. }
  355. } except (EXCEPTION_EXECUTE_HANDLER) {
  356. DebugPrint1( LVL_MINIMAL, L"Exception inside SfcGetFileVersion (0x%08X); bad image", GetExceptionCode() );
  357. // fall through bad image
  358. }
  359. //
  360. // Not a 16/32bit image. Compute a checksum. In the interest
  361. // of speed, we'll add up all the ULONGs in the file and
  362. // ignore any fraction at the end
  363. //
  364. if(Version != NULL)
  365. *Version = 1;
  366. if(Checksum != NULL) {
  367. PULONG Data = (PULONG) ImageBase;
  368. *Checksum = 0;
  369. try {
  370. while( dwFileSize >= sizeof( ULONG ) ) {
  371. *Checksum += *Data++;
  372. dwFileSize -= sizeof( ULONG );
  373. }
  374. } except(EXCEPTION_EXECUTE_HANDLER) {
  375. DebugPrint1( LVL_MINIMAL, L"Exception inside SfcGetFileVersion while calculating the checksum (0x%08X)", GetExceptionCode() );
  376. *Checksum = 0;
  377. }
  378. }
  379. lExit:
  380. SfcUnmapFile(SectionHandle,ImageBase);
  381. return TRUE;
  382. }