Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5536 lines
183 KiB

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