Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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