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.

3024 lines
89 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. ldrapi.c
  5. Abstract:
  6. This module implements the Ldr APIs that can be linked with
  7. an application to perform loader services. All of the APIs in
  8. this component are implemented in a DLL. They are not part of the
  9. DLL snap procedure.
  10. Author:
  11. Mike O'Leary (mikeol) 23-Mar-1990
  12. Revision History:
  13. --*/
  14. #include "ldrp.h"
  15. #include "ntos.h"
  16. #include "nt.h"
  17. #include "ntrtl.h"
  18. #include "nturtl.h"
  19. #include "objidl.h"
  20. #include <windows.h>
  21. #include <apcompat.h>
  22. #include <shimhapi.h>
  23. #if defined(_WIN64)
  24. #include <wow64t.h>
  25. #endif // defined(_WIN64)
  26. #define ULONG_PTR_IZE(_x) ((ULONG_PTR) (_x))
  27. #define ULONG_PTR_IZE_SHIFT_AND_MASK(_x, _shift, _mask) ((ULONG_PTR) ((ULONG_PTR_IZE((_x)) & (_mask)) << (_shift)))
  28. #define CHAR_BITS 8
  29. #define LOADER_LOCK_COOKIE_TYPE_BIT_LENGTH (4)
  30. #define LOADER_LOCK_COOKIE_TYPE_BIT_OFFSET ((CHAR_BITS * sizeof(PVOID)) - LOADER_LOCK_COOKIE_TYPE_BIT_LENGTH)
  31. #define LOADER_LOCK_COOKIE_TYPE_BIT_MASK ((1 << LOADER_LOCK_COOKIE_TYPE_BIT_LENGTH) - 1)
  32. #define LOADER_LOCK_COOKIE_TID_BIT_LENGTH (12)
  33. #define LOADER_LOCK_COOKIE_TID_BIT_OFFSET (LOADER_LOCK_COOKIE_TYPE_BIT_OFFSET - LOADER_LOCK_COOKIE_TID_BIT_LENGTH)
  34. #define LOADER_LOCK_COOKIE_TID_BIT_MASK ((1 << LOADER_LOCK_COOKIE_TID_BIT_LENGTH) - 1)
  35. #define LOADER_LOCK_COOKIE_CODE_BIT_LENGTH (16)
  36. #define LOADER_LOCK_COOKIE_CODE_BIT_OFFSET (0)
  37. #define LOADER_LOCK_COOKIE_CODE_BIT_MASK ((1 << LOADER_LOCK_COOKIE_CODE_BIT_LENGTH) - 1)
  38. #define MAKE_LOADER_LOCK_COOKIE(_type, _code) \
  39. ((ULONG_PTR) (ULONG_PTR_IZE_SHIFT_AND_MASK((_type), LOADER_LOCK_COOKIE_TYPE_BIT_OFFSET, LOADER_LOCK_COOKIE_TYPE_BIT_MASK) | \
  40. ULONG_PTR_IZE_SHIFT_AND_MASK((HandleToUlong((NtCurrentTeb())->ClientId.UniqueThread)), LOADER_LOCK_COOKIE_TID_BIT_OFFSET, LOADER_LOCK_COOKIE_TID_BIT_MASK) | \
  41. ULONG_PTR_IZE_SHIFT_AND_MASK((_code), LOADER_LOCK_COOKIE_CODE_BIT_OFFSET, LOADER_LOCK_COOKIE_CODE_BIT_MASK)))
  42. #define EXTRACT_LOADER_LOCK_COOKIE_FIELD(_cookie, _shift, _mask) ((((ULONG_PTR) (_cookie)) >> (_shift)) & (_mask))
  43. #define EXTRACT_LOADER_LOCK_COOKIE_TYPE(_cookie) EXTRACT_LOADER_LOCK_COOKIE_FIELD((_cookie), LOADER_LOCK_COOKIE_TYPE_BIT_OFFSET, LOADER_LOCK_COOKIE_TYPE_BIT_MASK)
  44. #define EXTRACT_LOADER_LOCK_COOKIE_TID(_cookie) EXTRACT_LOADER_LOCK_COOKIE_FIELD((_cookie), LOADER_LOCK_COOKIE_TID_BIT_OFFSET, LOADER_LOCK_COOKIE_TID_BIT_MASK)
  45. #define LOADER_LOCK_COOKIE_TYPE_NORMAL (0)
  46. LONG LdrpLoaderLockAcquisitionCount;
  47. // Note the case inconsistency is due to preserving case from earlier versions.
  48. WCHAR DllExtension[] = L".dll";
  49. UNICODE_STRING LdrApiDefaultExtension = RTL_CONSTANT_STRING(L".DLL");
  50. PLDR_MANIFEST_PROBER_ROUTINE LdrpManifestProberRoutine = NULL;
  51. extern PFNSE_DLLLOADED g_pfnSE_DllLoaded;
  52. extern PFNSE_DLLUNLOADED g_pfnSE_DllUnloaded;
  53. PLDR_APP_COMPAT_DLL_REDIRECTION_CALLBACK_FUNCTION LdrpAppCompatDllRedirectionCallbackFunction = NULL;
  54. PVOID LdrpAppCompatDllRedirectionCallbackData = NULL;
  55. BOOLEAN LdrpShowRecursiveDllLoads;
  56. BOOLEAN LdrpBreakOnRecursiveDllLoads;
  57. PLDR_DATA_TABLE_ENTRY LdrpCurrentDllInitializer;
  58. VOID
  59. RtlpDphDisableFaultInjection (
  60. );
  61. VOID
  62. RtlpDphEnableFaultInjection (
  63. );
  64. ULONG
  65. LdrpClearLoadInProgress(
  66. VOID
  67. );
  68. NTSTATUS
  69. LdrLoadDll (
  70. IN PCWSTR DllPath OPTIONAL,
  71. IN PULONG DllCharacteristics OPTIONAL,
  72. IN PCUNICODE_STRING DllName,
  73. OUT PVOID *DllHandle
  74. )
  75. /*++
  76. Routine Description:
  77. This function loads a DLL into the calling process address space.
  78. Arguments:
  79. DllPath - Supplies the search path to be used to locate the DLL.
  80. DllCharacteristics - Supplies an optional DLL characteristics flag,
  81. that if specified is used to match against the dll being loaded.
  82. DllName - Supplies the name of the DLL to load.
  83. DllHandle - Returns a handle to the loaded DLL.
  84. Return Value:
  85. NTSTATUS.
  86. --*/
  87. {
  88. NTSTATUS Status;
  89. WCHAR StaticRedirectedDllNameBuffer[DOS_MAX_PATH_LENGTH];
  90. UNICODE_STRING StaticRedirectedDllName;
  91. UNICODE_STRING DynamicRedirectedDllName = {0};
  92. ULONG LoadDllFlags = 0;
  93. PCUNICODE_STRING OldTopLevelDllBeingLoaded = NULL;
  94. PVOID LockCookie = NULL;
  95. PTEB Teb;
  96. //
  97. // We need to disable page heap fault injection while loader is active.
  98. // This is important so that we avoid lots of hits(failures) in this
  99. // area. The Disable/Enable function have basically zero impact on
  100. // performance because they just increment/decrement a lock variable
  101. // that is checked when an actual allocation is performed (page heap
  102. // needs to be enabled for that).
  103. //
  104. RtlpDphDisableFaultInjection ();
  105. StaticRedirectedDllName.Length = 0;
  106. StaticRedirectedDllName.MaximumLength = sizeof(StaticRedirectedDllNameBuffer);
  107. StaticRedirectedDllName.Buffer = StaticRedirectedDllNameBuffer;
  108. Status = RtlDosApplyFileIsolationRedirection_Ustr(
  109. RTL_DOS_APPLY_FILE_REDIRECTION_USTR_FLAG_RESPECT_DOT_LOCAL,
  110. DllName, // dll name to look up
  111. &LdrApiDefaultExtension,
  112. &StaticRedirectedDllName,
  113. &DynamicRedirectedDllName,
  114. (PUNICODE_STRING*)&DllName, // Result is either StaticRedirectedDllName or DynamicRedirectedDllName
  115. NULL,
  116. NULL, // not interested in where the filename starts
  117. NULL); // not interested in bytes required if we only had a static string
  118. if (NT_SUCCESS(Status)) {
  119. LoadDllFlags |= LDRP_LOAD_DLL_FLAG_DLL_IS_REDIRECTED;
  120. } else if (Status != STATUS_SXS_KEY_NOT_FOUND) {
  121. #if DBG
  122. DbgPrint("%s(%wZ): RtlDosApplyFileIsolationRedirection_Ustr() failed with status %08lx\n", __FUNCTION__, DllName, Status);
  123. #endif // DBG
  124. goto Exit;
  125. }
  126. LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, NULL, &LockCookie);
  127. OldTopLevelDllBeingLoaded = LdrpTopLevelDllBeingLoaded;
  128. if (OldTopLevelDllBeingLoaded) {
  129. if (ShowSnaps || LdrpShowRecursiveDllLoads || LdrpBreakOnRecursiveDllLoads) {
  130. Teb = NtCurrentTeb();
  131. DbgPrint(
  132. "[%lx,%lx] LDR: Recursive DLL load\n",
  133. HandleToULong(Teb->ClientId.UniqueProcess),
  134. HandleToULong(Teb->ClientId.UniqueThread));
  135. DbgPrint(
  136. "[%lx,%lx] Previous DLL being loaded: \"%wZ\"\n",
  137. HandleToULong(Teb->ClientId.UniqueProcess),
  138. HandleToULong(Teb->ClientId.UniqueThread),
  139. OldTopLevelDllBeingLoaded);
  140. DbgPrint(
  141. "[%lx,%lx] DLL being requested: \"%wZ\"\n",
  142. HandleToULong(Teb->ClientId.UniqueProcess),
  143. HandleToULong(Teb->ClientId.UniqueThread),
  144. DllName);
  145. if (LdrpCurrentDllInitializer != NULL) {
  146. DbgPrint(
  147. "[%lx,%lx] DLL whose initializer was currently running: \"%wZ\"\n",
  148. HandleToULong(Teb->ClientId.UniqueProcess),
  149. HandleToULong(Teb->ClientId.UniqueThread),
  150. &LdrpCurrentDllInitializer->FullDllName);
  151. } else {
  152. DbgPrint(
  153. "[%lx,%lx] No DLL initializer was running\n",
  154. HandleToULong(Teb->ClientId.UniqueProcess),
  155. HandleToULong(Teb->ClientId.UniqueThread));
  156. }
  157. }
  158. }
  159. LdrpTopLevelDllBeingLoaded = DllName;
  160. __try {
  161. Status = LdrpLoadDll (LoadDllFlags,
  162. DllPath,
  163. DllCharacteristics,
  164. DllName,
  165. DllHandle,
  166. TRUE);
  167. if (!NT_SUCCESS(Status)) {
  168. if ((Status != STATUS_NO_SUCH_FILE) &&
  169. (Status != STATUS_DLL_NOT_FOUND) &&
  170. (Status != STATUS_OBJECT_NAME_NOT_FOUND)) {
  171. // Dll initialization failure is common enough that we won't want to print unless snaps are turned on.
  172. if (ShowSnaps || (Status != STATUS_DLL_INIT_FAILED)) {
  173. DbgPrintEx(
  174. DPFLTR_LDR_ID,
  175. LDR_ERROR_DPFLTR,
  176. "LDR: %s - failing because LdrpLoadDll(%wZ) returned status %x\n",
  177. __FUNCTION__,
  178. DllName,
  179. Status);
  180. }
  181. }
  182. __leave;
  183. }
  184. Status = STATUS_SUCCESS;
  185. } __finally {
  186. LdrpTopLevelDllBeingLoaded = OldTopLevelDllBeingLoaded;
  187. LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, LockCookie);
  188. }
  189. Exit:
  190. if (DynamicRedirectedDllName.Buffer != NULL) {
  191. RtlFreeUnicodeString(&DynamicRedirectedDllName);
  192. }
  193. //
  194. // Reenable page heap fault injection.
  195. //
  196. RtlpDphEnableFaultInjection ();
  197. return Status;
  198. }
  199. NTSTATUS
  200. NTAPI
  201. LdrpLoadDll (
  202. IN ULONG Flags OPTIONAL,
  203. IN PCWSTR DllPath OPTIONAL,
  204. IN PULONG DllCharacteristics OPTIONAL,
  205. IN PCUNICODE_STRING DllName,
  206. OUT PVOID *DllHandle,
  207. IN BOOLEAN RunInitRoutines
  208. )
  209. {
  210. NTSTATUS st;
  211. PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
  212. PWSTR ActualDllName;
  213. PWCH p, pp;
  214. UNICODE_STRING ActualDllNameStr;
  215. WCHAR FreeBuffer[LDR_MAX_PATH + 1];
  216. BOOLEAN Redirected;
  217. ULONG DllNameLength;
  218. const InLdrInit = LdrpInLdrInit;
  219. if (Flags & LDRP_LOAD_DLL_FLAG_DLL_IS_REDIRECTED) {
  220. Redirected = TRUE;
  221. }
  222. else {
  223. Redirected = FALSE;
  224. }
  225. st = STATUS_SUCCESS;
  226. p = DllName->Buffer;
  227. pp = NULL;
  228. while (*p) {
  229. switch (*p++) {
  230. case L'.':
  231. //
  232. // pp will point to first character after the last '.', if
  233. // it occurs after the last '\'.
  234. //
  235. pp = p;
  236. break;
  237. case L'\\':
  238. pp = NULL;
  239. break;
  240. default:
  241. NOTHING;
  242. }
  243. }
  244. if (DllName->Length >= sizeof(FreeBuffer)) {
  245. return STATUS_NAME_TOO_LONG;
  246. }
  247. ActualDllName = FreeBuffer;
  248. RtlCopyMemory (ActualDllName, DllName->Buffer, DllName->Length);
  249. if (!pp || *pp == (WCHAR)'\\') {
  250. //
  251. // No extension found (just ..\)
  252. //
  253. DllNameLength = DllName->Length + sizeof(DllExtension) - sizeof(WCHAR);
  254. if ((DllNameLength + sizeof(WCHAR)) >= sizeof(FreeBuffer)) {
  255. DbgPrintEx(
  256. DPFLTR_LDR_ID,
  257. LDR_ERROR_DPFLTR,
  258. "LDR: %s - Dll name missing extension; with extension added the length is too long\n"
  259. " DllName: (@ %p) \"%wZ\"\n"
  260. " DllName->Length: %u\n",
  261. __FUNCTION__,
  262. DllName, DllName,
  263. DllName->Length);
  264. return STATUS_NAME_TOO_LONG;
  265. }
  266. RtlCopyMemory ((PCHAR)ActualDllName+DllName->Length, DllExtension, sizeof(DllExtension));
  267. ActualDllNameStr.Length = (USHORT)(DllNameLength);
  268. } else {
  269. ActualDllName[DllName->Length >> 1] = UNICODE_NULL;
  270. ActualDllNameStr.Length = DllName->Length;
  271. }
  272. ActualDllNameStr.MaximumLength = sizeof(FreeBuffer);
  273. ActualDllNameStr.Buffer = ActualDllName;
  274. LdrDataTableEntry = NULL;
  275. //
  276. // Except during process initialization, grab loader lock and
  277. // Snap all links to the specified DLL.
  278. //
  279. if (!InLdrInit) {
  280. RtlEnterCriticalSection (&LdrpLoaderLock);
  281. }
  282. try {
  283. if (ShowSnaps) {
  284. DbgPrint("LDR: LdrLoadDll, loading %ws from %ws\n",
  285. ActualDllName,
  286. ARGUMENT_PRESENT(DllPath) ? DllPath : L""
  287. );
  288. }
  289. if (!LdrpCheckForLoadedDll( DllPath,
  290. &ActualDllNameStr,
  291. FALSE,
  292. Redirected,
  293. &LdrDataTableEntry)) {
  294. st = LdrpMapDll(DllPath,
  295. ActualDllName,
  296. DllCharacteristics,
  297. FALSE,
  298. Redirected,
  299. &LdrDataTableEntry);
  300. if (!NT_SUCCESS(st)) {
  301. leave;
  302. }
  303. #if defined(_X86_)
  304. //
  305. // Register dll with the stack tracing module.
  306. // This is used for getting reliable stack traces on X86.
  307. //
  308. RtlpStkMarkDllRange (LdrDataTableEntry);
  309. #endif
  310. if (ARGUMENT_PRESENT( DllCharacteristics ) &&
  311. *DllCharacteristics & IMAGE_FILE_EXECUTABLE_IMAGE) {
  312. LdrDataTableEntry->EntryPoint = 0;
  313. LdrDataTableEntry->Flags &= ~LDRP_IMAGE_DLL;
  314. }
  315. //
  316. // walk the import descriptor table of the dll
  317. //
  318. if (LdrDataTableEntry->Flags & LDRP_IMAGE_DLL) {
  319. try {
  320. //
  321. // if the image is COR-ILONLY, then don't walk the import descriptor
  322. // as it is assumed that it only imports %windir%\system32\mscoree.dll, otherwise
  323. // walk the import descriptor table of the dll.
  324. //
  325. if ((LdrDataTableEntry->Flags & LDRP_COR_IMAGE) == 0) {
  326. st = LdrpWalkImportDescriptor(
  327. DllPath,
  328. LdrDataTableEntry
  329. );
  330. }
  331. } __except(LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {
  332. st = GetExceptionCode();
  333. DbgPrintEx(
  334. DPFLTR_LDR_ID,
  335. LDR_ERROR_DPFLTR,
  336. "LDR: %s - Exception %x thrown by LdrpWalkImportDescriptor\n",
  337. __FUNCTION__,
  338. st);
  339. }
  340. if ( LdrDataTableEntry->LoadCount != 0xffff ) {
  341. LdrDataTableEntry->LoadCount += 1;
  342. }
  343. LdrpReferenceLoadedDll (LdrDataTableEntry);
  344. if (!NT_SUCCESS(st)) {
  345. LdrDataTableEntry->EntryPoint = NULL;
  346. InsertTailList(
  347. &PebLdr.InInitializationOrderModuleList,
  348. &LdrDataTableEntry->InInitializationOrderLinks);
  349. LdrpClearLoadInProgress();
  350. if (ShowSnaps) {
  351. DbgPrint("LDR: Unloading %wZ due to error %x walking import descriptors\n", DllName, st);
  352. }
  353. LdrUnloadDll((PVOID)LdrDataTableEntry->DllBase);
  354. leave;
  355. }
  356. }
  357. else {
  358. if ( LdrDataTableEntry->LoadCount != 0xffff ) {
  359. LdrDataTableEntry->LoadCount += 1;
  360. }
  361. }
  362. //
  363. // Add init routine to list
  364. //
  365. InsertTailList(&PebLdr.InInitializationOrderModuleList,
  366. &LdrDataTableEntry->InInitializationOrderLinks);
  367. //
  368. // If the loader data base is not fully setup, this load was because
  369. // of a forwarder in the static load set. Can't run init routines
  370. // yet because the load counts are NOT set
  371. //
  372. if ( RunInitRoutines && LdrpLdrDatabaseIsSetup ) {
  373. //
  374. // Shim engine callback. This is the chance to patch
  375. // dynamically loaded modules.
  376. //
  377. if (g_pfnSE_DllLoaded != NULL) {
  378. (*g_pfnSE_DllLoaded)(LdrDataTableEntry);
  379. }
  380. try {
  381. st = LdrpRunInitializeRoutines (NULL);
  382. if ( !NT_SUCCESS(st) ) {
  383. if (ShowSnaps) {
  384. DbgPrint("LDR: Unloading %wZ because either its init routine or one of its static imports failed; status = 0x%08lx", DllName, st);
  385. }
  386. LdrUnloadDll((PVOID)LdrDataTableEntry->DllBase);
  387. }
  388. }
  389. __except (LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {
  390. st = GetExceptionCode();
  391. DbgPrintEx(
  392. DPFLTR_LDR_ID,
  393. LDR_ERROR_DPFLTR,
  394. "LDR: %s - Exception %08lx thrown running initialization routines for %wZ\n",
  395. __FUNCTION__,
  396. st,
  397. &LdrDataTableEntry->FullDllName);
  398. LdrUnloadDll((PVOID)LdrDataTableEntry->DllBase);
  399. leave;
  400. }
  401. }
  402. else {
  403. st = STATUS_SUCCESS;
  404. }
  405. }
  406. else {
  407. //
  408. // Count it and everything that it imports.
  409. //
  410. if ( LdrDataTableEntry->Flags & LDRP_IMAGE_DLL &&
  411. LdrDataTableEntry->LoadCount != 0xffff ) {
  412. LdrDataTableEntry->LoadCount += 1;
  413. LdrpReferenceLoadedDll(LdrDataTableEntry);
  414. //
  415. // Now clear the Load in progress bits
  416. //
  417. LdrpClearLoadInProgress();
  418. }
  419. else {
  420. if ( LdrDataTableEntry->LoadCount != 0xffff ) {
  421. LdrDataTableEntry->LoadCount += 1;
  422. }
  423. }
  424. }
  425. }
  426. __finally {
  427. if (!InLdrInit) {
  428. RtlLeaveCriticalSection(&LdrpLoaderLock);
  429. }
  430. }
  431. if (NT_SUCCESS(st)) {
  432. *DllHandle = (PVOID)LdrDataTableEntry->DllBase;
  433. }
  434. else {
  435. *DllHandle = NULL;
  436. }
  437. return st;
  438. }
  439. NTSTATUS
  440. LdrGetDllHandle(
  441. IN PCWSTR DllPath OPTIONAL,
  442. IN PULONG DllCharacteristics OPTIONAL,
  443. IN PCUNICODE_STRING DllName,
  444. OUT PVOID *DllHandle
  445. )
  446. {
  447. //
  448. // Preserve the old behavior.
  449. //
  450. return LdrGetDllHandleEx (LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT,
  451. DllPath,
  452. DllCharacteristics,
  453. DllName,
  454. DllHandle);
  455. }
  456. NTSTATUS
  457. LdrGetDllHandleEx(
  458. IN ULONG Flags,
  459. IN PCWSTR DllPath OPTIONAL,
  460. IN PULONG DllCharacteristics OPTIONAL,
  461. IN PCUNICODE_STRING ConstDllName,
  462. OUT PVOID *DllHandle OPTIONAL
  463. )
  464. /*++
  465. Routine Description:
  466. This function locates the specified DLL and returns its handle.
  467. Arguments:
  468. Flags - various bits to affect the behavior
  469. default: the returned handle is addrefed
  470. LDR_GET_DLL_HANDLE_EX_PIN - the dll will not be unloaded until
  471. the process exits
  472. LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT - the dll's reference
  473. count is not changed
  474. DllPath - Supplies the search path to be used to locate the DLL.
  475. DllCharacteristics - Supplies an optional DLL characteristics flag,
  476. that if specified is used to match against the dll being loaded.
  477. The currently supported flags are:
  478. IMAGE_FILE_EXECUTABLE_IMAGE - indicates that imported dll
  479. referenced by the DLL being loaded should not be followed.
  480. This corresponds to DONT_RESOLVE_DLL_REFERENCES
  481. IMAGE_FILE_SYSTEM - indicates that the DLL is a known trusted
  482. system component and that WinSafer sandbox checking
  483. should not be performed on the DLL before loading it.
  484. DllName - Supplies the name of the DLL to load.
  485. DllHandle - Returns a handle to the loaded DLL.
  486. Return Value:
  487. NTSTATUS.
  488. --*/
  489. {
  490. NTSTATUS st = STATUS_ACCESS_VIOLATION;
  491. PLDR_DATA_TABLE_ENTRY LdrDataTableEntry = NULL;
  492. PWCH p, pp, pEnd;
  493. UNICODE_STRING ActualDllNameStr = {0, 0, NULL};
  494. UNICODE_STRING DynamicRedirectedDllName = {0, 0, NULL};
  495. BOOLEAN Redirected = FALSE;
  496. BOOLEAN HoldingLoaderLock = FALSE;
  497. const BOOLEAN InLdrInit = LdrpInLdrInit;
  498. PVOID LockCookie = NULL;
  499. const ULONG ValidFlags = LDR_GET_DLL_HANDLE_EX_PIN | LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT;
  500. UNICODE_STRING xDllName;
  501. const PUNICODE_STRING DllName = &xDllName;
  502. UNREFERENCED_PARAMETER (DllCharacteristics);
  503. xDllName = *ConstDllName;
  504. __try {
  505. if (DllHandle != NULL) {
  506. *DllHandle = NULL;
  507. }
  508. if (Flags & ~ValidFlags) {
  509. st = STATUS_INVALID_PARAMETER;
  510. goto Exit;
  511. }
  512. //
  513. // DllHandle is optional if you are pinning the .dll, otherwise it is mandatory.
  514. //
  515. if ((DllHandle == NULL) &&
  516. (Flags & LDR_GET_DLL_HANDLE_EX_PIN) == 0) {
  517. st = STATUS_INVALID_PARAMETER;
  518. goto Exit;
  519. }
  520. if ((Flags & LDR_GET_DLL_HANDLE_EX_PIN) &&
  521. (Flags & LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT)) {
  522. st = STATUS_INVALID_PARAMETER;
  523. goto Exit;
  524. }
  525. //
  526. // Grab Ldr lock
  527. //
  528. if (!InLdrInit) {
  529. st = LdrLockLoaderLock(0, NULL, &LockCookie);
  530. if (!NT_SUCCESS(st)) {
  531. goto Exit;
  532. }
  533. HoldingLoaderLock = TRUE;
  534. }
  535. st = RtlDosApplyFileIsolationRedirection_Ustr(
  536. RTL_DOS_APPLY_FILE_REDIRECTION_USTR_FLAG_RESPECT_DOT_LOCAL,
  537. DllName,
  538. &LdrApiDefaultExtension,
  539. NULL,
  540. &DynamicRedirectedDllName,
  541. (PUNICODE_STRING*)&DllName,
  542. NULL,
  543. NULL,
  544. NULL);
  545. if (NT_SUCCESS(st)) {
  546. Redirected = TRUE;
  547. } else if (st != STATUS_SXS_KEY_NOT_FOUND) {
  548. // Something unusual and bad happened.
  549. __leave;
  550. }
  551. st = STATUS_DLL_NOT_FOUND;
  552. if ( LdrpGetModuleHandleCache ) {
  553. if (Redirected) {
  554. if (((LdrpGetModuleHandleCache->Flags & LDRP_REDIRECTED) != 0) &&
  555. RtlEqualUnicodeString(DllName, &LdrpGetModuleHandleCache->FullDllName, TRUE)) {
  556. LdrDataTableEntry = LdrpGetModuleHandleCache;
  557. st = STATUS_SUCCESS;
  558. goto Exit;
  559. }
  560. } else {
  561. // Not redirected...
  562. if (((LdrpGetModuleHandleCache->Flags & LDRP_REDIRECTED) == 0) &&
  563. RtlEqualUnicodeString(DllName, &LdrpGetModuleHandleCache->BaseDllName, TRUE)) {
  564. LdrDataTableEntry = LdrpGetModuleHandleCache;
  565. st = STATUS_SUCCESS;
  566. goto Exit;
  567. }
  568. }
  569. }
  570. p = DllName->Buffer;
  571. pEnd = p + (DllName->Length / sizeof(WCHAR));
  572. pp = NULL;
  573. while (p != pEnd) {
  574. switch (*p++) {
  575. case L'.':
  576. //
  577. // pp will point to the first character after the last
  578. // '.', if it occurs after the last '\'.
  579. //
  580. pp = p;
  581. break;
  582. case L'\\':
  583. pp = NULL;
  584. break;
  585. default:
  586. NOTHING;
  587. }
  588. }
  589. if ((pp == NULL) || (*pp == L'\\') || (*pp == L'/')) {
  590. //
  591. // The max length here must include the null-termination, but the length itself
  592. // should not. NB that sizeof(DllExtension) will include the size for the
  593. // terminating UNICODE_NULL
  594. //
  595. ActualDllNameStr.MaximumLength = DllName->Length + sizeof(DllExtension);
  596. ActualDllNameStr.Length = ActualDllNameStr.MaximumLength - sizeof(WCHAR);
  597. ActualDllNameStr.Buffer = RtlAllocateHeap(RtlProcessHeap(), 0, ActualDllNameStr.MaximumLength);
  598. if (ActualDllNameStr.Buffer == NULL) {
  599. st = STATUS_NO_MEMORY;
  600. goto Exit;
  601. }
  602. //
  603. // Copy the name and the default extension onto the string This magically null-terminates,
  604. // as DllExtension includes the unicode null character.
  605. //
  606. RtlCopyMemory(ActualDllNameStr.Buffer, DllName->Buffer, DllName->Length);
  607. RtlCopyMemory(((PCHAR)ActualDllNameStr.Buffer) + DllName->Length, DllExtension, sizeof(DllExtension));
  608. } else {
  609. //
  610. // Trim the trailing dot
  611. //
  612. if ((DllName->Length != 0) && (DllName->Buffer[(DllName->Length / sizeof(WCHAR)) - 1] == L'.')) {
  613. DllName->Length -= sizeof(WCHAR);
  614. }
  615. //
  616. // Size the buffer, allocate - set the max length to include the NULL character
  617. //
  618. ActualDllNameStr.MaximumLength = DllName->Length + sizeof(WCHAR);
  619. ActualDllNameStr.Length = DllName->Length;
  620. ActualDllNameStr.Buffer = RtlAllocateHeap(RtlProcessHeap(), 0, ActualDllNameStr.MaximumLength);
  621. if (ActualDllNameStr.Buffer == NULL) {
  622. st = STATUS_NO_MEMORY;
  623. goto Exit;
  624. }
  625. //
  626. // Copy data into it
  627. //
  628. RtlCopyMemory(ActualDllNameStr.Buffer, DllName->Buffer, DllName->Length);
  629. //
  630. // And null-terminate by hand
  631. //
  632. ActualDllNameStr.Buffer[ActualDllNameStr.Length / sizeof(WCHAR)] = UNICODE_NULL;
  633. }
  634. //
  635. // Check the LdrTable to see if Dll has already been loaded
  636. // into this image.
  637. //
  638. if (ShowSnaps) {
  639. DbgPrint(
  640. "LDR: LdrGetDllHandle, searching for %wZ from %ws\n",
  641. &ActualDllNameStr,
  642. ARGUMENT_PRESENT(DllPath) ? (DllPath == (PWSTR)1 ? L"" : DllPath) : L""
  643. );
  644. }
  645. //
  646. // sort of a hack, but done to speed up GetModuleHandle. kernel32
  647. // now does a two pass call here to avoid computing
  648. // process dll path
  649. //
  650. if (LdrpCheckForLoadedDll(DllPath,
  651. &ActualDllNameStr,
  652. (BOOLEAN)(DllPath == (PWSTR)1 ? TRUE : FALSE),
  653. Redirected,
  654. &LdrDataTableEntry)) {
  655. LdrpGetModuleHandleCache = LdrDataTableEntry;
  656. st = STATUS_SUCCESS;
  657. goto Exit;
  658. }
  659. LdrDataTableEntry = NULL;
  660. RTL_SOFT_ASSERT(st == STATUS_DLL_NOT_FOUND);
  661. Exit:
  662. ASSERT((LdrDataTableEntry != NULL) == NT_SUCCESS(st));
  663. if (LdrDataTableEntry != NULL && NT_SUCCESS(st)) {
  664. //
  665. // It's standard gross procedure to put the check for 0xffff,
  666. // and the updates of the root LoadCount outside the
  667. // call to LdrpUpdateLoadCount..
  668. //
  669. if (LdrDataTableEntry->LoadCount != 0xffff) {
  670. if ((Flags & LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT) != 0) {
  671. // nothing
  672. }
  673. else {
  674. if (Flags & LDR_GET_DLL_HANDLE_EX_PIN) {
  675. LdrDataTableEntry->LoadCount = 0xffff;
  676. LdrpPinLoadedDll(LdrDataTableEntry);
  677. }
  678. else {
  679. LdrDataTableEntry->LoadCount++;
  680. LdrpReferenceLoadedDll(LdrDataTableEntry);
  681. }
  682. LdrpClearLoadInProgress();
  683. }
  684. }
  685. if (DllHandle != NULL) {
  686. *DllHandle = (PVOID)LdrDataTableEntry->DllBase;
  687. }
  688. }
  689. } __finally {
  690. if (DynamicRedirectedDllName.Buffer != NULL) {
  691. RtlFreeUnicodeString(&DynamicRedirectedDllName);
  692. }
  693. if (ActualDllNameStr.Buffer != NULL) {
  694. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)ActualDllNameStr.Buffer);
  695. ActualDllNameStr.Buffer = NULL;
  696. }
  697. if (HoldingLoaderLock) {
  698. LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, LockCookie);
  699. HoldingLoaderLock = FALSE;
  700. }
  701. }
  702. return st;
  703. }
  704. NTSTATUS
  705. LdrDisableThreadCalloutsForDll (
  706. IN PVOID DllHandle
  707. )
  708. /*++
  709. Routine Description:
  710. This function disables thread attach and detach notification
  711. for the specified DLL.
  712. Arguments:
  713. DllHandle - Supplies a handle to the DLL to disable.
  714. Return Value:
  715. NTSTATUS.
  716. --*/
  717. {
  718. NTSTATUS st = STATUS_SUCCESS;
  719. PLDR_DATA_TABLE_ENTRY LdrDataTableEntry = NULL;
  720. const BOOLEAN InLdrInit = LdrpInLdrInit;
  721. BOOL HoldingLoaderLock = FALSE;
  722. PVOID LockCookie = NULL;
  723. if ( LdrpShutdownInProgress ) {
  724. return STATUS_SUCCESS;
  725. }
  726. try {
  727. if ( InLdrInit == FALSE ) {
  728. st = LdrLockLoaderLock(0, NULL, &LockCookie);
  729. if (!NT_SUCCESS(st))
  730. goto Exit;
  731. HoldingLoaderLock = TRUE;
  732. }
  733. if (LdrpCheckForLoadedDllHandle(DllHandle, &LdrDataTableEntry)) {
  734. if ( LdrDataTableEntry->TlsIndex ) {
  735. st = STATUS_DLL_NOT_FOUND;
  736. }
  737. else {
  738. LdrDataTableEntry->Flags |= LDRP_DONT_CALL_FOR_THREADS;
  739. }
  740. }
  741. Exit:
  742. ;
  743. }
  744. finally {
  745. if (HoldingLoaderLock) {
  746. LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, LockCookie);
  747. HoldingLoaderLock = FALSE;
  748. }
  749. }
  750. return st;
  751. }
  752. ULONG LdrpUnloadIndex = 0;
  753. RTL_UNLOAD_EVENT_TRACE RtlpUnloadEventTrace[RTL_UNLOAD_EVENT_TRACE_NUMBER];
  754. NTSYSAPI
  755. PRTL_UNLOAD_EVENT_TRACE
  756. NTAPI
  757. RtlGetUnloadEventTrace (
  758. VOID
  759. )
  760. {
  761. return RtlpUnloadEventTrace;
  762. }
  763. VOID
  764. LdrpRecordUnloadEvent (
  765. IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry
  766. )
  767. /*++
  768. Routine Description:
  769. This function records in a ring buffer the last few dll unloads
  770. Arguments:
  771. LdrDataTableEntry - The ldr entry for this dll
  772. Return Value:
  773. None.
  774. --*/
  775. {
  776. ULONG Seq, i, Len;
  777. PVOID BaseAddress;
  778. PIMAGE_NT_HEADERS NtHeaders;
  779. Seq = LdrpUnloadIndex++;
  780. i = Seq % RTL_UNLOAD_EVENT_TRACE_NUMBER;
  781. BaseAddress = LdrDataTableEntry->DllBase;
  782. RtlpUnloadEventTrace[i].Sequence = Seq;
  783. RtlpUnloadEventTrace[i].BaseAddress = BaseAddress;
  784. RtlpUnloadEventTrace[i].SizeOfImage = LdrDataTableEntry->SizeOfImage;
  785. Len = LdrDataTableEntry->BaseDllName.Length;
  786. if (Len > sizeof (RtlpUnloadEventTrace[i].ImageName)) {
  787. Len = sizeof (RtlpUnloadEventTrace[i].ImageName);
  788. }
  789. RtlCopyMemory (RtlpUnloadEventTrace[i].ImageName,
  790. LdrDataTableEntry->BaseDllName.Buffer,
  791. Len);
  792. if (Len < sizeof (RtlpUnloadEventTrace[i].ImageName)) {
  793. RtlpUnloadEventTrace[i].ImageName[Len/sizeof (WCHAR)] = L'\0';
  794. }
  795. NtHeaders = RtlImageNtHeader (BaseAddress);
  796. if (NtHeaders != NULL) {
  797. RtlpUnloadEventTrace[i].TimeDateStamp = NtHeaders->FileHeader.TimeDateStamp;
  798. RtlpUnloadEventTrace[i].CheckSum = NtHeaders->OptionalHeader.CheckSum;
  799. } else {
  800. RtlpUnloadEventTrace[i].TimeDateStamp = 0;
  801. RtlpUnloadEventTrace[i].CheckSum = 0;
  802. }
  803. }
  804. NTSTATUS
  805. LdrUnloadDll (
  806. IN PVOID DllHandle
  807. )
  808. /*++
  809. Routine Description:
  810. This function unloads the DLL from the specified process
  811. Arguments:
  812. DllHandle - Supplies a handle to the DLL to unload.
  813. Return Value:
  814. NTSTATUS.
  815. --*/
  816. {
  817. NTSTATUS st;
  818. PPEB Peb;
  819. PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
  820. PLDR_DATA_TABLE_ENTRY Entry;
  821. PDLL_INIT_ROUTINE InitRoutine;
  822. LIST_ENTRY LocalUnloadHead;
  823. PLIST_ENTRY Next;
  824. ULONG Cor20HeaderSize;
  825. PIMAGE_COR20_HEADER *Cor20Header;
  826. PRTL_PATCH_HEADER RundownPatchList = NULL;
  827. Peb = NtCurrentPeb();
  828. st = STATUS_SUCCESS;
  829. //
  830. // Grab Peb lock and decrement reference count of all affected DLLs
  831. //
  832. if (!LdrpInLdrInit) {
  833. RtlEnterCriticalSection(&LdrpLoaderLock);
  834. }
  835. try {
  836. LdrpActiveUnloadCount += 1;
  837. if (LdrpShutdownInProgress) {
  838. goto leave_finally;
  839. }
  840. if (!LdrpCheckForLoadedDllHandle(DllHandle, &LdrDataTableEntry)) {
  841. st = STATUS_DLL_NOT_FOUND;
  842. goto leave_finally;
  843. }
  844. //
  845. // Now that we have the data table entry, unload it
  846. //
  847. if (LdrDataTableEntry->LoadCount != 0xffff) {
  848. LdrDataTableEntry->LoadCount -= 1;
  849. if (LdrDataTableEntry->Flags & LDRP_IMAGE_DLL) {
  850. RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame = { sizeof(Frame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
  851. RtlActivateActivationContextUnsafeFast(&Frame, LdrDataTableEntry->EntryPointActivationContext);
  852. __try {
  853. LdrpDereferenceLoadedDll(LdrDataTableEntry);
  854. } __finally {
  855. RtlDeactivateActivationContextUnsafeFast(&Frame);
  856. }
  857. }
  858. } else {
  859. //
  860. // if the load count is 0xffff, then we do not need to recurse
  861. // through this DLL's import table.
  862. //
  863. // Additionally, we don't have to scan more LoadCount == 0
  864. // modules since nothing could have happened as a result of a free on this
  865. // DLL.
  866. goto leave_finally;
  867. }
  868. //
  869. // Now process init routines and then in a second pass, unload
  870. // DLLs
  871. //
  872. if (ShowSnaps) {
  873. DbgPrint("LDR: UNINIT LIST\n");
  874. }
  875. if (LdrpActiveUnloadCount == 1) {
  876. InitializeListHead(&LdrpUnloadHead);
  877. }
  878. //
  879. // Go in reverse order initialization order and build
  880. // the unload list
  881. //
  882. Next = PebLdr.InInitializationOrderModuleList.Blink;
  883. while ( Next != &PebLdr.InInitializationOrderModuleList) {
  884. LdrDataTableEntry
  885. = (PLDR_DATA_TABLE_ENTRY)
  886. (CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,InInitializationOrderLinks));
  887. Next = Next->Blink;
  888. LdrDataTableEntry->Flags &= ~LDRP_UNLOAD_IN_PROGRESS;
  889. if (LdrDataTableEntry->LoadCount == 0) {
  890. if (ShowSnaps) {
  891. DbgPrint(" (%d) [%ws] %ws (%lx) deinit %lx\n",
  892. LdrpActiveUnloadCount,
  893. LdrDataTableEntry->BaseDllName.Buffer,
  894. LdrDataTableEntry->FullDllName.Buffer,
  895. (ULONG)LdrDataTableEntry->LoadCount,
  896. LdrDataTableEntry->EntryPoint
  897. );
  898. }
  899. Entry = LdrDataTableEntry;
  900. //
  901. // Shim engine callback. Remove it from the shim list of hooked modules
  902. //
  903. if (g_pfnSE_DllUnloaded != NULL) {
  904. (*g_pfnSE_DllUnloaded)(Entry);
  905. }
  906. RemoveEntryList(&Entry->InInitializationOrderLinks);
  907. RemoveEntryList(&Entry->InMemoryOrderLinks);
  908. RemoveEntryList(&Entry->HashLinks);
  909. if ( LdrpActiveUnloadCount > 1 ) {
  910. LdrpLoadedDllHandleCache = NULL;
  911. Entry->InMemoryOrderLinks.Flink = NULL;
  912. }
  913. InsertTailList(&LdrpUnloadHead,&Entry->HashLinks);
  914. }
  915. }
  916. //
  917. // End of new code
  918. //
  919. //
  920. // We only do init routine call's and module free's at the top level,
  921. // so if the active count is > 1, just return
  922. //
  923. if (LdrpActiveUnloadCount > 1 ) {
  924. goto leave_finally;
  925. }
  926. //
  927. // Now that the unload list is built, walk through the unload
  928. // list in order and call the init routine. The dll must remain
  929. // on the InLoadOrderLinks so that the pctoheader stuff will
  930. // still work
  931. //
  932. InitializeListHead(&LocalUnloadHead);
  933. Entry = NULL;
  934. Next = LdrpUnloadHead.Flink;
  935. while ( Next != &LdrpUnloadHead ) {
  936. top:
  937. if ( Entry ) {
  938. #if defined(_AMD64_) || defined(_IA64_)
  939. RtlRemoveInvertedFunctionTable(&LdrpInvertedFunctionTable,
  940. Entry->DllBase);
  941. #endif
  942. RemoveEntryList(&(Entry->InLoadOrderLinks));
  943. Entry = NULL;
  944. Next = LdrpUnloadHead.Flink;
  945. if (Next == &LdrpUnloadHead ) {
  946. goto bottom;
  947. }
  948. }
  949. LdrDataTableEntry
  950. = (PLDR_DATA_TABLE_ENTRY)
  951. (CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,HashLinks));
  952. LdrpRecordUnloadEvent (LdrDataTableEntry);
  953. //
  954. // Remove dll from the global unload list and place
  955. // on the local unload list. This is because the global list
  956. // can change during the callout to the init routine
  957. //
  958. Entry = LdrDataTableEntry;
  959. LdrpLoadedDllHandleCache = NULL;
  960. Entry->InMemoryOrderLinks.Flink = NULL;
  961. RemoveEntryList(&Entry->HashLinks);
  962. InsertTailList(&LocalUnloadHead,&Entry->HashLinks);
  963. //
  964. // If the function has an init routine, call it.
  965. //
  966. InitRoutine = (PDLL_INIT_ROUTINE)(ULONG_PTR)LdrDataTableEntry->EntryPoint;
  967. if (InitRoutine && (LdrDataTableEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) ) {
  968. try {
  969. if (ShowSnaps) {
  970. DbgPrint("LDR: Calling deinit %lx\n",InitRoutine);
  971. }
  972. LDRP_ACTIVATE_ACTIVATION_CONTEXT(LdrDataTableEntry);
  973. LdrpCallInitRoutine(InitRoutine,
  974. LdrDataTableEntry->DllBase,
  975. DLL_PROCESS_DETACH,
  976. NULL);
  977. LDRP_DEACTIVATE_ACTIVATION_CONTEXT();
  978. #if defined(_AMD64_) || defined(_IA64_)
  979. RtlRemoveInvertedFunctionTable(&LdrpInvertedFunctionTable,
  980. Entry->DllBase);
  981. #endif
  982. RemoveEntryList(&Entry->InLoadOrderLinks);
  983. Entry = NULL;
  984. Next = LdrpUnloadHead.Flink;
  985. }
  986. except(LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)){
  987. DbgPrintEx(
  988. DPFLTR_LDR_ID,
  989. LDR_ERROR_DPFLTR,
  990. "LDR: %s - exception %08lx caught while sending DLL_PROCESS_DETACH\n",
  991. __FUNCTION__,
  992. GetExceptionCode());
  993. DbgPrintEx(
  994. DPFLTR_LDR_ID,
  995. LDR_ERROR_DPFLTR,
  996. " Dll Name: %wZ\n",
  997. &LdrDataTableEntry->FullDllName);
  998. DbgPrintEx(
  999. DPFLTR_LDR_ID,
  1000. LDR_ERROR_DPFLTR,
  1001. " InitRoutine: %p\n",
  1002. InitRoutine);
  1003. goto top;
  1004. }
  1005. } else {
  1006. #if defined(_AMD64_) || defined(_IA64_)
  1007. RtlRemoveInvertedFunctionTable(&LdrpInvertedFunctionTable,
  1008. Entry->DllBase);
  1009. #endif
  1010. RemoveEntryList(&(Entry->InLoadOrderLinks));
  1011. Entry = NULL;
  1012. Next = LdrpUnloadHead.Flink;
  1013. }
  1014. }
  1015. bottom:
  1016. //
  1017. // Now, go through the modules and unmap them
  1018. //
  1019. Next = LocalUnloadHead.Flink;
  1020. while ( Next != &LocalUnloadHead ) {
  1021. LdrDataTableEntry
  1022. = (PLDR_DATA_TABLE_ENTRY)
  1023. (CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,HashLinks));
  1024. Next = Next->Flink;
  1025. Entry = LdrDataTableEntry;
  1026. //
  1027. // Notify verifier that a dll will be unloaded.
  1028. //
  1029. // Now that we called the all the init routines with `detach'
  1030. // there is no excuse if we find a live CS in that region.
  1031. //
  1032. // Note: gdi32.dll's critical sections are deleted only on
  1033. // user32.dll'd DllMain( DLL_PROCESS_DETACH ) so we cannot
  1034. // do this check for leaked critical sections prior to this point.
  1035. //
  1036. if (Peb->NtGlobalFlag & FLG_APPLICATION_VERIFIER) {
  1037. AVrfDllUnloadNotification (LdrDataTableEntry);
  1038. }
  1039. //
  1040. // Unmap this DLL.
  1041. //
  1042. if (ShowSnaps) {
  1043. DbgPrint("LDR: Unmapping [%ws]\n",
  1044. LdrDataTableEntry->BaseDllName.Buffer
  1045. );
  1046. }
  1047. Cor20Header = RtlImageDirectoryEntryToData(Entry->DllBase,
  1048. TRUE,
  1049. IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
  1050. &Cor20HeaderSize);
  1051. if (Cor20Header != NULL) {
  1052. LdrpCorUnloadImage(Entry->DllBase);
  1053. }
  1054. if (!(Entry->Flags & LDRP_COR_OWNS_UNMAP)) {
  1055. st = NtUnmapViewOfSection(NtCurrentProcess(),Entry->DllBase);
  1056. ASSERT(NT_SUCCESS(st));
  1057. }
  1058. LdrUnloadAlternateResourceModule(Entry->DllBase);
  1059. LdrpSendDllNotifications (Entry,
  1060. LDR_DLL_NOTIFICATION_REASON_UNLOADED,
  1061. (LdrpShutdownInProgress ? LDR_DLL_UNLOADED_FLAG_PROCESS_TERMINATION : 0));
  1062. //
  1063. // See if we have hotpatch information and push each hotpatch block
  1064. // to the rundown list
  1065. //
  1066. while (Entry->PatchInformation) {
  1067. PRTL_PATCH_HEADER PatchHead = Entry->PatchInformation;
  1068. Entry->PatchInformation = PatchHead->NextPatch;
  1069. PatchHead->NextPatch = RundownPatchList;
  1070. RundownPatchList = PatchHead;
  1071. }
  1072. LdrpFinalizeAndDeallocateDataTableEntry(Entry);
  1073. if ( Entry == LdrpGetModuleHandleCache ) {
  1074. LdrpGetModuleHandleCache = NULL;
  1075. }
  1076. }
  1077. leave_finally:;
  1078. }
  1079. finally {
  1080. LdrpActiveUnloadCount -= 1;
  1081. if (!LdrpInLdrInit) {
  1082. RtlLeaveCriticalSection(&LdrpLoaderLock);
  1083. }
  1084. }
  1085. if ( RundownPatchList ) {
  1086. LdrpRundownHotpatchList( RundownPatchList );
  1087. }
  1088. return st;
  1089. }
  1090. NTSTATUS
  1091. LdrGetProcedureAddress (
  1092. IN PVOID DllHandle,
  1093. IN CONST ANSI_STRING* ProcedureName OPTIONAL,
  1094. IN ULONG ProcedureNumber OPTIONAL,
  1095. OUT PVOID *ProcedureAddress
  1096. )
  1097. {
  1098. return LdrpGetProcedureAddress(DllHandle,ProcedureName,ProcedureNumber,ProcedureAddress,TRUE);
  1099. }
  1100. NTSTATUS
  1101. LdrpGetProcedureAddress (
  1102. IN PVOID DllHandle,
  1103. IN CONST ANSI_STRING* ProcedureName OPTIONAL,
  1104. IN ULONG ProcedureNumber OPTIONAL,
  1105. OUT PVOID *ProcedureAddress,
  1106. IN BOOLEAN RunInitRoutines
  1107. )
  1108. /*++
  1109. Routine Description:
  1110. This function locates the address of the specified procedure in the
  1111. specified DLL and returns its address.
  1112. Arguments:
  1113. DllHandle - Supplies a handle to the DLL that the address is being
  1114. looked up in.
  1115. ProcedureName - Supplies that address of a string that contains the
  1116. name of the procedure to lookup in the DLL. If this argument is
  1117. not specified, then the ProcedureNumber is used.
  1118. ProcedureNumber - Supplies the procedure number to lookup. If
  1119. ProcedureName is specified, then this argument is ignored.
  1120. Otherwise, it specifies the procedure ordinal number to locate
  1121. in the DLL.
  1122. ProcedureAddress - Returns the address of the procedure found in
  1123. the DLL.
  1124. Return Value:
  1125. NTSTATUS.
  1126. --*/
  1127. {
  1128. NTSTATUS st;
  1129. UCHAR FunctionNameBuffer[64];
  1130. ULONG cb, ExportSize;
  1131. PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
  1132. IMAGE_THUNK_DATA Thunk;
  1133. PVOID ImageBase;
  1134. PIMAGE_IMPORT_BY_NAME FunctionName;
  1135. PCIMAGE_EXPORT_DIRECTORY ExportDirectory;
  1136. PLIST_ENTRY Next;
  1137. if (ShowSnaps) {
  1138. DbgPrint("LDR: LdrGetProcedureAddress by ");
  1139. }
  1140. RtlZeroMemory( &Thunk, sizeof( Thunk ) );
  1141. FunctionName = NULL;
  1142. if ( ARGUMENT_PRESENT(ProcedureName) ) {
  1143. if (ShowSnaps) {
  1144. DbgPrint("NAME - %s\n", ProcedureName->Buffer);
  1145. }
  1146. cb = ProcedureName->Length + FIELD_OFFSET(IMAGE_IMPORT_BY_NAME, Name) +
  1147. sizeof( UCHAR );
  1148. if (cb > MAXUSHORT) {
  1149. return STATUS_NAME_TOO_LONG;
  1150. }
  1151. if (cb > sizeof( FunctionNameBuffer )) {
  1152. FunctionName = (PIMAGE_IMPORT_BY_NAME)RtlAllocateHeap(
  1153. RtlProcessHeap(),
  1154. MAKE_TAG( TEMP_TAG ),
  1155. cb
  1156. );
  1157. if ( !FunctionName ) {
  1158. return STATUS_INVALID_PARAMETER;
  1159. }
  1160. } else {
  1161. FunctionName = (PIMAGE_IMPORT_BY_NAME) FunctionNameBuffer;
  1162. }
  1163. FunctionName->Hint = 0;
  1164. cb = ProcedureName->Length;
  1165. RtlCopyMemory (FunctionName->Name, ProcedureName->Buffer, cb);
  1166. FunctionName->Name[cb] = '\0';
  1167. //
  1168. // Make sure we don't pass in address with high bit set so we
  1169. // can still use it as ordinal flag
  1170. //
  1171. ImageBase = FunctionName;
  1172. Thunk.u1.AddressOfData = 0;
  1173. } else {
  1174. ImageBase = NULL;
  1175. if (ShowSnaps) {
  1176. DbgPrint("ORDINAL - %lx\n", ProcedureNumber);
  1177. }
  1178. if (ProcedureNumber) {
  1179. Thunk.u1.Ordinal = ProcedureNumber | IMAGE_ORDINAL_FLAG;
  1180. } else {
  1181. return STATUS_INVALID_PARAMETER;
  1182. }
  1183. }
  1184. st = STATUS_ACCESS_VIOLATION;
  1185. if (!LdrpInLdrInit) {
  1186. RtlEnterCriticalSection (&LdrpLoaderLock);
  1187. }
  1188. try {
  1189. if (!LdrpCheckForLoadedDllHandle (DllHandle, &LdrDataTableEntry)) {
  1190. st = STATUS_DLL_NOT_FOUND;
  1191. leave;
  1192. }
  1193. ExportDirectory = (PCIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(
  1194. LdrDataTableEntry->DllBase,
  1195. TRUE,
  1196. IMAGE_DIRECTORY_ENTRY_EXPORT,
  1197. &ExportSize);
  1198. if (!ExportDirectory) {
  1199. st = STATUS_PROCEDURE_NOT_FOUND;
  1200. leave;
  1201. }
  1202. st = LdrpSnapThunk(LdrDataTableEntry->DllBase,
  1203. ImageBase,
  1204. &Thunk,
  1205. &Thunk,
  1206. ExportDirectory,
  1207. ExportSize,
  1208. FALSE,
  1209. NULL);
  1210. if (NT_SUCCESS(st) && RunInitRoutines) {
  1211. PLDR_DATA_TABLE_ENTRY LdrInitEntry;
  1212. //
  1213. // Look at last entry in init order list. If entry processed
  1214. // flag is not set, then a forwarded dll was loaded during the
  1215. // getprocaddr call and we need to run init routines
  1216. //
  1217. Next = PebLdr.InInitializationOrderModuleList.Blink;
  1218. LdrInitEntry = CONTAINING_RECORD(Next,
  1219. LDR_DATA_TABLE_ENTRY,
  1220. InInitializationOrderLinks);
  1221. if ( !(LdrInitEntry->Flags & LDRP_ENTRY_PROCESSED) ) {
  1222. //
  1223. // Shim engine callback. This is the chance to patch
  1224. // dynamically loaded modules.
  1225. //
  1226. try {
  1227. st = LdrpRunInitializeRoutines(NULL);
  1228. }
  1229. except(LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {
  1230. st = GetExceptionCode();
  1231. DbgPrintEx(
  1232. DPFLTR_LDR_ID,
  1233. LDR_ERROR_DPFLTR,
  1234. "LDR: %s - Exception %x thrown by LdrpRunInitializeRoutines\n",
  1235. __FUNCTION__,
  1236. st);
  1237. }
  1238. }
  1239. }
  1240. if ( NT_SUCCESS(st) ) {
  1241. *ProcedureAddress = (PVOID)Thunk.u1.Function;
  1242. }
  1243. } finally {
  1244. if ( FunctionName && (FunctionName != (PIMAGE_IMPORT_BY_NAME) FunctionNameBuffer) ) {
  1245. RtlFreeHeap(RtlProcessHeap(),0,FunctionName);
  1246. }
  1247. if (!LdrpInLdrInit) {
  1248. RtlLeaveCriticalSection(&LdrpLoaderLock);
  1249. }
  1250. }
  1251. return st;
  1252. }
  1253. NTSTATUS
  1254. NTAPI
  1255. LdrVerifyImageMatchesChecksum (
  1256. IN HANDLE ImageFileHandle,
  1257. IN PLDR_IMPORT_MODULE_CALLBACK ImportCallbackRoutine OPTIONAL,
  1258. IN PVOID ImportCallbackParameter,
  1259. OUT PUSHORT ImageCharacteristics OPTIONAL
  1260. )
  1261. {
  1262. NTSTATUS Status;
  1263. HANDLE Section;
  1264. PVOID ViewBase;
  1265. SIZE_T ViewSize;
  1266. IO_STATUS_BLOCK IoStatusBlock;
  1267. FILE_STANDARD_INFORMATION StandardInfo;
  1268. PIMAGE_SECTION_HEADER LastRvaSection;
  1269. BOOLEAN b = FALSE;
  1270. BOOLEAN JustDoSideEffects;
  1271. //
  1272. // stevewo added all sorts of side effects to this API. We want to stop
  1273. // doing checksums for known dll's, but really want the sideeffects
  1274. // (ImageCharacteristics write, and Import descriptor walk).
  1275. //
  1276. if ( (UINT_PTR) ImageFileHandle & 1 ) {
  1277. JustDoSideEffects = TRUE;
  1278. }
  1279. else {
  1280. JustDoSideEffects = FALSE;
  1281. }
  1282. Status = NtCreateSection (&Section,
  1283. SECTION_MAP_EXECUTE,
  1284. NULL,
  1285. NULL,
  1286. PAGE_EXECUTE,
  1287. SEC_COMMIT,
  1288. ImageFileHandle);
  1289. if (!NT_SUCCESS(Status)) {
  1290. return Status;
  1291. }
  1292. ViewBase = NULL;
  1293. ViewSize = 0;
  1294. Status = NtMapViewOfSection (Section,
  1295. NtCurrentProcess(),
  1296. (PVOID *)&ViewBase,
  1297. 0L,
  1298. 0L,
  1299. NULL,
  1300. &ViewSize,
  1301. ViewShare,
  1302. 0L,
  1303. PAGE_EXECUTE);
  1304. if ( !NT_SUCCESS(Status) ) {
  1305. NtClose(Section);
  1306. return Status;
  1307. }
  1308. //
  1309. // now the image is mapped as a data file... Calculate it's size and then
  1310. // check it's checksum
  1311. //
  1312. Status = NtQueryInformationFile(
  1313. ImageFileHandle,
  1314. &IoStatusBlock,
  1315. &StandardInfo,
  1316. sizeof(StandardInfo),
  1317. FileStandardInformation
  1318. );
  1319. if ( !NT_SUCCESS(Status) ) {
  1320. NtUnmapViewOfSection(NtCurrentProcess(),ViewBase);
  1321. NtClose(Section);
  1322. return Status;
  1323. }
  1324. try {
  1325. if ( JustDoSideEffects ) {
  1326. b = TRUE;
  1327. }
  1328. else {
  1329. b = LdrVerifyMappedImageMatchesChecksum(ViewBase,StandardInfo.EndOfFile.LowPart);
  1330. }
  1331. if (b && ARGUMENT_PRESENT( (ULONG_PTR)ImportCallbackRoutine )) {
  1332. PIMAGE_NT_HEADERS NtHeaders;
  1333. PCIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
  1334. ULONG ImportSize;
  1335. PCHAR ImportName;
  1336. //
  1337. // Caller wants to enumerate the import descriptors while we have
  1338. // the image mapped. Call back to their routine for each module
  1339. // name in the import descriptor table.
  1340. //
  1341. LastRvaSection = NULL;
  1342. NtHeaders = RtlImageNtHeader( ViewBase );
  1343. if (! NtHeaders) {
  1344. b = FALSE;
  1345. leave;
  1346. }
  1347. if (ARGUMENT_PRESENT( ImageCharacteristics )) {
  1348. *ImageCharacteristics = NtHeaders->FileHeader.Characteristics;
  1349. }
  1350. ImportDescriptor = (PCIMAGE_IMPORT_DESCRIPTOR)
  1351. RtlImageDirectoryEntryToData( ViewBase,
  1352. FALSE,
  1353. IMAGE_DIRECTORY_ENTRY_IMPORT,
  1354. &ImportSize
  1355. );
  1356. if (ImportDescriptor != NULL) {
  1357. while (ImportDescriptor->Name) {
  1358. ImportName = (PSZ)RtlImageRvaToVa( NtHeaders,
  1359. ViewBase,
  1360. ImportDescriptor->Name,
  1361. &LastRvaSection
  1362. );
  1363. (*ImportCallbackRoutine)( ImportCallbackParameter, ImportName );
  1364. ImportDescriptor += 1;
  1365. }
  1366. }
  1367. }
  1368. }
  1369. except (LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {
  1370. DbgPrintEx(
  1371. DPFLTR_LDR_ID,
  1372. LDR_ERROR_DPFLTR,
  1373. "LDR: %s - caught exception %08lx while checking image checksums\n",
  1374. __FUNCTION__,
  1375. GetExceptionCode());
  1376. NtUnmapViewOfSection(NtCurrentProcess(),ViewBase);
  1377. NtClose(Section);
  1378. return STATUS_IMAGE_CHECKSUM_MISMATCH;
  1379. }
  1380. NtUnmapViewOfSection(NtCurrentProcess(),ViewBase);
  1381. NtClose(Section);
  1382. if ( !b ) {
  1383. Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
  1384. }
  1385. return Status;
  1386. }
  1387. NTSTATUS
  1388. LdrReadMemory(
  1389. IN HANDLE Process OPTIONAL,
  1390. IN PVOID BaseAddress,
  1391. IN OUT PVOID Buffer,
  1392. IN SIZE_T Size)
  1393. {
  1394. NTSTATUS Status = STATUS_SUCCESS;
  1395. if (ARGUMENT_PRESENT( Process )) {
  1396. SIZE_T nRead;
  1397. Status = NtReadVirtualMemory(Process, BaseAddress, Buffer, Size, &nRead);
  1398. if (NT_SUCCESS( Status ) && (Size != nRead)) {
  1399. Status = STATUS_UNSUCCESSFUL;
  1400. }
  1401. }
  1402. else {
  1403. __try {
  1404. RtlCopyMemory(Buffer, BaseAddress, Size);
  1405. }
  1406. __except(LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {
  1407. DbgPrintEx(
  1408. DPFLTR_LDR_ID,
  1409. LDR_ERROR_DPFLTR,
  1410. "LDR: %s - exception %08lx caught while copying %u bytes from %p to %p\n",
  1411. __FUNCTION__,
  1412. GetExceptionCode(),
  1413. BaseAddress,
  1414. Buffer);
  1415. if (NT_SUCCESS(Status = GetExceptionCode())) {
  1416. Status = STATUS_UNSUCCESSFUL;
  1417. }
  1418. }
  1419. }
  1420. return Status;
  1421. }
  1422. NTSTATUS
  1423. LdrGetModuleName(
  1424. IN HANDLE Process OPTIONAL,
  1425. IN PCUNICODE_STRING LdrFullDllName,
  1426. IN OUT PRTL_PROCESS_MODULE_INFORMATION ModuleInfo,
  1427. IN BOOL Wow64Redirect)
  1428. {
  1429. NTSTATUS Status;
  1430. UNICODE_STRING FullDllName;
  1431. ANSI_STRING AnsiString;
  1432. PCHAR s;
  1433. WCHAR Buffer[ LDR_NUMBER_OF(ModuleInfo->FullPathName) + 1];
  1434. USHORT Length = (USHORT)min(LdrFullDllName->Length,
  1435. sizeof(Buffer) - sizeof(Buffer[0]));
  1436. Status = LdrReadMemory(Process,
  1437. LdrFullDllName->Buffer,
  1438. Buffer,
  1439. Length);
  1440. if (!NT_SUCCESS( Status )) {
  1441. return Status;
  1442. }
  1443. Buffer[LDR_NUMBER_OF(Buffer) - 1] = UNICODE_NULL; // Ensure NULL termination
  1444. #if defined(_WIN64)
  1445. if (Wow64Redirect) {
  1446. C_ASSERT( WOW64_SYSTEM_DIRECTORY_U_SIZE ==
  1447. (sizeof(L"system32") - sizeof(WCHAR)));
  1448. // including preceding '\\' if exists
  1449. SIZE_T System32Offset = wcslen(USER_SHARED_DATA->NtSystemRoot);
  1450. ASSERT(System32Offset != 0);
  1451. if (USER_SHARED_DATA->NtSystemRoot[System32Offset - 1] == L'\\') {
  1452. --System32Offset;
  1453. }
  1454. if (!_wcsnicmp(Buffer, USER_SHARED_DATA->NtSystemRoot, System32Offset) &&
  1455. !_wcsnicmp(Buffer + System32Offset,
  1456. L"\\system32",
  1457. WOW64_SYSTEM_DIRECTORY_U_SIZE / sizeof(WCHAR) + 1)) {
  1458. RtlCopyMemory(Buffer + System32Offset + 1,
  1459. WOW64_SYSTEM_DIRECTORY_U,
  1460. WOW64_SYSTEM_DIRECTORY_U_SIZE);
  1461. }
  1462. }
  1463. #else
  1464. UNREFERENCED_PARAMETER (Wow64Redirect);
  1465. #endif // defined(_WIN64)
  1466. FullDllName.Buffer = Buffer;
  1467. FullDllName.Length = FullDllName.MaximumLength = Length;
  1468. AnsiString.Buffer = (PCHAR)ModuleInfo->FullPathName;
  1469. AnsiString.Length = 0;
  1470. AnsiString.MaximumLength = sizeof( ModuleInfo->FullPathName );
  1471. Status = RtlUnicodeStringToAnsiString(&AnsiString,
  1472. &FullDllName,
  1473. FALSE);
  1474. if (!NT_SUCCESS (Status)) {
  1475. return Status;
  1476. }
  1477. s = AnsiString.Buffer + AnsiString.Length;
  1478. while (s > AnsiString.Buffer && *--s) {
  1479. if (*s == (UCHAR)OBJ_NAME_PATH_SEPARATOR) {
  1480. s++;
  1481. break;
  1482. }
  1483. }
  1484. ModuleInfo->OffsetToFileName = (USHORT)(s - AnsiString.Buffer);
  1485. return STATUS_SUCCESS;
  1486. }
  1487. NTSTATUS
  1488. LdrQueryProcessPeb (
  1489. IN HANDLE Process OPTIONAL,
  1490. IN OUT PPEB* Peb)
  1491. {
  1492. NTSTATUS Status;
  1493. PROCESS_BASIC_INFORMATION BasicInfo;
  1494. if (ARGUMENT_PRESENT (Process)) {
  1495. Status = NtQueryInformationProcess (Process,
  1496. ProcessBasicInformation,
  1497. &BasicInfo,
  1498. sizeof(BasicInfo),
  1499. NULL);
  1500. if (NT_SUCCESS (Status)) {
  1501. *Peb = BasicInfo.PebBaseAddress;
  1502. }
  1503. }
  1504. else {
  1505. *Peb = NtCurrentPeb ();
  1506. Status = STATUS_SUCCESS;
  1507. }
  1508. return Status;
  1509. }
  1510. NTSTATUS
  1511. LdrQueryInLoadOrderModuleList (
  1512. IN HANDLE Process OPTIONAL,
  1513. IN OUT PLIST_ENTRY* Head,
  1514. IN OUT PLIST_ENTRY* InInitOrderHead OPTIONAL
  1515. )
  1516. {
  1517. PPEB_LDR_DATA Ldr;
  1518. UNREFERENCED_PARAMETER (Process);
  1519. Ldr = &PebLdr;
  1520. *Head = &Ldr->InLoadOrderModuleList;
  1521. if (ARGUMENT_PRESENT (InInitOrderHead)) {
  1522. *InInitOrderHead = &Ldr->InInitializationOrderModuleList;
  1523. }
  1524. return STATUS_SUCCESS;
  1525. }
  1526. NTSTATUS
  1527. LdrQueryNextListEntry (
  1528. IN HANDLE Process OPTIONAL,
  1529. IN PLIST_ENTRY Head,
  1530. IN OUT PLIST_ENTRY* Tail
  1531. )
  1532. {
  1533. return LdrReadMemory (Process, &Head->Flink, Tail, sizeof(*Tail));
  1534. }
  1535. NTSTATUS
  1536. LdrQueryModuleInfoFromLdrEntry (
  1537. IN HANDLE Process OPTIONAL,
  1538. IN PRTL_PROCESS_MODULES ModuleInformation,
  1539. IN OUT PRTL_PROCESS_MODULE_INFORMATION ModuleInfo,
  1540. IN PLIST_ENTRY LdrEntry,
  1541. IN PLIST_ENTRY InitOrderList)
  1542. {
  1543. NTSTATUS Status;
  1544. PLDR_DATA_TABLE_ENTRY LdrDataTableEntryPtr;
  1545. LDR_DATA_TABLE_ENTRY LdrDataTableEntry;
  1546. UNREFERENCED_PARAMETER (ModuleInformation);
  1547. LdrDataTableEntryPtr = CONTAINING_RECORD(LdrEntry,
  1548. LDR_DATA_TABLE_ENTRY,
  1549. InLoadOrderLinks);
  1550. Status = LdrReadMemory(Process,
  1551. LdrEntry,
  1552. &LdrDataTableEntry,
  1553. sizeof(LdrDataTableEntry));
  1554. if (!NT_SUCCESS (Status)) {
  1555. return Status;
  1556. }
  1557. ModuleInfo->ImageBase = LdrDataTableEntry.DllBase;
  1558. ModuleInfo->ImageSize = LdrDataTableEntry.SizeOfImage;
  1559. ModuleInfo->Flags = LdrDataTableEntry.Flags;
  1560. ModuleInfo->LoadCount = LdrDataTableEntry.LoadCount;
  1561. if (!ARGUMENT_PRESENT( Process )) {
  1562. UINT LoopDetectorCount = 10240; // 10K modules max
  1563. PLIST_ENTRY Next1 = InitOrderList->Flink;
  1564. while ( Next1 != InitOrderList ) {
  1565. PLDR_DATA_TABLE_ENTRY Entry1 =
  1566. CONTAINING_RECORD(Next1,
  1567. LDR_DATA_TABLE_ENTRY,
  1568. InInitializationOrderLinks);
  1569. ModuleInfo->InitOrderIndex++;
  1570. if ((LdrDataTableEntryPtr == Entry1) ||
  1571. (!LoopDetectorCount--))
  1572. {
  1573. break;
  1574. }
  1575. Next1 = Next1->Flink;
  1576. }
  1577. }
  1578. Status = LdrGetModuleName(Process,
  1579. &LdrDataTableEntry.FullDllName,
  1580. ModuleInfo,
  1581. FALSE);
  1582. return Status;
  1583. }
  1584. PRTL_CRITICAL_SECTION
  1585. LdrQueryModuleInfoLocalLoaderLock (
  1586. VOID
  1587. )
  1588. {
  1589. PRTL_CRITICAL_SECTION LoaderLock = NULL;
  1590. if (!LdrpInLdrInit) {
  1591. LoaderLock = &LdrpLoaderLock;
  1592. if (LoaderLock != NULL) {
  1593. RtlEnterCriticalSection (LoaderLock);
  1594. }
  1595. }
  1596. return LoaderLock;
  1597. }
  1598. VOID
  1599. LdrQueryModuleInfoLocalLoaderUnlock (
  1600. IN PRTL_CRITICAL_SECTION LoaderLock
  1601. )
  1602. {
  1603. if (LoaderLock) {
  1604. RtlLeaveCriticalSection(LoaderLock);
  1605. }
  1606. }
  1607. #if defined(_WIN64)
  1608. NTSTATUS
  1609. LdrQueryProcessPeb32(
  1610. IN HANDLE Process OPTIONAL,
  1611. IN OUT PPEB32* Peb
  1612. )
  1613. {
  1614. NTSTATUS Status;
  1615. HANDLE TargetProcess;
  1616. if (ARGUMENT_PRESENT (Process)) {
  1617. TargetProcess = Process;
  1618. }
  1619. else {
  1620. TargetProcess = NtCurrentProcess ();
  1621. }
  1622. Status = NtQueryInformationProcess (TargetProcess,
  1623. ProcessWow64Information,
  1624. Peb,
  1625. sizeof(*Peb),
  1626. NULL);
  1627. return Status;
  1628. }
  1629. NTSTATUS
  1630. LdrQueryInLoadOrderModuleList32(
  1631. IN HANDLE Process OPTIONAL,
  1632. IN OUT PLIST_ENTRY32 *Head,
  1633. IN OUT PLIST_ENTRY32 *InInitOrderHead OPTIONAL
  1634. )
  1635. {
  1636. NTSTATUS Status;
  1637. PPEB32 Peb;
  1638. PPEB_LDR_DATA32 Ldr;
  1639. ULONG32 Ptr32;
  1640. Status = LdrQueryProcessPeb32 (Process, &Peb);
  1641. if (!NT_SUCCESS (Status)) {
  1642. return Status;
  1643. }
  1644. if (!Peb) {
  1645. //
  1646. // The process isn't a WOW process.
  1647. //
  1648. *Head = NULL;
  1649. return STATUS_SUCCESS;
  1650. }
  1651. //
  1652. // Ldr = Peb->Ldr
  1653. //
  1654. Status = LdrReadMemory (Process, &Peb->Ldr, &Ptr32, sizeof(Ptr32));
  1655. if (!NT_SUCCESS (Status)) {
  1656. return Status;
  1657. }
  1658. Ldr = (PPEB_LDR_DATA32)(ULONG_PTR) Ptr32;
  1659. if (!Ldr) {
  1660. *Head = NULL;
  1661. return STATUS_SUCCESS;
  1662. }
  1663. *Head = &Ldr->InLoadOrderModuleList;
  1664. if (ARGUMENT_PRESENT (InInitOrderHead)) {
  1665. *InInitOrderHead = &Ldr->InInitializationOrderModuleList;
  1666. }
  1667. return Status;
  1668. }
  1669. NTSTATUS
  1670. LdrQueryNextListEntry32 (
  1671. IN HANDLE Process OPTIONAL,
  1672. IN PLIST_ENTRY32 Head,
  1673. IN OUT PLIST_ENTRY32 *Tail
  1674. )
  1675. {
  1676. NTSTATUS Status;
  1677. ULONG32 Ptr32;
  1678. Status = LdrReadMemory (Process, &Head->Flink, &Ptr32, sizeof(Ptr32));
  1679. *Tail = (PLIST_ENTRY32)(ULONG_PTR)Ptr32;
  1680. return Status;
  1681. }
  1682. NTSTATUS
  1683. LdrQueryModuleInfoFromLdrEntry32 (
  1684. IN HANDLE Process OPTIONAL,
  1685. IN PRTL_PROCESS_MODULES ModuleInformation,
  1686. IN OUT PRTL_PROCESS_MODULE_INFORMATION ModuleInfo,
  1687. IN PLIST_ENTRY32 LdrEntry,
  1688. IN PLIST_ENTRY32 InitOrderList
  1689. )
  1690. {
  1691. NTSTATUS Status;
  1692. PLDR_DATA_TABLE_ENTRY32 LdrDataTableEntryPtr;
  1693. LDR_DATA_TABLE_ENTRY32 LdrDataTableEntry;
  1694. UNICODE_STRING FullDllName;
  1695. UNREFERENCED_PARAMETER (ModuleInformation);
  1696. LdrDataTableEntryPtr = CONTAINING_RECORD(LdrEntry,
  1697. LDR_DATA_TABLE_ENTRY32,
  1698. InLoadOrderLinks);
  1699. Status = LdrReadMemory (Process,
  1700. LdrEntry,
  1701. &LdrDataTableEntry,
  1702. sizeof(LdrDataTableEntry));
  1703. if (!NT_SUCCESS (Status)) {
  1704. return Status;
  1705. }
  1706. ModuleInfo->ImageBase = (PVOID)(ULONG_PTR) LdrDataTableEntry.DllBase;
  1707. ModuleInfo->ImageSize = LdrDataTableEntry.SizeOfImage;
  1708. ModuleInfo->Flags = LdrDataTableEntry.Flags;
  1709. ModuleInfo->LoadCount = LdrDataTableEntry.LoadCount;
  1710. if (!ARGUMENT_PRESENT( Process )) {
  1711. UINT LoopDetectorCount = 500;
  1712. PLIST_ENTRY32 Next1 = (PLIST_ENTRY32)(ULONG_PTR)
  1713. (InitOrderList->Flink);
  1714. while (Next1 != InitOrderList) {
  1715. PLDR_DATA_TABLE_ENTRY32 Entry1 =
  1716. CONTAINING_RECORD(Next1,
  1717. LDR_DATA_TABLE_ENTRY32,
  1718. InInitializationOrderLinks);
  1719. ModuleInfo->InitOrderIndex++;
  1720. if ((LdrDataTableEntryPtr == Entry1) ||
  1721. (!LoopDetectorCount--))
  1722. {
  1723. break;
  1724. }
  1725. Next1 = (PLIST_ENTRY32)(ULONG_PTR)(Next1->Flink);
  1726. }
  1727. }
  1728. FullDllName.Buffer = (PWSTR)(ULONG_PTR)LdrDataTableEntry.FullDllName.Buffer;
  1729. FullDllName.Length = LdrDataTableEntry.FullDllName.Length;
  1730. FullDllName.MaximumLength = LdrDataTableEntry.FullDllName.MaximumLength;
  1731. Status = LdrGetModuleName(Process, &FullDllName, ModuleInfo, TRUE);
  1732. return Status;
  1733. }
  1734. PRTL_CRITICAL_SECTION32
  1735. LdrQueryModuleInfoLocalLoaderLock32 (
  1736. VOID
  1737. )
  1738. {
  1739. return NULL;
  1740. }
  1741. VOID
  1742. LdrQueryModuleInfoLocalLoaderUnlock32 (
  1743. IN PRTL_CRITICAL_SECTION32 LoaderLock)
  1744. {
  1745. UNREFERENCED_PARAMETER (LoaderLock);
  1746. }
  1747. #endif // defined(_WIN64)
  1748. typedef
  1749. NTSTATUS
  1750. (*PLDR_QUERY_IN_LOAD_ORDER_MODULE_LIST)(
  1751. IN HANDLE Process OPTIONAL,
  1752. IN OUT PLIST_ENTRY* Head,
  1753. IN OUT PLIST_ENTRY* InInitOrderHead OPTIONAL);
  1754. typedef NTSTATUS
  1755. (*PLDR_QUERY_NEXT_LIST_ENTRY)(
  1756. IN HANDLE Process OPTIONAL,
  1757. IN PLIST_ENTRY Head,
  1758. IN OUT PLIST_ENTRY* Tail);
  1759. typedef
  1760. NTSTATUS
  1761. (*PLDR_QUERY_MODULE_INFO_FROM_LDR_ENTRY)(
  1762. IN HANDLE Process OPTIONAL,
  1763. IN PRTL_PROCESS_MODULES ModuleInformation,
  1764. IN OUT PRTL_PROCESS_MODULE_INFORMATION ModuleInfo,
  1765. IN PLIST_ENTRY LdrEntry,
  1766. IN PLIST_ENTRY InitOrderList);
  1767. typedef
  1768. PRTL_CRITICAL_SECTION
  1769. (*PLDR_QUERY_MODULE_INFO_LOCAL_LOADER_LOCK)(VOID);
  1770. typedef
  1771. VOID
  1772. (*PLDR_QUERY_MODULE_INFO_LOCAL_LOADER_UNLOCK)(PRTL_CRITICAL_SECTION);
  1773. static struct {
  1774. PLDR_QUERY_IN_LOAD_ORDER_MODULE_LIST LdrQueryInLoadOrderModuleList;
  1775. PLDR_QUERY_NEXT_LIST_ENTRY LdrQueryNextListEntry;
  1776. PLDR_QUERY_MODULE_INFO_FROM_LDR_ENTRY LdrQueryModuleInfoFromLdrEntry;
  1777. PLDR_QUERY_MODULE_INFO_LOCAL_LOADER_LOCK LdrQueryModuleInfoLocalLoaderLock;
  1778. PLDR_QUERY_MODULE_INFO_LOCAL_LOADER_UNLOCK LdrQueryModuleInfoLocalLoaderUnlock;
  1779. } LdrQueryMethods[] = {
  1780. {
  1781. LdrQueryInLoadOrderModuleList,
  1782. LdrQueryNextListEntry,
  1783. LdrQueryModuleInfoFromLdrEntry,
  1784. LdrQueryModuleInfoLocalLoaderLock,
  1785. LdrQueryModuleInfoLocalLoaderUnlock
  1786. }
  1787. #if defined(_WIN64)
  1788. ,
  1789. {
  1790. (PLDR_QUERY_IN_LOAD_ORDER_MODULE_LIST)LdrQueryInLoadOrderModuleList32,
  1791. (PLDR_QUERY_NEXT_LIST_ENTRY)LdrQueryNextListEntry32,
  1792. (PLDR_QUERY_MODULE_INFO_FROM_LDR_ENTRY)LdrQueryModuleInfoFromLdrEntry32,
  1793. (PLDR_QUERY_MODULE_INFO_LOCAL_LOADER_LOCK)LdrQueryModuleInfoLocalLoaderLock32,
  1794. (PLDR_QUERY_MODULE_INFO_LOCAL_LOADER_UNLOCK)LdrQueryModuleInfoLocalLoaderUnlock32
  1795. }
  1796. #endif defined(_WIN64)
  1797. };
  1798. NTSTATUS
  1799. LdrQueryProcessModuleInformationEx(
  1800. IN HANDLE Process OPTIONAL,
  1801. IN ULONG_PTR Flags OPTIONAL,
  1802. OUT PRTL_PROCESS_MODULES ModuleInformation,
  1803. IN ULONG ModuleInformationLength,
  1804. OUT PULONG ReturnLength OPTIONAL)
  1805. {
  1806. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  1807. PRTL_CRITICAL_SECTION LoaderLock = NULL;
  1808. SIZE_T mid;
  1809. ULONG RequiredLength = FIELD_OFFSET( RTL_PROCESS_MODULES, Modules );
  1810. PLIST_ENTRY List;
  1811. PLIST_ENTRY InInitOrderList;
  1812. PRTL_PROCESS_MODULE_INFORMATION ModuleInfo;
  1813. if (ModuleInformationLength < RequiredLength) {
  1814. Status = STATUS_INFO_LENGTH_MISMATCH;
  1815. ModuleInfo = NULL;
  1816. }
  1817. else {
  1818. ModuleInformation->NumberOfModules = 0;
  1819. ModuleInfo = &ModuleInformation->Modules[ 0 ];
  1820. Status = STATUS_SUCCESS;
  1821. }
  1822. for (mid = 0;
  1823. mid < (ARGUMENT_PRESENT( Flags ) ? LDR_NUMBER_OF(LdrQueryMethods) : 1);
  1824. ++mid)
  1825. {
  1826. NTSTATUS Status1;
  1827. PLIST_ENTRY Entry;
  1828. __try {
  1829. UINT LoopDetectorCount = 10240; // allow not more than 10K modules
  1830. if ( !ARGUMENT_PRESENT( Process )) {
  1831. LoaderLock = LdrQueryMethods[mid].LdrQueryModuleInfoLocalLoaderLock();
  1832. }
  1833. Status1 = LdrQueryMethods[mid].LdrQueryInLoadOrderModuleList(Process, &List, &InInitOrderList);
  1834. if (!NT_SUCCESS( Status1 )) {
  1835. Status = Status1;
  1836. __leave;
  1837. }
  1838. if (!List) {
  1839. __leave;
  1840. }
  1841. Status1 = LdrQueryMethods[mid].LdrQueryNextListEntry(Process,
  1842. List,
  1843. &Entry);
  1844. if (!NT_SUCCESS( Status1 )) {
  1845. Status = Status1;
  1846. __leave;
  1847. }
  1848. while (Entry != List) {
  1849. if (!LoopDetectorCount--) {
  1850. Status = STATUS_FAIL_CHECK;
  1851. __leave;
  1852. }
  1853. RequiredLength += sizeof( RTL_PROCESS_MODULE_INFORMATION );
  1854. if (ModuleInformationLength < RequiredLength) {
  1855. Status = STATUS_INFO_LENGTH_MISMATCH;
  1856. }
  1857. else {
  1858. Status1 = LdrQueryMethods[mid].LdrQueryModuleInfoFromLdrEntry(Process,
  1859. ModuleInformation,
  1860. ModuleInfo,
  1861. Entry, InInitOrderList);
  1862. if (!NT_SUCCESS( Status1 )) {
  1863. Status = Status1;
  1864. __leave;
  1865. }
  1866. ModuleInfo++;
  1867. }
  1868. //
  1869. // NOTICE-2002/03/15-ELi
  1870. // This chould be non-NULL and not a valid access
  1871. // should check ModuleInfo or ModuleInformationLength instead
  1872. // Assuming ModuleInfo is not NULL when the code can safely
  1873. // reference ModuleInformation->NumberOfModules
  1874. //
  1875. if ((ModuleInfo != NULL) && (ModuleInformation != NULL)) {
  1876. ModuleInformation->NumberOfModules++;
  1877. }
  1878. Status1 = LdrQueryMethods[mid].LdrQueryNextListEntry(Process,
  1879. Entry,
  1880. &Entry);
  1881. if (!NT_SUCCESS( Status1 )) {
  1882. Status = Status1;
  1883. __leave;
  1884. }
  1885. } // while
  1886. }
  1887. __finally {
  1888. if (LoaderLock) {
  1889. LdrQueryMethods[mid].LdrQueryModuleInfoLocalLoaderUnlock(LoaderLock);
  1890. }
  1891. if (ARGUMENT_PRESENT( ReturnLength )) {
  1892. *ReturnLength = RequiredLength;
  1893. }
  1894. }
  1895. } // for
  1896. return Status;
  1897. }
  1898. NTSTATUS
  1899. LdrQueryProcessModuleInformation(
  1900. OUT PRTL_PROCESS_MODULES ModuleInformation,
  1901. IN ULONG ModuleInformationLength,
  1902. OUT PULONG ReturnLength OPTIONAL)
  1903. {
  1904. return LdrQueryProcessModuleInformationEx(NULL,
  1905. 0,
  1906. ModuleInformation,
  1907. ModuleInformationLength,
  1908. ReturnLength);
  1909. }
  1910. NTSTATUS
  1911. NTAPI
  1912. LdrRegisterDllNotification (
  1913. ULONG Flags,
  1914. PLDR_DLL_NOTIFICATION_FUNCTION NotificationFunction,
  1915. PVOID Context,
  1916. PVOID *Cookie
  1917. )
  1918. {
  1919. NTSTATUS Status = STATUS_SUCCESS;
  1920. PLDRP_DLL_NOTIFICATION_BLOCK NotificationBlock = NULL;
  1921. BOOLEAN HoldingLoaderLock = FALSE;
  1922. const BOOLEAN InLdrInit = LdrpInLdrInit;
  1923. PVOID LockCookie = NULL;
  1924. __try {
  1925. if (Cookie != NULL) {
  1926. *Cookie = NULL;
  1927. }
  1928. if ((Flags != 0) ||
  1929. (Cookie == NULL) ||
  1930. (NotificationFunction == NULL)) {
  1931. Status = STATUS_INVALID_PARAMETER;
  1932. goto Exit;
  1933. }
  1934. NotificationBlock = (PLDRP_DLL_NOTIFICATION_BLOCK)
  1935. RtlAllocateHeap(RtlProcessHeap(), 0, sizeof(LDRP_DLL_NOTIFICATION_BLOCK));
  1936. if (NotificationBlock == NULL) {
  1937. Status = STATUS_NO_MEMORY;
  1938. goto Exit;
  1939. }
  1940. NotificationBlock->NotificationFunction = NotificationFunction;
  1941. NotificationBlock->Context = Context;
  1942. if (!InLdrInit) {
  1943. __try {
  1944. Status = LdrLockLoaderLock(0, NULL, &LockCookie);
  1945. if (!NT_SUCCESS(Status)) {
  1946. goto Exit;
  1947. }
  1948. HoldingLoaderLock = TRUE;
  1949. } __except (LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {
  1950. Status = GetExceptionCode();
  1951. goto Exit;
  1952. }
  1953. }
  1954. InsertTailList(&LdrpDllNotificationList, &NotificationBlock->Links);
  1955. *Cookie = (PVOID) NotificationBlock;
  1956. NotificationBlock = NULL;
  1957. Status = STATUS_SUCCESS;
  1958. Exit:
  1959. ;
  1960. } __finally {
  1961. if (HoldingLoaderLock) {
  1962. LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, LockCookie);
  1963. HoldingLoaderLock = FALSE;
  1964. }
  1965. if (NotificationBlock != NULL) {
  1966. RtlFreeHeap(RtlProcessHeap(), 0, NotificationBlock);
  1967. }
  1968. }
  1969. return Status;
  1970. }
  1971. NTSTATUS
  1972. NTAPI
  1973. LdrUnregisterDllNotification (
  1974. PVOID Cookie
  1975. )
  1976. {
  1977. PLDRP_DLL_NOTIFICATION_BLOCK NotificationBlock;
  1978. NTSTATUS Status;
  1979. BOOLEAN HoldingLoaderLock;
  1980. BOOLEAN InLdrInit;
  1981. PVOID LockCookie;
  1982. if (Cookie == NULL) {
  1983. return STATUS_INVALID_PARAMETER;
  1984. }
  1985. Status = STATUS_SUCCESS;
  1986. HoldingLoaderLock = FALSE;
  1987. InLdrInit = LdrpInLdrInit;
  1988. LockCookie = NULL;
  1989. __try {
  1990. if (!InLdrInit) {
  1991. __try {
  1992. Status = LdrLockLoaderLock (0, NULL, &LockCookie);
  1993. if (!NT_SUCCESS(Status)) {
  1994. goto Exit;
  1995. }
  1996. HoldingLoaderLock = TRUE;
  1997. } __except (LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {
  1998. Status = GetExceptionCode();
  1999. goto Exit;
  2000. }
  2001. }
  2002. NotificationBlock = CONTAINING_RECORD(LdrpDllNotificationList.Flink, LDRP_DLL_NOTIFICATION_BLOCK, Links);
  2003. while (&NotificationBlock->Links != &LdrpDllNotificationList) {
  2004. if (NotificationBlock == Cookie)
  2005. break;
  2006. NotificationBlock = CONTAINING_RECORD(NotificationBlock->Links.Flink, LDRP_DLL_NOTIFICATION_BLOCK, Links);
  2007. }
  2008. if (&NotificationBlock->Links != &LdrpDllNotificationList) {
  2009. RemoveEntryList(&NotificationBlock->Links);
  2010. RtlFreeHeap(RtlProcessHeap(), 0, NotificationBlock);
  2011. Status = STATUS_SUCCESS;
  2012. } else {
  2013. Status = STATUS_NOT_FOUND;
  2014. }
  2015. Exit:
  2016. ;
  2017. } __finally {
  2018. if (HoldingLoaderLock) {
  2019. LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, LockCookie);
  2020. HoldingLoaderLock = FALSE;
  2021. }
  2022. }
  2023. return Status;
  2024. }
  2025. VOID
  2026. LdrpSendDllNotifications (
  2027. IN PLDR_DATA_TABLE_ENTRY Entry,
  2028. IN ULONG NotificationType,
  2029. IN ULONG Flags
  2030. )
  2031. {
  2032. PLIST_ENTRY Next;
  2033. LDR_DLL_NOTIFICATION_DATA Data;
  2034. Data.Loaded.Flags = Flags;
  2035. Data.Loaded.FullDllName = &Entry->FullDllName;
  2036. Data.Loaded.BaseDllName = &Entry->BaseDllName;
  2037. Data.Loaded.DllBase = Entry->DllBase;
  2038. Data.Loaded.SizeOfImage = Entry->SizeOfImage;
  2039. Next = LdrpDllNotificationList.Flink;
  2040. while (Next != &LdrpDllNotificationList) {
  2041. PLDRP_DLL_NOTIFICATION_BLOCK Block = CONTAINING_RECORD(Next, LDRP_DLL_NOTIFICATION_BLOCK, Links);
  2042. __try {
  2043. (*Block->NotificationFunction)(NotificationType, &Data, Block->Context);
  2044. } __except (LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {
  2045. // just go on to the next one...
  2046. }
  2047. Next = Next->Flink;
  2048. }
  2049. }
  2050. BOOLEAN
  2051. NTAPI
  2052. RtlDllShutdownInProgress (
  2053. VOID
  2054. )
  2055. /*++
  2056. Routine Description:
  2057. This routine returns the status of DLL shutdown.
  2058. Arguments:
  2059. None
  2060. Return Value:
  2061. BOOLEAN - TRUE: Shutdown is in progress, FALSE: Shutdown is not currently in progress.
  2062. --*/
  2063. {
  2064. if (LdrpShutdownInProgress) {
  2065. return TRUE;
  2066. } else {
  2067. return FALSE;
  2068. }
  2069. }
  2070. NTSTATUS
  2071. NTAPI
  2072. LdrLockLoaderLock (
  2073. ULONG Flags,
  2074. PULONG Disposition,
  2075. PVOID *Cookie
  2076. )
  2077. {
  2078. NTSTATUS Status;
  2079. BOOLEAN InLdrInit;
  2080. InLdrInit = LdrpInLdrInit;
  2081. if (Disposition != NULL) {
  2082. *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_INVALID;
  2083. }
  2084. if (Cookie != NULL) {
  2085. *Cookie = NULL;
  2086. }
  2087. if ((Flags & ~(LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY | LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)) != 0) {
  2088. if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) {
  2089. RtlRaiseStatus(STATUS_INVALID_PARAMETER_1);
  2090. }
  2091. Status = STATUS_INVALID_PARAMETER_1;
  2092. goto Exit;
  2093. }
  2094. if (Cookie == NULL) {
  2095. if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) {
  2096. RtlRaiseStatus (STATUS_INVALID_PARAMETER_3);
  2097. }
  2098. Status = STATUS_INVALID_PARAMETER_3;
  2099. goto Exit;
  2100. }
  2101. //
  2102. // If you hit this assertion failure, you specified that you only wanted to
  2103. // try acquiring the lock, but you forgot to specify a Disposition out where
  2104. // this function could indicate whether the lock was actually acquired.
  2105. //
  2106. ASSERT((Disposition != NULL) || !(Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY));
  2107. if ((Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY) &&
  2108. (Disposition == NULL)) {
  2109. if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) {
  2110. RtlRaiseStatus(STATUS_INVALID_PARAMETER_2);
  2111. }
  2112. Status = STATUS_INVALID_PARAMETER_2;
  2113. goto Exit;
  2114. }
  2115. if (InLdrInit) {
  2116. Status = STATUS_SUCCESS;
  2117. goto Exit;
  2118. }
  2119. if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) {
  2120. if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY) {
  2121. if (RtlTryEnterCriticalSection(&LdrpLoaderLock)) {
  2122. *Cookie = (PVOID) MAKE_LOADER_LOCK_COOKIE(LOADER_LOCK_COOKIE_TYPE_NORMAL, InterlockedIncrement(&LdrpLoaderLockAcquisitionCount));
  2123. *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
  2124. } else {
  2125. *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED;
  2126. }
  2127. } else {
  2128. RtlEnterCriticalSection(&LdrpLoaderLock);
  2129. if (Disposition != NULL) {
  2130. *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
  2131. }
  2132. *Cookie = (PVOID) MAKE_LOADER_LOCK_COOKIE(LOADER_LOCK_COOKIE_TYPE_NORMAL, InterlockedIncrement(&LdrpLoaderLockAcquisitionCount));
  2133. }
  2134. } else {
  2135. __try {
  2136. if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY) {
  2137. if (RtlTryEnterCriticalSection(&LdrpLoaderLock)) {
  2138. *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
  2139. *Cookie = (PVOID) MAKE_LOADER_LOCK_COOKIE(LOADER_LOCK_COOKIE_TYPE_NORMAL, InterlockedIncrement(&LdrpLoaderLockAcquisitionCount));
  2140. } else {
  2141. *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED;
  2142. }
  2143. } else {
  2144. RtlEnterCriticalSection(&LdrpLoaderLock);
  2145. if (Disposition != NULL) {
  2146. *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
  2147. }
  2148. *Cookie = (PVOID) MAKE_LOADER_LOCK_COOKIE(LOADER_LOCK_COOKIE_TYPE_NORMAL, InterlockedIncrement(&LdrpLoaderLockAcquisitionCount));
  2149. }
  2150. } __except (LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {
  2151. Status = GetExceptionCode();
  2152. DbgPrintEx(
  2153. DPFLTR_LDR_ID,
  2154. LDR_ERROR_DPFLTR,
  2155. "LDR: %s - Caught exception %08lx\n",
  2156. __FUNCTION__,
  2157. Status);
  2158. goto Exit;
  2159. }
  2160. }
  2161. Status = STATUS_SUCCESS;
  2162. Exit:
  2163. return Status;
  2164. }
  2165. NTSTATUS
  2166. NTAPI
  2167. LdrUnlockLoaderLock(
  2168. ULONG Flags,
  2169. PVOID CookieIn
  2170. )
  2171. {
  2172. NTSTATUS Status;
  2173. const ULONG_PTR Cookie = (ULONG_PTR) CookieIn;
  2174. if ((Flags & ~(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)) != 0) {
  2175. if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
  2176. RtlRaiseStatus(STATUS_INVALID_PARAMETER_1);
  2177. Status = STATUS_INVALID_PARAMETER_1;
  2178. goto Exit;
  2179. }
  2180. if (CookieIn == NULL) {
  2181. Status = STATUS_SUCCESS;
  2182. goto Exit;
  2183. }
  2184. // A little validation on the cookie...
  2185. if (EXTRACT_LOADER_LOCK_COOKIE_TYPE(Cookie) != LOADER_LOCK_COOKIE_TYPE_NORMAL) {
  2186. if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
  2187. RtlRaiseStatus(STATUS_INVALID_PARAMETER_2);
  2188. Status = STATUS_INVALID_PARAMETER_2;
  2189. goto Exit;
  2190. }
  2191. if (EXTRACT_LOADER_LOCK_COOKIE_TID(Cookie) != (HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread) & LOADER_LOCK_COOKIE_TID_BIT_MASK)) {
  2192. if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
  2193. RtlRaiseStatus(STATUS_INVALID_PARAMETER_2);
  2194. Status = STATUS_INVALID_PARAMETER_2;
  2195. goto Exit;
  2196. }
  2197. if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS) {
  2198. RtlLeaveCriticalSection(&LdrpLoaderLock);
  2199. } else {
  2200. __try {
  2201. RtlLeaveCriticalSection(&LdrpLoaderLock);
  2202. } __except (LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {
  2203. Status = GetExceptionCode();
  2204. goto Exit;
  2205. }
  2206. }
  2207. Status = STATUS_SUCCESS;
  2208. Exit:
  2209. return Status;
  2210. }
  2211. NTSTATUS
  2212. NTAPI
  2213. LdrDoesCurrentThreadOwnLoaderLock(
  2214. BOOLEAN *DoesOwnLock
  2215. )
  2216. {
  2217. NTSTATUS Status;
  2218. PTEB Teb;
  2219. if (DoesOwnLock != NULL)
  2220. *DoesOwnLock = FALSE;
  2221. if (DoesOwnLock == NULL) {
  2222. Status = STATUS_INVALID_PARAMETER;
  2223. goto Exit;
  2224. }
  2225. Teb = NtCurrentTeb();
  2226. if (LdrpLoaderLock.OwningThread == Teb->ClientId.UniqueThread)
  2227. *DoesOwnLock = TRUE;
  2228. Status = STATUS_SUCCESS;
  2229. Exit:
  2230. return Status;
  2231. }
  2232. NTSTATUS
  2233. NTAPI
  2234. LdrEnumerateLoadedModules (
  2235. ULONG Flags,
  2236. PLDR_LOADED_MODULE_ENUMERATION_CALLBACK_FUNCTION CallbackFunction,
  2237. PVOID Context
  2238. )
  2239. {
  2240. NTSTATUS Status;
  2241. BOOLEAN LoaderLockLocked = FALSE;
  2242. PLIST_ENTRY LoadOrderListHead = NULL;
  2243. PLIST_ENTRY ListEntry;
  2244. BOOLEAN StopEnumeration = FALSE;
  2245. PVOID LockCookie = NULL;
  2246. if ((Flags != 0) ||
  2247. (CallbackFunction == NULL)) {
  2248. Status = STATUS_INVALID_PARAMETER;
  2249. goto Exit;
  2250. }
  2251. Status = LdrLockLoaderLock(0, NULL, &LockCookie);
  2252. if (!NT_SUCCESS(Status))
  2253. goto Exit;
  2254. LoaderLockLocked = TRUE;
  2255. LoadOrderListHead = &PebLdr.InLoadOrderModuleList;
  2256. ListEntry = LoadOrderListHead->Flink;
  2257. while (ListEntry != LoadOrderListHead) {
  2258. __try {
  2259. (*CallbackFunction)(
  2260. CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks),
  2261. Context,
  2262. &StopEnumeration);
  2263. } __except (LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {
  2264. Status = GetExceptionCode();
  2265. goto Exit;
  2266. }
  2267. if (StopEnumeration)
  2268. break;
  2269. ListEntry = ListEntry->Flink;
  2270. }
  2271. Status = LdrUnlockLoaderLock(0, LockCookie);
  2272. LoaderLockLocked = FALSE;
  2273. if (!NT_SUCCESS(Status)) {
  2274. goto Exit;
  2275. }
  2276. Status = STATUS_SUCCESS;
  2277. Exit:
  2278. if (LoaderLockLocked) {
  2279. NTSTATUS Status2;
  2280. Status2 = LdrUnlockLoaderLock(0, LockCookie);
  2281. ASSERT(NT_SUCCESS(Status2));
  2282. }
  2283. return Status;
  2284. }
  2285. NTSTATUS
  2286. NTAPI
  2287. LdrAddRefDll(
  2288. ULONG Flags,
  2289. PVOID DllHandle
  2290. )
  2291. {
  2292. NTSTATUS Status = STATUS_SUCCESS;
  2293. PLDR_DATA_TABLE_ENTRY LdrDataTableEntry = NULL;
  2294. const BOOLEAN InLdrInit = LdrpInLdrInit;
  2295. PVOID LockCookie = NULL;
  2296. BOOLEAN HoldingLoaderLock = FALSE;
  2297. const ULONG ValidFlags = LDR_ADDREF_DLL_PIN;
  2298. __try {
  2299. if (Flags & ~ValidFlags
  2300. ) {
  2301. Status = STATUS_INVALID_PARAMETER;
  2302. goto Exit;
  2303. }
  2304. if (!InLdrInit
  2305. ) {
  2306. Status = LdrLockLoaderLock(0, NULL, &LockCookie);
  2307. if (!NT_SUCCESS(Status))
  2308. goto Exit;
  2309. HoldingLoaderLock = TRUE;
  2310. }
  2311. if (!LdrpCheckForLoadedDllHandle(DllHandle, &LdrDataTableEntry)
  2312. ) {
  2313. Status = STATUS_INVALID_PARAMETER;
  2314. goto Exit;
  2315. }
  2316. if (!RTL_SOFT_VERIFY(LdrDataTableEntry != NULL)
  2317. ) {
  2318. Status = STATUS_INTERNAL_ERROR;
  2319. goto Exit;
  2320. }
  2321. //
  2322. // Gross. Everyone inlines the first part..
  2323. //
  2324. if (LdrDataTableEntry->LoadCount != 0xffff) {
  2325. if (Flags & LDR_ADDREF_DLL_PIN
  2326. ) {
  2327. LdrDataTableEntry->LoadCount = 0xffff;
  2328. LdrpPinLoadedDll(LdrDataTableEntry);
  2329. } else {
  2330. LdrDataTableEntry->LoadCount++;
  2331. LdrpReferenceLoadedDll(LdrDataTableEntry);
  2332. }
  2333. LdrpClearLoadInProgress();
  2334. }
  2335. Exit:
  2336. if (LdrpShouldDbgPrintStatus(Status)
  2337. ) {
  2338. DbgPrint("LDR: "__FUNCTION__"(%p) 0x%08lx\n", DllHandle, Status);
  2339. }
  2340. } __finally {
  2341. if (HoldingLoaderLock) {
  2342. LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, LockCookie);
  2343. HoldingLoaderLock = FALSE;
  2344. }
  2345. }
  2346. return Status;
  2347. }
  2348. VOID
  2349. NTAPI
  2350. LdrSetDllManifestProber(
  2351. IN PLDR_MANIFEST_PROBER_ROUTINE ManifestProberRoutine
  2352. )
  2353. {
  2354. LdrpManifestProberRoutine = ManifestProberRoutine;
  2355. }
  2356. NTSTATUS
  2357. NTAPI
  2358. LdrSetAppCompatDllRedirectionCallback(
  2359. IN ULONG Flags,
  2360. IN PLDR_APP_COMPAT_DLL_REDIRECTION_CALLBACK_FUNCTION CallbackFunction,
  2361. IN PVOID CallbackData
  2362. )
  2363. /*++
  2364. Routine Description:
  2365. This routine allows the application compatibility facility to set a callback
  2366. function that it can use to redirect DLL loads wherever it wants them to go.
  2367. Arguments:
  2368. Flags - None defined now; must be zero.
  2369. CallbackFunction - Function pointer to function which is called to resolve
  2370. path names prior to actually loading the DLL.
  2371. CallbackData - PVOID value passed through to the CallbackFunction when it is
  2372. called.
  2373. Return Value:
  2374. NTSTATUS indicating the success/failure of the function.
  2375. --*/
  2376. {
  2377. NTSTATUS st = STATUS_INTERNAL_ERROR;
  2378. PVOID LockCookie = NULL;
  2379. if (Flags != 0) {
  2380. st = STATUS_INVALID_PARAMETER;
  2381. goto Exit;
  2382. }
  2383. LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, NULL, &LockCookie);
  2384. __try {
  2385. LdrpAppCompatDllRedirectionCallbackFunction = CallbackFunction;
  2386. LdrpAppCompatDllRedirectionCallbackData = CallbackData;
  2387. } __finally {
  2388. LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, LockCookie);
  2389. }
  2390. st = STATUS_SUCCESS;
  2391. Exit:
  2392. return st;
  2393. }
  2394. PTEB LdrpTopLevelDllBeingLoadedTeb=NULL;
  2395. BOOLEAN
  2396. RtlIsThreadWithinLoaderCallout (
  2397. VOID
  2398. )
  2399. {
  2400. if (LdrpTopLevelDllBeingLoadedTeb == NtCurrentTeb ()) {
  2401. return TRUE;
  2402. } else {
  2403. return FALSE;
  2404. }
  2405. }