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.

691 lines
18 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. ImportTableHash.c
  5. Abstract:
  6. This module contains hash computation routine
  7. RtlComputeImportTableHash to compute the hash
  8. based on the import table of an exe.
  9. Author:
  10. Vishnu Patankar (VishnuP) 31-May-2001
  11. Revision History:
  12. --*/
  13. #include "ImportTableHash.h"
  14. NTSTATUS
  15. RtlComputeImportTableHash(
  16. IN HANDLE hFile,
  17. IN PCHAR Hash,
  18. IN ULONG ImportTableHashRevision
  19. )
  20. /*++
  21. Routine Description:
  22. This routine computes the limited MD5 hash.
  23. First, the image is memory mapped and a canonical
  24. sorted list of module name and function name is created
  25. from the exe's import table.
  26. Second, the hash value is computed using the canonical
  27. information.
  28. Arguments:
  29. hFile - the handle of the file to compute the hash for
  30. Hash - the hash value returned - this has to be atleast 16 bytes long
  31. ImportTableHashRevision - the revision of the computation method for compatibility
  32. only ITH_REVISION_1 is supported today
  33. Return Value:
  34. The status of the hash computation.
  35. --*/
  36. {
  37. PIMPORTTABLEP_SORTED_LIST_ENTRY ListEntry = NULL;
  38. PIMPORTTABLEP_SORTED_LIST_ENTRY ImportedNameList = NULL;
  39. PIMPORTTABLEP_SORTED_FUNCTION_LIST_ENTRY FunctionListEntry;
  40. ULONG ImportDescriptorSize = 0;
  41. HANDLE hMap = INVALID_HANDLE_VALUE;
  42. LPVOID FileMapping = NULL;
  43. PIMAGE_THUNK_DATA OriginalFirstThunk;
  44. PIMAGE_IMPORT_BY_NAME AddressOfData;
  45. PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
  46. ACCESS_MASK DesiredAccess;
  47. ULONG AllocationAttributes;
  48. DWORD flProtect = PAGE_READONLY;
  49. LARGE_INTEGER SectionOffset;
  50. SIZE_T ViewSize;
  51. NTSTATUS Status = STATUS_SUCCESS;
  52. if ( ITH_REVISION_1 != ImportTableHashRevision ) {
  53. Status = STATUS_UNKNOWN_REVISION;
  54. goto ExitHandler;
  55. }
  56. //
  57. // Unwrap CreateFileMappingW (since that API is not available in ntdll.dll)
  58. //
  59. DesiredAccess = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ;
  60. AllocationAttributes = flProtect & (SEC_FILE | SEC_IMAGE | SEC_RESERVE | SEC_COMMIT | SEC_NOCACHE);
  61. flProtect ^= AllocationAttributes;
  62. if (AllocationAttributes == 0) {
  63. AllocationAttributes = SEC_COMMIT;
  64. }
  65. Status = NtCreateSection(
  66. &hMap,
  67. DesiredAccess,
  68. NULL,
  69. NULL,
  70. flProtect,
  71. AllocationAttributes,
  72. hFile
  73. );
  74. if ( hMap == INVALID_HANDLE_VALUE || !NT_SUCCESS(Status) ) {
  75. Status = STATUS_INVALID_HANDLE;
  76. goto ExitHandler;
  77. }
  78. SectionOffset.LowPart = 0;
  79. SectionOffset.HighPart = 0;
  80. ViewSize = 0;
  81. Status = NtMapViewOfSection(
  82. hMap,
  83. NtCurrentProcess(),
  84. &FileMapping,
  85. 0L,
  86. 0L,
  87. &SectionOffset,
  88. &ViewSize,
  89. ViewShare,
  90. 0L,
  91. PAGE_READONLY
  92. );
  93. NtClose(hMap);
  94. if (FileMapping == NULL || !NT_SUCCESS(Status) ) {
  95. Status = STATUS_NOT_MAPPED_VIEW;
  96. goto ExitHandler;
  97. }
  98. ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData (
  99. FileMapping,
  100. FALSE,
  101. IMAGE_DIRECTORY_ENTRY_IMPORT,
  102. &ImportDescriptorSize
  103. );
  104. if (ImportDescriptor == NULL) {
  105. Status = STATUS_RESOURCE_DATA_NOT_FOUND;
  106. goto ExitHandler;
  107. }
  108. //
  109. // outer loop that iterates over all modules in the import table of the exe
  110. //
  111. while (ImportDescriptor && ImportDescriptor->Name != 0 && ImportDescriptor->FirstThunk != 0) {
  112. PSZ ImportName = (PSZ)RtlAddressInSectionTable(
  113. RtlImageNtHeader(FileMapping),
  114. FileMapping,
  115. ImportDescriptor->Name
  116. );
  117. if ( ImportName == NULL ) {
  118. Status = STATUS_RESOURCE_NAME_NOT_FOUND;
  119. goto ExitHandler;
  120. }
  121. ListEntry = (PIMPORTTABLEP_SORTED_LIST_ENTRY)RtlAllocateHeap(RtlProcessHeap(), 0, sizeof( IMPORTTABLEP_SORTED_LIST_ENTRY ));
  122. if ( ListEntry == NULL ) {
  123. Status = STATUS_NO_MEMORY;
  124. goto ExitHandler;
  125. }
  126. ListEntry->String = ImportName;
  127. ListEntry->FunctionList = NULL;
  128. ListEntry->Next = NULL;
  129. ImportTablepInsertModuleSorted( ListEntry, &ImportedNameList );
  130. OriginalFirstThunk = (PIMAGE_THUNK_DATA)RtlAddressInSectionTable(
  131. RtlImageNtHeader(FileMapping),
  132. FileMapping,
  133. ImportDescriptor->OriginalFirstThunk
  134. );
  135. //
  136. // inner loop that iterates over all functions for a given module
  137. //
  138. while (OriginalFirstThunk && OriginalFirstThunk->u1.Ordinal) {
  139. if (!IMAGE_SNAP_BY_ORDINAL( OriginalFirstThunk->u1.Ordinal)) {
  140. AddressOfData = (PIMAGE_IMPORT_BY_NAME)RtlAddressInSectionTable(
  141. RtlImageNtHeader(FileMapping),
  142. FileMapping,
  143. (ULONG)OriginalFirstThunk->u1.AddressOfData
  144. );
  145. if ( AddressOfData == NULL || AddressOfData->Name == NULL ) {
  146. Status = STATUS_RESOURCE_NAME_NOT_FOUND;
  147. goto ExitHandler;
  148. }
  149. FunctionListEntry = (PIMPORTTABLEP_SORTED_FUNCTION_LIST_ENTRY)RtlAllocateHeap(RtlProcessHeap(), 0, sizeof( IMPORTTABLEP_SORTED_FUNCTION_LIST_ENTRY ));
  150. if (FunctionListEntry == NULL ) {
  151. Status = STATUS_NO_MEMORY;
  152. goto ExitHandler;
  153. }
  154. FunctionListEntry->Next = NULL;
  155. FunctionListEntry->String = (PSZ)AddressOfData->Name;
  156. ImportTablepInsertFunctionSorted( FunctionListEntry, &ListEntry->FunctionList );
  157. }
  158. OriginalFirstThunk++;
  159. }
  160. ImportDescriptor++;
  161. }
  162. //
  163. // finally hash the canonical information (sorted module and sorted function list)
  164. //
  165. Status = ImportTablepHashCanonicalLists( ImportedNameList, (PBYTE) Hash );
  166. ExitHandler:
  167. ImportTablepFreeModuleSorted( ImportedNameList );
  168. if (FileMapping) {
  169. NTSTATUS StatusUnmap;
  170. //
  171. // unwrap UnmapViewOfFile (since that API is not available in ntdll.dll)
  172. //
  173. StatusUnmap = NtUnmapViewOfSection(NtCurrentProcess(),(PVOID)FileMapping);
  174. if ( !NT_SUCCESS(StatusUnmap) ) {
  175. if (StatusUnmap == STATUS_INVALID_PAGE_PROTECTION) {
  176. //
  177. // Unlock any pages that were locked with MmSecureVirtualMemory.
  178. // This is useful for SANs.
  179. //
  180. if (RtlFlushSecureMemoryCache((PVOID)FileMapping, 0)) {
  181. StatusUnmap = NtUnmapViewOfSection(NtCurrentProcess(),
  182. (PVOID)FileMapping
  183. );
  184. }
  185. }
  186. }
  187. }
  188. return Status;
  189. }
  190. VOID
  191. ImportTablepInsertFunctionSorted(
  192. IN PIMPORTTABLEP_SORTED_FUNCTION_LIST_ENTRY pFunctionName,
  193. OUT PIMPORTTABLEP_SORTED_FUNCTION_LIST_ENTRY * ppFunctionNameList
  194. )
  195. /*++
  196. Routine Description:
  197. This routine inserts a function name in a sorted order.
  198. Arguments:
  199. pFunctionName - name of the function
  200. ppFunctionNameList - pointer to the head of the function list to be updated
  201. Return Value:
  202. None:
  203. --*/
  204. {
  205. PIMPORTTABLEP_SORTED_FUNCTION_LIST_ENTRY pPrev;
  206. PIMPORTTABLEP_SORTED_FUNCTION_LIST_ENTRY pTemp;
  207. //
  208. // Special case, list is empty, insert at the front.
  209. //
  210. if (*ppFunctionNameList == NULL
  211. || _stricmp((*ppFunctionNameList)->String, pFunctionName->String) > 0) {
  212. pFunctionName->Next = *ppFunctionNameList;
  213. *ppFunctionNameList = pFunctionName;
  214. return;
  215. }
  216. pPrev = *ppFunctionNameList;
  217. pTemp = (*ppFunctionNameList)->Next;
  218. while (pTemp) {
  219. if (_stricmp(pTemp->String, pFunctionName->String) >= 0) {
  220. pFunctionName->Next = pTemp;
  221. pPrev->Next = pFunctionName;
  222. return;
  223. }
  224. pPrev = pTemp;
  225. pTemp = pTemp->Next;
  226. }
  227. pFunctionName->Next = NULL;
  228. pPrev->Next = pFunctionName;
  229. return;
  230. }
  231. VOID
  232. ImportTablepInsertModuleSorted(
  233. IN PIMPORTTABLEP_SORTED_LIST_ENTRY pImportName,
  234. OUT PIMPORTTABLEP_SORTED_LIST_ENTRY * ppImportNameList
  235. )
  236. /*++
  237. Routine Description:
  238. This routine inserts a module name (dll) in a sorted order.
  239. Arguments:
  240. pImportName - the import name that needs to be inserted
  241. ppImportNameList - pointer to the head of the list to be updated
  242. Return Value:
  243. None:
  244. --*/
  245. {
  246. PIMPORTTABLEP_SORTED_LIST_ENTRY pPrev;
  247. PIMPORTTABLEP_SORTED_LIST_ENTRY pTemp;
  248. //
  249. // Special case, list is empty, insert at the front.
  250. //
  251. if (*ppImportNameList == NULL
  252. || _stricmp((*ppImportNameList)->String, pImportName->String) > 0) {
  253. pImportName->Next = *ppImportNameList;
  254. *ppImportNameList = pImportName;
  255. return;
  256. }
  257. pPrev = *ppImportNameList;
  258. pTemp = (*ppImportNameList)->Next;
  259. while (pTemp) {
  260. if (_stricmp(pTemp->String, pImportName->String) >= 0) {
  261. pImportName->Next = pTemp;
  262. pPrev->Next = pImportName;
  263. return;
  264. }
  265. pPrev = pTemp;
  266. pTemp = pTemp->Next;
  267. }
  268. pImportName->Next = NULL;
  269. pPrev->Next = pImportName;
  270. return;
  271. }
  272. static HANDLE AdvApi32ModuleHandle = (HANDLE) (ULONG_PTR) -1;
  273. NTSTATUS
  274. ImportTablepHashCanonicalLists(
  275. IN PIMPORTTABLEP_SORTED_LIST_ENTRY ImportedNameList,
  276. OUT PBYTE Hash
  277. )
  278. /*++
  279. Routine Description:
  280. This routine computes the hash values from a given import list.
  281. advapi32.dll is dynamically loaded - once only per process,
  282. and the md5 APIs are used to compute the hash value.
  283. Arguments:
  284. ImportedNameList - the head of the module name/function name list
  285. Hash - the buffer to use to fill in the hash value
  286. Return Value:
  287. STATUS_SUCCESS if the hash value is calculated, otherwise the error status
  288. --*/
  289. {
  290. NTSTATUS Status = STATUS_SUCCESS;
  291. PIMPORTTABLEP_SORTED_LIST_ENTRY pTemp;
  292. MD5_CTX md5ctx;
  293. typedef VOID (RSA32API *MD5Init) (
  294. MD5_CTX *
  295. );
  296. typedef VOID (RSA32API *MD5Update) (
  297. MD5_CTX *,
  298. const unsigned char *,
  299. unsigned int
  300. );
  301. typedef VOID (RSA32API *MD5Final) (
  302. MD5_CTX *
  303. );
  304. const static UNICODE_STRING ModuleName =
  305. RTL_CONSTANT_STRING(L"ADVAPI32.DLL");
  306. const static ANSI_STRING ProcedureNameMD5Init =
  307. RTL_CONSTANT_STRING("MD5Init");
  308. const static ANSI_STRING ProcedureNameMD5Update =
  309. RTL_CONSTANT_STRING("MD5Update");
  310. const static ANSI_STRING ProcedureNameMD5Final =
  311. RTL_CONSTANT_STRING("MD5Final");
  312. static MD5Init lpfnMD5Init;
  313. static MD5Update lpfnMD5Update;
  314. static MD5Final lpfnMD5Final;
  315. if (AdvApi32ModuleHandle == NULL) {
  316. //
  317. // We tried to load ADVAPI32.DLL once before, but failed.
  318. //
  319. return STATUS_ENTRYPOINT_NOT_FOUND;
  320. }
  321. if (AdvApi32ModuleHandle == LongToHandle(-1)) {
  322. HANDLE TempModuleHandle;
  323. //
  324. // Load advapi32.dll for MD5 functions. We'll pass a special flag in
  325. // DllCharacteristics to eliminate WinSafer checking on advapi.
  326. //
  327. {
  328. ULONG DllCharacteristics = IMAGE_FILE_SYSTEM;
  329. Status = LdrLoadDll(NULL,
  330. &DllCharacteristics,
  331. &ModuleName,
  332. &TempModuleHandle);
  333. if (!NT_SUCCESS(Status)) {
  334. AdvApi32ModuleHandle = NULL;
  335. return STATUS_DLL_NOT_FOUND;
  336. }
  337. }
  338. //
  339. // Get function pointers to the APIs that we'll need. If we fail
  340. // to get pointers for any of them, then just unload advapi and
  341. // ignore all future attempts to load it within this process.
  342. //
  343. Status = LdrGetProcedureAddress(
  344. TempModuleHandle,
  345. (PANSI_STRING) &ProcedureNameMD5Init,
  346. 0,
  347. (PVOID*)&lpfnMD5Init);
  348. if (!NT_SUCCESS(Status) || !lpfnMD5Init) {
  349. //
  350. // Couldn't get the fn ptr. Make sure we won't try again
  351. //
  352. AdvapiLoadFailure:
  353. LdrUnloadDll(TempModuleHandle);
  354. AdvApi32ModuleHandle = NULL;
  355. return STATUS_ENTRYPOINT_NOT_FOUND;
  356. }
  357. Status = LdrGetProcedureAddress(
  358. TempModuleHandle,
  359. (PANSI_STRING) &ProcedureNameMD5Update,
  360. 0,
  361. (PVOID*)&lpfnMD5Update);
  362. if (!NT_SUCCESS(Status) || !lpfnMD5Update) {
  363. goto AdvapiLoadFailure;
  364. }
  365. Status = LdrGetProcedureAddress(
  366. TempModuleHandle,
  367. (PANSI_STRING) &ProcedureNameMD5Final,
  368. 0,
  369. (PVOID*)&lpfnMD5Final);
  370. if (!NT_SUCCESS(Status) || !lpfnMD5Final) {
  371. goto AdvapiLoadFailure;
  372. }
  373. AdvApi32ModuleHandle = TempModuleHandle;
  374. }
  375. ASSERT(lpfnMD5Init != NULL);
  376. lpfnMD5Init(&md5ctx);
  377. //
  378. // Loop though all of the module names and function names and create a hash
  379. //
  380. pTemp = ImportedNameList;
  381. //
  382. // loop through each module
  383. //
  384. while (pTemp != NULL) {
  385. PIMPORTTABLEP_SORTED_FUNCTION_LIST_ENTRY pTemp2 = pTemp->FunctionList;
  386. ASSERT(lpfnMD5Update != NULL);
  387. lpfnMD5Update(&md5ctx,
  388. (LPBYTE) pTemp->String,
  389. (ULONG) strlen( pTemp->String )
  390. );
  391. //
  392. // loop through each function
  393. //
  394. while (pTemp2 != NULL) {
  395. ASSERT(lpfnMD5Update != NULL);
  396. lpfnMD5Update(&md5ctx,
  397. (LPBYTE) pTemp2->String,
  398. (ULONG) strlen( pTemp2->String )
  399. );
  400. pTemp2 = pTemp2->Next;
  401. }
  402. pTemp = pTemp->Next;
  403. }
  404. ASSERT(lpfnMD5Final != NULL);
  405. lpfnMD5Final( &md5ctx );
  406. //
  407. // Copy the hash to the user's buffer.
  408. //
  409. RtlCopyMemory(Hash, &md5ctx.digest[0], IMPORT_TABLE_MAX_HASH_SIZE);
  410. return Status;
  411. }
  412. VOID
  413. ImportTablepFreeModuleSorted(
  414. IN PIMPORTTABLEP_SORTED_LIST_ENTRY pImportNameList
  415. )
  416. /*++
  417. Routine Description:
  418. This routine frees the entire module/function list.
  419. Arguments:
  420. pImportNameList - head of the two level singly linked list
  421. Return Value:
  422. None:
  423. --*/
  424. {
  425. PIMPORTTABLEP_SORTED_LIST_ENTRY pToFree, pTemp;
  426. if ( !pImportNameList ) {
  427. return;
  428. }
  429. pToFree = pImportNameList;
  430. pTemp = pToFree->Next;
  431. while ( pToFree ) {
  432. ImportTablepFreeFunctionSorted( pToFree->FunctionList );
  433. RtlFreeHeap(RtlProcessHeap(), 0, pToFree);
  434. pToFree = pTemp;
  435. if ( pTemp ) {
  436. pTemp = pTemp->Next;
  437. }
  438. }
  439. return;
  440. }
  441. VOID
  442. ImportTablepFreeFunctionSorted(
  443. IN PIMPORTTABLEP_SORTED_FUNCTION_LIST_ENTRY pFunctionNameList
  444. )
  445. /*++
  446. Routine Description:
  447. This routine frees function list.
  448. Arguments:
  449. pFunctionNameList - head of function name list
  450. Return Value:
  451. None:
  452. --*/
  453. {
  454. PIMPORTTABLEP_SORTED_FUNCTION_LIST_ENTRY pToFree, pTemp;
  455. if ( !pFunctionNameList ) {
  456. return;
  457. }
  458. pToFree = pFunctionNameList;
  459. pTemp = pToFree->Next;
  460. while ( pToFree ) {
  461. RtlFreeHeap(RtlProcessHeap(), 0, pToFree);
  462. pToFree = pTemp;
  463. if ( pTemp ) {
  464. pTemp = pTemp->Next;
  465. }
  466. }
  467. return;
  468. }