Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

ldrapi.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 ldrapi.c 00008 00009 Abstract: 00010 00011 This module implements the Ldr APIs that can be linked with 00012 an application to perform loader services. All of the APIs in 00013 this component are implemented in a DLL. They are not part of the 00014 DLL snap procedure. 00015 00016 Author: 00017 00018 Mike O'Leary (mikeol) 23-Mar-1990 00019 00020 Revision History: 00021 00022 --*/ 00023 00024 #include "ldrp.h" 00025 00026 #define DLLEXTENSION ((PWSTR)".\0d\0l\0l\0\0") // .dll 00027 00028 00029 ULONG 00030 LdrpClearLoadInProgress( 00031 VOID 00032 ); 00033 00034 NTSTATUS 00035 LdrLoadDll ( 00036 IN PWSTR DllPath OPTIONAL, 00037 IN PULONG DllCharacteristics OPTIONAL, 00038 IN PUNICODE_STRING DllName, 00039 OUT PVOID *DllHandle 00040 ) 00041 00042 /*++ 00043 00044 Routine Description: 00045 00046 This function loads a DLL into the calling process address space. 00047 00048 Arguments: 00049 00050 DllPath - Supplies the search path to be used to locate the DLL. 00051 00052 DllCharacteristics - Supplies an optional DLL characteristics flag, 00053 that if specified is used to match against the dll being loaded. 00054 00055 DllName - Supplies the name of the DLL to load. 00056 00057 DllHandle - Returns a handle to the loaded DLL. 00058 00059 Return Value: 00060 00061 TBD 00062 00063 --*/ 00064 { 00065 return LdrpLoadDll(DllPath,DllCharacteristics,DllName,DllHandle,TRUE); 00066 } 00067 00068 NTSTATUS 00069 NTAPI 00070 LdrpLoadDll( 00071 IN PWSTR DllPath OPTIONAL, 00072 IN PULONG DllCharacteristics OPTIONAL, 00073 IN PUNICODE_STRING DllName, 00074 OUT PVOID *DllHandle, 00075 IN BOOLEAN RunInitRoutines 00076 ) 00077 00078 { 00079 PPEB Peb; 00080 PTEB Teb; 00081 NTSTATUS st; 00082 PLDR_DATA_TABLE_ENTRY LdrDataTableEntry; 00083 PWSTR ActualDllName; 00084 PWCH p, pp; 00085 UNICODE_STRING ActualDllNameStr; 00086 BOOLEAN Wx86KnownDll = FALSE; 00087 WCHAR FreeBuffer[266]; 00088 00089 Peb = NtCurrentPeb(); 00090 Teb = NtCurrentTeb(); 00091 00092 st = STATUS_SUCCESS; 00093 00094 try { 00095 00096 // 00097 // Grab Peb lock and Snap All Links to specified DLL 00098 // 00099 00100 if ( LdrpInLdrInit == FALSE ) { 00101 RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock); 00102 } 00103 00104 00105 00106 #if defined (WX86) 00107 00108 if (Teb->Wx86Thread.UseKnownWx86Dll) { 00109 Wx86KnownDll = Teb->Wx86Thread.UseKnownWx86Dll; 00110 Teb->Wx86Thread.UseKnownWx86Dll = FALSE; 00111 } 00112 #endif 00113 00114 00115 00116 p = DllName->Buffer; 00117 pp = NULL; 00118 while (*p) { 00119 if (*p++ == (WCHAR)'.') { 00120 // 00121 // pp will point to first character after last '.' 00122 // 00123 pp = p; 00124 } 00125 } 00126 00127 00128 ActualDllName = FreeBuffer; 00129 if ( DllName->Length >= sizeof(FreeBuffer)) { 00130 return STATUS_NAME_TOO_LONG; 00131 } 00132 RtlMoveMemory(ActualDllName, DllName->Buffer, DllName->Length); 00133 00134 00135 if (!pp || *pp == (WCHAR)'\\') { 00136 // 00137 // No extension found (just ..\) 00138 // 00139 if ( DllName->Length+10 >= sizeof(FreeBuffer) ) { 00140 return STATUS_NAME_TOO_LONG; 00141 } 00142 00143 RtlMoveMemory((PCHAR)ActualDllName+DllName->Length, DLLEXTENSION, 10); 00144 } 00145 else { 00146 ActualDllName[DllName->Length >> 1] = UNICODE_NULL; 00147 } 00148 00149 if (ShowSnaps) { 00150 DbgPrint("LDR: LdrLoadDll, loading %ws from %ws\n", 00151 ActualDllName, 00152 ARGUMENT_PRESENT(DllPath) ? DllPath : L"" 00153 ); 00154 } 00155 00156 00157 RtlInitUnicodeString(&ActualDllNameStr,ActualDllName); 00158 ActualDllNameStr.MaximumLength = sizeof(FreeBuffer); 00159 00160 if (!LdrpCheckForLoadedDll( DllPath, 00161 &ActualDllNameStr, 00162 FALSE, 00163 Wx86KnownDll, 00164 &LdrDataTableEntry 00165 ) 00166 ) { 00167 st = LdrpMapDll(DllPath, 00168 ActualDllName, 00169 DllCharacteristics, 00170 FALSE, 00171 Wx86KnownDll, 00172 &LdrDataTableEntry 00173 ); 00174 00175 if (!NT_SUCCESS(st)) { 00176 return st; 00177 } 00178 00179 if (ARGUMENT_PRESENT( DllCharacteristics ) && 00180 *DllCharacteristics & IMAGE_FILE_EXECUTABLE_IMAGE 00181 ) { 00182 LdrDataTableEntry->EntryPoint = 0; 00183 LdrDataTableEntry->Flags &= ~LDRP_IMAGE_DLL; 00184 } 00185 00186 // 00187 // and walk the import descriptor. 00188 // 00189 00190 if (LdrDataTableEntry->Flags & LDRP_IMAGE_DLL) { 00191 00192 try { 00193 st = LdrpWalkImportDescriptor( 00194 DllPath, 00195 LdrDataTableEntry 00196 ); 00197 } 00198 except(EXCEPTION_EXECUTE_HANDLER) { 00199 st = GetExceptionCode(); 00200 } 00201 if ( LdrDataTableEntry->LoadCount != 0xffff ) { 00202 LdrDataTableEntry->LoadCount++; 00203 } 00204 LdrpReferenceLoadedDll(LdrDataTableEntry); 00205 if (!NT_SUCCESS(st)) { 00206 LdrDataTableEntry->EntryPoint = NULL; 00207 InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList, 00208 &LdrDataTableEntry->InInitializationOrderLinks); 00209 LdrpClearLoadInProgress(); 00210 LdrUnloadDll((PVOID)LdrDataTableEntry->DllBase); 00211 return st; 00212 } 00213 } 00214 else { 00215 if ( LdrDataTableEntry->LoadCount != 0xffff ) { 00216 LdrDataTableEntry->LoadCount++; 00217 } 00218 } 00219 00220 // 00221 // Add init routine to list 00222 // 00223 00224 InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList, 00225 &LdrDataTableEntry->InInitializationOrderLinks); 00226 00227 00228 // 00229 // If the loader data base is not fully setup, this load was because 00230 // of a forwarder in the static load set. Can't run init routines 00231 // yet because the load counts are NOT set 00232 // 00233 00234 if ( RunInitRoutines && LdrpLdrDatabaseIsSetup ) { 00235 00236 try { 00237 st = LdrpRunInitializeRoutines(NULL); 00238 if ( !NT_SUCCESS(st) ) { 00239 LdrUnloadDll((PVOID)LdrDataTableEntry->DllBase); 00240 } 00241 } 00242 except( EXCEPTION_EXECUTE_HANDLER ) { 00243 LdrUnloadDll((PVOID)LdrDataTableEntry->DllBase); 00244 return GetExceptionCode(); 00245 } 00246 } 00247 else { 00248 st = STATUS_SUCCESS; 00249 } 00250 00251 } 00252 else { 00253 00254 // 00255 // Count it. And everything that it imports. 00256 // 00257 00258 if ( LdrDataTableEntry->Flags & LDRP_IMAGE_DLL && 00259 LdrDataTableEntry->LoadCount != 0xffff ) { 00260 00261 LdrDataTableEntry->LoadCount++; 00262 00263 LdrpReferenceLoadedDll(LdrDataTableEntry); 00264 00265 // 00266 // Now clear the Load in progress bits 00267 // 00268 00269 LdrpClearLoadInProgress(); 00270 00271 } 00272 else { 00273 if ( LdrDataTableEntry->LoadCount != 0xffff ) { 00274 LdrDataTableEntry->LoadCount++; 00275 } 00276 } 00277 } 00278 } 00279 finally { 00280 if ( LdrpInLdrInit == FALSE ) { 00281 RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock); 00282 } 00283 00284 } 00285 if ( NT_SUCCESS(st) ) { 00286 *DllHandle = (PVOID)LdrDataTableEntry->DllBase; 00287 } 00288 else { 00289 *DllHandle = NULL; 00290 } 00291 return st; 00292 } 00293 00294 NTSTATUS 00295 LdrGetDllHandle ( 00296 IN PWSTR DllPath OPTIONAL, 00297 IN PULONG DllCharacteristics OPTIONAL, 00298 IN PUNICODE_STRING DllName, 00299 OUT PVOID *DllHandle 00300 ) 00301 00302 /*++ 00303 00304 Routine Description: 00305 00306 This function locates the specified DLL and returns its handle. 00307 00308 Arguments: 00309 00310 DllPath - Supplies the search path to be used to locate the DLL. 00311 00312 DllCharacteristics - Supplies an optional DLL characteristics flag, 00313 that if specified is used to match against the dll being loaded. 00314 00315 DllName - Supplies the name of the DLL to load. 00316 00317 DllHandle - Returns a handle to the loaded DLL. 00318 00319 Return Value: 00320 00321 TBD 00322 00323 --*/ 00324 00325 { 00326 NTSTATUS st; 00327 PPEB Peb; 00328 PTEB Teb; 00329 PLDR_DATA_TABLE_ENTRY LdrDataTableEntry; 00330 PWSTR ActualDllName; 00331 PWCH p, pp; 00332 UNICODE_STRING ActualDllNameStr; 00333 BOOLEAN Wx86KnownDll = FALSE; 00334 WCHAR FreeBuffer[266]; 00335 00336 00337 DllCharacteristics; 00338 00339 Peb = NtCurrentPeb(); 00340 Teb = NtCurrentTeb(); 00341 00342 st = STATUS_DLL_NOT_FOUND; 00343 00344 try { 00345 00346 // 00347 // Grab Peb lock 00348 // 00349 00350 if ( LdrpInLdrInit == FALSE ) { 00351 RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock); 00352 } 00353 00354 #if defined (WX86) 00355 00356 00357 if (Teb->Wx86Thread.UseKnownWx86Dll) { 00358 Wx86KnownDll = Teb->Wx86Thread.UseKnownWx86Dll; 00359 Teb->Wx86Thread.UseKnownWx86Dll = FALSE; 00360 } 00361 00362 // 00363 // No module handle cache lookup for Wx86, 00364 // (relies on unique basename) 00365 // 00366 if (Wx86ProcessInit) { 00367 LdrpGetModuleHandleCache = NULL; 00368 } 00369 00370 #endif 00371 00372 00373 if ( LdrpGetModuleHandleCache ) { 00374 if (RtlEqualUnicodeString(DllName, 00375 &LdrpGetModuleHandleCache->BaseDllName, 00376 TRUE 00377 )) { 00378 *DllHandle = (PVOID)LdrpGetModuleHandleCache->DllBase; 00379 st = STATUS_SUCCESS; 00380 leave; 00381 } 00382 } 00383 00384 00385 00386 p = DllName->Buffer; 00387 pp = NULL; 00388 while (*p) { 00389 if (*p++ == (WCHAR)'.') { 00390 // 00391 // pp will point to first character after last '.' 00392 // 00393 pp = p; 00394 } 00395 } 00396 00397 ActualDllName = FreeBuffer; 00398 if ( DllName->Length >= sizeof(FreeBuffer)) { 00399 return STATUS_NAME_TOO_LONG; 00400 } 00401 RtlMoveMemory(ActualDllName, DllName->Buffer, DllName->Length); 00402 00403 if (!pp || *pp == (WCHAR)'\\') { 00404 // 00405 // No extension found (just ..\) 00406 // 00407 if ( DllName->Length+10 >= sizeof(FreeBuffer) ) { 00408 return STATUS_NAME_TOO_LONG; 00409 } 00410 00411 RtlMoveMemory((PCHAR)ActualDllName+DllName->Length, DLLEXTENSION, 10); 00412 } 00413 00414 else { 00415 00416 // 00417 // see if the name ends in . If it does, trim out the trailing 00418 // . 00419 // 00420 00421 if ( ActualDllName[ (DllName->Length-2) >> 1] == L'.' ) { 00422 DllName->Length -= 2; 00423 } 00424 00425 ActualDllName[DllName->Length >> 1] = UNICODE_NULL; 00426 } 00427 00428 00429 00430 // 00431 // Check the LdrTable to see if Dll has already been loaded 00432 // into this image. 00433 // 00434 00435 RtlInitUnicodeString(&ActualDllNameStr,ActualDllName); 00436 ActualDllNameStr.MaximumLength = sizeof(FreeBuffer); 00437 00438 if (ShowSnaps) { 00439 DbgPrint("LDR: LdrGetDllHandle, searching for %ws from %ws\n", 00440 ActualDllName, 00441 ARGUMENT_PRESENT(DllPath) ? (DllPath == (PWSTR)1 ? L"" : DllPath) : L"" 00442 ); 00443 } 00444 00445 00446 // 00447 // sort of a hack, but done to speed up GetModuleHandle. kernel32 00448 // now does a two pass call here to avoid computing 00449 // process dll path 00450 // 00451 00452 00453 if (LdrpCheckForLoadedDll( DllPath, 00454 &ActualDllNameStr, 00455 (BOOLEAN)(DllPath == (PWSTR)1 ? TRUE : FALSE), 00456 Wx86KnownDll, 00457 &LdrDataTableEntry 00458 ) 00459 ) { 00460 *DllHandle = (PVOID)LdrDataTableEntry->DllBase; 00461 LdrpGetModuleHandleCache = LdrDataTableEntry; 00462 st = STATUS_SUCCESS; 00463 00464 } 00465 } finally { 00466 if ( LdrpInLdrInit == FALSE ) { 00467 RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock); 00468 } 00469 } 00470 return st; 00471 } 00472 00473 NTSTATUS 00474 LdrDisableThreadCalloutsForDll ( 00475 IN PVOID DllHandle 00476 ) 00477 00478 /*++ 00479 00480 Routine Description: 00481 00482 This function disables thread attach and detach notification 00483 for the specified DLL. 00484 00485 Arguments: 00486 00487 DllHandle - Supplies a handle to the DLL to disable. 00488 00489 Return Value: 00490 00491 TBD 00492 00493 --*/ 00494 00495 { 00496 NTSTATUS st; 00497 PLDR_DATA_TABLE_ENTRY LdrDataTableEntry; 00498 00499 st = STATUS_SUCCESS; 00500 00501 try { 00502 00503 if ( LdrpInLdrInit == FALSE ) { 00504 RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock); 00505 } 00506 if ( LdrpShutdownInProgress ) { 00507 return STATUS_SUCCESS; 00508 } 00509 00510 if (LdrpCheckForLoadedDllHandle(DllHandle, &LdrDataTableEntry)) { 00511 if ( LdrDataTableEntry->TlsIndex ) { 00512 st = STATUS_DLL_NOT_FOUND; 00513 } 00514 else { 00515 LdrDataTableEntry->Flags |= LDRP_DONT_CALL_FOR_THREADS; 00516 } 00517 } 00518 } 00519 finally { 00520 if ( LdrpInLdrInit == FALSE ) { 00521 RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock); 00522 } 00523 } 00524 return st; 00525 } 00526 00527 NTSTATUS 00528 LdrUnloadDll ( 00529 IN PVOID DllHandle 00530 ) 00531 00532 /*++ 00533 00534 Routine Description: 00535 00536 This function unloads the DLL from the specified process 00537 00538 Arguments: 00539 00540 DllHandle - Supplies a handle to the DLL to unload. 00541 00542 Return Value: 00543 00544 TBD 00545 00546 --*/ 00547 00548 { 00549 NTSTATUS st; 00550 PPEB Peb; 00551 PLDR_DATA_TABLE_ENTRY LdrDataTableEntry; 00552 PLDR_DATA_TABLE_ENTRY Entry; 00553 PDLL_INIT_ROUTINE InitRoutine; 00554 LIST_ENTRY LocalUnloadHead; 00555 PLIST_ENTRY Next; 00556 #if defined (WX86) 00557 PVOID Wx86Plugin = NULL; 00558 #endif 00559 00560 Peb = NtCurrentPeb(); 00561 st = STATUS_SUCCESS; 00562 00563 try { 00564 00565 // 00566 // Grab Peb lock and decrement reference count of all affected DLLs 00567 // 00568 00569 00570 if ( LdrpInLdrInit == FALSE ) { 00571 RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock); 00572 } 00573 00574 LdrpActiveUnloadCount++; 00575 00576 if ( LdrpShutdownInProgress ) { 00577 goto leave_finally; 00578 } 00579 00580 if (!LdrpCheckForLoadedDllHandle(DllHandle, &LdrDataTableEntry)) { 00581 st = STATUS_DLL_NOT_FOUND; 00582 goto leave_finally; 00583 } 00584 00585 // 00586 // Now that we have the data table entry, unload it 00587 // 00588 00589 if ( LdrDataTableEntry->LoadCount != 0xffff ) { 00590 LdrDataTableEntry->LoadCount--; 00591 if ( LdrDataTableEntry->Flags & LDRP_IMAGE_DLL ) { 00592 LdrpDereferenceLoadedDll(LdrDataTableEntry); 00593 } 00594 } else { 00595 00596 // 00597 // if the load count is 0xffff, then we do not need to recurse 00598 // through this DLL's import table. 00599 // 00600 // Additionally, we don't have to scan more LoadCount == 0 00601 // modules since nothing could have happened as a result of a free on this 00602 // DLL. 00603 00604 goto leave_finally; 00605 } 00606 00607 // 00608 // Now process init routines and then in a second pass, unload 00609 // DLLs 00610 // 00611 00612 if (ShowSnaps) { 00613 DbgPrint("LDR: UNINIT LIST\n"); 00614 } 00615 00616 if (LdrpActiveUnloadCount == 1 ) { 00617 InitializeListHead(&LdrpUnloadHead); 00618 } 00619 00620 // 00621 // Go in reverse order initialization order and build 00622 // the unload list 00623 // 00624 00625 Next = Peb->Ldr->InInitializationOrderModuleList.Blink; 00626 while ( Next != &Peb->Ldr->InInitializationOrderModuleList) { 00627 LdrDataTableEntry 00628 = (PLDR_DATA_TABLE_ENTRY) 00629 (CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,InInitializationOrderLinks)); 00630 00631 Next = Next->Blink; 00632 LdrDataTableEntry->Flags &= ~LDRP_UNLOAD_IN_PROGRESS; 00633 00634 if (LdrDataTableEntry->LoadCount == 0) { 00635 00636 if (ShowSnaps) { 00637 DbgPrint(" (%d) [%ws] %ws (%lx) deinit %lx\n", 00638 LdrpActiveUnloadCount, 00639 LdrDataTableEntry->BaseDllName.Buffer, 00640 LdrDataTableEntry->FullDllName.Buffer, 00641 (ULONG)LdrDataTableEntry->LoadCount, 00642 LdrDataTableEntry->EntryPoint 00643 ); 00644 } 00645 00646 Entry = LdrDataTableEntry; 00647 00648 RemoveEntryList(&Entry->InInitializationOrderLinks); 00649 RemoveEntryList(&Entry->InMemoryOrderLinks); 00650 RemoveEntryList(&Entry->HashLinks); 00651 00652 if ( LdrpActiveUnloadCount > 1 ) { 00653 LdrpLoadedDllHandleCache = NULL; 00654 Entry->InMemoryOrderLinks.Flink = NULL; 00655 } 00656 InsertTailList(&LdrpUnloadHead,&Entry->HashLinks); 00657 } 00658 } 00659 // 00660 // End of new code 00661 // 00662 00663 // 00664 // We only do init routine call's and module free's at the top level, 00665 // so if the active count is > 1, just return 00666 // 00667 00668 if (LdrpActiveUnloadCount > 1 ) { 00669 goto leave_finally; 00670 } 00671 00672 // 00673 // Now that the unload list is built, walk through the unload 00674 // list in order and call the init routine. The dll must remain 00675 // on the InLoadOrderLinks so that the pctoheader stuff will 00676 // still work 00677 // 00678 00679 InitializeListHead(&LocalUnloadHead); 00680 Entry = NULL; 00681 Next = LdrpUnloadHead.Flink; 00682 while ( Next != &LdrpUnloadHead ) { 00683 top: 00684 if ( Entry ) { 00685 RemoveEntryList(&(Entry->InLoadOrderLinks)); 00686 Entry = NULL; 00687 Next = LdrpUnloadHead.Flink; 00688 if (Next == &LdrpUnloadHead ) { 00689 goto bottom; 00690 } 00691 } 00692 LdrDataTableEntry 00693 = (PLDR_DATA_TABLE_ENTRY) 00694 (CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,HashLinks)); 00695 00696 // 00697 // Remove dll from the global unload list and place 00698 // on the local unload list. This is because the global list 00699 // can change during the callout to the init routine 00700 // 00701 00702 Entry = LdrDataTableEntry; 00703 LdrpLoadedDllHandleCache = NULL; 00704 Entry->InMemoryOrderLinks.Flink = NULL; 00705 00706 RemoveEntryList(&Entry->HashLinks); 00707 InsertTailList(&LocalUnloadHead,&Entry->HashLinks); 00708 00709 // 00710 // If the function has an init routine, call it. 00711 // 00712 00713 InitRoutine = (PDLL_INIT_ROUTINE)LdrDataTableEntry->EntryPoint; 00714 00715 #if defined (WX86) 00716 if (Wx86ProcessInit) { 00717 try { 00718 LdrpWx86DllProcessDetach(LdrDataTableEntry); 00719 RemoveEntryList(&Entry->InLoadOrderLinks); 00720 Entry = NULL; 00721 Next = LdrpUnloadHead.Flink; 00722 } 00723 except(EXCEPTION_EXECUTE_HANDLER){ 00724 goto top; 00725 } 00726 } 00727 else 00728 #endif 00729 if (InitRoutine && (LdrDataTableEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) ) { 00730 try { 00731 if (ShowSnaps) { 00732 DbgPrint("LDR: Calling deinit %lx\n",InitRoutine); 00733 } 00734 00735 LdrpCallInitRoutine(InitRoutine, 00736 LdrDataTableEntry->DllBase, 00737 DLL_PROCESS_DETACH, 00738 NULL); 00739 00740 RemoveEntryList(&Entry->InLoadOrderLinks); 00741 Entry = NULL; 00742 Next = LdrpUnloadHead.Flink; 00743 } 00744 except(EXCEPTION_EXECUTE_HANDLER){ 00745 goto top; 00746 } 00747 } else { 00748 RemoveEntryList(&(Entry->InLoadOrderLinks)); 00749 Entry = NULL; 00750 Next = LdrpUnloadHead.Flink; 00751 } 00752 } 00753 bottom: 00754 00755 #if defined (WX86) 00756 if (Wx86ProcessInit) { 00757 00758 // 00759 // Notify Wx86 that the modules are about to be unmapped. This 00760 // must be done in a separate pass from the unmap loop, as wx86.dll 00761 // might be in the list of modules to unmap. 00762 // 00763 Next = LocalUnloadHead.Flink; 00764 while ( Next != &LocalUnloadHead ) { 00765 LdrDataTableEntry 00766 = (PLDR_DATA_TABLE_ENTRY) 00767 (CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,HashLinks)); 00768 00769 Next = Next->Flink; 00770 00771 LdrpWx86DllMapNotify(LdrDataTableEntry->DllBase, FALSE); 00772 00773 // Remember if we are unloading a plugin dll 00774 00775 if ((LdrDataTableEntry->DllBase == DllHandle) && 00776 (LdrDataTableEntry->Flags & LDRP_WX86_PLUGIN)) { 00777 Wx86Plugin = DllHandle; 00778 } 00779 } 00780 } 00781 #endif 00782 00783 // 00784 // Now, go through the modules and unmap them 00785 // 00786 00787 Next = LocalUnloadHead.Flink; 00788 while ( Next != &LocalUnloadHead ) { 00789 LdrDataTableEntry 00790 = (PLDR_DATA_TABLE_ENTRY) 00791 (CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,HashLinks)); 00792 00793 Next = Next->Flink; 00794 Entry = LdrDataTableEntry; 00795 00796 if (ShowSnaps) { 00797 DbgPrint("LDR: Unmapping [%ws]\n", 00798 LdrDataTableEntry->BaseDllName.Buffer 00799 ); 00800 } 00801 st = NtUnmapViewOfSection(NtCurrentProcess(),Entry->DllBase); 00802 ASSERT(NT_SUCCESS(st)); 00803 00804 LdrUnloadAlternateResourceModule(Entry->DllBase); 00805 00806 if (Entry->FullDllName.Buffer) { 00807 RtlFreeUnicodeString(&Entry->FullDllName); 00808 } 00809 if (Entry->BaseDllName.Buffer) { 00810 RtlFreeUnicodeString(&Entry->BaseDllName); 00811 } 00812 00813 if ( Entry == LdrpGetModuleHandleCache ) { 00814 LdrpGetModuleHandleCache = NULL; 00815 } 00816 00817 RtlFreeHeap(Peb->ProcessHeap, 0,Entry); 00818 } 00819 00820 leave_finally:; 00821 } 00822 finally { 00823 LdrpActiveUnloadCount--; 00824 if ( LdrpInLdrInit == FALSE ) { 00825 00826 #if defined (WX86) 00827 if (Wx86ProcessInit && Wx86Plugin) { 00828 Wx86UnloadProviders( Wx86Plugin ); 00829 } 00830 #endif 00831 RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock); 00832 } 00833 } 00834 return st; 00835 } 00836 00837 NTSTATUS 00838 LdrGetProcedureAddress ( 00839 IN PVOID DllHandle, 00840 IN PANSI_STRING ProcedureName OPTIONAL, 00841 IN ULONG ProcedureNumber OPTIONAL, 00842 OUT PVOID *ProcedureAddress 00843 ) 00844 { 00845 00846 return LdrpGetProcedureAddress(DllHandle,ProcedureName,ProcedureNumber,ProcedureAddress,TRUE); 00847 00848 } 00849 00850 NTSTATUS 00851 LdrpGetProcedureAddress ( 00852 IN PVOID DllHandle, 00853 IN PANSI_STRING ProcedureName OPTIONAL, 00854 IN ULONG ProcedureNumber OPTIONAL, 00855 OUT PVOID *ProcedureAddress, 00856 IN BOOLEAN RunInitRoutines 00857 ) 00858 00859 /*++ 00860 00861 Routine Description: 00862 00863 This function locates the address of the specified procedure in the 00864 specified DLL and returns its address. 00865 00866 Arguments: 00867 00868 DllHandle - Supplies a handle to the DLL that the address is being 00869 looked up in. 00870 00871 ProcedureName - Supplies that address of a string that contains the 00872 name of the procedure to lookup in the DLL. If this argument is 00873 not specified, then the ProcedureNumber is used. 00874 00875 ProcedureNumber - Supplies the procedure number to lookup. If 00876 ProcedureName is specified, then this argument is ignored. 00877 Otherwise, it specifies the procedure ordinal number to locate 00878 in the DLL. 00879 00880 ProcedureAddress - Returns the address of the procedure found in 00881 the DLL. 00882 00883 Return Value: 00884 00885 TBD 00886 00887 --*/ 00888 00889 { 00890 NTSTATUS st; 00891 UCHAR FunctionNameBuffer[64]; 00892 PUCHAR src, dst; 00893 ULONG cb, ExportSize; 00894 PLDR_DATA_TABLE_ENTRY LdrDataTableEntry; 00895 IMAGE_THUNK_DATA Thunk; 00896 PVOID ImageBase; 00897 PIMAGE_IMPORT_BY_NAME FunctionName; 00898 PIMAGE_EXPORT_DIRECTORY ExportDirectory; 00899 PLIST_ENTRY Next; 00900 #if defined (WX86) 00901 PTEB Teb; 00902 BOOLEAN Wx86KnownDll = FALSE; 00903 #endif 00904 00905 if (ShowSnaps) { 00906 DbgPrint("LDR: LdrGetProcedureAddress by "); 00907 } 00908 00909 #if defined (WX86) 00910 Teb = NtCurrentTeb(); 00911 if (Teb->Wx86Thread.UseKnownWx86Dll) { 00912 Wx86KnownDll = Teb->Wx86Thread.UseKnownWx86Dll; 00913 Teb->Wx86Thread.UseKnownWx86Dll = FALSE; 00914 } 00915 #endif 00916 00917 FunctionName = NULL; 00918 if ( ARGUMENT_PRESENT(ProcedureName) ) { 00919 00920 if (ShowSnaps) { 00921 DbgPrint("NAME - %s\n", ProcedureName->Buffer); 00922 } 00923 00924 // 00925 // BUGBUG need STRING to PSZ 00926 // 00927 00928 00929 if (ProcedureName->Length >= sizeof( FunctionNameBuffer )-1 ) { 00930 FunctionName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TEMP_TAG ),ProcedureName->Length+1+sizeof(USHORT)); 00931 if ( !FunctionName ) { 00932 return STATUS_INVALID_PARAMETER; 00933 } 00934 } else { 00935 FunctionName = (PIMAGE_IMPORT_BY_NAME) FunctionNameBuffer; 00936 } 00937 00938 FunctionName->Hint = 0; 00939 00940 cb = ProcedureName->Length; 00941 src = ProcedureName->Buffer; 00942 dst = FunctionName->Name; 00943 00944 while (cb--) { 00945 *dst++ = *src++; 00946 } 00947 *dst = '\0'; 00948 00949 // 00950 // Make sure we don't pass in address with high bit set so we 00951 // can still use it as ordinal flag 00952 // 00953 00954 ImageBase = FunctionName; 00955 Thunk.u1.AddressOfData = 0; 00956 00957 } else { 00958 ImageBase = NULL; 00959 if (ShowSnaps) { 00960 DbgPrint("ORDINAL - %lx\n", ProcedureNumber); 00961 } 00962 00963 if (ProcedureNumber) { 00964 Thunk.u1.Ordinal = ProcedureNumber | IMAGE_ORDINAL_FLAG; 00965 } else { 00966 return STATUS_INVALID_PARAMETER; 00967 } 00968 } 00969 00970 if ( LdrpInLdrInit == FALSE ) { 00971 RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock); 00972 } 00973 try { 00974 00975 if (!LdrpCheckForLoadedDllHandle(DllHandle, &LdrDataTableEntry)) { 00976 st = STATUS_DLL_NOT_FOUND; 00977 return st; 00978 } 00979 00980 ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData( 00981 LdrDataTableEntry->DllBase, 00982 TRUE, 00983 IMAGE_DIRECTORY_ENTRY_EXPORT, 00984 &ExportSize 00985 ); 00986 00987 if (!ExportDirectory) { 00988 return STATUS_PROCEDURE_NOT_FOUND; 00989 } 00990 00991 st = LdrpSnapThunk(LdrDataTableEntry->DllBase, 00992 ImageBase, 00993 &Thunk, 00994 &Thunk, 00995 ExportDirectory, 00996 ExportSize, 00997 FALSE, 00998 NULL 00999 ); 01000 01001 if ( RunInitRoutines ) { 01002 PLDR_DATA_TABLE_ENTRY LdrInitEntry; 01003 01004 // 01005 // Look at last entry in init order list. If entry processed 01006 // flag is not set, then a forwarded dll was loaded during the 01007 // getprocaddr call and we need to run init routines 01008 // 01009 01010 Next = NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Blink; 01011 LdrInitEntry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks); 01012 if ( !(LdrInitEntry->Flags & LDRP_ENTRY_PROCESSED) ) { 01013 try { 01014 st = LdrpRunInitializeRoutines(NULL); 01015 } 01016 except( EXCEPTION_EXECUTE_HANDLER ) { 01017 st = GetExceptionCode(); 01018 } 01019 01020 } 01021 } 01022 01023 if ( NT_SUCCESS(st) ) { 01024 *ProcedureAddress = (PVOID)Thunk.u1.Function; 01025 #if defined (WX86) 01026 // For dlls loaded as a Wx86 plugin ... 01027 01028 if (Wx86ProcessInit && (LdrDataTableEntry->Flags & LDRP_WX86_PLUGIN)) { 01029 PVOID ExportThunk = NULL; 01030 USHORT MachineType = RtlImageNtHeader(LdrDataTableEntry->DllBase)->FileHeader.Machine; 01031 01032 // and the GetProcAddress call is cross-architecture ... 01033 01034 if ((!Wx86KnownDll && (MachineType == IMAGE_FILE_MACHINE_I386)) 01035 || (Wx86KnownDll && (MachineType != IMAGE_FILE_MACHINE_I386))) { 01036 01037 // Thunk the export 01038 01039 st = Wx86ThunkPluginExport(LdrDataTableEntry->DllBase, 01040 FunctionName? FunctionName->Name : NULL, 01041 ProcedureNumber, 01042 (PVOID)(Thunk.u1.Function), 01043 &ExportThunk 01044 ); 01045 if (NT_SUCCESS(st) && ExportThunk) { 01046 *ProcedureAddress = ExportThunk; 01047 } else { 01048 // Don't let unthunked cross-architecture addresses get out 01049 *ProcedureAddress = NULL; 01050 st = STATUS_INVALID_IMAGE_FORMAT; 01051 } 01052 } 01053 } 01054 #endif 01055 } 01056 } finally { 01057 if ( FunctionName && (FunctionName != (PIMAGE_IMPORT_BY_NAME) FunctionNameBuffer) ) { 01058 RtlFreeHeap(RtlProcessHeap(),0,FunctionName); 01059 } 01060 if ( LdrpInLdrInit == FALSE ) { 01061 RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock); 01062 } 01063 } 01064 return st; 01065 } 01066 01067 NTSTATUS 01068 NTAPI 01069 LdrVerifyImageMatchesChecksum ( 01070 IN HANDLE ImageFileHandle, 01071 IN PLDR_IMPORT_MODULE_CALLBACK ImportCallbackRoutine OPTIONAL, 01072 IN PVOID ImportCallbackParameter, 01073 OUT PUSHORT ImageCharacteristics OPTIONAL 01074 ) 01075 { 01076 01077 NTSTATUS Status; 01078 HANDLE Section; 01079 PVOID ViewBase; 01080 SIZE_T ViewSize; 01081 IO_STATUS_BLOCK IoStatusBlock; 01082 FILE_STANDARD_INFORMATION StandardInfo; 01083 PIMAGE_SECTION_HEADER LastRvaSection; 01084 BOOLEAN b; 01085 BOOLEAN JustDoSideEffects; 01086 01087 // 01088 // stevewo added all sorts of side effects to this API. We want to stop 01089 // doing checksums for known dll's, but really want the sideeffects 01090 // (ImageCharacteristics write, and Import descriptor walk). 01091 // 01092 01093 if ( (UINT_PTR) ImageFileHandle & 1 ) { 01094 JustDoSideEffects = TRUE; 01095 } 01096 else { 01097 JustDoSideEffects = FALSE; 01098 } 01099 01100 Status = NtCreateSection( 01101 &Section, 01102 SECTION_MAP_EXECUTE, 01103 NULL, 01104 NULL, 01105 PAGE_EXECUTE, 01106 SEC_COMMIT, 01107 ImageFileHandle 01108 ); 01109 if ( !NT_SUCCESS(Status) ) { 01110 return Status; 01111 } 01112 01113 ViewBase = NULL; 01114 ViewSize = 0; 01115 01116 Status = NtMapViewOfSection( 01117 Section, 01118 NtCurrentProcess(), 01119 (PVOID *)&ViewBase, 01120 0L, 01121 0L, 01122 NULL, 01123 &ViewSize, 01124 ViewShare, 01125 0L, 01126 PAGE_EXECUTE 01127 ); 01128 01129 if ( !NT_SUCCESS(Status) ) { 01130 NtClose(Section); 01131 return Status; 01132 } 01133 01134 // 01135 // now the image is mapped as a data file... Calculate it's size and then 01136 // check it's checksum 01137 // 01138 01139 Status = NtQueryInformationFile( 01140 ImageFileHandle, 01141 &IoStatusBlock, 01142 &StandardInfo, 01143 sizeof(StandardInfo), 01144 FileStandardInformation 01145 ); 01146 01147 if ( !NT_SUCCESS(Status) ) { 01148 NtUnmapViewOfSection(NtCurrentProcess(),ViewBase); 01149 NtClose(Section); 01150 return Status; 01151 } 01152 01153 try { 01154 if ( JustDoSideEffects ) { 01155 b = TRUE; 01156 } 01157 else { 01158 b = LdrVerifyMappedImageMatchesChecksum(ViewBase,StandardInfo.EndOfFile.LowPart); 01159 } 01160 if (b && ARGUMENT_PRESENT( ImportCallbackRoutine )) { 01161 PIMAGE_NT_HEADERS NtHeaders; 01162 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor; 01163 ULONG ImportSize; 01164 PCHAR ImportName; 01165 01166 // 01167 // Caller wants to enumerate the import descriptors while we have 01168 // the image mapped. Call back to their routine for each module 01169 // name in the import descriptor table. 01170 // 01171 LastRvaSection = NULL; 01172 NtHeaders = RtlImageNtHeader( ViewBase ); 01173 if (ARGUMENT_PRESENT( ImageCharacteristics )) { 01174 *ImageCharacteristics = NtHeaders->FileHeader.Characteristics; 01175 } 01176 01177 ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR) 01178 RtlImageDirectoryEntryToData( ViewBase, 01179 FALSE, 01180 IMAGE_DIRECTORY_ENTRY_IMPORT, 01181 &ImportSize 01182 ); 01183 if (ImportDescriptor != NULL) { 01184 while (ImportDescriptor->Name) { 01185 ImportName = (PSZ)RtlImageRvaToVa( NtHeaders, 01186 ViewBase, 01187 ImportDescriptor->Name, 01188 &LastRvaSection 01189 ); 01190 (*ImportCallbackRoutine)( ImportCallbackParameter, ImportName ); 01191 ImportDescriptor += 1; 01192 } 01193 } 01194 } 01195 } 01196 except (EXCEPTION_EXECUTE_HANDLER) { 01197 NtUnmapViewOfSection(NtCurrentProcess(),ViewBase); 01198 NtClose(Section); 01199 return STATUS_IMAGE_CHECKSUM_MISMATCH; 01200 } 01201 NtUnmapViewOfSection(NtCurrentProcess(),ViewBase); 01202 NtClose(Section); 01203 if ( !b ) { 01204 Status = STATUS_IMAGE_CHECKSUM_MISMATCH; 01205 } 01206 return Status; 01207 } 01208 01209 NTSTATUS 01210 LdrQueryProcessModuleInformation( 01211 OUT PRTL_PROCESS_MODULES ModuleInformation, 01212 IN ULONG ModuleInformationLength, 01213 OUT PULONG ReturnLength OPTIONAL 01214 ) 01215 { 01216 NTSTATUS Status; 01217 PPEB Peb; 01218 PLIST_ENTRY LoadOrderListHead; 01219 PLIST_ENTRY InitOrderListHead; 01220 ULONG RequiredLength; 01221 PLIST_ENTRY Next; 01222 PLIST_ENTRY Next1; 01223 PRTL_PROCESS_MODULE_INFORMATION ModuleInfo; 01224 PLDR_DATA_TABLE_ENTRY LdrDataTableEntry; 01225 PLDR_DATA_TABLE_ENTRY LdrDataTableEntry1; 01226 ANSI_STRING AnsiString; 01227 PUCHAR s; 01228 01229 Peb = NtCurrentPeb(); 01230 01231 // 01232 // Grab Peb lock and capture information about of DLLs loaded in current process. 01233 // 01234 01235 if ( LdrpInLdrInit == FALSE ) { 01236 RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock); 01237 } 01238 01239 try { 01240 RequiredLength = FIELD_OFFSET( RTL_PROCESS_MODULES, Modules ); 01241 if (ModuleInformationLength < RequiredLength) { 01242 Status = STATUS_INFO_LENGTH_MISMATCH; 01243 ModuleInfo = NULL; 01244 } 01245 else { 01246 ModuleInformation->NumberOfModules = 0; 01247 ModuleInfo = &ModuleInformation->Modules[ 0 ]; 01248 Status = STATUS_SUCCESS; 01249 } 01250 01251 LoadOrderListHead = &Peb->Ldr->InLoadOrderModuleList; 01252 InitOrderListHead = &Peb->Ldr->InInitializationOrderModuleList; 01253 Next = LoadOrderListHead->Flink; 01254 while ( Next != LoadOrderListHead ) { 01255 LdrDataTableEntry = CONTAINING_RECORD( Next, 01256 LDR_DATA_TABLE_ENTRY, 01257 InLoadOrderLinks 01258 ); 01259 01260 RequiredLength += sizeof( RTL_PROCESS_MODULE_INFORMATION ); 01261 if (ModuleInformationLength < RequiredLength) { 01262 Status = STATUS_INFO_LENGTH_MISMATCH; 01263 } 01264 else { 01265 ModuleInfo->MappedBase = NULL; 01266 ModuleInfo->ImageBase = LdrDataTableEntry->DllBase; 01267 ModuleInfo->ImageSize = LdrDataTableEntry->SizeOfImage; 01268 ModuleInfo->Flags = LdrDataTableEntry->Flags; 01269 ModuleInfo->LoadCount = LdrDataTableEntry->LoadCount; 01270 01271 ModuleInfo->LoadOrderIndex = (USHORT)(ModuleInformation->NumberOfModules); 01272 01273 ModuleInfo->InitOrderIndex = 0; 01274 Next1 = InitOrderListHead->Flink; 01275 while ( Next1 != InitOrderListHead ) { 01276 LdrDataTableEntry1 = CONTAINING_RECORD( Next1, 01277 LDR_DATA_TABLE_ENTRY, 01278 InInitializationOrderLinks 01279 ); 01280 01281 ModuleInfo->InitOrderIndex++; 01282 if (LdrDataTableEntry1 == LdrDataTableEntry) { 01283 break; 01284 } 01285 01286 Next1 = Next1->Flink; 01287 } 01288 01289 AnsiString.Buffer = ModuleInfo->FullPathName; 01290 AnsiString.Length = 0; 01291 AnsiString.MaximumLength = sizeof( ModuleInfo->FullPathName ); 01292 RtlUnicodeStringToAnsiString( &AnsiString, 01293 &LdrDataTableEntry->FullDllName, 01294 FALSE 01295 ); 01296 s = AnsiString.Buffer + AnsiString.Length; 01297 while (s > AnsiString.Buffer && *--s) { 01298 if (*s == (UCHAR)OBJ_NAME_PATH_SEPARATOR) { 01299 s++; 01300 break; 01301 } 01302 } 01303 ModuleInfo->OffsetToFileName = (USHORT)(s - AnsiString.Buffer); 01304 01305 ModuleInfo++; 01306 } 01307 01308 if (ModuleInformation != NULL) { 01309 ModuleInformation->NumberOfModules++; 01310 } 01311 01312 Next = Next->Flink; 01313 } 01314 01315 if (ARGUMENT_PRESENT( ReturnLength )) { 01316 *ReturnLength = RequiredLength; 01317 } 01318 } 01319 finally { 01320 if ( LdrpInLdrInit == FALSE ) { 01321 RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock); 01322 } 01323 } 01324 01325 return( Status ); 01326 } 01327 01328 #if defined(MIPS) 01329 VOID 01330 LdrProcessStarterHelper( 01331 IN PPROCESS_STARTER_ROUTINE ProcessStarter, 01332 IN PVOID RealStartAddress 01333 ) 01334 01335 /*++ 01336 01337 Routine Description: 01338 01339 This function is used to call the code that calls the initial entry point 01340 of a win32 process. On all other platforms, this wrapper is not used since 01341 they can cope with a process entrypoint being in kernel32 prior to it being 01342 mapped. 01343 01344 Arguments: 01345 01346 ProcessStarter - Supplies the address of the function in Kernel32 that ends up 01347 calling the real process entrypoint 01348 01349 RealStartAddress - Supplies the real start address of the process 01350 . 01351 01352 Return Value: 01353 01354 None. 01355 01356 --*/ 01357 01358 { 01359 (ProcessStarter)(RealStartAddress); 01360 NtTerminateProcess(NtCurrentProcess(),0); 01361 } 01362 01363 #endif

Generated on Sat May 15 19:40:37 2004 for test by doxygen 1.3.7