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.

5328 lines
175 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. ldrsnap.c
  5. Abstract:
  6. This module implements the guts of the Ldr Dll Snap Routine.
  7. This code is executed only in user mode; the kernel mode
  8. loader is implemented as part of the memory manager kernel
  9. component.
  10. Author:
  11. Mike O'Leary (mikeol) 23-Mar-1990
  12. Revision History:
  13. Michael Grier (mgrier) 5/4/2000
  14. Isolate static (import) library loads when activation contexts
  15. are used to redirect so that a dynamically loaded library
  16. does not bind to whatever component dll may already be
  17. loaded for the process. When redirection is in effect,
  18. the full path names of the loads must match, not just the
  19. base names of the dlls.
  20. Also clean up path allocation policy so that we should be
  21. clean for 64k paths in the loader.
  22. --*/
  23. #define LDRDBG 0
  24. #include "ntos.h"
  25. #include <nt.h>
  26. #include <ntrtl.h>
  27. #include <nturtl.h>
  28. #include <heap.h>
  29. #include <winsnmp.h>
  30. #include <winsafer.h>
  31. #include "ldrp.h"
  32. #include <sxstypes.h>
  33. #include <ntrtlpath.h>
  34. #define DLL_EXTENSION L".DLL"
  35. #define DLL_REDIRECTION_LOCAL_SUFFIX L".Local"
  36. UNICODE_STRING DefaultExtension = RTL_CONSTANT_STRING(L".DLL");
  37. UNICODE_STRING User32String = RTL_CONSTANT_STRING(L"user32.dll");
  38. UNICODE_STRING Kernel32String = RTL_CONSTANT_STRING(L"kernel32.dll");
  39. #if DBG // DBG
  40. PUCHAR MonthOfYear[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  41. "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
  42. PUCHAR DaysOfWeek[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
  43. LARGE_INTEGER MapBeginTime, MapEndTime, MapElapsedTime;
  44. #endif // DBG
  45. PCUNICODE_STRING LdrpTopLevelDllBeingLoaded;
  46. BOOLEAN LdrpShowInitRoutines = FALSE;
  47. #if defined (_ALPHA_)
  48. VOID
  49. AlphaFindArchitectureFixups(
  50. PIMAGE_NT_HEADERS NtHeaders,
  51. PVOID ViewBase,
  52. BOOLEAN StaticLink
  53. );
  54. #endif
  55. #if defined(_WIN64)
  56. extern ULONG UseWOW64;
  57. #endif
  58. #if defined (_X86_)
  59. extern PVOID LdrpLockPrefixTable;
  60. //
  61. // Specify address of kernel32 lock prefixes
  62. //
  63. IMAGE_LOAD_CONFIG_DIRECTORY _load_config_used = {
  64. 0, // Reserved
  65. 0, // Reserved
  66. 0, // Reserved
  67. 0, // Reserved
  68. 0, // GlobalFlagsClear
  69. 0, // GlobalFlagsSet
  70. 0, // CriticalSectionTimeout (milliseconds)
  71. 0, // DeCommitFreeBlockThreshold
  72. 0, // DeCommitTotalFreeThreshold
  73. (ULONG_PTR) &LdrpLockPrefixTable, // LockPrefixTable
  74. 0, 0, 0, 0, 0, 0, 0 // Reserved
  75. };
  76. void
  77. LdrpValidateImageForMp(
  78. IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry
  79. )
  80. {
  81. PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData;
  82. ULONG i;
  83. PUCHAR *pb;
  84. ULONG ErrorParameters;
  85. ULONG ErrorResponse;
  86. //
  87. // If we are on an MP system and the DLL has image config info, check to see
  88. // if it has a lock prefix table and make sure the locks have not been converted
  89. // to NOPs
  90. //
  91. ImageConfigData = RtlImageDirectoryEntryToData( LdrDataTableEntry->DllBase,
  92. TRUE,
  93. IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
  94. &i
  95. );
  96. if (ImageConfigData != NULL &&
  97. i == sizeof( *ImageConfigData ) &&
  98. ImageConfigData->LockPrefixTable ) {
  99. pb = (PUCHAR *)ImageConfigData->LockPrefixTable;
  100. while ( *pb ) {
  101. if ( **pb == (UCHAR)0x90 ) {
  102. if ( LdrpNumberOfProcessors > 1 ) {
  103. //
  104. // Hard error time. One of the know DLL's is corrupt !
  105. //
  106. ErrorParameters = (ULONG)&LdrDataTableEntry->BaseDllName;
  107. NtRaiseHardError(
  108. STATUS_IMAGE_MP_UP_MISMATCH,
  109. 1,
  110. 1,
  111. &ErrorParameters,
  112. OptionOk,
  113. &ErrorResponse
  114. );
  115. if ( LdrpInLdrInit ) {
  116. LdrpFatalHardErrorCount++;
  117. }
  118. }
  119. }
  120. pb++;
  121. }
  122. }
  123. }
  124. #endif
  125. NTSTATUS
  126. LdrpWalkImportDescriptor (
  127. IN PWSTR DllPath OPTIONAL,
  128. IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry
  129. );
  130. NTSTATUS
  131. LdrpLoadImportModule(
  132. IN PWSTR DllPath OPTIONAL,
  133. IN LPSTR ImportName,
  134. IN PVOID DllBaseImporter,
  135. OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry,
  136. OUT PBOOLEAN AlreadyLoaded
  137. )
  138. {
  139. NTSTATUS st;
  140. ANSI_STRING AnsiString;
  141. PUNICODE_STRING ImportDescriptorName_U;
  142. WCHAR StaticRedirectedDllNameBuffer[DOS_MAX_PATH_LENGTH];
  143. UNICODE_STRING StaticRedirectedDllName;
  144. UNICODE_STRING DynamicRedirectedDllName;
  145. BOOLEAN Redirected = FALSE;
  146. DynamicRedirectedDllName.Buffer = NULL;
  147. ImportDescriptorName_U = &NtCurrentTeb()->StaticUnicodeString;
  148. RtlInitAnsiString(&AnsiString, ImportName);
  149. st = RtlAnsiStringToUnicodeString(ImportDescriptorName_U, &AnsiString, FALSE);
  150. if (!NT_SUCCESS(st)) {
  151. goto Exit;
  152. }
  153. //
  154. // If the module name has no '.' in the name then it can't have an extension.
  155. // Add .dll in this case as 9x does this and some apps rely on it.
  156. //
  157. if (strchr (ImportName, '.') == NULL) {
  158. RtlAppendUnicodeToString (ImportDescriptorName_U, L".dll");
  159. }
  160. RtlInitUnicodeString(&DynamicRedirectedDllName, NULL);
  161. StaticRedirectedDllName.Length = 0;
  162. StaticRedirectedDllName.MaximumLength = sizeof(StaticRedirectedDllNameBuffer);
  163. StaticRedirectedDllName.Buffer = StaticRedirectedDllNameBuffer;
  164. st = RtlDosApplyFileIsolationRedirection_Ustr(
  165. RTL_DOS_APPLY_FILE_REDIRECTION_USTR_FLAG_RESPECT_DOT_LOCAL,
  166. ImportDescriptorName_U,
  167. &DefaultExtension,
  168. &StaticRedirectedDllName,
  169. &DynamicRedirectedDllName,
  170. &ImportDescriptorName_U,
  171. NULL,
  172. NULL,
  173. NULL);
  174. if (NT_SUCCESS(st)){
  175. Redirected = TRUE;
  176. } else if (st != STATUS_SXS_KEY_NOT_FOUND) {
  177. if (ShowSnaps) {
  178. DbgPrint("LDR: %s - RtlDosApplyFileIsolationRedirection_Ustr failed with status %x\n", __FUNCTION__, st);
  179. }
  180. goto Exit;
  181. }
  182. st = STATUS_SUCCESS;
  183. //
  184. // Check the LdrTable to see if Dll has already been mapped
  185. // into this image. If not, map it.
  186. //
  187. if (LdrpCheckForLoadedDll( DllPath,
  188. ImportDescriptorName_U,
  189. TRUE,
  190. Redirected,
  191. DataTableEntry)) {
  192. *AlreadyLoaded = TRUE;
  193. } else {
  194. *AlreadyLoaded = FALSE;
  195. st = LdrpMapDll(DllPath,
  196. ImportDescriptorName_U->Buffer,
  197. NULL, // MOOCOW
  198. TRUE,
  199. Redirected,
  200. DataTableEntry
  201. );
  202. if (!NT_SUCCESS(st)) {
  203. if (ShowSnaps) {
  204. DbgPrint("LDR: %s - LdrpMapDll(%p, %ls, NULL, TRUE, %d, %p) failed with status %x\n", __FUNCTION__, DllPath, ImportDescriptorName_U->Buffer, Redirected, DataTableEntry, st);
  205. }
  206. goto Exit;
  207. }
  208. //
  209. // Register dll with the stack tracing module.
  210. // This is used for getting reliable stack traces on X86.
  211. //
  212. #if defined(_X86_)
  213. RtlpStkMarkDllRange (*DataTableEntry);
  214. #endif
  215. st = LdrpWalkImportDescriptor(
  216. DllPath,
  217. *DataTableEntry
  218. );
  219. if (!NT_SUCCESS(st)) {
  220. if (ShowSnaps) {
  221. DbgPrint("LDR: %s - LdrpWalkImportDescriptor [dll %ls] failed with status %x\n", __FUNCTION__, ImportDescriptorName_U->Buffer, st);
  222. }
  223. InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
  224. &(*DataTableEntry)->InInitializationOrderLinks);
  225. }
  226. }
  227. Exit:
  228. if (DynamicRedirectedDllName.Buffer != NULL)
  229. RtlFreeUnicodeString(&DynamicRedirectedDllName);
  230. return st;
  231. }
  232. NTSTATUS
  233. LdrpHandleOneNewFormatImportDescriptor(
  234. IN PPEB Peb,
  235. IN PWSTR DllPath OPTIONAL,
  236. IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry,
  237. PIMAGE_BOUND_IMPORT_DESCRIPTOR *NewImportDescriptorInOut,
  238. PSZ NewImportStringBase
  239. )
  240. {
  241. NTSTATUS st = STATUS_INTERNAL_ERROR;
  242. PIMAGE_BOUND_IMPORT_DESCRIPTOR NewImportDescriptor = *NewImportDescriptorInOut;
  243. PIMAGE_BOUND_FORWARDER_REF NewImportForwarder;
  244. PSZ ImportName, NewImportName, NewFwdImportName;
  245. BOOLEAN AlreadyLoaded = FALSE;
  246. BOOLEAN StaleBinding = FALSE;
  247. PLDR_DATA_TABLE_ENTRY DataTableEntry, FwdDataTableEntry;
  248. ULONG i;
  249. PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
  250. ULONG ImportSize, NewImportSize;
  251. NewImportName = NewImportStringBase + NewImportDescriptor->OffsetModuleName;
  252. if (ShowSnaps)
  253. DbgPrint("LDR: %wZ bound to %s\n", &LdrDataTableEntry->BaseDllName, NewImportName);
  254. st = LdrpLoadImportModule(
  255. DllPath,
  256. NewImportName,
  257. LdrDataTableEntry->DllBase,
  258. &DataTableEntry,
  259. &AlreadyLoaded);
  260. if (!NT_SUCCESS(st)) {
  261. if (ShowSnaps)
  262. DbgPrint("LDR: %wZ failed to load import module %s; status = %x\n", &LdrDataTableEntry->BaseDllName, NewImportName, st);
  263. goto Exit;
  264. }
  265. //
  266. // Add to initialization list.
  267. //
  268. if (!AlreadyLoaded)
  269. InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, &DataTableEntry->InInitializationOrderLinks);
  270. if ((NewImportDescriptor->TimeDateStamp != DataTableEntry->TimeDateStamp) ||
  271. (DataTableEntry->Flags & LDRP_IMAGE_NOT_AT_BASE)) {
  272. if (ShowSnaps)
  273. DbgPrint("LDR: %wZ has stale binding to %s\n", &LdrDataTableEntry->BaseDllName, NewImportName);
  274. StaleBinding = TRUE;
  275. } else {
  276. #if DBG
  277. LdrpSnapBypass++;
  278. #endif
  279. if (ShowSnaps)
  280. DbgPrint("LDR: %wZ has correct binding to %s\n", &LdrDataTableEntry->BaseDllName, NewImportName);
  281. StaleBinding = FALSE;
  282. }
  283. NewImportForwarder = (PIMAGE_BOUND_FORWARDER_REF) (NewImportDescriptor + 1);
  284. for (i=0; i<NewImportDescriptor->NumberOfModuleForwarderRefs; i++) {
  285. NewFwdImportName = NewImportStringBase + NewImportForwarder->OffsetModuleName;
  286. if (ShowSnaps) {
  287. DbgPrint("LDR: %wZ bound to %s via forwarder(s) from %wZ\n",
  288. &LdrDataTableEntry->BaseDllName,
  289. NewFwdImportName,
  290. &DataTableEntry->BaseDllName);
  291. }
  292. st = LdrpLoadImportModule( DllPath,
  293. NewFwdImportName,
  294. LdrDataTableEntry->DllBase,
  295. &FwdDataTableEntry,
  296. &AlreadyLoaded
  297. );
  298. if ( NT_SUCCESS(st) ) {
  299. if (!AlreadyLoaded)
  300. InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, &FwdDataTableEntry->InInitializationOrderLinks);
  301. }
  302. if ( (!NT_SUCCESS(st)) ||
  303. (NewImportForwarder->TimeDateStamp != FwdDataTableEntry->TimeDateStamp) ||
  304. (FwdDataTableEntry->Flags & LDRP_IMAGE_NOT_AT_BASE)) {
  305. if (ShowSnaps)
  306. DbgPrint("LDR: %wZ has stale binding to %s\n", &LdrDataTableEntry->BaseDllName, NewFwdImportName);
  307. StaleBinding = TRUE;
  308. } else {
  309. #if DBG
  310. LdrpSnapBypass++;
  311. #endif
  312. if (ShowSnaps) {
  313. DbgPrint("LDR: %wZ has correct binding to %s\n",
  314. &LdrDataTableEntry->BaseDllName,
  315. NewFwdImportName
  316. );
  317. }
  318. }
  319. NewImportForwarder += 1;
  320. }
  321. NewImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR) NewImportForwarder;
  322. if (StaleBinding) {
  323. #if DBG
  324. LdrpNormalSnap++;
  325. #endif
  326. //
  327. // Find the unbound import descriptor that matches this bound
  328. // import descriptor
  329. //
  330. ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(
  331. LdrDataTableEntry->DllBase,
  332. TRUE,
  333. IMAGE_DIRECTORY_ENTRY_IMPORT,
  334. &ImportSize);
  335. while (ImportDescriptor->Name != 0) {
  336. ImportName = (PSZ)((ULONG_PTR)LdrDataTableEntry->DllBase + ImportDescriptor->Name);
  337. if (_stricmp(ImportName, NewImportName) == 0)
  338. break;
  339. ImportDescriptor += 1;
  340. }
  341. if (ImportDescriptor->Name == 0) {
  342. if (ShowSnaps)
  343. DbgPrint("LDR: LdrpWalkImportTable - failing with STATUS_OBJECT_NAME_INVALID due to no import descriptor name\n");
  344. st = STATUS_OBJECT_NAME_INVALID;
  345. goto Exit;
  346. }
  347. if (ShowSnaps)
  348. DbgPrint("LDR: Stale Bind %s from %wZ\n", ImportName, &LdrDataTableEntry->BaseDllName);
  349. st = LdrpSnapIAT(
  350. DataTableEntry,
  351. LdrDataTableEntry,
  352. ImportDescriptor,
  353. FALSE);
  354. if (!NT_SUCCESS(st)) {
  355. if (ShowSnaps)
  356. DbgPrint("LDR: LdrpWalkImportTable - LdrpSnapIAT failed with status %x\n", st);
  357. goto Exit;
  358. }
  359. }
  360. st = STATUS_SUCCESS;
  361. Exit:
  362. *NewImportDescriptorInOut = NewImportDescriptor;
  363. return st;
  364. }
  365. NTSTATUS
  366. LdrpHandleNewFormatImportDescriptors(
  367. IN PPEB Peb,
  368. IN PWSTR DllPath OPTIONAL,
  369. IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry,
  370. PIMAGE_BOUND_IMPORT_DESCRIPTOR NewImportDescriptor
  371. )
  372. {
  373. NTSTATUS st = STATUS_INTERNAL_ERROR;
  374. PSZ NewImportStringBase;
  375. NewImportStringBase = (LPSTR) NewImportDescriptor;
  376. while (NewImportDescriptor->OffsetModuleName) {
  377. st = LdrpHandleOneNewFormatImportDescriptor(Peb, DllPath, LdrDataTableEntry, &NewImportDescriptor, NewImportStringBase);
  378. if (!NT_SUCCESS(st))
  379. goto Exit;
  380. }
  381. st = STATUS_SUCCESS;
  382. Exit:
  383. return st;
  384. }
  385. NTSTATUS
  386. LdrpHandleOneOldFormatImportDescriptor(
  387. IN PPEB Peb,
  388. IN PWSTR DllPath OPTIONAL,
  389. IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry,
  390. PIMAGE_IMPORT_DESCRIPTOR *ImportDescriptorInOut
  391. )
  392. {
  393. NTSTATUS st = STATUS_INTERNAL_ERROR;
  394. PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor = *ImportDescriptorInOut;
  395. PIMAGE_THUNK_DATA FirstThunk = NULL;
  396. PSTR ImportName = NULL;
  397. PLDR_DATA_TABLE_ENTRY DataTableEntry = NULL;
  398. BOOLEAN AlreadyLoaded = FALSE;
  399. BOOLEAN SnapForwardersOnly = FALSE;
  400. ImportName = (PSZ)((ULONG_PTR)LdrDataTableEntry->DllBase + ImportDescriptor->Name);
  401. //
  402. // check for import that has no references
  403. //
  404. FirstThunk = (PIMAGE_THUNK_DATA) ((ULONG_PTR)LdrDataTableEntry->DllBase + ImportDescriptor->FirstThunk);
  405. if (FirstThunk->u1.Function != 0) {
  406. if (ShowSnaps)
  407. DbgPrint("LDR: %s used by %wZ\n", ImportName, &LdrDataTableEntry->BaseDllName);
  408. st = LdrpLoadImportModule( DllPath,
  409. ImportName,
  410. LdrDataTableEntry->DllBase,
  411. &DataTableEntry,
  412. &AlreadyLoaded);
  413. if (!NT_SUCCESS(st)) {
  414. if (ShowSnaps)
  415. DbgPrint("LDR: LdrpWalkImportTable - LdrpLoadImportModule failed on import %s with status %x\n", ImportName, st);
  416. goto Exit;
  417. }
  418. if (ShowSnaps)
  419. DbgPrint("LDR: Snapping imports for %wZ from %s\n", &LdrDataTableEntry->BaseDllName, ImportName);
  420. //
  421. // If the image has been bound and the import date stamp
  422. // matches the date time stamp in the export modules header,
  423. // and the image was mapped at it's prefered base address,
  424. // then we are done.
  425. //
  426. SnapForwardersOnly = FALSE;
  427. //
  428. // This code segment is an optimization path,
  429. // which has never been executed or tested. The missing
  430. // parentheses around
  431. // DataTableEntry->Flags & LDRP_IMAGE_NOT_AT_BASE
  432. // cause the entire test condition statement to evaluate to
  433. // false since "!" has higher precedence that "&" and
  434. // LDRP_IMAGE_NOT_AT_BASE = 0x00200000.
  435. // Hence, this code segment is unreachable.
  436. // The correct conditional statement should of been:
  437. // ( !(DataTableEntry->Flags & LDRP_IMAGE_NOT_AT_BASE) )
  438. //
  439. // Since this code is an optimization path that would of been
  440. // executed infrequently by certain legacy formats, and this
  441. // code has never been executed or tested, the team decided not
  442. // to fix the test condition. This decision does not alter
  443. // any functionality of previous versions of the ldr.
  444. //
  445. // if ( ImportDescriptor->OriginalFirstThunk ) {
  446. // if ( ImportDescriptor->TimeDateStamp &&
  447. // ImportDescriptor->TimeDateStamp == DataTableEntry->TimeDateStamp &&
  448. // (! DataTableEntry->Flags & LDRP_IMAGE_NOT_AT_BASE) ) {
  449. // #if DBG
  450. // LdrpSnapBypass++;
  451. // #endif
  452. // if (ShowSnaps) {
  453. // DbgPrint("LDR: Snap bypass %s from %wZ\n",
  454. // ImportName,
  455. // &LdrDataTableEntry->BaseDllName
  456. // );
  457. // }
  458. //
  459. // if (ImportDescriptor->ForwarderChain == -1) {
  460. // goto bypass_snap;
  461. // }
  462. //
  463. // SnapForwardersOnly = TRUE;
  464. //
  465. // }
  466. // }
  467. #if DBG
  468. LdrpNormalSnap++;
  469. #endif
  470. //
  471. // Add to initialization list.
  472. //
  473. if (!AlreadyLoaded)
  474. InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, &DataTableEntry->InInitializationOrderLinks);
  475. st = LdrpSnapIAT(
  476. DataTableEntry,
  477. LdrDataTableEntry,
  478. ImportDescriptor,
  479. SnapForwardersOnly);
  480. if (!NT_SUCCESS(st)) {
  481. if (ShowSnaps)
  482. DbgPrint("LDR: LdrpWalkImportTable - LdrpSnapIAT #2 failed with status %x\n", st);
  483. goto Exit;
  484. }
  485. AlreadyLoaded = TRUE;
  486. // See comment above. Snap is always taken, so bypass_snap
  487. // never gets reference during execution.
  488. // bypass_snap:
  489. //
  490. // Add to initialization list.
  491. //
  492. if (!AlreadyLoaded)
  493. InsertTailList(&Peb->Ldr->InInitializationOrderModuleList, &DataTableEntry->InInitializationOrderLinks);
  494. }
  495. ++ImportDescriptor;
  496. st = STATUS_SUCCESS;
  497. Exit:
  498. *ImportDescriptorInOut = ImportDescriptor;
  499. return st;
  500. }
  501. NTSTATUS
  502. LdrpHandleOldFormatImportDescriptors(
  503. IN PPEB Peb,
  504. IN PWSTR DllPath OPTIONAL,
  505. IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry,
  506. PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
  507. )
  508. {
  509. NTSTATUS st = STATUS_INTERNAL_ERROR;
  510. //
  511. // For each DLL used by this DLL, load the dll. Then snap
  512. // the IAT, and call the DLL's init routine.
  513. //
  514. while (ImportDescriptor->Name && ImportDescriptor->FirstThunk) {
  515. st = LdrpHandleOneOldFormatImportDescriptor(Peb, DllPath, LdrDataTableEntry, &ImportDescriptor);
  516. if (!NT_SUCCESS(st))
  517. goto Exit;
  518. }
  519. st = STATUS_SUCCESS;
  520. Exit:
  521. return st;
  522. }
  523. NTSTATUS
  524. LdrpMungHeapImportsForTagging(
  525. IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry
  526. )
  527. {
  528. NTSTATUS st = STATUS_INTERNAL_ERROR;
  529. PVOID IATBase;
  530. SIZE_T BigIATSize;
  531. ULONG LittleIATSize;
  532. PVOID *ProcAddresses;
  533. ULONG NumberOfProcAddresses;
  534. ULONG OldProtect;
  535. USHORT TagIndex;
  536. //
  537. // Determine the location and size of the IAT. If found, scan the
  538. // IAT address to see if any are pointing to RtlAllocateHeap. If so
  539. // replace when with a pointer to a unique thunk function that will
  540. // replace the tag with a unique tag for this image.
  541. //
  542. IATBase = RtlImageDirectoryEntryToData( LdrDataTableEntry->DllBase,
  543. TRUE,
  544. IMAGE_DIRECTORY_ENTRY_IAT,
  545. &LittleIATSize
  546. );
  547. if (IATBase != NULL) {
  548. BigIATSize = LittleIATSize;
  549. st = NtProtectVirtualMemory( NtCurrentProcess(),
  550. &IATBase,
  551. &BigIATSize,
  552. PAGE_READWRITE,
  553. &OldProtect);
  554. if (!NT_SUCCESS(st)) {
  555. DbgPrint( "LDR: Unable to unprotect IAT to enable tagging by DLL.\n");
  556. st = STATUS_SUCCESS;
  557. goto Exit;
  558. }
  559. ProcAddresses = (PVOID *)IATBase;
  560. NumberOfProcAddresses = (ULONG)(BigIATSize / sizeof(PVOID));
  561. while (NumberOfProcAddresses--) {
  562. if (*ProcAddresses == RtlAllocateHeap) {
  563. *ProcAddresses = LdrpDefineDllTag(LdrDataTableEntry->BaseDllName.Buffer, &TagIndex);
  564. if (*ProcAddresses == NULL)
  565. *ProcAddresses = RtlAllocateHeap;
  566. }
  567. ProcAddresses += 1;
  568. }
  569. NtProtectVirtualMemory( NtCurrentProcess(),
  570. &IATBase,
  571. &BigIATSize,
  572. OldProtect,
  573. &OldProtect);
  574. }
  575. st = STATUS_SUCCESS;
  576. Exit:
  577. return st;
  578. }
  579. NTSTATUS
  580. LdrpWalkImportDescriptor (
  581. IN PWSTR DllPath OPTIONAL,
  582. IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry
  583. )
  584. /*++
  585. Routine Description:
  586. This is a recursive routine which walks the Import Descriptor
  587. Table and loads each DLL that is referenced.
  588. Arguments:
  589. DllPath - Supplies an optional search path to be used to locate
  590. the DLL.
  591. LdrDataTableEntry - Supplies the address of the data table entry
  592. to initialize.
  593. Return Value:
  594. Status value.
  595. --*/
  596. {
  597. ULONG ImportSize, NewImportSize;
  598. PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor = NULL;
  599. PIMAGE_BOUND_IMPORT_DESCRIPTOR NewImportDescriptor = NULL;
  600. NTSTATUS st;
  601. CONST PPEB Peb = NtCurrentPeb();
  602. RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActivationFrame = { sizeof(ActivationFrame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
  603. CONST PLDR_DATA_TABLE_ENTRY Entry = LdrDataTableEntry;
  604. if (LdrpManifestProberRoutine != NULL) {
  605. PVOID SavedEntry = Peb->Ldr->EntryInProgress;
  606. __try {
  607. //
  608. // don't check .exes that have id 1 manifest, id 1 in an .exe makes Peb->ActivationContextData not NULL
  609. //
  610. if (Peb->ActivationContextData == NULL || LdrDataTableEntry != LdrpImageEntry) {
  611. CONST PVOID ViewBase = LdrDataTableEntry->DllBase;
  612. PVOID ResourceViewBase = ViewBase;
  613. NTSTATUS stTemp;
  614. PCWSTR DllName;
  615. #if defined(_WIN64)
  616. PIMAGE_NT_HEADERS NtHeaders = RtlImageNtHeader(ViewBase);
  617. if (NtHeaders->OptionalHeader.SectionAlignment < NATIVE_PAGE_SIZE) {
  618. ResourceViewBase = LDR_VIEW_TO_DATAFILE(ViewBase);
  619. }
  620. #endif
  621. DllName = Entry->FullDllName.Buffer;
  622. //
  623. // RtlCreateUserProcess() causes this.
  624. //
  625. if (LdrDataTableEntry == LdrpImageEntry &&
  626. DllName[0] == L'\\' &&
  627. DllName[1] == L'?' &&
  628. DllName[2] == L'?' &&
  629. DllName[3] == L'\\' &&
  630. DllName[4] != UNICODE_NULL &&
  631. DllName[5] == ':' &&
  632. DllName[6] == L'\\'
  633. ) {
  634. DllName += 4;
  635. }
  636. Peb->Ldr->EntryInProgress = Entry;
  637. stTemp = (*LdrpManifestProberRoutine)(ResourceViewBase, DllName, &Entry->EntryPointActivationContext);
  638. if (!NT_SUCCESS(stTemp)) {
  639. if ((stTemp != STATUS_NO_SUCH_FILE) &&
  640. (stTemp != STATUS_RESOURCE_DATA_NOT_FOUND) &&
  641. (stTemp != STATUS_RESOURCE_TYPE_NOT_FOUND) &&
  642. (stTemp != STATUS_RESOURCE_LANG_NOT_FOUND) &&
  643. (stTemp != STATUS_RESOURCE_NAME_NOT_FOUND)) {
  644. DbgPrintEx(
  645. DPFLTR_SXS_ID,
  646. DPFLTR_ERROR_LEVEL,
  647. "LDR: LdrpWalkImportDescriptor() failed to probe %wZ for its manifest, ntstatus 0x%08lx\n", &LdrDataTableEntry->FullDllName, stTemp);
  648. st = stTemp;
  649. goto Exit;
  650. }
  651. }
  652. }
  653. } __finally {
  654. Peb->Ldr->EntryInProgress = SavedEntry;
  655. }
  656. }
  657. // If we didn't start a private activation context for the DLL, let's use the currently/previously active one.
  658. if (Entry->EntryPointActivationContext == NULL) {
  659. st = RtlGetActiveActivationContext((PACTIVATION_CONTEXT *) &LdrDataTableEntry->EntryPointActivationContext);
  660. if (!NT_SUCCESS(st)) {
  661. #if DBG
  662. DbgPrintEx(
  663. DPFLTR_SXS_ID,
  664. DPFLTR_ERROR_LEVEL,
  665. "LDR: RtlGetActiveActivationContext() failed; ntstatus = 0x%08lx\n", st);
  666. #endif
  667. goto Exit;
  668. }
  669. }
  670. RtlActivateActivationContextUnsafeFast(&ActivationFrame, LdrDataTableEntry->EntryPointActivationContext);
  671. __try {
  672. //
  673. // See if there is a bound import table. If so, walk that to
  674. // verify if the binding is good. If so, then succeed with
  675. // having touched the .idata section, as all the information
  676. // in the bound imports table is stored in the header. If any
  677. // are stale, then fall out into the unbound case.
  678. //
  679. // Don't allow binding to redirected .dlls, because the Bind machinery
  680. // is too weak. It breaks when different files with the same leaf name
  681. // are built at the same time. This has been seen to happen,
  682. // with comctl32.dll and comctlv6.dll on September 30, 2000. a-JayK
  683. //
  684. if ((LdrDataTableEntry->Flags & LDRP_REDIRECTED) == 0) {
  685. NewImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(
  686. LdrDataTableEntry->DllBase,
  687. TRUE,
  688. IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
  689. &NewImportSize
  690. );
  691. }
  692. ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(
  693. LdrDataTableEntry->DllBase,
  694. TRUE,
  695. IMAGE_DIRECTORY_ENTRY_IMPORT,
  696. &ImportSize
  697. );
  698. if (NewImportDescriptor != NULL) {
  699. st = LdrpHandleNewFormatImportDescriptors(Peb, DllPath, LdrDataTableEntry, NewImportDescriptor);
  700. if (!NT_SUCCESS(st))
  701. goto Exit;
  702. } else if (ImportDescriptor != NULL) {
  703. st = LdrpHandleOldFormatImportDescriptors(Peb, DllPath, LdrDataTableEntry, ImportDescriptor);
  704. if (!NT_SUCCESS(st))
  705. goto Exit;
  706. }
  707. if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAG_BY_DLL) {
  708. st = LdrpMungHeapImportsForTagging(LdrDataTableEntry);
  709. if (!NT_SUCCESS(st))
  710. goto Exit;
  711. }
  712. //
  713. // Notify page heap per dll part of verifier that a dll got loaded.
  714. // It is important to call this before the main verifier hook so that
  715. // heap related imports are redirected before any redirection from
  716. // verifier providers. In time all this logic should move into
  717. // verifier.dll.
  718. //
  719. if (Peb->NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS) {
  720. AVrfPageHeapDllNotification (LdrDataTableEntry);
  721. }
  722. //
  723. // Notify verifier that a dll got loaded.
  724. //
  725. if (Peb->NtGlobalFlag & FLG_APPLICATION_VERIFIER) {
  726. AVrfDllLoadNotification (LdrDataTableEntry);
  727. }
  728. } __finally {
  729. RtlDeactivateActivationContextUnsafeFast(&ActivationFrame);
  730. }
  731. st = STATUS_SUCCESS;
  732. Exit:
  733. return st;
  734. }
  735. ULONG
  736. LdrpClearLoadInProgress(
  737. VOID
  738. )
  739. {
  740. PLIST_ENTRY Head, Next;
  741. PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
  742. ULONG i;
  743. Head = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
  744. Next = Head->Flink;
  745. i = 0;
  746. while ( Next != Head ) {
  747. LdrDataTableEntry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
  748. LdrDataTableEntry->Flags &= ~LDRP_LOAD_IN_PROGRESS;
  749. //
  750. // return the number of entries that have not been processed, but
  751. // have init routines
  752. //
  753. if ( !(LdrDataTableEntry->Flags & LDRP_ENTRY_PROCESSED) && LdrDataTableEntry->EntryPoint) {
  754. i++;
  755. }
  756. Next = Next->Flink;
  757. }
  758. return i;
  759. }
  760. NTSTATUS
  761. LdrpRunInitializeRoutines(
  762. IN PCONTEXT Context OPTIONAL
  763. )
  764. {
  765. PLIST_ENTRY Head, Next;
  766. PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
  767. PLDR_DATA_TABLE_ENTRY *LdrDataTableBase;
  768. PDLL_INIT_ROUTINE InitRoutine;
  769. BOOLEAN InitStatus;
  770. ULONG NumberOfRoutines;
  771. ULONG i;
  772. NTSTATUS Status;
  773. ULONG BreakOnDllLoad;
  774. PLDR_DATA_TABLE_ENTRY StackLdrDataTable[16];
  775. PTEB OldTopLevelDllBeingLoadedTeb;
  776. LdrpEnsureLoaderLockIsHeld();
  777. //
  778. // Run the Init routines
  779. //
  780. //
  781. // capture the entries that have init routines
  782. //
  783. NumberOfRoutines = LdrpClearLoadInProgress();
  784. if (NumberOfRoutines != 0) {
  785. if (NumberOfRoutines <= RTL_NUMBER_OF(StackLdrDataTable))
  786. LdrDataTableBase = StackLdrDataTable;
  787. else {
  788. LdrDataTableBase = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TEMP_TAG), NumberOfRoutines * sizeof(PLDR_DATA_TABLE_ENTRY));
  789. if (LdrDataTableBase == NULL) {
  790. DbgPrintEx(
  791. DPFLTR_LDR_ID,
  792. LDR_ERROR_DPFLTR,
  793. "LDR: %s - failed to allocate dynamic array of %u DLL initializers to run\n",
  794. __FUNCTION__,
  795. NumberOfRoutines);
  796. return STATUS_NO_MEMORY;
  797. }
  798. }
  799. } else
  800. LdrDataTableBase = NULL;
  801. Head = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
  802. Next = Head->Flink;
  803. if (ShowSnaps || LdrpShowInitRoutines) {
  804. DbgPrint("[%x,%x] LDR: Real INIT LIST for process %wZ pid %u 0x%x\n",
  805. HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess),
  806. HandleToULong(NtCurrentTeb()->ClientId.UniqueThread),
  807. &NtCurrentPeb()->ProcessParameters->ImagePathName,
  808. HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess),
  809. HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess)
  810. );
  811. }
  812. i = 0;
  813. while ( Next != Head ) {
  814. LdrDataTableEntry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
  815. if (LdrDataTableBase && !(LdrDataTableEntry->Flags & LDRP_ENTRY_PROCESSED) && LdrDataTableEntry->EntryPoint) {
  816. ASSERT(i < NumberOfRoutines);
  817. LdrDataTableBase[i] = LdrDataTableEntry;
  818. if (ShowSnaps || LdrpShowInitRoutines) {
  819. DbgPrint("[%x,%x] %wZ init routine %p\n",
  820. HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess),
  821. HandleToULong(NtCurrentTeb()->ClientId.UniqueThread),
  822. &LdrDataTableEntry->FullDllName,
  823. LdrDataTableEntry->EntryPoint);
  824. }
  825. i++;
  826. }
  827. LdrDataTableEntry->Flags |= LDRP_ENTRY_PROCESSED;
  828. Next = Next->Flink;
  829. }
  830. ASSERT(i == NumberOfRoutines);
  831. if (LdrDataTableBase == NULL) {
  832. return STATUS_SUCCESS;
  833. }
  834. i = 0;
  835. OldTopLevelDllBeingLoadedTeb = LdrpTopLevelDllBeingLoadedTeb;
  836. LdrpTopLevelDllBeingLoadedTeb = NtCurrentTeb();
  837. try {
  838. while ( i < NumberOfRoutines ) {
  839. LdrDataTableEntry = LdrDataTableBase[i];
  840. i++;
  841. InitRoutine = (PDLL_INIT_ROUTINE)LdrDataTableEntry->EntryPoint;
  842. //
  843. // Walk through the entire list looking for un-processed
  844. // entries. For each entry, set the processed flag
  845. // and optionally call it's init routine
  846. //
  847. BreakOnDllLoad = 0;
  848. #if DBG
  849. if (TRUE)
  850. #else
  851. if (NtCurrentPeb()->BeingDebugged || NtCurrentPeb()->ReadImageFileExecOptions)
  852. #endif
  853. {
  854. Status = LdrQueryImageFileExecutionOptions( &LdrDataTableEntry->BaseDllName,
  855. L"BreakOnDllLoad",
  856. REG_DWORD,
  857. &BreakOnDllLoad,
  858. sizeof( BreakOnDllLoad ),
  859. NULL
  860. );
  861. if (!NT_SUCCESS( Status )) {
  862. BreakOnDllLoad = 0;
  863. }
  864. }
  865. if (BreakOnDllLoad) {
  866. if (ShowSnaps) {
  867. DbgPrint( "LDR: %wZ loaded.", &LdrDataTableEntry->BaseDllName );
  868. DbgPrint( " - About to call init routine at %p\n", InitRoutine );
  869. }
  870. DbgBreakPoint();
  871. } else if (ShowSnaps) {
  872. if ( InitRoutine ) {
  873. DbgPrint( "[%x,%x] LDR: %wZ loaded",
  874. HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess),
  875. HandleToULong(NtCurrentTeb()->ClientId.UniqueThread),
  876. &LdrDataTableEntry->BaseDllName);
  877. DbgPrint(" - Calling init routine at %p\n", InitRoutine);
  878. }
  879. }
  880. if ( InitRoutine ) {
  881. PLDR_DATA_TABLE_ENTRY SavedInitializer = LdrpCurrentDllInitializer;
  882. LdrpCurrentDllInitializer = LdrDataTableEntry;
  883. __try {
  884. LDRP_ACTIVATE_ACTIVATION_CONTEXT(LdrDataTableEntry);
  885. //
  886. // If the DLL has TLS data, then call the optional initializers
  887. //
  888. if ((LdrDataTableEntry->TlsIndex != 0) && (Context != NULL))
  889. LdrpCallTlsInitializers(LdrDataTableEntry->DllBase,DLL_PROCESS_ATTACH);
  890. if (LdrpShowInitRoutines) {
  891. DbgPrint("[%x,%x] LDR: calling init routine %p for DLL_PROCESS_ATTACH\n",
  892. HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess),
  893. HandleToULong(NtCurrentTeb()->ClientId.UniqueThread),
  894. InitRoutine);
  895. }
  896. InitStatus = LdrpCallInitRoutine(InitRoutine,
  897. LdrDataTableEntry->DllBase,
  898. DLL_PROCESS_ATTACH,
  899. Context);
  900. LDRP_DEACTIVATE_ACTIVATION_CONTEXT();
  901. } __finally {
  902. LdrpCurrentDllInitializer = SavedInitializer;
  903. }
  904. LdrDataTableEntry->Flags |= LDRP_PROCESS_ATTACH_CALLED;
  905. if (!InitStatus) {
  906. DbgPrintEx(
  907. DPFLTR_LDR_ID,
  908. LDR_ERROR_DPFLTR,
  909. "[%x,%x] LDR: DLL_PROCESS_ATTACH for dll \"%wZ\" (InitRoutine: %p) failed\n",
  910. HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess),
  911. HandleToULong(NtCurrentTeb()->ClientId.UniqueThread),
  912. &LdrDataTableEntry->FullDllName,
  913. InitRoutine);
  914. return STATUS_DLL_INIT_FAILED;
  915. }
  916. }
  917. }
  918. //
  919. // If the image has tls than call its initializers
  920. //
  921. if (LdrpImageHasTls && (Context != NULL))
  922. {
  923. LDRP_ACTIVATE_ACTIVATION_CONTEXT(LdrpImageEntry);
  924. LdrpCallTlsInitializers(NtCurrentPeb()->ImageBaseAddress,DLL_PROCESS_ATTACH);
  925. LDRP_DEACTIVATE_ACTIVATION_CONTEXT();
  926. }
  927. } finally {
  928. LdrpTopLevelDllBeingLoadedTeb = OldTopLevelDllBeingLoadedTeb;
  929. if ((LdrDataTableBase != NULL) &&
  930. (LdrDataTableBase != StackLdrDataTable))
  931. RtlFreeHeap(RtlProcessHeap(),0,LdrDataTableBase);
  932. }
  933. return STATUS_SUCCESS;
  934. }
  935. BOOLEAN
  936. LdrpCheckForLoadedDll (
  937. IN PWSTR DllPath OPTIONAL,
  938. IN PUNICODE_STRING DllName,
  939. IN BOOLEAN StaticLink,
  940. IN BOOLEAN Redirected,
  941. OUT PLDR_DATA_TABLE_ENTRY *LdrDataTableEntry
  942. )
  943. /*++
  944. Routine Description:
  945. This function scans the loader data table looking to see if
  946. the specified DLL has already been mapped into the image. If
  947. the dll has been loaded, the address of its data table entry
  948. is returned.
  949. Arguments:
  950. DllPath - Supplies an optional search path used to locate the DLL.
  951. DllName - Supplies the name to search for.
  952. StaticLink - TRUE if performing a static link.
  953. LdrDataTableEntry - Returns the address of the loader data table
  954. entry that describes the first dll section that implements the
  955. dll.
  956. Return Value:
  957. TRUE- The dll is already loaded. The address of the data table
  958. entries that implement the dll, and the number of data table
  959. entries are returned.
  960. FALSE - The dll is not already mapped.
  961. --*/
  962. {
  963. BOOLEAN Result = FALSE;
  964. PLDR_DATA_TABLE_ENTRY Entry;
  965. PLIST_ENTRY Head, Next;
  966. UNICODE_STRING FullDllName;
  967. HANDLE DllFile;
  968. BOOLEAN HardCodedPath;
  969. PWCH p;
  970. ULONG i;
  971. WCHAR FullDllNameStaticBuffer[LDR_MAX_PATH];
  972. UNICODE_STRING FullDllNameDynamicString;
  973. ULONG Length = 0;
  974. PWCH src,dest;
  975. NTSTATUS Status;
  976. FullDllNameDynamicString.Buffer = NULL;
  977. if (!DllName->Buffer || !DllName->Buffer[0]) {
  978. goto alldone;
  979. }
  980. Status = STATUS_SUCCESS; // just in case anyone asks...
  981. //
  982. // for static links, just go to the hash table
  983. //
  984. staticlink:
  985. if ( StaticLink ) {
  986. // If this is a redirected static load, the dll name is a fully qualified path. The
  987. // hash table is maintained based on the first character of the base dll name, so find
  988. // the base dll name.
  989. if (Redirected) {
  990. PWSTR LastChar = DllName->Buffer + (DllName->Length / sizeof(WCHAR)) - (DllName->Length == 0 ? 0 : 1);
  991. while (LastChar != DllName->Buffer) {
  992. const WCHAR wch = *LastChar;
  993. if ((wch == L'\\') || (wch == L'/'))
  994. break;
  995. LastChar--;
  996. }
  997. // This assert ignores the "possibility" that the first and only slash is the first character, but that's
  998. // an error, too. The redirection should be a complete DOS path.
  999. ASSERTMSG(
  1000. "Redirected DLL name does not have full path; either caller lied or redirection info is in error",
  1001. LastChar != DllName->Buffer);
  1002. if (LastChar == DllName->Buffer) {
  1003. if (ShowSnaps) {
  1004. DbgPrint("LDR: Failing LdrpCheckForLoadedDll because redirected DLL name %wZ does not include a slash\n", DllName);
  1005. }
  1006. Result = FALSE;
  1007. goto alldone;
  1008. }
  1009. LastChar++;
  1010. i = LDRP_COMPUTE_HASH_INDEX(*LastChar);
  1011. } else {
  1012. i = LDRP_COMPUTE_HASH_INDEX(DllName->Buffer[0]);
  1013. }
  1014. Head = &LdrpHashTable[i];
  1015. Next = Head->Flink;
  1016. while ( Next != Head ) {
  1017. Entry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, HashLinks);
  1018. #if DBG
  1019. LdrpCompareCount++;
  1020. #endif
  1021. // Redirected static loads never match unredirected entries and vice versa
  1022. if (Redirected) {
  1023. if (((Entry->Flags & LDRP_REDIRECTED) != 0) &&
  1024. RtlEqualUnicodeString(DllName, &Entry->FullDllName, TRUE)) {
  1025. *LdrDataTableEntry = Entry;
  1026. Result = TRUE;
  1027. goto alldone;
  1028. }
  1029. } else {
  1030. // Not redirected...
  1031. if (((Entry->Flags & LDRP_REDIRECTED) == 0) &&
  1032. RtlEqualUnicodeString(DllName, &Entry->BaseDllName, TRUE)) {
  1033. *LdrDataTableEntry = Entry;
  1034. Result = TRUE;
  1035. goto alldone;
  1036. }
  1037. }
  1038. Next = Next->Flink;
  1039. }
  1040. }
  1041. if ( StaticLink ) {
  1042. Result = FALSE;
  1043. goto alldone;
  1044. }
  1045. //
  1046. // If the dll name contained a hard coded path
  1047. // (dynamic link only), then the fully qualified
  1048. // name needs to be compared to make sure we
  1049. // have the correct dll.
  1050. //
  1051. p = DllName->Buffer;
  1052. HardCodedPath = FALSE;
  1053. if (Redirected) {
  1054. HardCodedPath = TRUE;
  1055. FullDllName.Length = DllName->Length;
  1056. FullDllName.MaximumLength = DllName->MaximumLength;
  1057. FullDllName.Buffer = DllName->Buffer;
  1058. } else {
  1059. while (*p) {
  1060. const WCHAR wch = *p++;
  1061. if (wch == (WCHAR)'\\' || wch == (WCHAR)'/' ) {
  1062. HardCodedPath = TRUE;
  1063. //
  1064. // We have a hard coded path, so we have to search path
  1065. // for the DLL. We need the full DLL name so we can
  1066. FullDllName.Buffer = FullDllNameStaticBuffer;
  1067. Length = RtlDosSearchPath_U(
  1068. ARGUMENT_PRESENT(DllPath) ? DllPath : LdrpDefaultPath.Buffer,
  1069. DllName->Buffer,
  1070. NULL,
  1071. sizeof(FullDllNameStaticBuffer)-sizeof(UNICODE_NULL),
  1072. FullDllName.Buffer,
  1073. NULL
  1074. );
  1075. if (Length == 0) {
  1076. if (ShowSnaps) {
  1077. DbgPrint("LDR: LdrpCheckForLoadedDll - Unable To Locate ");
  1078. DbgPrint("%ws from %ws\n",
  1079. DllName->Buffer,
  1080. ARGUMENT_PRESENT(DllPath) ? DllPath : LdrpDefaultPath.Buffer
  1081. );
  1082. }
  1083. Result = FALSE;
  1084. goto alldone;
  1085. }
  1086. if ((Length + sizeof(WCHAR)) > sizeof(FullDllNameStaticBuffer)) {
  1087. if (Length > UNICODE_STRING_MAX_BYTES) {
  1088. if (ShowSnaps) {
  1089. DbgPrint("LDR: LdrpCheckForLoadedDll - Failing load of ");
  1090. DbgPrint("%wZ from %ws", DllName, ARGUMENT_PRESENT(DllPath) ? DllPath : LdrpDefaultPath.Buffer);
  1091. DbgPrint(" because path search required %u bytes\n", Length + sizeof(WCHAR));
  1092. }
  1093. Result = FALSE;
  1094. goto alldone;
  1095. }
  1096. FullDllNameDynamicString.Buffer = (RtlAllocateStringRoutine)(Length + sizeof(WCHAR));
  1097. if (FullDllNameDynamicString.Buffer == NULL) {
  1098. if (ShowSnaps) {
  1099. DbgPrint("LDR: LdrpCheckForLoadedDll - Failing load of %wZ because we could not dynamically allocate its full dll path buffer\n", DllName);
  1100. }
  1101. Result = FALSE;
  1102. goto alldone;
  1103. }
  1104. FullDllNameDynamicString.MaximumLength = (USHORT) (Length + sizeof(WCHAR));
  1105. FullDllNameDynamicString.Length = 0;
  1106. Length = RtlDosSearchPath_U(
  1107. ARGUMENT_PRESENT(DllPath) ? DllPath : LdrpDefaultPath.Buffer,
  1108. DllName->Buffer,
  1109. NULL,
  1110. Length,
  1111. FullDllNameDynamicString.Buffer,
  1112. NULL
  1113. );
  1114. if ((Length == 0) || ((Length + sizeof(WCHAR)) > FullDllNameDynamicString.MaximumLength)) {
  1115. if (ShowSnaps) {
  1116. DbgPrint("LDR: LdrpCheckForLoadedDll - Failing load of %wZ because searching path into dynamic buffer failed; buffer size: returned length: %lu\n",
  1117. DllName, FullDllNameDynamicString.MaximumLength, Length);
  1118. }
  1119. Result = FALSE;
  1120. goto alldone;
  1121. }
  1122. FullDllName.Buffer = FullDllNameDynamicString.Buffer;
  1123. }
  1124. FullDllName.Buffer[Length / sizeof(WCHAR)] = UNICODE_NULL;
  1125. FullDllName.Length = (USHORT)Length;
  1126. FullDllName.MaximumLength = FullDllName.Length + (USHORT)sizeof(UNICODE_NULL);
  1127. break;
  1128. }
  1129. }
  1130. }
  1131. //
  1132. // if this is a dynamic load lib, and there is not a hard
  1133. // coded path, then go to the static lib hash table for resolution
  1134. //
  1135. if ( !HardCodedPath ) {
  1136. // If we're redirecting this DLL, don't check if there's another DLL by the same name already loaded.
  1137. if (NT_SUCCESS(RtlFindActivationContextSectionString(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, DllName, NULL)))
  1138. return FALSE;
  1139. StaticLink = TRUE;
  1140. goto staticlink;
  1141. }
  1142. Result = FALSE;
  1143. Head = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
  1144. Next = Head->Flink;
  1145. while ( Next != Head ) {
  1146. Entry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
  1147. Next = Next->Flink;
  1148. //
  1149. // when we unload, the memory order links flink field is nulled.
  1150. // this is used to skip the entry pending list removal.
  1151. //
  1152. if ( !Entry->InMemoryOrderLinks.Flink ) {
  1153. continue;
  1154. }
  1155. // Since this is a full string comparison, we don't worry about redirection - we don't
  1156. // want to load the dll from a particular path more than once just because one of them
  1157. // explicitly (and erroneously) specified the magic side-by-side location of the
  1158. // DLL and the other loaded it via side-by-side isolation automagically.
  1159. if (RtlEqualUnicodeString(
  1160. &FullDllName,
  1161. &Entry->FullDllName,
  1162. TRUE
  1163. ) ) {
  1164. Result = TRUE;
  1165. *LdrDataTableEntry = Entry;
  1166. break;
  1167. }
  1168. }
  1169. if ( !Result ) {
  1170. //
  1171. // no names matched. This might be a long short name mismatch or
  1172. // any kind of alias pathname. Deal with this by opening and mapping
  1173. // full dll name and then repeat the scan this time checking for
  1174. // timedatestamp matches
  1175. //
  1176. HANDLE File;
  1177. HANDLE Section;
  1178. NTSTATUS st;
  1179. OBJECT_ATTRIBUTES ObjectAttributes;
  1180. IO_STATUS_BLOCK IoStatus;
  1181. PVOID ViewBase;
  1182. SIZE_T ViewSize;
  1183. PIMAGE_NT_HEADERS NtHeadersSrc,NtHeadersE;
  1184. UNICODE_STRING NtFileName;
  1185. if (!RtlDosPathNameToNtPathName_U( FullDllName.Buffer,
  1186. &NtFileName,
  1187. NULL,
  1188. NULL
  1189. )
  1190. ) {
  1191. goto alldone;
  1192. }
  1193. InitializeObjectAttributes(
  1194. &ObjectAttributes,
  1195. &NtFileName,
  1196. OBJ_CASE_INSENSITIVE,
  1197. NULL,
  1198. NULL
  1199. );
  1200. st = NtOpenFile(
  1201. &File,
  1202. SYNCHRONIZE | FILE_EXECUTE,
  1203. &ObjectAttributes,
  1204. &IoStatus,
  1205. FILE_SHARE_READ | FILE_SHARE_DELETE,
  1206. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
  1207. );
  1208. RtlFreeHeap(RtlProcessHeap(), 0, NtFileName.Buffer);
  1209. if (!NT_SUCCESS(st)) {
  1210. goto alldone;
  1211. }
  1212. st = NtCreateSection(
  1213. &Section,
  1214. SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_MAP_WRITE,
  1215. NULL,
  1216. NULL,
  1217. PAGE_EXECUTE,
  1218. SEC_COMMIT,
  1219. File
  1220. );
  1221. NtClose( File );
  1222. if (!NT_SUCCESS(st)) {
  1223. goto alldone;
  1224. }
  1225. ViewBase = NULL;
  1226. ViewSize = 0;
  1227. st = NtMapViewOfSection(
  1228. Section,
  1229. NtCurrentProcess(),
  1230. (PVOID *)&ViewBase,
  1231. 0L,
  1232. 0L,
  1233. NULL,
  1234. &ViewSize,
  1235. ViewShare,
  1236. 0L,
  1237. PAGE_EXECUTE
  1238. );
  1239. NtClose(Section);
  1240. if (!NT_SUCCESS(st)) {
  1241. goto alldone;
  1242. }
  1243. //
  1244. // The section is mapped. Now find the headers
  1245. //
  1246. NtHeadersSrc = RtlImageNtHeader(ViewBase);
  1247. if ( !NtHeadersSrc ) {
  1248. NtUnmapViewOfSection(NtCurrentProcess(),ViewBase);
  1249. goto alldone;
  1250. }
  1251. Head = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
  1252. Next = Head->Flink;
  1253. while ( Next != Head ) {
  1254. Entry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
  1255. Next = Next->Flink;
  1256. //
  1257. // when we unload, the memory order links flink field is nulled.
  1258. // this is used to skip the entry pending list removal.
  1259. //
  1260. if ( !Entry->InMemoryOrderLinks.Flink ) {
  1261. continue;
  1262. }
  1263. try {
  1264. if ( Entry->TimeDateStamp == NtHeadersSrc->FileHeader.TimeDateStamp &&
  1265. Entry->SizeOfImage == NtHeadersSrc->OptionalHeader.SizeOfImage ) {
  1266. //
  1267. // there is a very good chance we have an image match. Check the
  1268. // entire file header and optional header. If they match, declare
  1269. // this a match
  1270. //
  1271. NtHeadersE = RtlImageNtHeader(Entry->DllBase);
  1272. if ( RtlCompareMemory(NtHeadersE,NtHeadersSrc,sizeof(*NtHeadersE)) ) {
  1273. //
  1274. // Now that it looks like we have a match, compare
  1275. // volume serial number's and file index's
  1276. //
  1277. st = NtAreMappedFilesTheSame(Entry->DllBase,ViewBase);
  1278. if ( !NT_SUCCESS(st) ) {
  1279. continue;
  1280. }
  1281. else {
  1282. Result = TRUE;
  1283. *LdrDataTableEntry = Entry;
  1284. break;
  1285. }
  1286. }
  1287. }
  1288. }
  1289. except (LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {
  1290. DbgPrintEx(
  1291. DPFLTR_LDR_ID,
  1292. LDR_ERROR_DPFLTR,
  1293. "LDR: %s - Caught exception %08lx\n",
  1294. __FUNCTION__,
  1295. GetExceptionCode());
  1296. break;
  1297. }
  1298. }
  1299. NtUnmapViewOfSection(NtCurrentProcess(),ViewBase);
  1300. }
  1301. alldone:
  1302. if (FullDllNameDynamicString.Buffer != NULL) {
  1303. RtlFreeUnicodeString(&FullDllNameDynamicString);
  1304. }
  1305. return Result;
  1306. }
  1307. BOOLEAN
  1308. LdrpCheckForLoadedDllHandle (
  1309. IN PVOID DllHandle,
  1310. OUT PLDR_DATA_TABLE_ENTRY *LdrDataTableEntry
  1311. )
  1312. /*++
  1313. Routine Description:
  1314. This function scans the loader data table looking to see if
  1315. the specified DLL has already been mapped into the image address
  1316. space. If the dll has been loaded, the address of its data table
  1317. entry that describes the dll is returned.
  1318. Arguments:
  1319. DllHandle - Supplies the DllHandle of the DLL being searched for.
  1320. LdrDataTableEntry - Returns the address of the loader data table
  1321. entry that describes the dll.
  1322. Return Value:
  1323. TRUE- The dll is loaded. The address of the data table entry is
  1324. returned.
  1325. FALSE - The dll is not loaded.
  1326. --*/
  1327. {
  1328. PLDR_DATA_TABLE_ENTRY Entry;
  1329. PLIST_ENTRY Head,Next;
  1330. if ( LdrpLoadedDllHandleCache &&
  1331. (PVOID) LdrpLoadedDllHandleCache->DllBase == DllHandle ) {
  1332. *LdrDataTableEntry = LdrpLoadedDllHandleCache;
  1333. return TRUE;
  1334. }
  1335. Head = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
  1336. Next = Head->Flink;
  1337. while ( Next != Head ) {
  1338. Entry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
  1339. Next = Next->Flink;
  1340. //
  1341. // when we unload, the memory order links flink field is nulled.
  1342. // this is used to skip the entry pending list removal.
  1343. //
  1344. if ( !Entry->InMemoryOrderLinks.Flink ) {
  1345. continue;
  1346. }
  1347. if (DllHandle == (PVOID)Entry->DllBase ){
  1348. LdrpLoadedDllHandleCache = Entry;
  1349. *LdrDataTableEntry = Entry;
  1350. return TRUE;
  1351. }
  1352. }
  1353. return FALSE;
  1354. }
  1355. NTSTATUS
  1356. LdrpCheckCorImage (
  1357. IN PIMAGE_COR20_HEADER Cor20Header,
  1358. IN PUNICODE_STRING FullDllName,
  1359. IN OUT PVOID *ViewBase,
  1360. OUT PBOOLEAN Cor20ILOnly
  1361. )
  1362. {
  1363. PIMAGE_NT_HEADERS NtHeaders;
  1364. NTSTATUS NtStatus = STATUS_SUCCESS;
  1365. PVOID OriginalViewBase = *ViewBase;
  1366. if (Cor20Header) {
  1367. #if defined(_WIN64)
  1368. //
  1369. // Validate that the COM+ image contains the right flags
  1370. //
  1371. if ((Cor20Header->Flags & (COMIMAGE_FLAGS_32BITREQUIRED | COMIMAGE_FLAGS_ILONLY)) != COMIMAGE_FLAGS_ILONLY) {
  1372. if (ShowSnaps) {
  1373. DbgPrint("LDR: COM+ image (dll) flags %lx didn't specify ILONLY\n", Cor20Header->Flags);
  1374. }
  1375. NtStatus = STATUS_INVALID_IMAGE_FORMAT;
  1376. goto return_result;
  1377. }
  1378. #endif
  1379. //
  1380. // The image is COM+ so notify the runtime that the image was loaded
  1381. // and allow it to verify the image for correctness.
  1382. //
  1383. NtStatus = LdrpCorValidateImage(ViewBase, FullDllName->Buffer);
  1384. if (!NT_SUCCESS (NtStatus)) {
  1385. //
  1386. // Image is bad, or mscoree failed, etc.
  1387. //
  1388. *ViewBase = OriginalViewBase;
  1389. goto return_result;
  1390. }
  1391. //
  1392. // Indicates it's an ILONLY image if the flag is set in the header.
  1393. //
  1394. if ((Cor20Header->Flags & COMIMAGE_FLAGS_ILONLY) == COMIMAGE_FLAGS_ILONLY) {
  1395. *Cor20ILOnly = TRUE;
  1396. }
  1397. if (*ViewBase != OriginalViewBase) {
  1398. //
  1399. // Mscoree has substituted a new image at a new base in place
  1400. // of the original image. Unmap the original image and use
  1401. // the new image from now on.
  1402. //
  1403. NtUnmapViewOfSection(NtCurrentProcess(), OriginalViewBase);
  1404. NtHeaders = RtlImageNtHeader(*ViewBase);
  1405. if (!NtHeaders) {
  1406. NtStatus = STATUS_INVALID_IMAGE_FORMAT;
  1407. goto return_result;
  1408. }
  1409. }
  1410. }
  1411. return_result:
  1412. return NtStatus;
  1413. }
  1414. NTSTATUS
  1415. LdrpMapDll(
  1416. IN PWSTR DllPath OPTIONAL,
  1417. IN PWSTR DllName,
  1418. IN PULONG DllCharacteristics OPTIONAL,
  1419. IN BOOLEAN StaticLink,
  1420. IN BOOLEAN Redirected,
  1421. OUT PLDR_DATA_TABLE_ENTRY *LdrDataTableEntry
  1422. )
  1423. /*++
  1424. Routine Description:
  1425. This routine maps the DLL into the users address space.
  1426. Arguments:
  1427. DllPath - Supplies an optional search path to be used to locate the DLL.
  1428. DllName - Supplies the name of the DLL to load.
  1429. StaticLink - TRUE if this DLL has a static link to it.
  1430. LdrDataTableEntry - Supplies the address of the data table entry.
  1431. Return Value:
  1432. Status value.
  1433. --*/
  1434. {
  1435. NTSTATUS st = STATUS_INTERNAL_ERROR;
  1436. PVOID ViewBase = NULL;
  1437. PTEB Teb = NtCurrentTeb();
  1438. SIZE_T ViewSize;
  1439. HANDLE Section, DllFile;
  1440. UNICODE_STRING FullDllName, BaseDllName;
  1441. UNICODE_STRING NtFileName;
  1442. PLDR_DATA_TABLE_ENTRY Entry;
  1443. PIMAGE_NT_HEADERS NtHeaders;
  1444. PVOID ArbitraryUserPointer;
  1445. BOOLEAN KnownDll;
  1446. UNICODE_STRING CollidingDll;
  1447. PUCHAR ImageBase, ImageBounds, ScanBase, ScanTop;
  1448. PLDR_DATA_TABLE_ENTRY ScanEntry;
  1449. PLIST_ENTRY ScanHead,ScanNext;
  1450. BOOLEAN CollidingDllFound;
  1451. NTSTATUS ErrorStatus;
  1452. ULONG_PTR ErrorParameters[2];
  1453. ULONG ErrorResponse;
  1454. IMAGE_COR20_HEADER *Cor20Header;
  1455. ULONG Cor20HeaderSize;
  1456. BOOLEAN Cor20ILOnly = FALSE;
  1457. PVOID OriginalViewBase;
  1458. NTSTATUS stTemp;
  1459. PWSTR AppCompatDllName = NULL;
  1460. //
  1461. // Get section handle of DLL being snapped
  1462. //
  1463. #if LDRDBG
  1464. if (ShowSnaps) {
  1465. DbgPrint("LDR: LdrpMapDll: Image Name %ws, Search Path %ws\n",
  1466. DllName,
  1467. ARGUMENT_PRESENT(DllPath) ? DllPath : L""
  1468. );
  1469. }
  1470. #endif
  1471. Entry = NULL;
  1472. KnownDll = FALSE;
  1473. Section = NULL;
  1474. LdrpEnsureLoaderLockIsHeld();
  1475. // No capturing etc. of the globals since we "know" that the loader lock is taken to synchronize access.
  1476. if (LdrpAppCompatDllRedirectionCallbackFunction != NULL) {
  1477. st = (*LdrpAppCompatDllRedirectionCallbackFunction)(
  1478. 0, // Flags - reserved for the future
  1479. DllName,
  1480. DllPath,
  1481. DllCharacteristics,
  1482. LdrpAppCompatDllRedirectionCallbackData,
  1483. &AppCompatDllName);
  1484. if (!NT_SUCCESS(st)) {
  1485. DbgPrintEx(
  1486. DPFLTR_LDR_ID,
  1487. LDR_ERROR_DPFLTR,
  1488. "LDR: %s - call back to app compat redirection function @ %p (cb data: %p) failed with status %x\n",
  1489. __FUNCTION__,
  1490. LdrpAppCompatDllRedirectionCallbackFunction,
  1491. LdrpAppCompatDllRedirectionCallbackData,
  1492. st);
  1493. goto Exit;
  1494. }
  1495. if (AppCompatDllName != NULL) {
  1496. Redirected = TRUE;
  1497. DllName = AppCompatDllName;
  1498. }
  1499. }
  1500. if ((LdrpKnownDllObjectDirectory != NULL) && !Redirected) {
  1501. PCWCH p = DllName;
  1502. WCHAR wch;
  1503. //
  1504. // Skip the KnownDll check if this is an explicit path.
  1505. //
  1506. while ((wch = *p) != L'\0') {
  1507. p++;
  1508. if (RTL_IS_PATH_SEPARATOR(wch))
  1509. break;
  1510. }
  1511. // If we hit the end of the string, there must have not been a path separator.
  1512. if (wch == L'\0') {
  1513. st = LdrpCheckForKnownDll(DllName, &FullDllName, &BaseDllName, &Section);
  1514. if ((!NT_SUCCESS(st)) && (st != STATUS_DLL_NOT_FOUND)) {
  1515. DbgPrintEx(
  1516. DPFLTR_LDR_ID,
  1517. LDR_ERROR_DPFLTR,
  1518. "LDR: %s - call to LdrpCheckForKnownDll(\"%ws\", ...) failed with status %x\n",
  1519. __FUNCTION__,
  1520. DllName,
  1521. st);
  1522. goto Exit;
  1523. }
  1524. }
  1525. }
  1526. if (Section == NULL) {
  1527. st = LdrpResolveDllName(DllPath, DllName, Redirected, &FullDllName, &BaseDllName, &DllFile);
  1528. if (!NT_SUCCESS(st)) {
  1529. if (st == STATUS_DLL_NOT_FOUND) {
  1530. if (StaticLink) {
  1531. UNICODE_STRING ErrorDllName, ErrorDllPath;
  1532. PUNICODE_STRING ErrorStrings[2] = { &ErrorDllName, &ErrorDllPath };
  1533. ULONG ErrorResponse;
  1534. RtlInitUnicodeString(&ErrorDllName,DllName);
  1535. RtlInitUnicodeString(&ErrorDllPath,ARGUMENT_PRESENT(DllPath) ? DllPath : LdrpDefaultPath.Buffer);
  1536. NtRaiseHardError(
  1537. STATUS_DLL_NOT_FOUND,
  1538. 2, // Number of error strings
  1539. 0x00000003,
  1540. (PULONG_PTR)ErrorStrings,
  1541. OptionOk,
  1542. &ErrorResponse);
  1543. if (LdrpInLdrInit)
  1544. LdrpFatalHardErrorCount++;
  1545. }
  1546. } else {
  1547. DbgPrintEx(
  1548. DPFLTR_LDR_ID,
  1549. LDR_ERROR_DPFLTR,
  1550. "LDR: %s - call to LdrpResolveDllName on dll \"%ws\" failed with status %x\n",
  1551. __FUNCTION__,
  1552. DllName,
  1553. st);
  1554. }
  1555. goto Exit;
  1556. }
  1557. if (ShowSnaps) {
  1558. PSZ type;
  1559. PSZ type2;
  1560. type = StaticLink ? "STATIC" : "DYNAMIC";
  1561. type2 = Redirected ? "REDIRECTED" : "NON_REDIRECTED";
  1562. DbgPrint(
  1563. "LDR: Loading (%s, %s) %wZ\n",
  1564. type,
  1565. type2,
  1566. &FullDllName);
  1567. }
  1568. if (!RtlDosPathNameToNtPathName_U(
  1569. FullDllName.Buffer,
  1570. &NtFileName,
  1571. NULL,
  1572. NULL)) {
  1573. st = STATUS_OBJECT_PATH_SYNTAX_BAD;
  1574. DbgPrintEx(
  1575. DPFLTR_LDR_ID,
  1576. LDR_ERROR_DPFLTR,
  1577. "LDR: %s - call to RtlDosPathNameToNtPathName_U on path \"%wZ\" failed; returning status %x\n",
  1578. __FUNCTION__,
  1579. &FullDllName,
  1580. st);
  1581. goto Exit;
  1582. }
  1583. st = LdrpCreateDllSection(&NtFileName,
  1584. DllFile,
  1585. &BaseDllName,
  1586. DllCharacteristics,
  1587. &Section);
  1588. if (!NT_SUCCESS(st)) {
  1589. DbgPrintEx(
  1590. DPFLTR_LDR_ID,
  1591. LDR_ERROR_DPFLTR,
  1592. "LDR: %s - LdrpCreateDllSection (%wZ) failed with status %x\n",
  1593. __FUNCTION__,
  1594. &NtFileName,
  1595. st);
  1596. LdrpFreeUnicodeString(&FullDllName);
  1597. // We do not free BaseDllName since it's just a substring of FullDllName.
  1598. RtlFreeHeap(RtlProcessHeap(), 0, NtFileName.Buffer);
  1599. goto Exit;
  1600. }
  1601. RtlFreeHeap(RtlProcessHeap(), 0, NtFileName.Buffer);
  1602. #if DBG
  1603. LdrpSectionCreates++;
  1604. #endif
  1605. } else {
  1606. KnownDll = TRUE;
  1607. }
  1608. ViewBase = NULL;
  1609. ViewSize = 0;
  1610. #if DBG
  1611. LdrpSectionMaps++;
  1612. if (LdrpDisplayLoadTime) {
  1613. NtQueryPerformanceCounter(&MapBeginTime, NULL);
  1614. }
  1615. #endif
  1616. //
  1617. // arrange for debugger to pick up the image name
  1618. //
  1619. ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer;
  1620. Teb->NtTib.ArbitraryUserPointer = (PVOID)FullDllName.Buffer;
  1621. st = NtMapViewOfSection(
  1622. Section,
  1623. NtCurrentProcess(),
  1624. (PVOID *)&ViewBase,
  1625. 0L,
  1626. 0L,
  1627. NULL,
  1628. &ViewSize,
  1629. ViewShare,
  1630. 0L,
  1631. PAGE_READWRITE
  1632. );
  1633. Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer;
  1634. if (!NT_SUCCESS(st)) {
  1635. DbgPrintEx(
  1636. DPFLTR_LDR_ID,
  1637. LDR_ERROR_DPFLTR,
  1638. "LDR: %s - failed to map view of section; status = %x\n",
  1639. __FUNCTION__,
  1640. st);
  1641. goto Exit;
  1642. }
  1643. NtHeaders = RtlImageNtHeader(ViewBase);
  1644. if ( !NtHeaders ) {
  1645. NtUnmapViewOfSection(NtCurrentProcess(),ViewBase);
  1646. st = STATUS_INVALID_IMAGE_FORMAT;
  1647. DbgPrintEx(
  1648. DPFLTR_LDR_ID,
  1649. LDR_ERROR_DPFLTR,
  1650. "LDR: %s - unable to map ViewBase (%p) to image headers; failing with status %x\n",
  1651. __FUNCTION__,
  1652. ViewBase,
  1653. st);
  1654. goto Exit;
  1655. }
  1656. #if _WIN64
  1657. if (st != STATUS_IMAGE_NOT_AT_BASE &&
  1658. (NtCurrentPeb()->NtGlobalFlag & FLG_LDR_TOP_DOWN) &&
  1659. !(NtHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)) {
  1660. // The image was loaded at its preferred base and has relocs. Map
  1661. // it again using the default ViewBase. This will collide with the
  1662. // initial mapping, and force the mm to choose a new base address.
  1663. // On Win64, the mm will do this top-down, forcing the DLL to
  1664. // be mapped above 4gb if possible, to catch pointer truncations.
  1665. PCUNICODE_STRING SystemDll;
  1666. PVOID AlternateViewBase;
  1667. ULONG_PTR AlternateViewSize;
  1668. NTSTATUS AlternateSt;
  1669. BOOLEAN LoadTopDown;
  1670. LoadTopDown = TRUE;
  1671. SystemDll = &User32String;
  1672. if (RtlEqualUnicodeString(&BaseDllName, &User32String, TRUE)) {
  1673. LoadTopDown = FALSE;
  1674. } else {
  1675. SystemDll = &Kernel32String;
  1676. if (RtlEqualUnicodeString(&BaseDllName, &Kernel32String, TRUE)) {
  1677. LoadTopDown = FALSE;
  1678. }
  1679. }
  1680. if (LoadTopDown) {
  1681. //
  1682. // Map the image again. It will collide with itself, and
  1683. // the 64-bit mm will find a new base address for it,
  1684. // working top-down
  1685. //
  1686. AlternateViewBase = NULL;
  1687. AlternateViewSize = 0;
  1688. ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer;
  1689. Teb->NtTib.ArbitraryUserPointer = (PVOID)FullDllName.Buffer;
  1690. AlternateSt = NtMapViewOfSection(
  1691. Section,
  1692. NtCurrentProcess(),
  1693. (PVOID *)&AlternateViewBase,
  1694. 0L,
  1695. 0L,
  1696. NULL,
  1697. &AlternateViewSize,
  1698. ViewShare,
  1699. 0L,
  1700. PAGE_READWRITE
  1701. );
  1702. Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer;
  1703. if (NT_SUCCESS(AlternateSt)) {
  1704. //
  1705. // Success. Unmap the original image from the low
  1706. // part of the address space and keep the new mapping
  1707. // which was allocated top-down.
  1708. //
  1709. NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
  1710. ViewSize = AlternateViewSize;
  1711. ViewBase = AlternateViewBase;
  1712. NtHeaders = RtlImageNtHeader(ViewBase);
  1713. st = AlternateSt;
  1714. if ( !NtHeaders ) {
  1715. NtUnmapViewOfSection(NtCurrentProcess(),AlternateViewBase);
  1716. NtUnmapViewOfSection(NtCurrentProcess(),ViewBase);
  1717. st = STATUS_INVALID_IMAGE_FORMAT;
  1718. goto Exit;
  1719. }
  1720. }
  1721. }
  1722. }
  1723. #endif
  1724. #if defined (BUILD_WOW6432)
  1725. if (NtHeaders->OptionalHeader.SectionAlignment < NATIVE_PAGE_SIZE) {
  1726. if (!NT_SUCCESS(stTemp = LdrpWx86FormatVirtualImage(&FullDllName, (PIMAGE_NT_HEADERS32)NtHeaders, ViewBase))) {
  1727. st = stTemp;
  1728. DbgPrintEx(
  1729. DPFLTR_LDR_ID,
  1730. LDR_ERROR_DPFLTR,
  1731. "LDR: %s - Call to LdrpWx86FormatVirtualImage(%ls) failed with status 0x%08lx\n",
  1732. __FUNCTION__,
  1733. FullDllName.Buffer,
  1734. st);
  1735. goto Exit;
  1736. }
  1737. }
  1738. #endif
  1739. Cor20Header = RtlImageDirectoryEntryToData(ViewBase,
  1740. TRUE,
  1741. IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
  1742. &Cor20HeaderSize);
  1743. OriginalViewBase = ViewBase;
  1744. //
  1745. // if this is an IL_ONLY image, then validate the image now
  1746. //
  1747. if ((Cor20Header != NULL) &&
  1748. ((Cor20Header->Flags & COMIMAGE_FLAGS_ILONLY) != 0)) {
  1749. // This is wacky but code later on depends on the fact that st *was* STATUS_IMAGE_MACHINE_TYPE_MISMATCH
  1750. // and got overwritten with STATUS_SUCCESS. This in effect means that COR images can never have
  1751. // relocation information. -mgrier 5/21/2001, XP Bug #400007.
  1752. st = LdrpCheckCorImage (Cor20Header,
  1753. &FullDllName,
  1754. &ViewBase,
  1755. &Cor20ILOnly);
  1756. if (!NT_SUCCESS(st))
  1757. goto Exit;
  1758. }
  1759. #if DBG
  1760. if (LdrpDisplayLoadTime) {
  1761. NtQueryPerformanceCounter(&MapEndTime, NULL);
  1762. MapElapsedTime.QuadPart = MapEndTime.QuadPart - MapBeginTime.QuadPart;
  1763. DbgPrint("Map View of Section Time %ld %ws\n", MapElapsedTime.LowPart, DllName);
  1764. }
  1765. #endif
  1766. //
  1767. // Allocate a data table entry.
  1768. //
  1769. Entry = LdrpAllocateDataTableEntry(ViewBase);
  1770. if (!Entry) {
  1771. DbgPrintEx(
  1772. DPFLTR_LDR_ID,
  1773. LDR_ERROR_DPFLTR,
  1774. "LDR: %s - failed to allocate new data table entry for %p\n",
  1775. __FUNCTION__,
  1776. ViewBase);
  1777. st = STATUS_NO_MEMORY;
  1778. goto Exit;
  1779. }
  1780. Entry->Flags = 0;
  1781. if (StaticLink)
  1782. Entry->Flags |= LDRP_STATIC_LINK;
  1783. if (Redirected)
  1784. Entry->Flags |= LDRP_REDIRECTED;
  1785. Entry->LoadCount = 0;
  1786. Entry->FullDllName = FullDllName;
  1787. FullDllName.Length = 0;
  1788. FullDllName.MaximumLength = 0;
  1789. FullDllName.Buffer = NULL;
  1790. Entry->BaseDllName = BaseDllName;
  1791. BaseDllName.Length = 0;
  1792. BaseDllName.MaximumLength = 0;
  1793. BaseDllName.Buffer = NULL;
  1794. Entry->EntryPoint = LdrpFetchAddressOfEntryPoint(Entry->DllBase);
  1795. #if LDRDBG
  1796. if (ShowSnaps)
  1797. DbgPrint(
  1798. "LDR: LdrpMapDll: Full Name %wZ, Base Name %wZ\n",
  1799. &Entry->FullDllName,
  1800. &Entry->BaseDllName);
  1801. #endif
  1802. LdrpInsertMemoryTableEntry(Entry);
  1803. LdrpSendDllLoadedNotifications(Entry, (st == STATUS_IMAGE_NOT_AT_BASE) ? LDR_DLL_LOADED_FLAG_RELOCATED : 0);
  1804. if ( st == STATUS_IMAGE_MACHINE_TYPE_MISMATCH ) {
  1805. PIMAGE_NT_HEADERS ImageHeader = RtlImageNtHeader( NtCurrentPeb()->ImageBaseAddress );
  1806. //
  1807. // apps compiled for NT 3.x and below can load cross architecture
  1808. // images
  1809. //
  1810. ErrorStatus = STATUS_SUCCESS;
  1811. ErrorResponse = ResponseCancel;
  1812. if ( ImageHeader->OptionalHeader.MajorSubsystemVersion <= 3 ) {
  1813. Entry->EntryPoint = 0;
  1814. //
  1815. // Hard Error Time
  1816. //
  1817. //
  1818. // Its error time...
  1819. //
  1820. ErrorParameters[0] = (ULONG_PTR)&FullDllName;
  1821. ErrorStatus = NtRaiseHardError(
  1822. STATUS_IMAGE_MACHINE_TYPE_MISMATCH,
  1823. 1,
  1824. 1,
  1825. ErrorParameters,
  1826. OptionOkCancel,
  1827. &ErrorResponse
  1828. );
  1829. }
  1830. if ( NT_SUCCESS(ErrorStatus) && ErrorResponse == ResponseCancel ) {
  1831. #if defined(_AMD64_) // || defined(_IA64_)
  1832. RtlRemoveInvertedFunctionTable(&LdrpInvertedFunctionTable,
  1833. Entry->DllBase);
  1834. #endif
  1835. RemoveEntryList(&Entry->InLoadOrderLinks);
  1836. RemoveEntryList(&Entry->InMemoryOrderLinks);
  1837. RemoveEntryList(&Entry->HashLinks);
  1838. LdrpDeallocateDataTableEntry(Entry);
  1839. if ( ImageHeader->OptionalHeader.MajorSubsystemVersion <= 3 ) {
  1840. if ( LdrpInLdrInit ) {
  1841. LdrpFatalHardErrorCount++;
  1842. }
  1843. }
  1844. st = STATUS_INVALID_IMAGE_FORMAT;
  1845. goto Exit;
  1846. }
  1847. }
  1848. else {
  1849. if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) {
  1850. Entry->Flags |= LDRP_IMAGE_DLL;
  1851. }
  1852. if (!(Entry->Flags & LDRP_IMAGE_DLL)) {
  1853. Entry->EntryPoint = 0;
  1854. }
  1855. }
  1856. *LdrDataTableEntry = Entry;
  1857. if (st == STATUS_IMAGE_NOT_AT_BASE) {
  1858. Entry->Flags |= LDRP_IMAGE_NOT_AT_BASE;
  1859. //
  1860. // now find the colliding dll. If we can not find a dll,
  1861. // then the colliding dll must be dynamic memory
  1862. //
  1863. ImageBase = (PUCHAR)NtHeaders->OptionalHeader.ImageBase;
  1864. ImageBounds = ImageBase + ViewSize;
  1865. CollidingDllFound = FALSE;
  1866. ScanHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
  1867. ScanNext = ScanHead->Flink;
  1868. while ( ScanNext != ScanHead ) {
  1869. ScanEntry = CONTAINING_RECORD(ScanNext, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
  1870. ScanNext = ScanNext->Flink;
  1871. ScanBase = (PUCHAR)ScanEntry->DllBase;
  1872. ScanTop = ScanBase + ScanEntry->SizeOfImage;
  1873. //
  1874. // when we unload, the memory order links flink field is nulled.
  1875. // this is used to skip the entry pending list removal.
  1876. //
  1877. if ( !ScanEntry->InMemoryOrderLinks.Flink ) {
  1878. continue;
  1879. }
  1880. //
  1881. // See if the base address of the scan image is within the relocating dll
  1882. // or if the top address of the scan image is within the relocating dll
  1883. //
  1884. if ( (ImageBase >= ScanBase && ImageBase <= ScanTop)
  1885. ||
  1886. (ImageBounds >= ScanBase && ImageBounds <= ScanTop)
  1887. ||
  1888. (ScanBase >= ImageBase && ScanBase <= ImageBounds)
  1889. ){
  1890. CollidingDllFound = TRUE;
  1891. CollidingDll = ScanEntry->FullDllName;
  1892. break;
  1893. }
  1894. }
  1895. if ( !CollidingDllFound ) {
  1896. RtlInitUnicodeString(&CollidingDll, L"Dynamically Allocated Memory");
  1897. }
  1898. #if DBG
  1899. if ( BeginTime.LowPart || BeginTime.HighPart ) {
  1900. DbgPrint(
  1901. "\nLDR: %s Relocating Image Name %ws\n",
  1902. __FUNCTION__,
  1903. DllName
  1904. );
  1905. }
  1906. LdrpSectionRelocates++;
  1907. #endif
  1908. if (Entry->Flags & LDRP_IMAGE_DLL) {
  1909. BOOLEAN AllowRelocation;
  1910. PCUNICODE_STRING SystemDll;
  1911. if (!(NtHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)) {
  1912. PVOID pBaseRelocs;
  1913. ULONG BaseRelocCountBytes = 0;
  1914. //
  1915. // If the image doesn't have the reloc stripped bit set and there's no
  1916. // relocs in the data directory, allow this through. This is probably
  1917. // a pure forwarder dll or data w/o relocs.
  1918. //
  1919. pBaseRelocs = RtlImageDirectoryEntryToData(
  1920. ViewBase, TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &BaseRelocCountBytes);
  1921. if (!pBaseRelocs && !BaseRelocCountBytes)
  1922. goto NoRelocNeeded;
  1923. }
  1924. //
  1925. // decide whether or not to allow the relocation
  1926. // certain system dll's like user32 and kernel32 are not relocatable
  1927. // since addresses within these dll's are not always stored per process
  1928. // do not allow these dll's to be relocated
  1929. //
  1930. AllowRelocation = TRUE;
  1931. SystemDll = &User32String;
  1932. if ( RtlEqualUnicodeString(&Entry->BaseDllName, SystemDll, TRUE)) {
  1933. AllowRelocation = FALSE;
  1934. } else {
  1935. SystemDll = &Kernel32String;
  1936. if (RtlEqualUnicodeString(&Entry->BaseDllName, SystemDll, TRUE))
  1937. AllowRelocation = FALSE;
  1938. }
  1939. if ( !AllowRelocation && KnownDll ) {
  1940. //
  1941. // totally disallow the relocation since this is a knowndll
  1942. // that matches our system binaries and is being relocated
  1943. //
  1944. //
  1945. // Hard Error Time
  1946. //
  1947. ErrorParameters[0] = (ULONG_PTR)SystemDll;
  1948. ErrorParameters[1] = (ULONG_PTR)&CollidingDll;
  1949. NtRaiseHardError(
  1950. STATUS_ILLEGAL_DLL_RELOCATION,
  1951. 2,
  1952. 3,
  1953. ErrorParameters,
  1954. OptionOk,
  1955. &ErrorResponse);
  1956. if ( LdrpInLdrInit ) {
  1957. LdrpFatalHardErrorCount++;
  1958. }
  1959. st = STATUS_CONFLICTING_ADDRESSES;
  1960. goto skipreloc;
  1961. }
  1962. st = LdrpSetProtection(ViewBase, FALSE, StaticLink );
  1963. if (NT_SUCCESS(st)) {
  1964. __try {
  1965. st = LdrRelocateImage(ViewBase,
  1966. "LDR",
  1967. STATUS_SUCCESS,
  1968. STATUS_CONFLICTING_ADDRESSES,
  1969. STATUS_INVALID_IMAGE_FORMAT);
  1970. } __except (LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {
  1971. st = GetExceptionCode();
  1972. }
  1973. if (NT_SUCCESS(st)) {
  1974. //
  1975. // If we did relocations, then map the section again.
  1976. // this will force the debug event
  1977. //
  1978. //
  1979. // arrange for debugger to pick up the image name
  1980. //
  1981. ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer;
  1982. Teb->NtTib.ArbitraryUserPointer = (PVOID)FullDllName.Buffer;
  1983. st = NtMapViewOfSection(
  1984. Section,
  1985. NtCurrentProcess(),
  1986. (PVOID *)&ViewBase,
  1987. 0L,
  1988. 0L,
  1989. NULL,
  1990. &ViewSize,
  1991. ViewShare,
  1992. 0L,
  1993. PAGE_READWRITE);
  1994. if ((st != STATUS_CONFLICTING_ADDRESSES) && !NT_SUCCESS(st)) {
  1995. DbgPrintEx(
  1996. DPFLTR_LDR_ID,
  1997. LDR_ERROR_DPFLTR,
  1998. "[%x,%x] LDR: Failed to map view of section; ntstatus = %x\n",
  1999. HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess),
  2000. HandleToULong(NtCurrentTeb()->ClientId.UniqueThread),
  2001. st);
  2002. goto Exit;
  2003. }
  2004. Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer;
  2005. st = LdrpSetProtection(ViewBase, TRUE, StaticLink);
  2006. }
  2007. }
  2008. skipreloc:
  2009. //
  2010. // if the set protection failed, or if the relocation failed, then
  2011. // remove the partially loaded dll from the lists and clear entry
  2012. // that it has been freed.
  2013. //
  2014. if ( !NT_SUCCESS(st) ) {
  2015. #if defined(_AMD64_) // || defined(_IA64_)
  2016. RtlRemoveInvertedFunctionTable(&LdrpInvertedFunctionTable,
  2017. Entry->DllBase);
  2018. #endif
  2019. RemoveEntryList(&Entry->InLoadOrderLinks);
  2020. RemoveEntryList(&Entry->InMemoryOrderLinks);
  2021. RemoveEntryList(&Entry->HashLinks);
  2022. if (ShowSnaps) {
  2023. DbgPrint("LDR: Fixups unsuccessfully re-applied @ %p\n",
  2024. ViewBase);
  2025. }
  2026. goto Exit;
  2027. }
  2028. if (ShowSnaps) {
  2029. DbgPrint("LDR: Fixups successfully re-applied @ %p\n",
  2030. ViewBase);
  2031. }
  2032. } else {
  2033. NoRelocNeeded:
  2034. st = STATUS_SUCCESS;
  2035. //
  2036. // arrange for debugger to pick up the image name
  2037. //
  2038. ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer;
  2039. Teb->NtTib.ArbitraryUserPointer = (PVOID)FullDllName.Buffer;
  2040. st = NtMapViewOfSection(
  2041. Section,
  2042. NtCurrentProcess(),
  2043. (PVOID *)&ViewBase,
  2044. 0L,
  2045. 0L,
  2046. NULL,
  2047. &ViewSize,
  2048. ViewShare,
  2049. 0L,
  2050. PAGE_READWRITE
  2051. );
  2052. Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer;
  2053. // If the thing was relocated, we get back the failure status STATUS_CONFLICTING_ADDRESSES
  2054. // but of all the strange things, the relocations aren't done. I have questions in to folks
  2055. // asking about this behavior but who knows how many legacy apps depend on dlls that statically
  2056. // link to EXEs which from time to time are not loaded at their default addresses. -mgrier 4/9/2001
  2057. if ((st != STATUS_CONFLICTING_ADDRESSES) && !NT_SUCCESS(st))
  2058. DbgPrintEx(
  2059. DPFLTR_LDR_ID,
  2060. LDR_ERROR_DPFLTR,
  2061. "[%x,%x] LDR: %s - NtMapViewOfSection on no reloc needed dll failed with status %x\n",
  2062. HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess),
  2063. HandleToULong(NtCurrentTeb()->ClientId.UniqueThread),
  2064. __FUNCTION__,
  2065. st);
  2066. else
  2067. st = STATUS_SUCCESS;
  2068. if (ShowSnaps)
  2069. DbgPrint("LDR: Fixups won't be re-applied to non-Dll @ %p\n", ViewBase);
  2070. }
  2071. }
  2072. //
  2073. // if this is NOT an IL_ONLY image, then validate the image now after applying the
  2074. // fixups
  2075. //
  2076. if ((Cor20Header != NULL) &&
  2077. ((Cor20Header->Flags & COMIMAGE_FLAGS_ILONLY) == 0)) {
  2078. st = LdrpCheckCorImage (Cor20Header,
  2079. &FullDllName,
  2080. &ViewBase,
  2081. &Cor20ILOnly);
  2082. if (!NT_SUCCESS (st)) {
  2083. goto Exit;
  2084. }
  2085. }
  2086. if (Cor20ILOnly) {
  2087. Entry->Flags |= LDRP_COR_IMAGE;
  2088. }
  2089. if (ViewBase != OriginalViewBase) {
  2090. Entry->Flags |= LDRP_COR_OWNS_UNMAP;
  2091. }
  2092. #if defined (_ALPHA_)
  2093. //
  2094. // Find and apply Alpha architecture fixups for this dll
  2095. //
  2096. if (Entry->Flags & LDRP_IMAGE_DLL)
  2097. AlphaFindArchitectureFixups(NtHeaders, ViewBase, StaticLink);
  2098. #endif
  2099. #if defined(_X86_)
  2100. if ( LdrpNumberOfProcessors > 1 && (Entry->Flags & LDRP_IMAGE_DLL) ) {
  2101. LdrpValidateImageForMp(Entry);
  2102. }
  2103. #endif
  2104. ViewBase = NULL;
  2105. Exit:
  2106. if (ViewBase != NULL) {
  2107. if (Cor20ILOnly)
  2108. LdrpCorUnloadImage(ViewBase);
  2109. if (ViewBase == OriginalViewBase)
  2110. NtUnmapViewOfSection(NtCurrentProcess(),ViewBase);
  2111. }
  2112. if (Section != NULL)
  2113. NtClose(Section);
  2114. if (AppCompatDllName != NULL)
  2115. (*RtlFreeStringRoutine)(AppCompatDllName);
  2116. if (FullDllName.Buffer != NULL)
  2117. LdrpFreeUnicodeString(&FullDllName);
  2118. #if DBG
  2119. if (!NT_SUCCESS(st) && (ShowSnaps || st != STATUS_DLL_NOT_FOUND))
  2120. DbgPrint("LDR: %s(%ws) failing 0x%lx\n", __FUNCTION__, DllName, st);
  2121. #endif
  2122. return st;
  2123. }
  2124. #if defined (_ALPHA_)
  2125. #define asm __asm
  2126. #pragma intrinsic (__asm)
  2127. VOID
  2128. AlphaApplyArchitectureFixups(
  2129. IN PIMAGE_ARCHITECTURE_HEADER ArchHeader,
  2130. IN ULONG ArchHeaderByteSize,
  2131. IN ULONG_PTR BaseAddr
  2132. )
  2133. /*++
  2134. Routine Description:
  2135. This applies the Alpha architecture enhancement fixups. If an image contains
  2136. a .arch section, then the image/dll, if running on a newer chip, may
  2137. be eligible to take advantage of new instructions. Check the replacement
  2138. constraints vs. chip capabilities and apply fixup if warranted.
  2139. Arguments:
  2140. ArchHeader - Supplies a pointer to the first architecture specific
  2141. fixup header record.
  2142. ArchHeaderByteSize - Supplies the size (in bytes) of the
  2143. Architecture headers to be processed.
  2144. BaseAddr - Base address to be added to RVA's in architecture section
  2145. Return Value:
  2146. None.
  2147. --*/
  2148. {
  2149. ULONG Count, Entry;
  2150. ULONG SystemAmask;
  2151. ULONG ReplacementInstruction;
  2152. PIMAGE_ARCHITECTURE_HEADER ArchHeaderEnd;
  2153. PIMAGE_ARCHITECTURE_ENTRY ArchEntry;
  2154. // Figure out the end value for ArchHeader
  2155. ArchHeaderEnd = (PIMAGE_ARCHITECTURE_HEADER)((PCHAR)ArchHeader + ArchHeaderByteSize);
  2156. //
  2157. // Get the architecture mask and implementation version
  2158. // of the running system
  2159. //
  2160. while (*(PULONGLONG)ArchHeader == 0L)
  2161. ArchHeader++; // skip over quadwords of zero
  2162. SystemAmask = ~asm("amask $16, $0", -1);
  2163. while ((*(PULONGLONG)ArchHeader != 0xffffffffL) && (ArchHeader < ArchHeaderEnd)) {
  2164. if (*(PULONGLONG)ArchHeader != 0L) { // maybe zero's intermixed
  2165. #if DBG && ARCH_DBG
  2166. DbgPrint("ARCH: Amask=0x%x, Current Header=0x%08x, Shift=%d, Value=%d\n",
  2167. SystemAmask, *ArchHeader,
  2168. ArchHeader->AmaskShift, ArchHeader->AmaskValue);
  2169. #endif
  2170. if (((SystemAmask >> ArchHeader->AmaskShift) & 1) != ArchHeader->AmaskValue) {
  2171. //
  2172. // fixup needed
  2173. //
  2174. PIMAGE_ARCHITECTURE_ENTRY ArchEntry;
  2175. ArchEntry = (PIMAGE_ARCHITECTURE_ENTRY)(ArchHeader->FirstEntryRVA + BaseAddr);
  2176. while (*(PULONGLONG)ArchEntry != 0xffffffffL) {
  2177. if (*(PULONGLONG)ArchEntry != 0L) { // maybe zero's intermixed
  2178. #if DBG && ARCH_DBG
  2179. DbgPrint("ARCH: 0x%08x -> 0x%08x\n",
  2180. *(PALPHA_INSTRUCTION)(ArchEntry->FixupInstRVA + BaseAddr),
  2181. ArchEntry->NewInst
  2182. );
  2183. #endif
  2184. *(ULONG *)(ArchEntry->FixupInstRVA + BaseAddr) = ArchEntry->NewInst;
  2185. }
  2186. ArchEntry++;
  2187. }
  2188. } // if this header describes fixups for this machine
  2189. }
  2190. ArchHeader++;
  2191. }
  2192. }
  2193. VOID
  2194. AlphaFindArchitectureFixups(
  2195. PIMAGE_NT_HEADERS NtHeaders,
  2196. PVOID ViewBase,
  2197. BOOLEAN StaticLink
  2198. )
  2199. /*++
  2200. Routine Description:
  2201. This routine runs through a mapped image/dll looking for an architecture
  2202. enhancement section (.arch). If found, it applies the architecture
  2203. fixups.
  2204. Arguments:
  2205. NtHeaders - the NT header for this image or dll.
  2206. ViewBase - the Mapped view base used for page protection munging.
  2207. StaticLink - TRUE if this DLL has a static link to it
  2208. Return Value:
  2209. None.
  2210. --*/
  2211. {
  2212. ULONG Size;
  2213. PIMAGE_ARCHITECTURE_HEADER ImageArchData;
  2214. if (NtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_ALPHA) {
  2215. //
  2216. // If the image isnt Alpha, don't try to find/apply Alpha fixups.
  2217. // The image may be an x86 image linked with the x86 Watcom
  2218. // linker which stuffed its version number in the .arch directory
  2219. // entry in the image, fooling the Alpha .arch checker.
  2220. //
  2221. return;
  2222. }
  2223. ImageArchData =
  2224. (PIMAGE_ARCHITECTURE_HEADER)RtlImageDirectoryEntryToData(
  2225. ViewBase,
  2226. TRUE,
  2227. IMAGE_DIRECTORY_ENTRY_ARCHITECTURE,
  2228. &Size
  2229. );
  2230. if (ImageArchData) {
  2231. NTSTATUS st;
  2232. st = LdrpSetProtection(ViewBase, FALSE, StaticLink); // access to r/w
  2233. if (NT_SUCCESS(st)) {
  2234. AlphaApplyArchitectureFixups(ImageArchData, Size, (ULONG_PTR)ViewBase);
  2235. LdrpSetProtection(ViewBase, TRUE, StaticLink); // back to r/o
  2236. }
  2237. }
  2238. }
  2239. #endif
  2240. //#define SAFER_DEBUGGING
  2241. //#define SAFER_ERRORS_ARE_FATAL
  2242. NTSTATUS
  2243. LdrpCodeAuthzCheckDllAllowed(
  2244. IN PUNICODE_STRING FileName,
  2245. IN HANDLE FileImageHandle
  2246. )
  2247. /*++
  2248. Routine Description:
  2249. This routine dynamically loads ADVAPI32.DLL and obtains entry points
  2250. to the WinSafer sandboxing APIs, so that the trustworthiness of the
  2251. requested library can be determined. Libraries that are equally
  2252. or greater "trusted" than the Access Token of the process loading
  2253. the library are allowed to be loaded. Libraries that are less
  2254. trusted than the process will be denied.
  2255. Care must be taken to ensure that this function is kept threadsafe
  2256. without requiring the use of critical sections. In particular,
  2257. the usage of the variable "AdvApi32ModuleHandleMaster" needs to be
  2258. accessed only through a copy, since it may be changed unexpected by
  2259. another thread.
  2260. Arguments:
  2261. FileName - the fully qualified NT filename of the library being loaded.
  2262. The filename will be used to perform path validation checks.
  2263. FileImageHandle - the opened file handle of the library being loaded.
  2264. This handle will be used to read the contents of the library to
  2265. perform size and hash validation checks by WinSafer.
  2266. Return Value:
  2267. STATUS_SUCCESS - the library is of equal or greater trustworthiness
  2268. than that process it is being loaded into, and should be allowed.
  2269. STATUS_NOT_FOUND - the library does not have a trust level configured
  2270. and no default rule in in effect (treat same as STATUS_SUCCESS).
  2271. STATUS_ACCESS_DENIED - the library is less trustworthy than the
  2272. process and the load should be denied.
  2273. Other non-success - an error occurred trying to load/determine the
  2274. trust of the library, so the load should be denied.
  2275. (including STATUS_ENTRY_POINT_NOT_FOUND)
  2276. --*/
  2277. {
  2278. #define SAFER_USER_KEY_NAME L"\\Software\\Policies\\Microsoft\\Windows\\Safer\\CodeIdentifiers"
  2279. typedef BOOL (WINAPI *ComputeAccessTokenFromCodeAuthzLevelT) (
  2280. IN SAFER_LEVEL_HANDLE LevelObject,
  2281. IN HANDLE InAccessToken OPTIONAL,
  2282. OUT PHANDLE OutAccessToken,
  2283. IN DWORD dwFlags,
  2284. IN LPVOID lpReserved
  2285. );
  2286. typedef BOOL (WINAPI *IdentifyCodeAuthzLevelWT) (
  2287. IN DWORD dwCheckFlags,
  2288. IN PSAFER_CODE_PROPERTIES CodeProperties,
  2289. OUT SAFER_LEVEL_HANDLE *pLevelObject,
  2290. IN LPVOID lpReserved
  2291. );
  2292. typedef BOOL (WINAPI *CloseCodeAuthzLevelT) (
  2293. IN SAFER_LEVEL_HANDLE hLevelObject);
  2294. NTSTATUS Status;
  2295. SAFER_LEVEL_HANDLE hAuthzLevel = NULL;
  2296. SAFER_CODE_PROPERTIES codeproperties;
  2297. DWORD dwCompareResult = 0;
  2298. HANDLE hProcessToken= NULL;
  2299. HANDLE TempAdvApi32Handle = NULL;
  2300. const static SID_IDENTIFIER_AUTHORITY NtAuthority =
  2301. SECURITY_NT_AUTHORITY;
  2302. const static UNICODE_STRING UnicodeSafeBootKeyName =
  2303. RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\SafeBoot\\Option");
  2304. const static UNICODE_STRING UnicodeSafeBootValueName =
  2305. RTL_CONSTANT_STRING(L"OptionValue");
  2306. const static OBJECT_ATTRIBUTES ObjectAttributesSafeBoot =
  2307. RTL_CONSTANT_OBJECT_ATTRIBUTES(&UnicodeSafeBootKeyName, OBJ_CASE_INSENSITIVE);
  2308. const static UNICODE_STRING UnicodeKeyName =
  2309. RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Policies\\Microsoft\\Windows\\Safer\\CodeIdentifiers");
  2310. const static UNICODE_STRING UnicodeTransparentValueName =
  2311. RTL_CONSTANT_STRING(L"TransparentEnabled");
  2312. const static OBJECT_ATTRIBUTES ObjectAttributesCodeIdentifiers =
  2313. RTL_CONSTANT_OBJECT_ATTRIBUTES(&UnicodeKeyName, OBJ_CASE_INSENSITIVE);
  2314. const static UNICODE_STRING ModuleNameAdvapi =
  2315. RTL_CONSTANT_STRING(L"ADVAPI32.DLL");
  2316. const static ANSI_STRING ProcedureNameIdentify =
  2317. RTL_CONSTANT_STRING("SaferIdentifyLevel");
  2318. const static ANSI_STRING ProcedureNameCompute =
  2319. RTL_CONSTANT_STRING("SaferComputeTokenFromLevel");
  2320. const static ANSI_STRING ProcedureNameClose =
  2321. RTL_CONSTANT_STRING("SaferCloseLevel");
  2322. static volatile HANDLE AdvApi32ModuleHandleMaster = (HANDLE) (ULONG_PTR) -1;
  2323. static IdentifyCodeAuthzLevelWT lpfnIdentifyCodeAuthzLevelW;
  2324. static ComputeAccessTokenFromCodeAuthzLevelT
  2325. lpfnComputeAccessTokenFromCodeAuthzLevel;
  2326. static CloseCodeAuthzLevelT lpfnCloseCodeAuthzLevel;
  2327. PIMAGE_NT_HEADERS NtHeader;
  2328. NtHeader = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
  2329. // Check for NULL header.
  2330. if (!NtHeader) {
  2331. return STATUS_SUCCESS;
  2332. }
  2333. // Continue only if this is a windows subsystem app. We run into all sorts
  2334. // of problems because kernel32 might not initialize for others.
  2335. if (!((NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) ||
  2336. (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI))) {
  2337. return STATUS_SUCCESS;
  2338. }
  2339. //
  2340. // If either of these two cases are true, then we should bail out
  2341. // as quickly as possible because we know that WinSafer evaluations
  2342. // should definitely not occur for this process anymore.
  2343. //
  2344. TempAdvApi32Handle = AdvApi32ModuleHandleMaster;
  2345. if (TempAdvApi32Handle == NULL) {
  2346. // We tried to load ADVAPI32.DLL once before, but failed.
  2347. Status = STATUS_ACCESS_DENIED;
  2348. goto ExitHandler;
  2349. } else if (TempAdvApi32Handle == LongToHandle(-2)) {
  2350. // Indicates that DLL checking should never be done for this process.
  2351. Status = STATUS_SUCCESS;
  2352. goto ExitHandler;
  2353. }
  2354. //
  2355. // Open a handle to the current process's access token.
  2356. // We care only about the process token, and not the
  2357. // thread impersonation token.
  2358. //
  2359. Status = NtOpenProcessToken(
  2360. NtCurrentProcess(),
  2361. TOKEN_QUERY,
  2362. &hProcessToken);
  2363. if (!NT_SUCCESS(Status)) {
  2364. #ifdef SAFER_ERRORS_ARE_FATAL
  2365. AdvApi32ModuleHandleMaster = NULL;
  2366. Status = STATUS_ACCESS_DENIED;
  2367. #else
  2368. AdvApi32ModuleHandleMaster = LongToHandle(-2);
  2369. Status = STATUS_SUCCESS;
  2370. #endif
  2371. goto ExitHandler;
  2372. }
  2373. //
  2374. // If this is our first time through here, then we need to
  2375. // load ADVAPI32.DLL and get pointers to our functions.
  2376. //
  2377. if (TempAdvApi32Handle == LongToHandle(-1))
  2378. {
  2379. static LONG LoadInProgress = 0;
  2380. //
  2381. // We need to prevent multiple threads from simultaneously
  2382. // getting stuck and trying to load advapi at the same time.
  2383. //
  2384. if (InterlockedCompareExchange(&LoadInProgress, 1, 0) != 0) {
  2385. Status = STATUS_SUCCESS;
  2386. goto ExitHandler2;
  2387. }
  2388. //
  2389. // Check if this process's access token is running as
  2390. // the Local SYSTEM account, and disable enforcement if so.
  2391. //
  2392. {
  2393. BYTE tokenuserbuff[sizeof(TOKEN_USER) + 128];
  2394. PTOKEN_USER ptokenuser = (PTOKEN_USER) tokenuserbuff;
  2395. BYTE localsystembuff[128];
  2396. PSID LocalSystemSid = (PSID) localsystembuff;
  2397. ULONG ulReturnLength;
  2398. Status = NtQueryInformationToken(
  2399. hProcessToken, TokenUser,
  2400. tokenuserbuff, sizeof(tokenuserbuff),
  2401. &ulReturnLength);
  2402. if (NT_SUCCESS(Status)) {
  2403. Status = RtlInitializeSid(
  2404. LocalSystemSid,
  2405. (PSID_IDENTIFIER_AUTHORITY) &NtAuthority, 1);
  2406. ASSERTMSG("InitializeSid should not fail.", NT_SUCCESS(Status));
  2407. *RtlSubAuthoritySid(LocalSystemSid, 0) = SECURITY_LOCAL_SYSTEM_RID;
  2408. if (RtlEqualSid(ptokenuser->User.Sid, LocalSystemSid)) {
  2409. goto FailSuccessfully;
  2410. }
  2411. }
  2412. }
  2413. //
  2414. // If we are booting in safe mode and the user is a member of
  2415. // the local Administrators group, then disable enforcement.
  2416. // Notice that Windows itself does not perform any implicit
  2417. // restriction of only allowing Administrators to log in during
  2418. // Safe mode boot, so we must perform the test ourself.
  2419. //
  2420. {
  2421. HANDLE hKeySafeBoot;
  2422. BYTE QueryBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 64];
  2423. PKEY_VALUE_PARTIAL_INFORMATION pKeyValueInfo =
  2424. (PKEY_VALUE_PARTIAL_INFORMATION) QueryBuffer;
  2425. DWORD dwActualSize;
  2426. BOOLEAN bSafeModeBoot = FALSE;
  2427. // We open the key for SET access (in addition to QUERY)
  2428. // because only Administrators should be able to modify values
  2429. // under this key. This allows us to combine our test of
  2430. // being an Administrator and having booted in Safe mode.
  2431. Status = NtOpenKey(&hKeySafeBoot, KEY_QUERY_VALUE | KEY_SET_VALUE,
  2432. (POBJECT_ATTRIBUTES) &ObjectAttributesSafeBoot);
  2433. if (NT_SUCCESS(Status)) {
  2434. Status = NtQueryValueKey(
  2435. hKeySafeBoot,
  2436. (PUNICODE_STRING) &UnicodeSafeBootValueName,
  2437. KeyValuePartialInformation,
  2438. pKeyValueInfo,
  2439. sizeof(QueryBuffer),
  2440. &dwActualSize);
  2441. NtClose(hKeySafeBoot);
  2442. if (NT_SUCCESS(Status)) {
  2443. if (pKeyValueInfo->Type == REG_DWORD &&
  2444. pKeyValueInfo->DataLength == sizeof(DWORD) &&
  2445. *((PDWORD) pKeyValueInfo->Data) > 0) {
  2446. bSafeModeBoot = TRUE;
  2447. }
  2448. }
  2449. }
  2450. if (bSafeModeBoot) {
  2451. FailSuccessfully:
  2452. AdvApi32ModuleHandleMaster = LongToHandle(-2);
  2453. Status = STATUS_SUCCESS;
  2454. goto ExitHandler2;
  2455. }
  2456. }
  2457. //
  2458. // Allow a way for policy to enable whether transparent
  2459. // enforcement should be enabled or not (default to disable).
  2460. // Note that the following values have meanings:
  2461. // 0 = Transparent WinSafer enforcement disabled.
  2462. // 1 = means enable transparent EXE enforcement
  2463. // >1 = means enable transparent EXE and DLL enforcement.
  2464. //
  2465. {
  2466. // BUG 240635: change to use existence of policy instead.
  2467. HANDLE hKeyEnabled;
  2468. BYTE QueryBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 64];
  2469. PKEY_VALUE_PARTIAL_INFORMATION pKeyValueInfo =
  2470. (PKEY_VALUE_PARTIAL_INFORMATION) QueryBuffer;
  2471. DWORD dwActualSize;
  2472. BOOLEAN bPolicyEnabled = FALSE;
  2473. Status = NtOpenKey(&hKeyEnabled, KEY_QUERY_VALUE,
  2474. (POBJECT_ATTRIBUTES) &ObjectAttributesCodeIdentifiers);
  2475. if (NT_SUCCESS(Status)) {
  2476. Status = NtQueryValueKey(
  2477. hKeyEnabled,
  2478. (PUNICODE_STRING) &UnicodeTransparentValueName,
  2479. KeyValuePartialInformation,
  2480. pKeyValueInfo, sizeof(QueryBuffer), &dwActualSize);
  2481. NtClose(hKeyEnabled);
  2482. if (NT_SUCCESS(Status)) {
  2483. if (pKeyValueInfo->Type == REG_DWORD &&
  2484. pKeyValueInfo->DataLength == sizeof(DWORD) &&
  2485. *((PDWORD) pKeyValueInfo->Data) > 1) {
  2486. bPolicyEnabled = TRUE;
  2487. }
  2488. }
  2489. }
  2490. //
  2491. // There was no machine policy. Check if user policy is enabled.
  2492. //
  2493. if (!bPolicyEnabled) {
  2494. UNICODE_STRING CurrentUserKeyPath;
  2495. UNICODE_STRING SubKeyNameUser;
  2496. OBJECT_ATTRIBUTES ObjectAttributesUser;
  2497. //
  2498. // Get the prefix for the user key.
  2499. //
  2500. Status = RtlFormatCurrentUserKeyPath( &CurrentUserKeyPath );
  2501. if (NT_SUCCESS( Status ) ) {
  2502. SubKeyNameUser.Length = 0;
  2503. SubKeyNameUser.MaximumLength = CurrentUserKeyPath.Length +
  2504. sizeof(WCHAR) +
  2505. sizeof(SAFER_USER_KEY_NAME);
  2506. //
  2507. // Allocate memory big enough to hold the unicode string.
  2508. //
  2509. SubKeyNameUser.Buffer = RtlAllocateHeap(
  2510. RtlProcessHeap(),
  2511. MAKE_TAG( TEMP_TAG ),
  2512. SubKeyNameUser.MaximumLength);
  2513. if (SubKeyNameUser.Buffer != NULL) {
  2514. //
  2515. // Copy the prefix into the string.
  2516. // This is of the type Registry\S-1-5-21-xxx-xxx-xxx-xxx.
  2517. //
  2518. Status = RtlAppendUnicodeStringToString(
  2519. &SubKeyNameUser,
  2520. &CurrentUserKeyPath );
  2521. if (NT_SUCCESS( Status ) ) {
  2522. //
  2523. // Append the Safer suffix.
  2524. //
  2525. Status = RtlAppendUnicodeToString(
  2526. &SubKeyNameUser,
  2527. SAFER_USER_KEY_NAME );
  2528. if (NT_SUCCESS( Status ) ) {
  2529. InitializeObjectAttributes(
  2530. &ObjectAttributesUser,
  2531. &SubKeyNameUser,
  2532. OBJ_CASE_INSENSITIVE,
  2533. NULL,
  2534. NULL
  2535. );
  2536. Status = NtOpenKey( &hKeyEnabled,KEY_QUERY_VALUE,
  2537. (POBJECT_ATTRIBUTES) &ObjectAttributesUser);
  2538. if (NT_SUCCESS(Status)) {
  2539. Status = NtQueryValueKey(
  2540. hKeyEnabled,
  2541. (PUNICODE_STRING) &UnicodeTransparentValueName,
  2542. KeyValuePartialInformation,
  2543. pKeyValueInfo, sizeof(QueryBuffer), &dwActualSize);
  2544. if (NT_SUCCESS(Status)) {
  2545. if (pKeyValueInfo->Type == REG_DWORD &&
  2546. pKeyValueInfo->DataLength == sizeof(DWORD) &&
  2547. *((PDWORD) pKeyValueInfo->Data) > 1) {
  2548. bPolicyEnabled = TRUE;
  2549. }
  2550. }
  2551. }
  2552. }
  2553. }
  2554. RtlFreeHeap(RtlProcessHeap(), 0, SubKeyNameUser.Buffer);
  2555. }
  2556. RtlFreeUnicodeString( &CurrentUserKeyPath );
  2557. }
  2558. }
  2559. if (!bPolicyEnabled) {
  2560. goto FailSuccessfully;
  2561. }
  2562. }
  2563. //
  2564. // Finally load the library. We'll pass a special flag in
  2565. // DllCharacteristics to eliminate WinSafer checking on advapi
  2566. // itself, but that (currently) doesn't affect dependent DLLs
  2567. // so we still depend on the above LoadInProgress flag to
  2568. // prevent unintended recursion.
  2569. //
  2570. {
  2571. // BUG 241835: the WinSafer supression doesn't affect dependencies.
  2572. ULONG DllCharacteristics = IMAGE_FILE_SYSTEM;
  2573. Status = LdrLoadDll(UNICODE_NULL,
  2574. &DllCharacteristics, // prevents recursion too
  2575. (PUNICODE_STRING) &ModuleNameAdvapi,
  2576. &TempAdvApi32Handle);
  2577. if (!NT_SUCCESS(Status)) {
  2578. #if DBG
  2579. DbgPrint("LDR: AuthzCheck: load failure on advapi (Status=%d) inside %d for %wZ\n",
  2580. Status, HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess), FileName);
  2581. #endif
  2582. AdvApi32ModuleHandleMaster = NULL;
  2583. Status = STATUS_ENTRYPOINT_NOT_FOUND;
  2584. goto ExitHandler2;
  2585. }
  2586. }
  2587. //
  2588. // Get function pointers to the APIs that we'll need. If we fail
  2589. // to get pointers for any of them, then just unload advapi and
  2590. // ignore all future attempts to load it within this process.
  2591. //
  2592. Status = LdrpGetProcedureAddress(
  2593. TempAdvApi32Handle,
  2594. (PANSI_STRING) &ProcedureNameIdentify,
  2595. 0,
  2596. (PVOID*)&lpfnIdentifyCodeAuthzLevelW,
  2597. FALSE);
  2598. if (!NT_SUCCESS(Status) || !lpfnIdentifyCodeAuthzLevelW) {
  2599. #if DBG
  2600. DbgPrint("LDR: AuthzCheck: advapi getprocaddress identify (Status=%X) inside %d for %wZ\n",
  2601. Status, HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess), FileName);
  2602. #endif
  2603. LdrUnloadDll(TempAdvApi32Handle);
  2604. AdvApi32ModuleHandleMaster = NULL;
  2605. Status = STATUS_ENTRYPOINT_NOT_FOUND;
  2606. goto ExitHandler2;
  2607. }
  2608. Status = LdrpGetProcedureAddress(
  2609. TempAdvApi32Handle,
  2610. (PANSI_STRING) &ProcedureNameCompute,
  2611. 0,
  2612. (PVOID*)&lpfnComputeAccessTokenFromCodeAuthzLevel,
  2613. FALSE);
  2614. if (!NT_SUCCESS(Status) ||
  2615. !lpfnComputeAccessTokenFromCodeAuthzLevel) {
  2616. #if DBG
  2617. DbgPrint("LDR: AuthzCheck: advapi getprocaddress compute (Status=%X) inside %d for %wZ\n",
  2618. Status, HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess), FileName);
  2619. #endif
  2620. LdrUnloadDll(TempAdvApi32Handle);
  2621. AdvApi32ModuleHandleMaster = NULL;
  2622. Status = STATUS_ENTRYPOINT_NOT_FOUND;
  2623. goto ExitHandler2;
  2624. }
  2625. Status = LdrpGetProcedureAddress(
  2626. TempAdvApi32Handle,
  2627. (PANSI_STRING) &ProcedureNameClose,
  2628. 0,
  2629. (PVOID*)&lpfnCloseCodeAuthzLevel,
  2630. FALSE);
  2631. if (!NT_SUCCESS(Status) || !lpfnCloseCodeAuthzLevel) {
  2632. #if DBG
  2633. DbgPrint("LDR: AuthzCheck: advapi getprocaddress close (Status=%X) inside %d for %wZ\n",
  2634. Status, HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess), FileName);
  2635. #endif
  2636. LdrUnloadDll(TempAdvApi32Handle);
  2637. AdvApi32ModuleHandleMaster = NULL;
  2638. Status = STATUS_ENTRYPOINT_NOT_FOUND;
  2639. goto ExitHandler2;
  2640. }
  2641. AdvApi32ModuleHandleMaster = TempAdvApi32Handle;
  2642. }
  2643. //
  2644. // Prepare the code properties struct.
  2645. //
  2646. RtlZeroMemory(&codeproperties, sizeof(codeproperties));
  2647. codeproperties.cbSize = sizeof(codeproperties);
  2648. codeproperties.dwCheckFlags =
  2649. (SAFER_CRITERIA_IMAGEPATH | SAFER_CRITERIA_IMAGEHASH |
  2650. SAFER_CRITERIA_IMAGEPATH_NT);
  2651. ASSERTMSG("FileName not null terminated",
  2652. FileName->Buffer[FileName->Length / sizeof(WCHAR)] == UNICODE_NULL);
  2653. codeproperties.ImagePath = FileName->Buffer;
  2654. codeproperties.hImageFileHandle = FileImageHandle;
  2655. //
  2656. // Ask the system to find the Authorization Level that classifies it.
  2657. //
  2658. ASSERT(lpfnIdentifyCodeAuthzLevelW != NULL);
  2659. if (lpfnIdentifyCodeAuthzLevelW(
  2660. 1, // 1 structure
  2661. &codeproperties, // details to identify
  2662. &hAuthzLevel, // Safer level
  2663. NULL)) // reserved.
  2664. {
  2665. //
  2666. // We found an Authorization Level applicable to this application.
  2667. // See if this Level represents something less trusted than us.
  2668. //
  2669. ASSERT(lpfnComputeAccessTokenFromCodeAuthzLevel != NULL);
  2670. if (!lpfnComputeAccessTokenFromCodeAuthzLevel(
  2671. hAuthzLevel, // Safer Level
  2672. hProcessToken, // source token.
  2673. NULL, // output token not used for compare.
  2674. SAFER_TOKEN_COMPARE_ONLY, // we want to compare
  2675. &dwCompareResult)) // reserved
  2676. {
  2677. // failed to compare, for some reason.
  2678. #if DBG
  2679. DbgPrint("LDR: AuthzCheck: compute failed in %d for %wZ\n",
  2680. HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess), FileName);
  2681. #endif
  2682. Status = STATUS_ACCESS_DENIED;
  2683. } else if (dwCompareResult == -1) {
  2684. // less privileged, deny access.
  2685. #ifdef SAFER_DEBUGGING
  2686. DbgPrint("LDR: AuthzCheck: compute access denied in %d for %wZ\n",
  2687. HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess), FileName);
  2688. #endif
  2689. Status = STATUS_ACCESS_DENIED;
  2690. } else {
  2691. // greater or equally privileged, allow access to load.
  2692. #ifdef SAFER_DEBUGGING
  2693. DbgPrint("LDR: AuthzCheck: compute access ok in %d for %wZ\n",
  2694. HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess), FileName);
  2695. #endif
  2696. Status = STATUS_SUCCESS;
  2697. }
  2698. ASSERT(lpfnCloseCodeAuthzLevel != NULL);
  2699. lpfnCloseCodeAuthzLevel(hAuthzLevel);
  2700. } else {
  2701. // No authorization level found for this DLL, and the
  2702. // policy does not have a Default Level in effect.
  2703. Status = STATUS_NOT_FOUND;
  2704. }
  2705. ExitHandler2:
  2706. NtClose(hProcessToken);
  2707. ExitHandler:
  2708. return Status;
  2709. }
  2710. NTSTATUS
  2711. LdrpCreateDllSection(
  2712. IN PUNICODE_STRING NtFullDllName,
  2713. IN HANDLE DllFile,
  2714. IN PUNICODE_STRING BaseName,
  2715. IN PULONG DllCharacteristics OPTIONAL,
  2716. OUT PHANDLE SectionHandle
  2717. )
  2718. {
  2719. HANDLE File;
  2720. HANDLE Section;
  2721. NTSTATUS st;
  2722. OBJECT_ATTRIBUTES ObjectAttributes;
  2723. IO_STATUS_BLOCK IoStatus;
  2724. SECTION_IMAGE_INFORMATION ImageInformation;
  2725. if ( !DllFile ) {
  2726. //
  2727. // Since ntsdk does not search paths well, we can't use
  2728. // relative object names
  2729. //
  2730. InitializeObjectAttributes(
  2731. &ObjectAttributes,
  2732. NtFullDllName,
  2733. OBJ_CASE_INSENSITIVE,
  2734. NULL,
  2735. NULL
  2736. );
  2737. st = NtOpenFile(
  2738. &File,
  2739. SYNCHRONIZE | FILE_EXECUTE,
  2740. &ObjectAttributes,
  2741. &IoStatus,
  2742. FILE_SHARE_READ | FILE_SHARE_DELETE,
  2743. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
  2744. );
  2745. if (!NT_SUCCESS(st)) {
  2746. if (ShowSnaps) {
  2747. DbgPrint("LDR: %s - NtOpenFile failed; status = %x\n", __FUNCTION__, st);
  2748. }
  2749. *SectionHandle = NULL;
  2750. return st;
  2751. }
  2752. } else {
  2753. File = DllFile;
  2754. }
  2755. //
  2756. // Create a memory section of the library file's contents.
  2757. //
  2758. st = NtCreateSection(
  2759. SectionHandle,
  2760. SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_MAP_WRITE | SECTION_QUERY,
  2761. NULL,
  2762. NULL,
  2763. PAGE_EXECUTE,
  2764. SEC_IMAGE,
  2765. File
  2766. );
  2767. if (!NT_SUCCESS(st)) {
  2768. //
  2769. // hard error time
  2770. //
  2771. ULONG_PTR ErrorParameters[1];
  2772. ULONG ErrorResponse;
  2773. *SectionHandle = NULL;
  2774. ErrorParameters[0] = (ULONG_PTR)NtFullDllName;
  2775. NtRaiseHardError(
  2776. STATUS_INVALID_IMAGE_FORMAT,
  2777. 1,
  2778. 1,
  2779. ErrorParameters,
  2780. OptionOk,
  2781. &ErrorResponse);
  2782. if ( LdrpInLdrInit )
  2783. LdrpFatalHardErrorCount++;
  2784. #if DBG
  2785. if (st != STATUS_INVALID_IMAGE_NE_FORMAT &&
  2786. st != STATUS_INVALID_IMAGE_LE_FORMAT &&
  2787. st != STATUS_INVALID_IMAGE_WIN_16 &&
  2788. st != STATUS_INVALID_IMAGE_WIN_32 &&
  2789. st != STATUS_INVALID_IMAGE_WIN_64 &&
  2790. LdrpShouldDbgPrintStatus(st)
  2791. ) {
  2792. DbgPrint("LDR: " __FUNCTION__ " - NtCreateSection %wZ failed. Status == 0x%08lx\n",
  2793. NtFullDllName,
  2794. st
  2795. );
  2796. }
  2797. #endif
  2798. }
  2799. else {
  2800. if (ARGUMENT_PRESENT(DllCharacteristics) &&
  2801. (*DllCharacteristics & IMAGE_FILE_SYSTEM)) {
  2802. #if DBG
  2803. DbgPrint("LDR: WinSafer AuthzCheck on %wZ skipped by request\n",
  2804. &NtFullDllName);
  2805. #endif
  2806. } else {
  2807. //
  2808. // WOW64 processes should not load 64-bit dlls (advapi32.dll)
  2809. // but the dll's will get SAFERized when the
  2810. // 32-bit load kicks in
  2811. //
  2812. #if defined(_WIN64)
  2813. if ( UseWOW64 == FALSE ) {
  2814. #endif
  2815. //
  2816. // Ask the WinSafer code authorization sandboxing
  2817. // infrastructure if the library load should be permitted.
  2818. //
  2819. //
  2820. // The Winsafer check is moved here since the IMAGE_LOADER_FLAGS_COMPLUS
  2821. // information from the image will be made available shortly.
  2822. //
  2823. //
  2824. // Query the section to determine whether or not this is a .NET image.
  2825. // On failure to query, the error will be returned
  2826. //
  2827. st = NtQuerySection(
  2828. *SectionHandle,
  2829. SectionImageInformation,
  2830. &ImageInformation,
  2831. sizeof( ImageInformation ),
  2832. NULL
  2833. );
  2834. if (!NT_SUCCESS( st )) {
  2835. NtClose(*SectionHandle);
  2836. *SectionHandle = NULL;
  2837. NtClose( File );
  2838. return st;
  2839. }
  2840. if (((ImageInformation.LoaderFlags & IMAGE_LOADER_FLAGS_COMPLUS) == 0)) {
  2841. st = LdrpCodeAuthzCheckDllAllowed(NtFullDllName, File);
  2842. if (st != STATUS_NOT_FOUND && !NT_SUCCESS(st)) {
  2843. #if !DBG
  2844. if (ShowSnaps)
  2845. #endif
  2846. {
  2847. DbgPrint("LDR: Loading of (%wZ) blocked by WinSafer\n",
  2848. &NtFullDllName
  2849. );
  2850. }
  2851. NtClose(*SectionHandle);
  2852. *SectionHandle = NULL;
  2853. NtClose( File );
  2854. return st;
  2855. }
  2856. st = STATUS_SUCCESS;
  2857. }
  2858. #if defined(_WIN64)
  2859. }
  2860. #endif
  2861. }
  2862. }
  2863. NtClose( File );
  2864. return st;
  2865. }
  2866. NTSTATUS
  2867. LdrpSnapIAT (
  2868. IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry_Export,
  2869. IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry_Import,
  2870. IN PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor,
  2871. IN BOOLEAN SnapForwardersOnly
  2872. )
  2873. /*++
  2874. Routine Description:
  2875. This function snaps the Import Address Table for this
  2876. Import Descriptor.
  2877. Arguments:
  2878. LdrDataTableEntry_Export - Information about the image to import from.
  2879. LdrDataTableEntry_Import - Information about the image to import to.
  2880. ImportDescriptor - Contains a pointer to the IAT to snap.
  2881. SnapForwardersOnly - TRUE if just snapping forwarders only.
  2882. Return Value:
  2883. Status value
  2884. --*/
  2885. {
  2886. PPEB Peb;
  2887. NTSTATUS st;
  2888. ULONG ExportSize;
  2889. PIMAGE_EXPORT_DIRECTORY ExportDirectory;
  2890. PIMAGE_THUNK_DATA Thunk, OriginalThunk;
  2891. PSZ ImportName;
  2892. ULONG ForwarderChain;
  2893. PIMAGE_NT_HEADERS NtHeaders;
  2894. PIMAGE_SECTION_HEADER NtSection;
  2895. ULONG i, Rva;
  2896. PVOID IATBase;
  2897. SIZE_T IATSize;
  2898. ULONG LittleIATSize;
  2899. ULONG OldProtect;
  2900. Peb = NtCurrentPeb();
  2901. ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(
  2902. LdrDataTableEntry_Export->DllBase,
  2903. TRUE,
  2904. IMAGE_DIRECTORY_ENTRY_EXPORT,
  2905. &ExportSize
  2906. );
  2907. if (!ExportDirectory) {
  2908. KdPrint(("LDR: %wZ doesn't contain an EXPORT table\n", &LdrDataTableEntry_Export->BaseDllName));
  2909. return STATUS_INVALID_IMAGE_FORMAT;
  2910. }
  2911. //
  2912. // Determine the location and size of the IAT. If the linker did
  2913. // not tell use explicitly, then use the location and size of the
  2914. // image section that contains the import table.
  2915. //
  2916. IATBase = RtlImageDirectoryEntryToData( LdrDataTableEntry_Import->DllBase,
  2917. TRUE,
  2918. IMAGE_DIRECTORY_ENTRY_IAT,
  2919. &LittleIATSize
  2920. );
  2921. if (IATBase == NULL) {
  2922. NtHeaders = RtlImageNtHeader( LdrDataTableEntry_Import->DllBase );
  2923. if (! NtHeaders) {
  2924. return STATUS_INVALID_IMAGE_FORMAT;
  2925. }
  2926. NtSection = IMAGE_FIRST_SECTION( NtHeaders );
  2927. Rva = NtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ].VirtualAddress;
  2928. if (Rva != 0) {
  2929. for (i=0; i<NtHeaders->FileHeader.NumberOfSections; i++) {
  2930. if (Rva >= NtSection->VirtualAddress &&
  2931. Rva < (NtSection->VirtualAddress + NtSection->SizeOfRawData)
  2932. ) {
  2933. IATBase = (PVOID)
  2934. ((ULONG_PTR)(LdrDataTableEntry_Import->DllBase) + NtSection->VirtualAddress);
  2935. LittleIATSize = NtSection->Misc.VirtualSize;
  2936. if (LittleIATSize == 0) {
  2937. LittleIATSize = NtSection->SizeOfRawData;
  2938. }
  2939. break;
  2940. }
  2941. ++NtSection;
  2942. }
  2943. }
  2944. if (IATBase == NULL) {
  2945. KdPrint(( "LDR: Unable to unprotect IAT for %wZ (Image Base %p)\n",
  2946. &LdrDataTableEntry_Import->BaseDllName,
  2947. LdrDataTableEntry_Import->DllBase
  2948. ));
  2949. return STATUS_INVALID_IMAGE_FORMAT;
  2950. }
  2951. }
  2952. IATSize = LittleIATSize;
  2953. st = NtProtectVirtualMemory( NtCurrentProcess(),
  2954. &IATBase,
  2955. &IATSize,
  2956. PAGE_READWRITE,
  2957. &OldProtect
  2958. );
  2959. if (!NT_SUCCESS(st)) {
  2960. KdPrint(( "LDR: Unable to unprotect IAT for %wZ (Status %x)\n",
  2961. &LdrDataTableEntry_Import->BaseDllName,
  2962. st
  2963. ));
  2964. return st;
  2965. }
  2966. //
  2967. // If just snapping forwarded entries, walk that list
  2968. //
  2969. if (SnapForwardersOnly) {
  2970. ImportName = (PSZ)((ULONG_PTR)LdrDataTableEntry_Import->DllBase + ImportDescriptor->Name);
  2971. ForwarderChain = ImportDescriptor->ForwarderChain;
  2972. while (ForwarderChain != -1) {
  2973. OriginalThunk = (PIMAGE_THUNK_DATA)((ULONG_PTR)LdrDataTableEntry_Import->DllBase +
  2974. ImportDescriptor->OriginalFirstThunk +
  2975. (ForwarderChain * sizeof(IMAGE_THUNK_DATA)));
  2976. Thunk = (PIMAGE_THUNK_DATA)((ULONG_PTR)LdrDataTableEntry_Import->DllBase +
  2977. ImportDescriptor->FirstThunk +
  2978. (ForwarderChain * sizeof(IMAGE_THUNK_DATA)));
  2979. ForwarderChain = (ULONG) Thunk->u1.Ordinal;
  2980. try {
  2981. st = LdrpSnapThunk(LdrDataTableEntry_Export->DllBase,
  2982. LdrDataTableEntry_Import->DllBase,
  2983. OriginalThunk,
  2984. Thunk,
  2985. ExportDirectory,
  2986. ExportSize,
  2987. TRUE,
  2988. ImportName
  2989. );
  2990. Thunk++;
  2991. }
  2992. except (LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {
  2993. st = GetExceptionCode();
  2994. DbgPrintEx(
  2995. DPFLTR_LDR_ID,
  2996. LDR_ERROR_DPFLTR,
  2997. "LDR: %s - caught exception %08lx snapping thunks (#1)\n",
  2998. __FUNCTION__,
  2999. st);
  3000. }
  3001. if (!NT_SUCCESS(st) ) {
  3002. break;
  3003. }
  3004. }
  3005. }
  3006. else
  3007. //
  3008. // Otherwise, walk through the IAT and snap all the thunks.
  3009. //
  3010. if ( ImportDescriptor->FirstThunk ) {
  3011. Thunk = (PIMAGE_THUNK_DATA)((ULONG_PTR)LdrDataTableEntry_Import->DllBase + ImportDescriptor->FirstThunk);
  3012. NtHeaders = RtlImageNtHeader( LdrDataTableEntry_Import->DllBase );
  3013. //
  3014. // If the OriginalFirstThunk field does not point inside the image, then ignore
  3015. // it. This is will detect bogus Borland Linker 2.25 images that did not fill
  3016. // this field in.
  3017. //
  3018. if (ImportDescriptor->Characteristics < NtHeaders->OptionalHeader.SizeOfHeaders ||
  3019. ImportDescriptor->Characteristics >= NtHeaders->OptionalHeader.SizeOfImage
  3020. ) {
  3021. OriginalThunk = Thunk;
  3022. } else {
  3023. OriginalThunk = (PIMAGE_THUNK_DATA)((ULONG_PTR)LdrDataTableEntry_Import->DllBase +
  3024. ImportDescriptor->OriginalFirstThunk);
  3025. }
  3026. ImportName = (PSZ)((ULONG_PTR)LdrDataTableEntry_Import->DllBase + ImportDescriptor->Name);
  3027. while (OriginalThunk->u1.AddressOfData) {
  3028. try {
  3029. st = LdrpSnapThunk(LdrDataTableEntry_Export->DllBase,
  3030. LdrDataTableEntry_Import->DllBase,
  3031. OriginalThunk,
  3032. Thunk,
  3033. ExportDirectory,
  3034. ExportSize,
  3035. TRUE,
  3036. ImportName
  3037. );
  3038. OriginalThunk++;
  3039. Thunk++;
  3040. }
  3041. except (LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {
  3042. st = GetExceptionCode();
  3043. DbgPrintEx(
  3044. DPFLTR_LDR_ID,
  3045. LDR_ERROR_DPFLTR,
  3046. "LDR: %s - caught exception %08lx snapping thunks (#2)\n",
  3047. __FUNCTION__,
  3048. st);
  3049. }
  3050. if (!NT_SUCCESS(st) ) {
  3051. break;
  3052. }
  3053. }
  3054. }
  3055. //
  3056. // Restore protection for IAT and flush instruction cache.
  3057. //
  3058. NtProtectVirtualMemory( NtCurrentProcess(),
  3059. &IATBase,
  3060. &IATSize,
  3061. OldProtect,
  3062. &OldProtect
  3063. );
  3064. NtFlushInstructionCache( NtCurrentProcess(), IATBase, LittleIATSize );
  3065. return st;
  3066. }
  3067. NTSTATUS
  3068. LdrpSnapThunk (
  3069. IN PVOID DllBase,
  3070. IN PVOID ImageBase,
  3071. IN PIMAGE_THUNK_DATA OriginalThunk,
  3072. IN OUT PIMAGE_THUNK_DATA Thunk,
  3073. IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
  3074. IN ULONG ExportSize,
  3075. IN BOOLEAN StaticSnap,
  3076. IN PSZ DllName
  3077. )
  3078. /*++
  3079. Routine Description:
  3080. This function snaps a thunk using the specified Export Section data.
  3081. If the section data does not support the thunk, then the thunk is
  3082. partially snapped (Dll field is still non-null, but snap address is
  3083. set).
  3084. Arguments:
  3085. DllBase - Base of Dll.
  3086. ImageBase - Base of image that contains the thunks to snap.
  3087. Thunk - On input, supplies the thunk to snap. When successfully
  3088. snapped, the function field is set to point to the address in
  3089. the DLL, and the DLL field is set to NULL.
  3090. ExportDirectory - Supplies the Export Section data from a DLL.
  3091. StaticSnap - If TRUE, then loader is attempting a static snap,
  3092. and any ordinal/name lookup failure will be reported.
  3093. Return Value:
  3094. STATUS_SUCCESS or STATUS_PROCEDURE_NOT_FOUND
  3095. --*/
  3096. {
  3097. BOOLEAN Ordinal;
  3098. USHORT OrdinalNumber;
  3099. ULONG OriginalOrdinalNumber;
  3100. PIMAGE_IMPORT_BY_NAME AddressOfData;
  3101. PULONG NameTableBase;
  3102. PUSHORT NameOrdinalTableBase;
  3103. PULONG Addr;
  3104. USHORT HintIndex;
  3105. NTSTATUS st;
  3106. PSZ ImportString;
  3107. //
  3108. // Determine if snap is by name, or by ordinal
  3109. //
  3110. Ordinal = (BOOLEAN)IMAGE_SNAP_BY_ORDINAL(OriginalThunk->u1.Ordinal);
  3111. if (Ordinal) {
  3112. OriginalOrdinalNumber = (ULONG)IMAGE_ORDINAL(OriginalThunk->u1.Ordinal);
  3113. OrdinalNumber = (USHORT)(OriginalOrdinalNumber - ExportDirectory->Base);
  3114. } else {
  3115. //
  3116. // This should never happen, because we will only be called if either
  3117. // Ordinal is set or ImageBase is not NULL. But to satisfy prefix...
  3118. //
  3119. if (ImageBase == NULL) {
  3120. #if LDRDBG
  3121. DbgPrint("LDR: ImageBase=NULL and !Ordinal\n");
  3122. #endif
  3123. return STATUS_PROCEDURE_NOT_FOUND;
  3124. }
  3125. //
  3126. // Change AddressOfData from an RVA to a VA.
  3127. //
  3128. AddressOfData = (PIMAGE_IMPORT_BY_NAME)((ULONG_PTR)ImageBase + ((ULONG_PTR)OriginalThunk->u1.AddressOfData & 0xffffffff));
  3129. ImportString = (PSZ)AddressOfData->Name;
  3130. //
  3131. // Lookup Name in NameTable
  3132. //
  3133. NameTableBase = (PULONG)((ULONG_PTR)DllBase + (ULONG)ExportDirectory->AddressOfNames);
  3134. NameOrdinalTableBase = (PUSHORT)((ULONG_PTR)DllBase + (ULONG)ExportDirectory->AddressOfNameOrdinals);
  3135. //
  3136. // Before dropping into binary search, see if
  3137. // the hint index results in a successful
  3138. // match. If the hint index is zero, then
  3139. // drop into binary search.
  3140. //
  3141. HintIndex = AddressOfData->Hint;
  3142. if ((ULONG)HintIndex < ExportDirectory->NumberOfNames &&
  3143. !strcmp(ImportString, (PSZ)((ULONG_PTR)DllBase + NameTableBase[HintIndex]))) {
  3144. OrdinalNumber = NameOrdinalTableBase[HintIndex];
  3145. #if LDRDBG
  3146. if (ShowSnaps) {
  3147. DbgPrint("LDR: Snapping %s\n", ImportString);
  3148. }
  3149. #endif
  3150. } else {
  3151. #if LDRDBG
  3152. if (HintIndex) {
  3153. DbgPrint("LDR: Warning HintIndex Failure. Name %s (%lx) Hint 0x%lx\n",
  3154. ImportString,
  3155. (ULONG)ImportString,
  3156. (ULONG)HintIndex
  3157. );
  3158. }
  3159. #endif
  3160. OrdinalNumber = LdrpNameToOrdinal(
  3161. ImportString,
  3162. ExportDirectory->NumberOfNames,
  3163. DllBase,
  3164. NameTableBase,
  3165. NameOrdinalTableBase
  3166. );
  3167. }
  3168. }
  3169. //
  3170. // If OrdinalNumber is not within the Export Address Table,
  3171. // then DLL does not implement function. Snap to LDRP_BAD_DLL.
  3172. //
  3173. if ((ULONG)OrdinalNumber >= ExportDirectory->NumberOfFunctions) {
  3174. baddllref:
  3175. #if DBG
  3176. if (StaticSnap) {
  3177. if (Ordinal) {
  3178. DbgPrint("LDR: Can't locate ordinal 0x%lx\n", OriginalOrdinalNumber);
  3179. }
  3180. else {
  3181. DbgPrint("LDR: Can't locate %s\n", ImportString);
  3182. }
  3183. }
  3184. #endif
  3185. if ( StaticSnap ) {
  3186. //
  3187. // Hard Error Time
  3188. //
  3189. ULONG_PTR ErrorParameters[3];
  3190. UNICODE_STRING ErrorDllName, ErrorEntryPointName;
  3191. ANSI_STRING AnsiScratch;
  3192. ULONG ParameterStringMask;
  3193. ULONG ErrorResponse;
  3194. RtlInitAnsiString(&AnsiScratch,DllName ? DllName : "Unknown");
  3195. RtlAnsiStringToUnicodeString(&ErrorDllName,&AnsiScratch,TRUE);
  3196. ErrorParameters[1] = (ULONG_PTR)&ErrorDllName;
  3197. ParameterStringMask = 2;
  3198. if ( Ordinal ) {
  3199. ErrorParameters[0] = OriginalOrdinalNumber;
  3200. }
  3201. else {
  3202. RtlInitAnsiString(&AnsiScratch,ImportString);
  3203. RtlAnsiStringToUnicodeString(&ErrorEntryPointName,&AnsiScratch,TRUE);
  3204. ErrorParameters[0] = (ULONG_PTR)&ErrorEntryPointName;
  3205. ParameterStringMask = 3;
  3206. }
  3207. NtRaiseHardError(
  3208. Ordinal ? STATUS_ORDINAL_NOT_FOUND : STATUS_ENTRYPOINT_NOT_FOUND,
  3209. 2,
  3210. ParameterStringMask,
  3211. ErrorParameters,
  3212. OptionOk,
  3213. &ErrorResponse
  3214. );
  3215. if ( LdrpInLdrInit ) {
  3216. LdrpFatalHardErrorCount++;
  3217. }
  3218. RtlFreeUnicodeString(&ErrorDllName);
  3219. if ( !Ordinal ) {
  3220. RtlFreeUnicodeString(&ErrorEntryPointName);
  3221. RtlRaiseStatus(STATUS_ENTRYPOINT_NOT_FOUND);
  3222. }
  3223. RtlRaiseStatus(STATUS_ORDINAL_NOT_FOUND);
  3224. }
  3225. Thunk->u1.Function = (ULONG_PTR)LDRP_BAD_DLL;
  3226. st = Ordinal ? STATUS_ORDINAL_NOT_FOUND : STATUS_ENTRYPOINT_NOT_FOUND;
  3227. } else {
  3228. Addr = (PULONG)((ULONG_PTR)DllBase + (ULONG)ExportDirectory->AddressOfFunctions);
  3229. Thunk->u1.Function = ((ULONG_PTR)DllBase + Addr[OrdinalNumber]);
  3230. if (Thunk->u1.Function > (ULONG_PTR)ExportDirectory &&
  3231. Thunk->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize)) {
  3232. UNICODE_STRING UnicodeString;
  3233. ANSI_STRING ForwardDllName;
  3234. PVOID ForwardDllHandle;
  3235. PANSI_STRING ForwardProcName;
  3236. ULONG ForwardProcOrdinal;
  3237. ImportString = (PSZ)Thunk->u1.Function;
  3238. ForwardDllName.Buffer = ImportString,
  3239. ForwardDllName.Length = (USHORT)(strchr(ImportString, '.') - ImportString);
  3240. ForwardDllName.MaximumLength = ForwardDllName.Length;
  3241. // Most forwarders seem to point to NTDLL and since we know that every
  3242. // process has ntdll already loaded and pinned let's optimize away all
  3243. // the calls to load it. I was debugging the loader and there are just
  3244. // a rediculous number of loads of ntdll. -mgrier 4/8/2001
  3245. if (ASCII_STRING_IS_NTDLL(&ForwardDllName)) {
  3246. ForwardDllHandle = LdrpNtDllDataTableEntry->DllBase;
  3247. st = STATUS_SUCCESS;
  3248. } else {
  3249. st = RtlAnsiStringToUnicodeString(&UnicodeString, &ForwardDllName, TRUE);
  3250. if (NT_SUCCESS(st)) {
  3251. UNICODE_STRING AnotherUnicodeString = {0, 0, NULL};
  3252. PUNICODE_STRING UnicodeStringToUse = &UnicodeString;
  3253. ULONG LdrpLoadDllFlags = 0;
  3254. st = RtlDosApplyFileIsolationRedirection_Ustr(
  3255. RTL_DOS_APPLY_FILE_REDIRECTION_USTR_FLAG_RESPECT_DOT_LOCAL,
  3256. &UnicodeString,
  3257. &DefaultExtension,
  3258. NULL,
  3259. &AnotherUnicodeString,
  3260. &UnicodeStringToUse,
  3261. NULL,
  3262. NULL,
  3263. NULL);
  3264. if (NT_SUCCESS(st)) {
  3265. LdrpLoadDllFlags |= LDRP_LOAD_DLL_FLAG_DLL_IS_REDIRECTED;
  3266. }
  3267. if (st == STATUS_SXS_KEY_NOT_FOUND) {
  3268. st = STATUS_SUCCESS;
  3269. }
  3270. if (NT_SUCCESS(st)) {
  3271. st = LdrpLoadDll(LdrpLoadDllFlags, NULL, NULL, UnicodeStringToUse, &ForwardDllHandle, FALSE);
  3272. }
  3273. if (AnotherUnicodeString.Buffer != NULL)
  3274. RtlFreeUnicodeString(&AnotherUnicodeString);
  3275. RtlFreeUnicodeString(&UnicodeString);
  3276. }
  3277. }
  3278. if (!NT_SUCCESS(st)) {
  3279. goto baddllref;
  3280. }
  3281. RtlInitAnsiString( &ForwardDllName,
  3282. ImportString + ForwardDllName.Length + 1
  3283. );
  3284. if (ForwardDllName.Length > 1 &&
  3285. *ForwardDllName.Buffer == '#'
  3286. ) {
  3287. ForwardProcName = NULL;
  3288. st = RtlCharToInteger( ForwardDllName.Buffer+1,
  3289. 0,
  3290. &ForwardProcOrdinal
  3291. );
  3292. if (!NT_SUCCESS(st)) {
  3293. goto baddllref;
  3294. }
  3295. }
  3296. else {
  3297. ForwardProcName = &ForwardDllName;
  3298. //
  3299. // Following line is not needed since this is a by name lookup
  3300. //
  3301. //
  3302. //ForwardProcOrdinal = (ULONG)&ForwardDllName;
  3303. //
  3304. }
  3305. st = LdrpGetProcedureAddress( ForwardDllHandle,
  3306. ForwardProcName,
  3307. ForwardProcOrdinal,
  3308. (PVOID*)&Thunk->u1.Function,
  3309. FALSE
  3310. );
  3311. if (!NT_SUCCESS(st)) {
  3312. goto baddllref;
  3313. }
  3314. }
  3315. else {
  3316. if ( !Addr[OrdinalNumber] ) {
  3317. goto baddllref;
  3318. }
  3319. }
  3320. st = STATUS_SUCCESS;
  3321. }
  3322. return st;
  3323. }
  3324. USHORT
  3325. LdrpNameToOrdinal (
  3326. IN PSZ Name,
  3327. IN ULONG NumberOfNames,
  3328. IN PVOID DllBase,
  3329. IN PULONG NameTableBase,
  3330. IN PUSHORT NameOrdinalTableBase
  3331. )
  3332. {
  3333. LONG High;
  3334. LONG Low;
  3335. LONG Middle;
  3336. LONG Result;
  3337. //
  3338. // Lookup the import name in the name table using a binary search.
  3339. //
  3340. Low = 0;
  3341. High = NumberOfNames - 1;
  3342. while (High >= Low) {
  3343. //
  3344. // Compute the next probe index and compare the import name
  3345. // with the export name entry.
  3346. //
  3347. Middle = (Low + High) >> 1;
  3348. Result = strcmp(Name, (PCHAR)((ULONG_PTR)DllBase + NameTableBase[Middle]));
  3349. if (Result < 0) {
  3350. High = Middle - 1;
  3351. } else if (Result > 0) {
  3352. Low = Middle + 1;
  3353. } else {
  3354. break;
  3355. }
  3356. }
  3357. //
  3358. // If the high index is less than the low index, then a matching
  3359. // table entry was not found. Otherwise, get the ordinal number
  3360. // from the ordinal table.
  3361. //
  3362. if (High < Low) {
  3363. return (USHORT)-1;
  3364. } else {
  3365. return NameOrdinalTableBase[Middle];
  3366. }
  3367. }
  3368. #if 0
  3369. VOID
  3370. LdrpReferenceLoadedDll(
  3371. IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry
  3372. )
  3373. {
  3374. WCHAR PreAllocatedStringBuffer[DOS_MAX_PATH_LENGTH];
  3375. UNICODE_STRING PreAllocatedString = {0, sizeof(PreAllocatedStringBuffer), PreAllocatedStringBuffer};
  3376. LdrpUpdateLoadCount(LdrDataTableEntry, LDRP_UPDATE_LOAD_COUNT_INCREMENT, &PreAllocatedString);
  3377. }
  3378. VOID
  3379. LdrpDereferenceLoadedDll(
  3380. IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry
  3381. )
  3382. {
  3383. WCHAR PreAllocatedStringBuffer[DOS_MAX_PATH_LENGTH];
  3384. UNICODE_STRING PreAllocatedString = {0, sizeof(PreAllocatedStringBuffer), PreAllocatedStringBuffer};
  3385. LdrpUpdateLoadCount(LdrDataTableEntry, LDRP_UPDATE_LOAD_COUNT_DECREMENT, &PreAllocatedString);
  3386. }
  3387. VOID
  3388. LdrpPinLoadedDll(
  3389. IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry
  3390. )
  3391. {
  3392. WCHAR PreAllocatedStringBuffer[DOS_MAX_PATH_LENGTH];
  3393. UNICODE_STRING PreAllocatedString = {0, sizeof(PreAllocatedStringBuffer), PreAllocatedStringBuffer};
  3394. LdrpUpdateLoadCount(LdrDataTableEntry, LDRP_UPDATE_LOAD_COUNT_PIN, &PreAllocatedString);
  3395. }
  3396. #endif
  3397. VOID
  3398. LdrpUpdateLoadCount2(
  3399. IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry,
  3400. IN ULONG UpdateCountHow
  3401. )
  3402. {
  3403. WCHAR PreAllocatedStringBuffer[DOS_MAX_PATH_LENGTH];
  3404. UNICODE_STRING PreAllocatedString = {0, sizeof(PreAllocatedStringBuffer), PreAllocatedStringBuffer};
  3405. LdrpUpdateLoadCount3(LdrDataTableEntry, UpdateCountHow, &PreAllocatedString);
  3406. }
  3407. VOID
  3408. LdrpUpdateLoadCount3(
  3409. IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry,
  3410. IN ULONG UpdateCountHow,
  3411. IN OUT PUNICODE_STRING PreAllocatedRedirectionBuffer OPTIONAL
  3412. )
  3413. /*++
  3414. Routine Description:
  3415. This function dereferences a loaded DLL adjusting its reference
  3416. count. It then dereferences each dll referenced by this dll.
  3417. Arguments:
  3418. LdrDataTableEntry - Supplies the address of the DLL to dereference
  3419. UpdateCountHow -
  3420. LDRP_UPDATE_LOAD_COUNT_INCREMENT add one
  3421. LDRP_UPDATE_LOAD_COUNT_DECREMENT subtract one
  3422. LDRP_UPDATE_LOAD_COUNT_PIN set to 0xffff
  3423. PreAllocatedRedirectionBuffer - optional pointer to a caller-allocated
  3424. (usually on the stack) fixed-sized buffer to use for redirection
  3425. to avoid having a large buffer on our stack used during recursion.
  3426. Return Value:
  3427. None.
  3428. --*/
  3429. {
  3430. PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
  3431. PIMAGE_BOUND_IMPORT_DESCRIPTOR NewImportDescriptor;
  3432. PIMAGE_BOUND_FORWARDER_REF NewImportForwarder;
  3433. PSZ ImportName, NewImportStringBase;
  3434. ULONG i, ImportSize, NewImportSize;
  3435. ANSI_STRING AnsiString;
  3436. PUNICODE_STRING ImportDescriptorName_U;
  3437. PUNICODE_STRING ImportDescriptorNameToUse; // overrides ImportDescriptorName_U when redirection is turned on for a DLL
  3438. PLDR_DATA_TABLE_ENTRY Entry;
  3439. NTSTATUS st;
  3440. PIMAGE_THUNK_DATA FirstThunk;
  3441. UNICODE_STRING DynamicRedirectionString;
  3442. RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActivationFrame = { sizeof(ActivationFrame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
  3443. RtlActivateActivationContextUnsafeFast(&ActivationFrame, LdrDataTableEntry->EntryPointActivationContext);
  3444. __try {
  3445. switch (UpdateCountHow
  3446. ) {
  3447. case LDRP_UPDATE_LOAD_COUNT_PIN:
  3448. case LDRP_UPDATE_LOAD_COUNT_INCREMENT:
  3449. if (LdrDataTableEntry->Flags & LDRP_LOAD_IN_PROGRESS) {
  3450. return;
  3451. } else {
  3452. LdrDataTableEntry->Flags |= LDRP_LOAD_IN_PROGRESS;
  3453. }
  3454. break;
  3455. case LDRP_UPDATE_LOAD_COUNT_DECREMENT:
  3456. if (LdrDataTableEntry->Flags & LDRP_UNLOAD_IN_PROGRESS) {
  3457. return;
  3458. } else {
  3459. LdrDataTableEntry->Flags |= LDRP_UNLOAD_IN_PROGRESS;
  3460. }
  3461. break;
  3462. }
  3463. //
  3464. // For each DLL used by this DLL, reference or dereference the DLL.
  3465. //
  3466. if (LdrDataTableEntry->Flags & LDRP_COR_IMAGE) {
  3467. //
  3468. // The image is COR. Ignore its import table and make it import
  3469. // mscoree only.
  3470. //
  3471. UNICODE_STRING ImportName = RTL_CONSTANT_STRING(L"mscoree.dll");
  3472. if (LdrpCheckForLoadedDll( NULL,
  3473. &ImportName,
  3474. TRUE,
  3475. FALSE,
  3476. &Entry
  3477. )
  3478. ) {
  3479. if ( Entry->LoadCount != 0xffff ) {
  3480. PCSTR SnapString = NULL;
  3481. switch (UpdateCountHow) {
  3482. case LDRP_UPDATE_LOAD_COUNT_PIN:
  3483. Entry->LoadCount = 0xffff;
  3484. SnapString = "Pin";
  3485. break;
  3486. case LDRP_UPDATE_LOAD_COUNT_INCREMENT:
  3487. Entry->LoadCount++;
  3488. SnapString = "Refcount";
  3489. break;
  3490. case LDRP_UPDATE_LOAD_COUNT_DECREMENT:
  3491. Entry->LoadCount--;
  3492. SnapString = "Derefcount";
  3493. break;
  3494. }
  3495. if (ShowSnaps) {
  3496. DbgPrint("LDR: %s %wZ (%lx)\n",
  3497. SnapString,
  3498. &ImportName,
  3499. (ULONG)Entry->LoadCount
  3500. );
  3501. }
  3502. }
  3503. LdrpUpdateLoadCount3(Entry, UpdateCountHow, PreAllocatedRedirectionBuffer);
  3504. }
  3505. return;
  3506. }
  3507. ImportDescriptorName_U = &NtCurrentTeb()->StaticUnicodeString;
  3508. //
  3509. // See if there is a bound import table. If so, walk that to
  3510. // determine DLL names to reference or dereference. Avoids touching
  3511. // the .idata section
  3512. //
  3513. NewImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(
  3514. LdrDataTableEntry->DllBase,
  3515. TRUE,
  3516. IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
  3517. &NewImportSize
  3518. );
  3519. if (NewImportDescriptor) {
  3520. switch (UpdateCountHow) {
  3521. case LDRP_UPDATE_LOAD_COUNT_INCREMENT:
  3522. case LDRP_UPDATE_LOAD_COUNT_PIN:
  3523. LdrDataTableEntry->Flags |= LDRP_LOAD_IN_PROGRESS;
  3524. break;
  3525. case LDRP_UPDATE_LOAD_COUNT_DECREMENT:
  3526. LdrDataTableEntry->Flags |= LDRP_UNLOAD_IN_PROGRESS;
  3527. break;
  3528. }
  3529. NewImportStringBase = (LPSTR)NewImportDescriptor;
  3530. while (NewImportDescriptor->OffsetModuleName) {
  3531. ImportName = NewImportStringBase +
  3532. NewImportDescriptor->OffsetModuleName;
  3533. RtlInitAnsiString(&AnsiString, ImportName);
  3534. st = RtlAnsiStringToUnicodeString(ImportDescriptorName_U, &AnsiString, FALSE);
  3535. if ( NT_SUCCESS(st) ) {
  3536. BOOLEAN Redirected = FALSE;
  3537. ImportDescriptorNameToUse = ImportDescriptorName_U;
  3538. DynamicRedirectionString.Buffer = NULL;
  3539. st = RtlDosApplyFileIsolationRedirection_Ustr(
  3540. RTL_DOS_APPLY_FILE_REDIRECTION_USTR_FLAG_RESPECT_DOT_LOCAL,
  3541. ImportDescriptorName_U,
  3542. &DefaultExtension,
  3543. PreAllocatedRedirectionBuffer,
  3544. &DynamicRedirectionString,
  3545. &ImportDescriptorNameToUse,
  3546. NULL,
  3547. NULL,
  3548. NULL);
  3549. if (NT_SUCCESS(st)) {
  3550. Redirected = TRUE;
  3551. } else if (st == STATUS_SXS_KEY_NOT_FOUND) {
  3552. st = STATUS_SUCCESS;
  3553. }
  3554. if (NT_SUCCESS(st)) {
  3555. if (LdrpCheckForLoadedDll( NULL,
  3556. ImportDescriptorNameToUse,
  3557. TRUE,
  3558. Redirected,
  3559. &Entry
  3560. )
  3561. ) {
  3562. if ( Entry->LoadCount != 0xffff ) {
  3563. PCSTR SnapString = NULL;
  3564. switch (UpdateCountHow) {
  3565. case LDRP_UPDATE_LOAD_COUNT_PIN:
  3566. Entry->LoadCount = 0xffff;
  3567. SnapString = "Pin";
  3568. break;
  3569. case LDRP_UPDATE_LOAD_COUNT_INCREMENT:
  3570. Entry->LoadCount++;
  3571. SnapString = "Refcount";
  3572. break;
  3573. case LDRP_UPDATE_LOAD_COUNT_DECREMENT:
  3574. Entry->LoadCount--;
  3575. SnapString = "Derefcount";
  3576. break;
  3577. }
  3578. if (ShowSnaps) {
  3579. DbgPrint("LDR: %s %wZ (%lx)\n",
  3580. SnapString,
  3581. ImportDescriptorNameToUse,
  3582. (ULONG)Entry->LoadCount
  3583. );
  3584. }
  3585. }
  3586. LdrpUpdateLoadCount3(Entry, UpdateCountHow, PreAllocatedRedirectionBuffer);
  3587. }
  3588. if (DynamicRedirectionString.Buffer != NULL)
  3589. RtlFreeUnicodeString(&DynamicRedirectionString);
  3590. }
  3591. }
  3592. NewImportForwarder = (PIMAGE_BOUND_FORWARDER_REF)(NewImportDescriptor+1);
  3593. for (i=0; i<NewImportDescriptor->NumberOfModuleForwarderRefs; i++) {
  3594. ImportName = NewImportStringBase +
  3595. NewImportForwarder->OffsetModuleName;
  3596. RtlInitAnsiString(&AnsiString, ImportName);
  3597. st = RtlAnsiStringToUnicodeString(ImportDescriptorName_U, &AnsiString, FALSE);
  3598. if ( NT_SUCCESS(st) ) {
  3599. BOOLEAN Redirected = FALSE;
  3600. ImportDescriptorNameToUse = ImportDescriptorName_U;
  3601. DynamicRedirectionString.Buffer = NULL;
  3602. st = RtlDosApplyFileIsolationRedirection_Ustr(
  3603. RTL_DOS_APPLY_FILE_REDIRECTION_USTR_FLAG_RESPECT_DOT_LOCAL,
  3604. ImportDescriptorName_U,
  3605. &DefaultExtension,
  3606. PreAllocatedRedirectionBuffer,
  3607. &DynamicRedirectionString,
  3608. &ImportDescriptorNameToUse,
  3609. NULL,
  3610. NULL,
  3611. NULL);
  3612. if (NT_SUCCESS(st)) {
  3613. Redirected = TRUE;
  3614. } else if (st == STATUS_SXS_KEY_NOT_FOUND) {
  3615. st = STATUS_SUCCESS;
  3616. }
  3617. if (NT_SUCCESS(st)) {
  3618. if (LdrpCheckForLoadedDll( NULL,
  3619. ImportDescriptorNameToUse,
  3620. TRUE,
  3621. Redirected,
  3622. &Entry
  3623. )
  3624. ) {
  3625. if ( Entry->LoadCount != 0xffff ) {
  3626. PCSTR SnapString = NULL;
  3627. switch (UpdateCountHow) {
  3628. case LDRP_UPDATE_LOAD_COUNT_PIN:
  3629. Entry->LoadCount = 0xffff;
  3630. SnapString = "Pin";
  3631. break;
  3632. case LDRP_UPDATE_LOAD_COUNT_INCREMENT:
  3633. Entry->LoadCount++;
  3634. SnapString = "Refcount";
  3635. break;
  3636. case LDRP_UPDATE_LOAD_COUNT_DECREMENT:
  3637. Entry->LoadCount--;
  3638. SnapString = "Derefcount";
  3639. break;
  3640. }
  3641. if (ShowSnaps) {
  3642. DbgPrint("LDR: %s %wZ (%lx)\n",
  3643. SnapString,
  3644. ImportDescriptorNameToUse,
  3645. (ULONG)Entry->LoadCount
  3646. );
  3647. }
  3648. }
  3649. LdrpUpdateLoadCount3(Entry, UpdateCountHow, PreAllocatedRedirectionBuffer);
  3650. }
  3651. if (DynamicRedirectionString.Buffer != NULL)
  3652. RtlFreeUnicodeString(&DynamicRedirectionString);
  3653. }
  3654. }
  3655. NewImportForwarder += 1;
  3656. }
  3657. NewImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)NewImportForwarder;
  3658. }
  3659. return;
  3660. }
  3661. ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(
  3662. LdrDataTableEntry->DllBase,
  3663. TRUE,
  3664. IMAGE_DIRECTORY_ENTRY_IMPORT,
  3665. &ImportSize
  3666. );
  3667. if (ImportDescriptor) {
  3668. while (ImportDescriptor->Name && ImportDescriptor->FirstThunk) {
  3669. //
  3670. // Match code in walk that skips references like this. IE3 had
  3671. // some dll's with these bogus links to url.dll. On load, the url.dll
  3672. // ref was skipped. On unload, it was not skipped because
  3673. // this code was missing.
  3674. //
  3675. // Since the skip logic is only in the old style import
  3676. // descriptor path, it is only duplicated here.
  3677. //
  3678. // check for import that has no references
  3679. //
  3680. FirstThunk = (PIMAGE_THUNK_DATA)((ULONG_PTR)LdrDataTableEntry->DllBase + ImportDescriptor->FirstThunk);
  3681. if ( !FirstThunk->u1.Function ) {
  3682. goto skipskippedimport;
  3683. }
  3684. ImportName = (PSZ)((ULONG_PTR)LdrDataTableEntry->DllBase + ImportDescriptor->Name);
  3685. RtlInitAnsiString(&AnsiString, ImportName);
  3686. st = RtlAnsiStringToUnicodeString(ImportDescriptorName_U, &AnsiString, FALSE);
  3687. if ( NT_SUCCESS(st) ) {
  3688. BOOLEAN Redirected = FALSE;
  3689. ImportDescriptorNameToUse = ImportDescriptorName_U;
  3690. DynamicRedirectionString.Buffer = NULL;
  3691. st = RtlDosApplyFileIsolationRedirection_Ustr(
  3692. RTL_DOS_APPLY_FILE_REDIRECTION_USTR_FLAG_RESPECT_DOT_LOCAL,
  3693. ImportDescriptorName_U,
  3694. &DefaultExtension,
  3695. PreAllocatedRedirectionBuffer,
  3696. &DynamicRedirectionString,
  3697. &ImportDescriptorNameToUse,
  3698. NULL,
  3699. NULL,
  3700. NULL);
  3701. if (NT_SUCCESS(st)) {
  3702. Redirected = TRUE;
  3703. } else if (st == STATUS_SXS_KEY_NOT_FOUND) {
  3704. st = STATUS_SUCCESS;
  3705. }
  3706. if (NT_SUCCESS(st)) {
  3707. if (LdrpCheckForLoadedDll( NULL,
  3708. ImportDescriptorNameToUse,
  3709. TRUE,
  3710. Redirected,
  3711. &Entry
  3712. )
  3713. ) {
  3714. if ( Entry->LoadCount != 0xffff ) {
  3715. PCSTR SnapString = NULL;
  3716. switch (UpdateCountHow) {
  3717. case LDRP_UPDATE_LOAD_COUNT_PIN:
  3718. Entry->LoadCount = 0xffff;
  3719. SnapString = "Pin";
  3720. break;
  3721. case LDRP_UPDATE_LOAD_COUNT_INCREMENT:
  3722. Entry->LoadCount++;
  3723. SnapString = "Refcount";
  3724. break;
  3725. case LDRP_UPDATE_LOAD_COUNT_DECREMENT:
  3726. Entry->LoadCount--;
  3727. SnapString = "Derefcount";
  3728. break;
  3729. }
  3730. if (ShowSnaps) {
  3731. DbgPrint("LDR: %s %wZ (%lx)\n",
  3732. SnapString,
  3733. ImportDescriptorNameToUse,
  3734. (ULONG)Entry->LoadCount
  3735. );
  3736. }
  3737. }
  3738. LdrpUpdateLoadCount3(Entry, UpdateCountHow, PreAllocatedRedirectionBuffer);
  3739. }
  3740. if (DynamicRedirectionString.Buffer != NULL) {
  3741. RtlFreeUnicodeString(&DynamicRedirectionString);
  3742. }
  3743. }
  3744. }
  3745. skipskippedimport:
  3746. ++ImportDescriptor;
  3747. }
  3748. }
  3749. } __finally {
  3750. RtlDeactivateActivationContextUnsafeFast(&ActivationFrame);
  3751. }
  3752. }
  3753. VOID
  3754. LdrpInsertMemoryTableEntry (
  3755. IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry
  3756. )
  3757. /*++
  3758. Routine Description:
  3759. This function inserts a loader data table entry into the
  3760. list of loaded modules for this process. The insertion is
  3761. done in "image memory base order".
  3762. Arguments:
  3763. LdrDataTableEntry - Supplies the address of the loader data table
  3764. entry to insert in the list of loaded modules for this process.
  3765. Return Value:
  3766. None.
  3767. --*/
  3768. {
  3769. PPEB_LDR_DATA Ldr;
  3770. ULONG i;
  3771. Ldr = NtCurrentPeb()->Ldr;
  3772. i = LDRP_COMPUTE_HASH_INDEX(LdrDataTableEntry->BaseDllName.Buffer[0]);
  3773. InsertTailList(&LdrpHashTable[i],&LdrDataTableEntry->HashLinks);
  3774. InsertTailList(&Ldr->InLoadOrderModuleList, &LdrDataTableEntry->InLoadOrderLinks);
  3775. #if defined(_AMD64_) // || defined(_IA64_)
  3776. RtlInsertInvertedFunctionTable(&LdrpInvertedFunctionTable,
  3777. LdrDataTableEntry->DllBase,
  3778. LdrDataTableEntry->SizeOfImage);
  3779. #endif
  3780. InsertTailList(&Ldr->InMemoryOrderModuleList, &LdrDataTableEntry->InMemoryOrderLinks);
  3781. }
  3782. NTSTATUS
  3783. LdrpResolveDllName (
  3784. IN PWSTR DllPath OPTIONAL,
  3785. IN PWSTR DllName,
  3786. IN BOOLEAN Redirected,
  3787. OUT PUNICODE_STRING FullDllNameOut,
  3788. OUT PUNICODE_STRING BaseDllNameOut,
  3789. OUT PHANDLE DllFile
  3790. )
  3791. /*++
  3792. Routine Description:
  3793. This function computes the DLL pathname and base dll name (the
  3794. unqualified, extensionless portion of the file name) for the specified
  3795. DLL.
  3796. Arguments:
  3797. DllPath - Supplies the DLL search path.
  3798. DllName - Supplies the name of the DLL.
  3799. FullDllName - Returns the fully qualified pathname of the
  3800. DLL. The Buffer field of this string is dynamically
  3801. allocated from the loader heap.
  3802. BaseDLLName - Returns the base dll name of the dll. The base name
  3803. is the file name portion of the dll path without the trailing
  3804. extension. The Buffer field of this string points into the
  3805. FullDllName since the one is a substring of the other.
  3806. DllFile - Returns an open handle to the DLL file. This parameter may
  3807. still be NULL even upon success.
  3808. Return Value:
  3809. TRUE - The operation was successful. A DLL file was found, and the
  3810. FullDllName->Buffer & BaseDllName->Buffer field points to the
  3811. base of process heap allocated memory.
  3812. FALSE - The DLL could not be found.
  3813. --*/
  3814. {
  3815. PWCH p, pp;
  3816. PWCH FullBuffer = NULL;
  3817. NTSTATUS st = STATUS_INTERNAL_ERROR;
  3818. UNICODE_STRING DllNameString = { 0, 0, NULL };
  3819. UNICODE_STRING FullDllName = { 0, 0, NULL };
  3820. UNICODE_STRING BaseDllName = { 0, 0, NULL };
  3821. USHORT PrefixLength = 0;
  3822. PCWSTR EffectiveDllPath = (DllPath != NULL) ? DllPath : LdrpDefaultPath.Buffer;
  3823. WCHAR TempBuffer[40]; // Arbitrary short length so most d:\windows\system32\foobar.dll loads don't need to search the search path twice
  3824. if (DllFile != NULL)
  3825. *DllFile = NULL;
  3826. if (FullDllNameOut != NULL) {
  3827. FullDllNameOut->Length = 0;
  3828. FullDllNameOut->MaximumLength = 0;
  3829. FullDllNameOut->Buffer = NULL;
  3830. }
  3831. if (BaseDllNameOut != NULL) {
  3832. BaseDllNameOut->Length = 0;
  3833. BaseDllNameOut->MaximumLength = 0;
  3834. BaseDllNameOut->Buffer = NULL;
  3835. }
  3836. if ((DllFile == NULL) ||
  3837. (FullDllNameOut == NULL) ||
  3838. (BaseDllNameOut == NULL)) {
  3839. st = STATUS_INVALID_PARAMETER;
  3840. goto Exit;
  3841. }
  3842. RtlInitUnicodeString(&DllNameString, DllName);
  3843. // Look for ".local" redirection for this DLL.
  3844. st = LdrpResolveDllNameForAppPrivateRedirection(&DllNameString, &FullDllName);
  3845. if (!NT_SUCCESS(st)) {
  3846. DbgPrintEx(
  3847. DPFLTR_LDR_ID,
  3848. LDR_ERROR_DPFLTR,
  3849. "LDR: %s failed calling LdrpResolveDllNameForAppPrivateRediretion with status %lx\n",
  3850. __FUNCTION__,
  3851. st);
  3852. goto Exit;
  3853. }
  3854. // .local always wins, so only search other solutions if that wasn't the answer.
  3855. if (FullDllName.Length == 0) {
  3856. if (Redirected) {
  3857. // If the path was redirected, we assume that DllNameString is an absolute path to
  3858. // the DLL so there's nothing more to do.
  3859. st = LdrpCopyUnicodeString(&FullDllName, &DllNameString);
  3860. if (!NT_SUCCESS(st)) {
  3861. DbgPrintEx(
  3862. DPFLTR_LDR_ID,
  3863. LDR_ERROR_DPFLTR,
  3864. "LDR: %s failed call to LdrpCopyUnicodeString() in redirected case; status = %lx\n",
  3865. __FUNCTION__,
  3866. st);
  3867. goto Exit;
  3868. }
  3869. } else {
  3870. ULONG Length;
  3871. // Having an excessively long buffer could break code later that assumes
  3872. // that comparisons against the size of the buffer ensure that casting
  3873. // to USHORT is safe.
  3874. ASSERT(sizeof(TempBuffer) <= UNICODE_STRING_MAX_BYTES);
  3875. // Not redirected; search the search path.
  3876. Length = RtlDosSearchPath_U(
  3877. EffectiveDllPath,
  3878. DllName,
  3879. NULL,
  3880. sizeof(TempBuffer),
  3881. TempBuffer,
  3882. NULL);
  3883. if (Length == 0) {
  3884. if (ShowSnaps) {
  3885. DbgPrintEx(
  3886. DPFLTR_LDR_ID,
  3887. LDR_ERROR_DPFLTR,
  3888. "LDR: %s - call to RtlDosSearchPath_U failed\n",
  3889. __FUNCTION__);
  3890. DbgPrintEx(
  3891. DPFLTR_LDR_ID,
  3892. LDR_ERROR_DPFLTR,
  3893. " DllName: \"%ws\"\n",
  3894. DllName);
  3895. DbgPrintEx(
  3896. DPFLTR_LDR_ID,
  3897. LDR_ERROR_DPFLTR,
  3898. " Path: \"%ws\"\n",
  3899. EffectiveDllPath);
  3900. }
  3901. st = STATUS_DLL_NOT_FOUND;
  3902. goto Exit;
  3903. }
  3904. if (Length > UNICODE_STRING_MAX_BYTES) {
  3905. if (ShowSnaps)
  3906. DbgPrint(
  3907. "LDR: LdrResolveDllName - Failing resolution because found path too long (%u bytes; max is %u bytes)\n",
  3908. Length,
  3909. UNICODE_STRING_MAX_BYTES);
  3910. st = STATUS_NAME_TOO_LONG;
  3911. goto Exit;
  3912. }
  3913. st = LdrpAllocateUnicodeString(&FullDllName, (USHORT) Length);
  3914. if (!NT_SUCCESS(st)) {
  3915. DbgPrintEx(
  3916. DPFLTR_LDR_ID,
  3917. LDR_ERROR_DPFLTR,
  3918. "LDR: %s - failed to allocate string for full dll name; length requested: %u\n",
  3919. __FUNCTION__,
  3920. Length);
  3921. goto Exit;
  3922. }
  3923. // If the original stack buffer wasn't large enough, use the dynamically allocated one.
  3924. if (Length > sizeof(TempBuffer)) {
  3925. ULONG Length2 = RtlDosSearchPath_U(
  3926. EffectiveDllPath,
  3927. DllName,
  3928. NULL,
  3929. FullDllName.MaximumLength,
  3930. FullDllName.Buffer,
  3931. NULL);
  3932. FullDllName.Length = (USHORT) Length2;
  3933. // It's entirely possible that in a race condition here, the size of the filename required is
  3934. // even longer.
  3935. if (Length2 == 0) {
  3936. if (ShowSnaps) {
  3937. DbgPrintEx(
  3938. DPFLTR_LDR_ID,
  3939. LDR_ERROR_DPFLTR,
  3940. "LDR: %s - call to RtlDosSearchPath_U failed\n",
  3941. __FUNCTION__);
  3942. DbgPrintEx(
  3943. DPFLTR_LDR_ID,
  3944. LDR_ERROR_DPFLTR,
  3945. " DllName: \"%ws\"\n",
  3946. DllName);
  3947. DbgPrintEx(
  3948. DPFLTR_LDR_ID,
  3949. LDR_ERROR_DPFLTR,
  3950. " Path: \"%ws\"\n",
  3951. EffectiveDllPath);
  3952. }
  3953. LdrpFreeUnicodeString(&FullDllName);
  3954. st = STATUS_DLL_NOT_FOUND;
  3955. goto Exit;
  3956. } else if (Length2 > FullDllName.MaximumLength) {
  3957. if (ShowSnaps)
  3958. DbgPrint(
  3959. "LDR: %s - Required path length required for %ws changed from %lu to %lu; try launching the app again.\n",
  3960. __FUNCTION__,
  3961. DllName,
  3962. Length,
  3963. Length2);
  3964. LdrpFreeUnicodeString(&FullDllName);
  3965. st = STATUS_DLL_NOT_FOUND;
  3966. goto Exit;
  3967. } else if (Length2 < Length) {
  3968. // If the name shrunk, the trailing null character won't be there, so we put it
  3969. // in ourselves...
  3970. FullDllName.Buffer[Length2 / sizeof(WCHAR)] = L'\0';
  3971. }
  3972. } else {
  3973. // Note that LdrpAllocateUnicodeString() already put the null at the character after "Length".
  3974. FullDllName.Length = (USHORT) Length;
  3975. RtlCopyMemory(FullDllName.Buffer, TempBuffer, Length);
  3976. }
  3977. }
  3978. }
  3979. *FullDllNameOut = FullDllName;
  3980. RtlInitEmptyUnicodeString(&FullDllName, NULL, 0);
  3981. //
  3982. // Compute Length of base dll name
  3983. //
  3984. st = RtlFindCharInUnicodeString(
  3985. RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END,
  3986. FullDllNameOut,
  3987. &RtlDosPathSeperatorsString,
  3988. &PrefixLength);
  3989. if (st == STATUS_NOT_FOUND) {
  3990. *BaseDllNameOut = *FullDllNameOut;
  3991. } else if (!NT_SUCCESS(st)) {
  3992. DbgPrintEx(
  3993. DPFLTR_LDR_ID,
  3994. LDR_ERROR_DPFLTR,
  3995. "LDR: %s - failing because RtlFindCharInUnicodeString failed with status %x\n",
  3996. __FUNCTION__,
  3997. st);
  3998. goto Exit;
  3999. } else {
  4000. // The prefixlength is the number of bytes prior to the path separator. We also want to skip
  4001. // the path separator.
  4002. PrefixLength += sizeof(WCHAR);
  4003. BaseDllNameOut->Length = FullDllNameOut->Length - PrefixLength;
  4004. BaseDllNameOut->MaximumLength = FullDllNameOut->MaximumLength - PrefixLength;
  4005. BaseDllNameOut->Buffer = (PWSTR) (((ULONG_PTR) FullDllNameOut->Buffer) + PrefixLength);
  4006. }
  4007. st = STATUS_SUCCESS;
  4008. Exit:
  4009. ASSERT(st != STATUS_INTERNAL_ERROR);
  4010. return st;
  4011. }
  4012. PVOID
  4013. LdrpFetchAddressOfEntryPoint (
  4014. IN PVOID Base
  4015. )
  4016. /*++
  4017. Routine Description:
  4018. This function returns the address of the initialization routine.
  4019. Arguments:
  4020. Base - Base of image.
  4021. Return Value:
  4022. Status value
  4023. --*/
  4024. {
  4025. PIMAGE_NT_HEADERS NtHeaders;
  4026. ULONG_PTR ep;
  4027. NtHeaders = RtlImageNtHeader(Base);
  4028. if (NtHeaders == NULL)
  4029. return NULL;
  4030. ep = NtHeaders->OptionalHeader.AddressOfEntryPoint;
  4031. if (ep != 0)
  4032. ep += (ULONG_PTR) Base;
  4033. return (PVOID) ep;
  4034. }
  4035. NTSTATUS
  4036. LdrpCheckForKnownDll(
  4037. IN PWSTR DllName,
  4038. OUT PUNICODE_STRING FullDllNameOut,
  4039. OUT PUNICODE_STRING BaseDllNameOut,
  4040. OUT HANDLE *SectionOut
  4041. )
  4042. /*++
  4043. Routine Description:
  4044. This function checks to see if the specified DLL is a known DLL.
  4045. It assumes it is only called for static DLL's, and when
  4046. the known DLL directory structure has been set up.
  4047. Arguments:
  4048. DllName - Supplies the name of the DLL.
  4049. FullDllName - Returns the fully qualified pathname of the
  4050. DLL. The Buffer field of this string is dynamically
  4051. allocated from the processes heap.
  4052. BaseDLLName - Returns the base dll name of the dll. The base name
  4053. is the file name portion of the dll path without the trailing
  4054. extension. The Buffer field of this string is dynamically
  4055. allocated from the processes heap.
  4056. Return Value:
  4057. NON-NULL - Returns an open handle to the section associated with
  4058. the DLL.
  4059. NULL - The DLL is not known.
  4060. --*/
  4061. {
  4062. UNICODE_STRING Unicode;
  4063. HANDLE Section = NULL;
  4064. NTSTATUS Status;
  4065. OBJECT_ATTRIBUTES Obja;
  4066. PSZ p;
  4067. PWSTR pw;
  4068. ULONG FullLength = 0;
  4069. UNICODE_STRING FullDllName = { 0, 0, NULL };
  4070. if (SectionOut != NULL)
  4071. *SectionOut = NULL;
  4072. if (FullDllNameOut != NULL) {
  4073. FullDllNameOut->Length = 0;
  4074. FullDllNameOut->MaximumLength = 0;
  4075. FullDllNameOut->Buffer = NULL;
  4076. }
  4077. if (BaseDllNameOut != NULL) {
  4078. BaseDllNameOut->Length = 0;
  4079. BaseDllNameOut->MaximumLength = 0;
  4080. BaseDllNameOut->Buffer = NULL;
  4081. }
  4082. if ((SectionOut == NULL) ||
  4083. (FullDllNameOut == NULL) ||
  4084. (BaseDllNameOut == NULL)) {
  4085. Status = STATUS_INVALID_PARAMETER;
  4086. goto Exit;
  4087. }
  4088. LdrpEnsureLoaderLockIsHeld();
  4089. //
  4090. // calculate base name
  4091. //
  4092. RtlInitUnicodeString(&Unicode, DllName);
  4093. //check DLL_REDIRECTION by .local file
  4094. if ((NtCurrentPeb()->ProcessParameters != NULL) &&
  4095. (NtCurrentPeb()->ProcessParameters->Flags & RTL_USER_PROC_DLL_REDIRECTION_LOCAL) &&
  4096. (Unicode.Length != 0)) { // dll redirection with .local
  4097. UNICODE_STRING NewDllNameUnderImageDir, NewDllNameUnderLocalDir;
  4098. static WCHAR DllNameUnderImageDirBuffer[DOS_MAX_PATH_LENGTH];
  4099. static WCHAR DllNameUnderLocalDirBuffer[DOS_MAX_PATH_LENGTH];
  4100. BOOLEAN fIsKnownDll = TRUE; // not know yet,
  4101. NewDllNameUnderImageDir.Buffer = DllNameUnderImageDirBuffer;
  4102. NewDllNameUnderImageDir.Length = 0 ;
  4103. NewDllNameUnderImageDir.MaximumLength = sizeof(DllNameUnderImageDirBuffer) ;
  4104. NewDllNameUnderLocalDir.Buffer = DllNameUnderLocalDirBuffer;
  4105. NewDllNameUnderLocalDir.Length = 0 ;
  4106. NewDllNameUnderLocalDir.MaximumLength = sizeof(DllNameUnderLocalDirBuffer) ;
  4107. Status = RtlComputePrivatizedDllName_U(&Unicode, &NewDllNameUnderImageDir, &NewDllNameUnderLocalDir) ;
  4108. if(!NT_SUCCESS(Status))
  4109. goto Exit;
  4110. if ((RtlDoesFileExists_U(NewDllNameUnderLocalDir.Buffer)) ||
  4111. (RtlDoesFileExists_U(NewDllNameUnderImageDir.Buffer)))
  4112. fIsKnownDll = FALSE;
  4113. //cleanup
  4114. if (NewDllNameUnderLocalDir.Buffer != DllNameUnderLocalDirBuffer)
  4115. (*RtlFreeStringRoutine)(NewDllNameUnderLocalDir.Buffer);
  4116. if (NewDllNameUnderImageDir.Buffer != DllNameUnderImageDirBuffer)
  4117. (*RtlFreeStringRoutine)(NewDllNameUnderImageDir.Buffer);
  4118. if (!fIsKnownDll) { // must not be a known dll
  4119. Status = STATUS_SUCCESS;
  4120. goto Exit;
  4121. }
  4122. }
  4123. // If the DLL is being redirected via Fusion/Side-by-Side support, don't bother with the
  4124. // KnownDLL mechanism.
  4125. Status = RtlFindActivationContextSectionString(
  4126. 0, // flags - none for now
  4127. NULL, // default section group
  4128. ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
  4129. &Unicode, // string to look for
  4130. NULL); // we don't want any data back, just look for existence
  4131. if ((Status != STATUS_SXS_SECTION_NOT_FOUND) &&
  4132. (Status != STATUS_SXS_KEY_NOT_FOUND))
  4133. {
  4134. if (!NT_SUCCESS(Status))
  4135. goto Exit;
  4136. Status = STATUS_SUCCESS;
  4137. goto Exit;
  4138. }
  4139. //
  4140. // now compute the full name for the dll
  4141. //
  4142. FullLength = LdrpKnownDllPath.Length + // path prefix e.g. c:\windows\system32
  4143. RtlCanonicalDosPathSeperatorString.Length +
  4144. Unicode.Length; // base
  4145. if (FullLength > UNICODE_STRING_MAX_BYTES) {
  4146. Status = STATUS_NAME_TOO_LONG;
  4147. goto Exit;
  4148. }
  4149. Status = LdrpAllocateUnicodeString(&FullDllName, (USHORT) FullLength);
  4150. if (!NT_SUCCESS(Status))
  4151. goto Exit;
  4152. RtlAppendUnicodeStringToString(&FullDllName, &LdrpKnownDllPath);
  4153. RtlAppendUnicodeStringToString(&FullDllName, &RtlCanonicalDosPathSeperatorString);
  4154. RtlAppendUnicodeStringToString(&FullDllName, &Unicode);
  4155. ASSERT(FullDllName.Length == FullLength);
  4156. //
  4157. // open the section object
  4158. //
  4159. InitializeObjectAttributes(
  4160. &Obja,
  4161. &Unicode,
  4162. OBJ_CASE_INSENSITIVE,
  4163. LdrpKnownDllObjectDirectory,
  4164. NULL
  4165. );
  4166. Status = NtOpenSection(
  4167. &Section,
  4168. SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_MAP_WRITE,
  4169. &Obja);
  4170. if (!NT_SUCCESS(Status)) {
  4171. // STATUS_OBJECT_NAME_NOT_FOUND is the expected reason to fail, so it's OK
  4172. if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  4173. Status = STATUS_SUCCESS;
  4174. goto Exit;
  4175. }
  4176. #if DBG
  4177. LdrpSectionOpens++;
  4178. #endif // DBG
  4179. BaseDllNameOut->Length = Unicode.Length;
  4180. BaseDllNameOut->MaximumLength = Unicode.Length + sizeof(WCHAR);
  4181. BaseDllNameOut->Buffer = (PWSTR) (((ULONG_PTR) FullDllName.Buffer) + (FullDllName.Length - Unicode.Length));
  4182. *FullDllNameOut = FullDllName;
  4183. FullDllName.Length = 0;
  4184. FullDllName.MaximumLength = 0;
  4185. FullDllName.Buffer = NULL;
  4186. *SectionOut = Section;
  4187. Section = NULL;
  4188. Status = STATUS_SUCCESS;
  4189. Exit:
  4190. if (Section != NULL)
  4191. NtClose(Section);
  4192. if (FullDllName.Buffer != NULL)
  4193. LdrpFreeUnicodeString(&FullDllName);
  4194. return Status;
  4195. }
  4196. NTSTATUS
  4197. LdrpSetProtection (
  4198. IN PVOID Base,
  4199. IN BOOLEAN Reset,
  4200. IN BOOLEAN StaticLink
  4201. )
  4202. /*++
  4203. Routine Description:
  4204. This function loops thru the images sections/objects, setting
  4205. all sections/objects marked r/o to r/w. It also resets the
  4206. original section/object protections.
  4207. Arguments:
  4208. Base - Base of image.
  4209. Reset - If TRUE, reset section/object protection to original
  4210. protection described by the section/object headers.
  4211. If FALSE, then set all sections/objects to r/w.
  4212. StaticLink - TRUE if this is a static link.
  4213. Return Value:
  4214. SUCCESS or reason NtProtectVirtualMemory failed.
  4215. --*/
  4216. {
  4217. HANDLE CurrentProcessHandle;
  4218. SIZE_T RegionSize;
  4219. ULONG NewProtect, OldProtect;
  4220. PVOID VirtualAddress;
  4221. ULONG i;
  4222. PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
  4223. PIMAGE_NT_HEADERS NtHeaders;
  4224. PIMAGE_SECTION_HEADER SectionHeader;
  4225. NTSTATUS st;
  4226. CurrentProcessHandle = NtCurrentProcess();
  4227. NtHeaders = RtlImageNtHeader(Base);
  4228. if (! NtHeaders) {
  4229. return STATUS_INVALID_IMAGE_FORMAT;
  4230. }
  4231. #if defined(BUILD_WOW6432)
  4232. if (NtHeaders->OptionalHeader.SectionAlignment < NATIVE_PAGE_SIZE) {
  4233. //
  4234. // if SectionAlignment < PAGE_SIZE the entire image is
  4235. // exec-copy on write, so we have nothing to do.
  4236. //
  4237. return STATUS_SUCCESS;
  4238. }
  4239. #endif
  4240. SectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)NtHeaders + sizeof(ULONG) +
  4241. sizeof(IMAGE_FILE_HEADER) +
  4242. NtHeaders->FileHeader.SizeOfOptionalHeader
  4243. );
  4244. for (i=0; i<NtHeaders->FileHeader.NumberOfSections; i++) {
  4245. if (!(SectionHeader->Characteristics & IMAGE_SCN_MEM_WRITE) &&
  4246. (SectionHeader->SizeOfRawData))
  4247. {
  4248. //
  4249. // Object isn't writeable and has a non-zero on disk size, change it.
  4250. //
  4251. if (Reset) {
  4252. if (SectionHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE) {
  4253. NewProtect = PAGE_EXECUTE;
  4254. } else {
  4255. NewProtect = PAGE_READONLY;
  4256. }
  4257. NewProtect |= (SectionHeader->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) ? PAGE_NOCACHE : 0;
  4258. } else {
  4259. NewProtect = PAGE_READWRITE;
  4260. }
  4261. VirtualAddress = (PVOID)((ULONG_PTR)Base + SectionHeader->VirtualAddress);
  4262. RegionSize = SectionHeader->SizeOfRawData;
  4263. if (RegionSize != 0) {
  4264. st = NtProtectVirtualMemory(CurrentProcessHandle, &VirtualAddress,
  4265. &RegionSize, NewProtect, &OldProtect);
  4266. if (!NT_SUCCESS(st)) {
  4267. return st;
  4268. }
  4269. }
  4270. }
  4271. ++SectionHeader;
  4272. }
  4273. if (Reset) {
  4274. NtFlushInstructionCache(NtCurrentProcess(), NULL, 0);
  4275. }
  4276. return STATUS_SUCCESS;
  4277. }
  4278. NTSTATUS
  4279. LdrpResolveDllNameForAppPrivateRedirection(
  4280. PCUNICODE_STRING DllNameString,
  4281. PUNICODE_STRING FullDllName
  4282. )
  4283. /*++
  4284. Routine Description:
  4285. This function takes a DLL name that's to be loaded, and if there was
  4286. a .local file in the app dir to cause redirection, returns the full
  4287. path to the file.
  4288. Arguments:
  4289. DllNameString - Name of the DLL under consideration. May be a full or
  4290. partially qualified path.
  4291. FullDllName - output string. Must be deallocated using
  4292. LdrpFreeUnicodeString(). If no redirection was present, the
  4293. length will be left zero.
  4294. Return Value:
  4295. NTSTATUS indicating the success/failure of this function.
  4296. --*/
  4297. {
  4298. NTSTATUS st = STATUS_INTERNAL_ERROR;
  4299. UNICODE_STRING FullDllNameUnderImageDir;
  4300. UNICODE_STRING FullDllNameUnderLocalDir;
  4301. // These two are static to relieve some stack size issues; this function is only called with the
  4302. // loader lock taken so access is properly synchronized.
  4303. static WCHAR DllNameUnderImageDirBuffer[DOS_MAX_PATH_LENGTH];
  4304. static WCHAR DllNameUnderLocalDirBuffer[DOS_MAX_PATH_LENGTH];
  4305. // Initialize these so that cleanup at the Exit: label an always just check whether
  4306. // they're not null and don't point to the static buffers and then free them.
  4307. FullDllNameUnderImageDir.Buffer = DllNameUnderImageDirBuffer;
  4308. FullDllNameUnderImageDir.Length = 0 ;
  4309. FullDllNameUnderImageDir.MaximumLength = sizeof(DllNameUnderImageDirBuffer);
  4310. FullDllNameUnderLocalDir.Buffer = DllNameUnderLocalDirBuffer;
  4311. FullDllNameUnderLocalDir.Length = 0 ;
  4312. FullDllNameUnderLocalDir.MaximumLength = sizeof(DllNameUnderLocalDirBuffer);
  4313. if (FullDllName != NULL) {
  4314. FullDllName->Length = 0;
  4315. FullDllName->MaximumLength = 0;
  4316. FullDllName->Buffer = NULL;
  4317. }
  4318. if ((FullDllName == NULL) ||
  4319. (DllNameString == NULL)) {
  4320. st = STATUS_INVALID_PARAMETER;
  4321. goto Exit;
  4322. }
  4323. st = RtlValidateUnicodeString(0, DllNameString);
  4324. if (!NT_SUCCESS(st))
  4325. goto Exit;
  4326. if ((NtCurrentPeb()->ProcessParameters != NULL) &&
  4327. (NtCurrentPeb()->ProcessParameters->Flags & RTL_USER_PROC_DLL_REDIRECTION_LOCAL) &&
  4328. (DllNameString->Length != 0)) { // dll redirection with .local
  4329. st = RtlComputePrivatizedDllName_U(DllNameString, &FullDllNameUnderImageDir, &FullDllNameUnderLocalDir);
  4330. if(!NT_SUCCESS(st)) {
  4331. DbgPrintEx(
  4332. DPFLTR_LDR_ID,
  4333. DPFLTR_ERROR_LEVEL,
  4334. "LDR: %s call to RtlComputePrivatizedDllName_U() failed with status %lx\n",
  4335. __FUNCTION__,
  4336. st);
  4337. goto Exit;
  4338. }
  4339. if (RtlDoesFileExists_U(FullDllNameUnderLocalDir.Buffer)) {// there is a local dll, use it
  4340. st = LdrpCopyUnicodeString(FullDllName, &FullDllNameUnderLocalDir);
  4341. if (!NT_SUCCESS(st)) {
  4342. if (ShowSnaps)
  4343. DbgPrintEx(
  4344. DPFLTR_LDR_ID,
  4345. DPFLTR_ERROR_LEVEL,
  4346. "LDR: %s calling LdrpCopyUnicodeString() failed; exiting with status %lx\n",
  4347. __FUNCTION__,
  4348. st);
  4349. goto Exit;
  4350. }
  4351. } else if (RtlDoesFileExists_U(FullDllNameUnderImageDir.Buffer)) { // there is a local dll, use it
  4352. st = LdrpCopyUnicodeString(FullDllName, &FullDllNameUnderImageDir);
  4353. if (!NT_SUCCESS(st)) {
  4354. if (ShowSnaps)
  4355. DbgPrintEx(
  4356. DPFLTR_LDR_ID,
  4357. DPFLTR_ERROR_LEVEL,
  4358. "LDR: %s calling LdrpCopyUnicodeString() failed; exiting with status %lx\n",
  4359. __FUNCTION__,
  4360. st);
  4361. goto Exit;
  4362. }
  4363. }
  4364. }
  4365. st = STATUS_SUCCESS;
  4366. Exit:
  4367. if ((FullDllNameUnderImageDir.Buffer != NULL) &&
  4368. (FullDllNameUnderImageDir.Buffer != DllNameUnderImageDirBuffer))
  4369. (*RtlFreeStringRoutine)(FullDllNameUnderImageDir.Buffer);
  4370. if ((FullDllNameUnderLocalDir.Buffer != NULL) &&
  4371. (FullDllNameUnderLocalDir.Buffer != DllNameUnderLocalDirBuffer))
  4372. (*RtlFreeStringRoutine)(FullDllNameUnderLocalDir.Buffer);
  4373. return st;
  4374. }