Leaked source code of windows server 2003
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.

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