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.

389 lines
10 KiB

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <windows.h>
  5. #include <assert.h>
  6. #include <io.h>
  7. #include <md5.h>
  8. #define MD5_CHECKSUM_SIZE 16
  9. #define RESOURCE_CHECKSUM_LANGID 0x0409
  10. BOOL g_bVerbose = FALSE;
  11. typedef struct
  12. {
  13. BOOL bContainResource;
  14. MD5_CTX ChecksumContext;
  15. } CHECKSUM_ENUM_DATA;
  16. void PrintError()
  17. {
  18. LPTSTR lpMsgBuf;
  19. if (FormatMessage(
  20. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  21. NULL,
  22. GetLastError(),
  23. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  24. (LPTSTR) &lpMsgBuf,
  25. 0,
  26. NULL
  27. ))
  28. {
  29. printf("GetLastError():\n %s", lpMsgBuf);
  30. LocalFree( lpMsgBuf );
  31. }
  32. return;
  33. }
  34. ////////////////////////////////////////////////////////////////////////////////////
  35. //
  36. // ChecksumEnumNamesFunc
  37. //
  38. // The callback funciton for enumerating the resource names in the specified module and
  39. // type.
  40. // The side effect is that MD5 checksum context (contained in CHECKSUM_ENUM_DATA
  41. // pointed by lParam) will be updated.
  42. //
  43. // Return:
  44. // Always return TRUE so that we can finish all resource enumeration.
  45. //
  46. ////////////////////////////////////////////////////////////////////////////////////
  47. BOOL CALLBACK ChecksumEnumNamesFunc(HMODULE hModule, LPCTSTR lpType, LPTSTR lpName, LONG_PTR lParam){
  48. HRSRC hRsrc;
  49. HGLOBAL hRes;
  50. const unsigned char* pv;
  51. LONG ResSize=0L;
  52. WORD IdFlag=0xFFFF;
  53. DWORD dwHeaderSize=0L;
  54. CHECKSUM_ENUM_DATA* pChecksumEnumData = (CHECKSUM_ENUM_DATA*)lParam;
  55. if(!(hRsrc=FindResourceEx(hModule, lpType, lpName, RESOURCE_CHECKSUM_LANGID)))
  56. {
  57. //
  58. // If US English resource is not found for the specified type and name, we
  59. // will continue the resource enumeration.
  60. //
  61. return (TRUE);
  62. }
  63. pChecksumEnumData->bContainResource = TRUE;
  64. if (!(ResSize=SizeofResource(hModule, hRsrc)))
  65. {
  66. printf("WARNING: Can not get resource size when generating resource checksum.\n");
  67. return (TRUE);
  68. }
  69. if (!(hRes=LoadResource(hModule, hRsrc)))
  70. {
  71. printf("WARNING: Can not load resource when generating resource checksum.\n");
  72. return (TRUE);
  73. }
  74. pv=(unsigned char*)LockResource(hRes);
  75. //
  76. // Update MD5 context using the binary data of this particular resource.
  77. //
  78. MD5Update(&(pChecksumEnumData->ChecksumContext), pv, ResSize);
  79. return TRUE;
  80. }
  81. ////////////////////////////////////////////////////////////////////////////////////
  82. //
  83. // ChecksumEnumTypesFunc
  84. //
  85. // The callback function for enumerating the resource types in the specified module.
  86. // This function will call EnumResourceNames() to enumerate all resource names of
  87. // the specified resource type.
  88. //
  89. // Return:
  90. // TRUE if EnumResourceName() succeeds. Otherwise FALSE.
  91. //
  92. ////////////////////////////////////////////////////////////////////////////////////
  93. BOOL CALLBACK ChecksumEnumTypesFunc(HMODULE hModule, LPSTR lpType, LONG_PTR lParam)
  94. {
  95. CHECKSUM_ENUM_DATA* pChecksumEnumData = (CHECKSUM_ENUM_DATA*)lParam;
  96. //
  97. // Skip the version resource type, so that version is not included in the resource checksum.
  98. //
  99. if (lpType == RT_VERSION)
  100. {
  101. return (TRUE);
  102. }
  103. if(!EnumResourceNames(hModule, (LPCSTR)lpType, ChecksumEnumNamesFunc, (LONG_PTR)lParam))
  104. {
  105. return (FALSE);
  106. }
  107. return (TRUE);
  108. }
  109. ////////////////////////////////////////////////////////////////////////////////////
  110. //
  111. // GenerateResourceChecksum
  112. //
  113. // Generate the resource checksum for the US English resource in the specified file.
  114. //
  115. // Parameters:
  116. // pszSourceFileName The file used to generate resource checksum.
  117. // pResourceChecksum Pointer to a 16 bytes (128 bits) buffer for storing
  118. // the calcuated MD5 checksum.
  119. // Return:
  120. // TURE if resource checksum is generated from the given file. Otherwise FALSE.
  121. //
  122. // The following situation may return FALSE:
  123. // * The specified file does not contain resource.
  124. // * If the specified file contains resource, but the resource is not US English.
  125. // * The specified file only contains US English version resource.
  126. //
  127. ////////////////////////////////////////////////////////////////////////////////////
  128. BOOL GenerateResourceChecksum(LPCSTR pszSourceFileName, unsigned char* pResourceChecksum)
  129. {
  130. HMODULE hModule;
  131. ULONG i;
  132. DWORD dwResultLen;
  133. BOOL bRet = FALSE;
  134. //
  135. // The stucture to be passed into the resource enumeration functions.
  136. //
  137. CHECKSUM_ENUM_DATA checksumEnumData;
  138. checksumEnumData.bContainResource = FALSE;
  139. //
  140. // Start MD5 checksum calculation by initializing MD5 context.
  141. //
  142. MD5Init(&(checksumEnumData.ChecksumContext));
  143. if (g_bVerbose)
  144. {
  145. printf("Generate resource checksum for [%s]\n", pszSourceFileName);
  146. }
  147. if(!(hModule = LoadLibraryEx(pszSourceFileName, NULL, DONT_RESOLVE_DLL_REFERENCES|LOAD_LIBRARY_AS_DATAFILE)))
  148. {
  149. if (g_bVerbose)
  150. {
  151. printf("\nERROR: Error in opening resource checksum module [%s]\n", pszSourceFileName);
  152. }
  153. PrintError();
  154. goto GR_EXIT;
  155. }
  156. if (g_bVerbose)
  157. {
  158. printf("\nLoad checksum file: %s\n", pszSourceFileName);
  159. }
  160. //
  161. // Enumerate all resources in the specified module.
  162. // During the enumeration, the MD5 context will be updated.
  163. //
  164. if (!EnumResourceTypes(hModule, ChecksumEnumTypesFunc, (LONG_PTR)&checksumEnumData))
  165. {
  166. if (g_bVerbose)
  167. {
  168. printf("\nWARNING: Unable to generate resource checksum from resource checksum module [%s]\n", pszSourceFileName);
  169. }
  170. goto GR_EXIT;
  171. }
  172. if (checksumEnumData.bContainResource)
  173. {
  174. //
  175. // If the enumeration succeeds, and the specified file contains US English
  176. // resource, get the MD5 checksum from the accumulated MD5 context.
  177. //
  178. MD5Final(&checksumEnumData.ChecksumContext);
  179. memcpy(pResourceChecksum, checksumEnumData.ChecksumContext.digest, 16);
  180. if (g_bVerbose)
  181. {
  182. printf("Generated checksum: [");
  183. for (i = 0; i < MD5_CHECKSUM_SIZE; i++)
  184. {
  185. printf("%02x ", pResourceChecksum[i]);
  186. }
  187. printf("]\n");
  188. }
  189. bRet = TRUE;
  190. }
  191. GR_EXIT:
  192. if (hModule)
  193. {
  194. FreeLibrary(hModule);
  195. }
  196. return (bRet);
  197. }
  198. void PrintUsage()
  199. {
  200. printf("muiver - Print out MUI resource checksum\n");
  201. printf("Usage:\n\n");
  202. printf(" muiver <US English file name>\n");
  203. }
  204. void PrintChecksum(BYTE* lpChecksum, int nSize)
  205. {
  206. int i;
  207. for (i = 0; i < nSize; i++)
  208. {
  209. printf("%02x ", lpChecksum[i]);
  210. }
  211. }
  212. struct LANGANDCODEPAGE {
  213. WORD wLanguage;
  214. WORD wCodePage;
  215. };
  216. LPWSTR EmptyString = L"N/A";
  217. LPWSTR GetFileVersionStringData(LPVOID pVerData, LANGANDCODEPAGE* pLang, LPWSTR pVersionDataType)
  218. {
  219. WCHAR subBlcok[256];
  220. LPVOID lpBuffer;
  221. UINT dwBytes;
  222. wsprintfW( subBlcok,
  223. L"\\StringFileInfo\\%04x%04x\\%s",
  224. pLang->wLanguage,
  225. pLang->wCodePage,
  226. pVersionDataType);
  227. // Retrieve file description for language and code page "i".
  228. if (VerQueryValueW(pVerData,
  229. subBlcok,
  230. &lpBuffer,
  231. &dwBytes)) {
  232. return ((LPWSTR)lpBuffer);
  233. }
  234. return (EmptyString);
  235. }
  236. void PrintFileVersion(LPVOID pVerData)
  237. {
  238. UINT cbTranslate;
  239. LANGANDCODEPAGE *lpTranslate;
  240. // Read the list of languages and code pages.
  241. VerQueryValueW(pVerData,
  242. L"\\VarFileInfo\\Translation",
  243. (LPVOID*)&lpTranslate,
  244. &cbTranslate);
  245. // Read the file description for each language and code page.
  246. for(UINT i=0; i < (cbTranslate/sizeof(struct LANGANDCODEPAGE)); i++)
  247. {
  248. wprintf(L" Locale = 0x%04x, CodePage = %d\n", lpTranslate->wLanguage, lpTranslate->wCodePage);
  249. wprintf(L" FileDescriptions: [%s", GetFileVersionStringData(pVerData, lpTranslate+i, L"FileDescription"));
  250. wprintf(L"]\n");
  251. wprintf(L" FileVersion : [%s]\n", GetFileVersionStringData(pVerData, lpTranslate+i, L"FileVersion"));
  252. wprintf(L" ProductVersion : [%s]\n", GetFileVersionStringData(pVerData, lpTranslate+i, L"ProductVersion"));
  253. //wprintf(L" Comments : [%s]\n", GetFileVersionStringData(pVerData, lpTranslate+i, L"Comments"));
  254. }
  255. BYTE* lpResourceChecksum;
  256. UINT cbResourceChecksum;
  257. wprintf(L" ResourceChecksum: [");
  258. if (VerQueryValueW(pVerData,
  259. L"\\VarFileInfo\\ResourceChecksum",
  260. (LPVOID*)&lpResourceChecksum,
  261. &cbResourceChecksum))
  262. {
  263. for (i = 0; i < cbResourceChecksum; i++)
  264. {
  265. wprintf(L"%02x ", lpResourceChecksum[i]);
  266. }
  267. } else
  268. {
  269. wprintf(L"n/a");
  270. }
  271. wprintf(L"]\n");
  272. }
  273. void PrintResult(LPSTR fileName, LPVOID pVerData, BYTE* pChecksum)
  274. {
  275. printf("File: [%s]\n", fileName);
  276. printf("\nVersion information:\n");
  277. if (pVerData == NULL)
  278. {
  279. printf(" !!! Not availabe. Failed in GetFileVersionInfo()\n");
  280. } else
  281. {
  282. PrintFileVersion(pVerData);
  283. }
  284. printf("\n\n Resource Checksum:\n ", fileName);
  285. if (pChecksum == NULL)
  286. {
  287. printf(" n/a. Probably resources for 0x%04x is not available.\n", RESOURCE_CHECKSUM_LANGID);
  288. } else
  289. {
  290. PrintChecksum(pChecksum, MD5_CHECKSUM_SIZE);
  291. }
  292. printf("\n");
  293. }
  294. int __cdecl main(int argc, char *argv[]){
  295. LPSTR pFileName;
  296. LPBYTE lpVerData = NULL;
  297. DWORD dwVerDataSize;
  298. DWORD dwHandle;
  299. BYTE MD5Checksum[MD5_CHECKSUM_SIZE];
  300. if (argc == 1)
  301. {
  302. PrintUsage();
  303. return (1);
  304. }
  305. pFileName = argv[1];
  306. if (dwVerDataSize = GetFileVersionInfoSizeA(pFileName, &dwHandle))
  307. {
  308. lpVerData = new BYTE[dwVerDataSize];
  309. if (!GetFileVersionInfoA(pFileName, 0, dwVerDataSize, (LPVOID)lpVerData)) {
  310. lpVerData = NULL;
  311. }
  312. }
  313. if (GenerateResourceChecksum(pFileName, MD5Checksum))
  314. {
  315. PrintResult(pFileName, (LPVOID)lpVerData, MD5Checksum);
  316. } else
  317. {
  318. PrintResult(pFileName, (LPVOID)lpVerData, NULL);
  319. }
  320. if (!lpVerData)
  321. {
  322. delete [] lpVerData;
  323. }
  324. return (0);
  325. }