Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygensysldr.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: BSD - See COPYING.ARM in the top level directory 00004 * FILE: ntoskrnl/mm/ARM3/sysldr.c 00005 * PURPOSE: Contains the Kernel Loader (SYSLDR) for loading PE files. 00006 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 00007 * ReactOS Portable Systems Group 00008 */ 00009 00010 /* INCLUDES *******************************************************************/ 00011 00012 #include <ntoskrnl.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 #define MODULE_INVOLVED_IN_ARM3 00017 #include "../ARM3/miarm.h" 00018 00019 /* GCC's incompetence strikes again */ 00020 __inline 00021 VOID 00022 sprintf_nt(IN PCHAR Buffer, 00023 IN PCHAR Format, 00024 IN ...) 00025 { 00026 va_list ap; 00027 va_start(ap, Format); 00028 vsprintf(Buffer, Format, ap); 00029 va_end(ap); 00030 } 00031 00032 /* GLOBALS ********************************************************************/ 00033 00034 LIST_ENTRY PsLoadedModuleList; 00035 LIST_ENTRY MmLoadedUserImageList; 00036 KSPIN_LOCK PsLoadedModuleSpinLock; 00037 ERESOURCE PsLoadedModuleResource; 00038 ULONG_PTR PsNtosImageBase; 00039 KMUTANT MmSystemLoadLock; 00040 00041 PFN_NUMBER MmTotalSystemDriverPages; 00042 00043 PVOID MmUnloadedDrivers; 00044 PVOID MmLastUnloadedDrivers; 00045 00046 BOOLEAN MmMakeLowMemory; 00047 BOOLEAN MmEnforceWriteProtection = TRUE; 00048 00049 PMMPTE MiKernelResourceStartPte, MiKernelResourceEndPte; 00050 ULONG_PTR ExPoolCodeStart, ExPoolCodeEnd, MmPoolCodeStart, MmPoolCodeEnd; 00051 ULONG_PTR MmPteCodeStart, MmPteCodeEnd; 00052 00053 /* FUNCTIONS ******************************************************************/ 00054 00055 PVOID 00056 NTAPI 00057 MiCacheImageSymbols(IN PVOID BaseAddress) 00058 { 00059 ULONG DebugSize; 00060 PVOID DebugDirectory = NULL; 00061 PAGED_CODE(); 00062 00063 /* Make sure it's safe to access the image */ 00064 _SEH2_TRY 00065 { 00066 /* Get the debug directory */ 00067 DebugDirectory = RtlImageDirectoryEntryToData(BaseAddress, 00068 TRUE, 00069 IMAGE_DIRECTORY_ENTRY_DEBUG, 00070 &DebugSize); 00071 } 00072 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00073 { 00074 /* Nothing */ 00075 } 00076 _SEH2_END; 00077 00078 /* Return the directory */ 00079 return DebugDirectory; 00080 } 00081 00082 NTSTATUS 00083 NTAPI 00084 MiLoadImageSection(IN OUT PVOID *SectionPtr, 00085 OUT PVOID *ImageBase, 00086 IN PUNICODE_STRING FileName, 00087 IN BOOLEAN SessionLoad, 00088 IN PLDR_DATA_TABLE_ENTRY LdrEntry) 00089 { 00090 PROS_SECTION_OBJECT Section = *SectionPtr; 00091 NTSTATUS Status; 00092 PEPROCESS Process; 00093 PVOID Base = NULL; 00094 SIZE_T ViewSize = 0; 00095 KAPC_STATE ApcState; 00096 LARGE_INTEGER SectionOffset = {{0, 0}}; 00097 BOOLEAN LoadSymbols = FALSE; 00098 PFN_COUNT PteCount; 00099 PMMPTE PointerPte, LastPte; 00100 PVOID DriverBase; 00101 MMPTE TempPte; 00102 PAGED_CODE(); 00103 00104 /* Detect session load */ 00105 if (SessionLoad) 00106 { 00107 /* Fail */ 00108 DPRINT1("Session loading not yet supported!\n"); 00109 while (TRUE); 00110 } 00111 00112 /* Not session load, shouldn't have an entry */ 00113 ASSERT(LdrEntry == NULL); 00114 00115 /* Attach to the system process */ 00116 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState); 00117 00118 /* Check if we need to load symbols */ 00119 if (NtGlobalFlag & FLG_ENABLE_KDEBUG_SYMBOL_LOAD) 00120 { 00121 /* Yes we do */ 00122 LoadSymbols = TRUE; 00123 NtGlobalFlag &= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD; 00124 } 00125 00126 /* Map the driver */ 00127 Process = PsGetCurrentProcess(); 00128 Status = MmMapViewOfSection(Section, 00129 Process, 00130 &Base, 00131 0, 00132 0, 00133 &SectionOffset, 00134 &ViewSize, 00135 ViewUnmap, 00136 0, 00137 PAGE_EXECUTE); 00138 00139 /* Re-enable the flag */ 00140 if (LoadSymbols) NtGlobalFlag |= FLG_ENABLE_KDEBUG_SYMBOL_LOAD; 00141 00142 /* Check if we failed with distinguished status code */ 00143 if (Status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) 00144 { 00145 /* Change it to something more generic */ 00146 Status = STATUS_INVALID_IMAGE_FORMAT; 00147 } 00148 00149 /* Now check if we failed */ 00150 if (!NT_SUCCESS(Status)) 00151 { 00152 /* Detach and return */ 00153 DPRINT1("MmMapViewOfSection failed with status 0x%x\n", Status); 00154 KeUnstackDetachProcess(&ApcState); 00155 return Status; 00156 } 00157 00158 /* Reserve system PTEs needed */ 00159 PteCount = ROUND_TO_PAGES(Section->ImageSection->ImageSize) >> PAGE_SHIFT; 00160 PointerPte = MiReserveSystemPtes(PteCount, SystemPteSpace); 00161 if (!PointerPte) 00162 { 00163 DPRINT1("MiReserveSystemPtes failed\n"); 00164 KeUnstackDetachProcess(&ApcState); 00165 return STATUS_INSUFFICIENT_RESOURCES; 00166 } 00167 00168 /* New driver base */ 00169 LastPte = PointerPte + PteCount; 00170 DriverBase = MiPteToAddress(PointerPte); 00171 00172 /* The driver is here */ 00173 *ImageBase = DriverBase; 00174 DPRINT1("Loading: %wZ at %p with %lx pages\n", FileName, DriverBase, PteCount); 00175 00176 /* Loop the new driver PTEs */ 00177 TempPte = ValidKernelPte; 00178 while (PointerPte < LastPte) 00179 { 00180 /* Allocate a page */ 00181 MI_SET_USAGE(MI_USAGE_DRIVER_PAGE); 00182 #if MI_TRACE_PFNS 00183 PWCHAR pos = NULL; 00184 ULONG len = 0; 00185 if (FileName->Buffer) 00186 { 00187 pos = wcsrchr(FileName->Buffer, '\\'); 00188 len = wcslen(pos) * sizeof(WCHAR); 00189 if (pos) snprintf(MI_PFN_CURRENT_PROCESS_NAME, min(16, len), "%S", pos); 00190 } 00191 #endif 00192 TempPte.u.Hard.PageFrameNumber = MiAllocatePfn(PointerPte, MM_EXECUTE); 00193 00194 /* Write it */ 00195 MI_WRITE_VALID_PTE(PointerPte, TempPte); 00196 00197 /* Move on */ 00198 PointerPte++; 00199 } 00200 00201 /* Copy the image */ 00202 RtlCopyMemory(DriverBase, Base, PteCount << PAGE_SHIFT); 00203 00204 /* Now unmap the view */ 00205 Status = MmUnmapViewOfSection(Process, Base); 00206 ASSERT(NT_SUCCESS(Status)); 00207 00208 /* Detach and return status */ 00209 KeUnstackDetachProcess(&ApcState); 00210 return Status; 00211 } 00212 00213 PVOID 00214 NTAPI 00215 MiLocateExportName(IN PVOID DllBase, 00216 IN PCHAR ExportName) 00217 { 00218 PULONG NameTable; 00219 PUSHORT OrdinalTable; 00220 PIMAGE_EXPORT_DIRECTORY ExportDirectory; 00221 LONG Low = 0, Mid = 0, High, Ret; 00222 USHORT Ordinal; 00223 PVOID Function; 00224 ULONG ExportSize; 00225 PULONG ExportTable; 00226 PAGED_CODE(); 00227 00228 /* Get the export directory */ 00229 ExportDirectory = RtlImageDirectoryEntryToData(DllBase, 00230 TRUE, 00231 IMAGE_DIRECTORY_ENTRY_EXPORT, 00232 &ExportSize); 00233 if (!ExportDirectory) return NULL; 00234 00235 /* Setup name tables */ 00236 NameTable = (PULONG)((ULONG_PTR)DllBase + 00237 ExportDirectory->AddressOfNames); 00238 OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase + 00239 ExportDirectory->AddressOfNameOrdinals); 00240 00241 /* Do a binary search */ 00242 High = ExportDirectory->NumberOfNames - 1; 00243 while (High >= Low) 00244 { 00245 /* Get new middle value */ 00246 Mid = (Low + High) >> 1; 00247 00248 /* Compare name */ 00249 Ret = strcmp(ExportName, (PCHAR)DllBase + NameTable[Mid]); 00250 if (Ret < 0) 00251 { 00252 /* Update high */ 00253 High = Mid - 1; 00254 } 00255 else if (Ret > 0) 00256 { 00257 /* Update low */ 00258 Low = Mid + 1; 00259 } 00260 else 00261 { 00262 /* We got it */ 00263 break; 00264 } 00265 } 00266 00267 /* Check if we couldn't find it */ 00268 if (High < Low) return NULL; 00269 00270 /* Otherwise, this is the ordinal */ 00271 Ordinal = OrdinalTable[Mid]; 00272 00273 /* Resolve the address and write it */ 00274 ExportTable = (PULONG)((ULONG_PTR)DllBase + 00275 ExportDirectory->AddressOfFunctions); 00276 Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]); 00277 00278 /* Check if the function is actually a forwarder */ 00279 if (((ULONG_PTR)Function > (ULONG_PTR)ExportDirectory) && 00280 ((ULONG_PTR)Function < ((ULONG_PTR)ExportDirectory + ExportSize))) 00281 { 00282 /* It is, fail */ 00283 return NULL; 00284 } 00285 00286 /* We found it */ 00287 return Function; 00288 } 00289 00290 NTSTATUS 00291 NTAPI 00292 MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry, 00293 IN PLIST_ENTRY ListHead) 00294 { 00295 UNICODE_STRING ServicesKeyName = RTL_CONSTANT_STRING( 00296 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); 00297 PMM_DLL_INITIALIZE DllInit; 00298 UNICODE_STRING RegPath, ImportName; 00299 NTSTATUS Status; 00300 00301 /* Try to see if the image exports a DllInitialize routine */ 00302 DllInit = (PMM_DLL_INITIALIZE)MiLocateExportName(LdrEntry->DllBase, 00303 "DllInitialize"); 00304 if (!DllInit) return STATUS_SUCCESS; 00305 00306 /* Do a temporary copy of BaseDllName called ImportName 00307 * because we'll alter the length of the string 00308 */ 00309 ImportName.Length = LdrEntry->BaseDllName.Length; 00310 ImportName.MaximumLength = LdrEntry->BaseDllName.MaximumLength; 00311 ImportName.Buffer = LdrEntry->BaseDllName.Buffer; 00312 00313 /* Obtain the path to this dll's service in the registry */ 00314 RegPath.MaximumLength = ServicesKeyName.Length + 00315 ImportName.Length + sizeof(UNICODE_NULL); 00316 RegPath.Buffer = ExAllocatePoolWithTag(NonPagedPool, 00317 RegPath.MaximumLength, 00318 TAG_LDR_WSTR); 00319 00320 /* Check if this allocation was unsuccessful */ 00321 if (!RegPath.Buffer) return STATUS_INSUFFICIENT_RESOURCES; 00322 00323 /* Build and append the service name itself */ 00324 RegPath.Length = ServicesKeyName.Length; 00325 RtlCopyMemory(RegPath.Buffer, 00326 ServicesKeyName.Buffer, 00327 ServicesKeyName.Length); 00328 00329 /* Check if there is a dot in the filename */ 00330 if (wcschr(ImportName.Buffer, L'.')) 00331 { 00332 /* Remove the extension */ 00333 ImportName.Length = (USHORT)(wcschr(ImportName.Buffer, L'.') - 00334 ImportName.Buffer) * sizeof(WCHAR); 00335 } 00336 00337 /* Append service name (the basename without extension) */ 00338 RtlAppendUnicodeStringToString(&RegPath, &ImportName); 00339 00340 /* Now call the DllInit func */ 00341 DPRINT("Calling DllInit(%wZ)\n", &RegPath); 00342 Status = DllInit(&RegPath); 00343 00344 /* Clean up */ 00345 ExFreePoolWithTag(RegPath.Buffer, TAG_LDR_WSTR); 00346 00347 /* Return status value which DllInitialize returned */ 00348 return Status; 00349 } 00350 00351 BOOLEAN 00352 NTAPI 00353 MiCallDllUnloadAndUnloadDll(IN PLDR_DATA_TABLE_ENTRY LdrEntry) 00354 { 00355 NTSTATUS Status; 00356 PMM_DLL_UNLOAD Func; 00357 PAGED_CODE(); 00358 00359 /* Get the unload routine */ 00360 Func = (PMM_DLL_UNLOAD)MiLocateExportName(LdrEntry->DllBase, "DllUnload"); 00361 if (!Func) return FALSE; 00362 00363 /* Call it and check for success */ 00364 Status = Func(); 00365 if (!NT_SUCCESS(Status)) return FALSE; 00366 00367 /* Lie about the load count so we can unload the image */ 00368 ASSERT(LdrEntry->LoadCount == 0); 00369 LdrEntry->LoadCount = 1; 00370 00371 /* Unload it and return true */ 00372 MmUnloadSystemImage(LdrEntry); 00373 return TRUE; 00374 } 00375 00376 NTSTATUS 00377 NTAPI 00378 MiDereferenceImports(IN PLOAD_IMPORTS ImportList) 00379 { 00380 SIZE_T i; 00381 LOAD_IMPORTS SingleEntry; 00382 PLDR_DATA_TABLE_ENTRY LdrEntry; 00383 PVOID CurrentImports; 00384 PAGED_CODE(); 00385 00386 /* Check if there's no imports or if we're a boot driver */ 00387 if ((ImportList == MM_SYSLDR_NO_IMPORTS) || 00388 (ImportList == MM_SYSLDR_BOOT_LOADED) || 00389 (ImportList->Count == 0)) 00390 { 00391 /* Then there's nothing to do */ 00392 return STATUS_SUCCESS; 00393 } 00394 00395 /* Check for single-entry */ 00396 if ((ULONG_PTR)ImportList & MM_SYSLDR_SINGLE_ENTRY) 00397 { 00398 /* Set it up */ 00399 SingleEntry.Count = 1; 00400 SingleEntry.Entry[0] = (PVOID)((ULONG_PTR)ImportList &~ MM_SYSLDR_SINGLE_ENTRY); 00401 00402 /* Use this as the import list */ 00403 ImportList = &SingleEntry; 00404 } 00405 00406 /* Loop the import list */ 00407 for (i = 0; (i < ImportList->Count) && (ImportList->Entry[i]); i++) 00408 { 00409 /* Get the entry */ 00410 LdrEntry = ImportList->Entry[i]; 00411 DPRINT1("%wZ <%wZ>\n", &LdrEntry->FullDllName, &LdrEntry->BaseDllName); 00412 00413 /* Skip boot loaded images */ 00414 if (LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) continue; 00415 00416 /* Dereference the entry */ 00417 ASSERT(LdrEntry->LoadCount >= 1); 00418 if (!--LdrEntry->LoadCount) 00419 { 00420 /* Save the import data in case unload fails */ 00421 CurrentImports = LdrEntry->LoadedImports; 00422 00423 /* This is the last entry */ 00424 LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS; 00425 if (MiCallDllUnloadAndUnloadDll(LdrEntry)) 00426 { 00427 /* Unloading worked, parse this DLL's imports too */ 00428 MiDereferenceImports(CurrentImports); 00429 00430 /* Check if we had valid imports */ 00431 if ((CurrentImports != MM_SYSLDR_BOOT_LOADED) || 00432 (CurrentImports != MM_SYSLDR_NO_IMPORTS) || 00433 !((ULONG_PTR)LdrEntry->LoadedImports & MM_SYSLDR_SINGLE_ENTRY)) 00434 { 00435 /* Free them */ 00436 ExFreePoolWithTag(CurrentImports, TAG_LDR_IMPORTS); 00437 } 00438 } 00439 else 00440 { 00441 /* Unload failed, restore imports */ 00442 LdrEntry->LoadedImports = CurrentImports; 00443 } 00444 } 00445 } 00446 00447 /* Done */ 00448 return STATUS_SUCCESS; 00449 } 00450 00451 VOID 00452 NTAPI 00453 MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry) 00454 { 00455 PAGED_CODE(); 00456 00457 /* Check if there's no imports or we're a boot driver or only one entry */ 00458 if ((LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) || 00459 (LdrEntry->LoadedImports == MM_SYSLDR_NO_IMPORTS) || 00460 ((ULONG_PTR)LdrEntry->LoadedImports & MM_SYSLDR_SINGLE_ENTRY)) 00461 { 00462 /* Nothing to do */ 00463 return; 00464 } 00465 00466 /* Otherwise, free the import list */ 00467 ExFreePoolWithTag(LdrEntry->LoadedImports, TAG_LDR_IMPORTS); 00468 LdrEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED; 00469 } 00470 00471 PVOID 00472 NTAPI 00473 MiFindExportedRoutineByName(IN PVOID DllBase, 00474 IN PANSI_STRING ExportName) 00475 { 00476 PULONG NameTable; 00477 PUSHORT OrdinalTable; 00478 PIMAGE_EXPORT_DIRECTORY ExportDirectory; 00479 LONG Low = 0, Mid = 0, High, Ret; 00480 USHORT Ordinal; 00481 PVOID Function; 00482 ULONG ExportSize; 00483 PULONG ExportTable; 00484 PAGED_CODE(); 00485 00486 /* Get the export directory */ 00487 ExportDirectory = RtlImageDirectoryEntryToData(DllBase, 00488 TRUE, 00489 IMAGE_DIRECTORY_ENTRY_EXPORT, 00490 &ExportSize); 00491 if (!ExportDirectory) return NULL; 00492 00493 /* Setup name tables */ 00494 NameTable = (PULONG)((ULONG_PTR)DllBase + 00495 ExportDirectory->AddressOfNames); 00496 OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase + 00497 ExportDirectory->AddressOfNameOrdinals); 00498 00499 /* Do a binary search */ 00500 High = ExportDirectory->NumberOfNames - 1; 00501 while (High >= Low) 00502 { 00503 /* Get new middle value */ 00504 Mid = (Low + High) >> 1; 00505 00506 /* Compare name */ 00507 Ret = strcmp(ExportName->Buffer, (PCHAR)DllBase + NameTable[Mid]); 00508 if (Ret < 0) 00509 { 00510 /* Update high */ 00511 High = Mid - 1; 00512 } 00513 else if (Ret > 0) 00514 { 00515 /* Update low */ 00516 Low = Mid + 1; 00517 } 00518 else 00519 { 00520 /* We got it */ 00521 break; 00522 } 00523 } 00524 00525 /* Check if we couldn't find it */ 00526 if (High < Low) return NULL; 00527 00528 /* Otherwise, this is the ordinal */ 00529 Ordinal = OrdinalTable[Mid]; 00530 00531 /* Validate the ordinal */ 00532 if (Ordinal >= ExportDirectory->NumberOfFunctions) return NULL; 00533 00534 /* Resolve the address and write it */ 00535 ExportTable = (PULONG)((ULONG_PTR)DllBase + 00536 ExportDirectory->AddressOfFunctions); 00537 Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]); 00538 00539 /* We found it! */ 00540 ASSERT(!(Function > (PVOID)ExportDirectory) && 00541 (Function < (PVOID)((ULONG_PTR)ExportDirectory + ExportSize))); 00542 return Function; 00543 } 00544 00545 VOID 00546 NTAPI 00547 MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry, 00548 IN BOOLEAN Insert) 00549 { 00550 KIRQL OldIrql; 00551 00552 /* Acquire module list lock */ 00553 KeEnterCriticalRegion(); 00554 ExAcquireResourceExclusiveLite(&PsLoadedModuleResource, TRUE); 00555 00556 /* Acquire the spinlock too as we will insert or remove the entry */ 00557 OldIrql = KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock); 00558 00559 /* Insert or remove from the list */ 00560 Insert ? InsertTailList(&PsLoadedModuleList, &LdrEntry->InLoadOrderLinks) : 00561 RemoveEntryList(&LdrEntry->InLoadOrderLinks); 00562 00563 /* Release locks */ 00564 KeReleaseSpinLock(&PsLoadedModuleSpinLock, OldIrql); 00565 ExReleaseResourceLite(&PsLoadedModuleResource); 00566 KeLeaveCriticalRegion(); 00567 } 00568 00569 VOID 00570 NTAPI 00571 INIT_FUNCTION 00572 MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock, 00573 IN PVOID OldBase, 00574 IN PVOID NewBase, 00575 IN ULONG Size) 00576 { 00577 ULONG_PTR OldBaseTop, Delta; 00578 PLDR_DATA_TABLE_ENTRY LdrEntry; 00579 PLIST_ENTRY NextEntry; 00580 ULONG ImportSize; 00581 // 00582 // FIXME: MINGW-W64 must fix LD to generate drivers that Windows can load, 00583 // since a real version of Windows would fail at this point, but they seem 00584 // busy implementing features such as "HotPatch" support in GCC 4.6 instead, 00585 // a feature which isn't even used by Windows. Priorities, priorities... 00586 // Please note that Microsoft WDK EULA and license prohibits using 00587 // the information contained within it for the generation of "non-Windows" 00588 // drivers, which is precisely what LD will generate, since an LD driver 00589 // will not load on Windows. 00590 // 00591 #ifdef _WORKING_LINKER_ 00592 ULONG i; 00593 #endif 00594 PULONG_PTR ImageThunk; 00595 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor; 00596 00597 /* Calculate the top and delta */ 00598 OldBaseTop = (ULONG_PTR)OldBase + Size - 1; 00599 Delta = (ULONG_PTR)NewBase - (ULONG_PTR)OldBase; 00600 00601 /* Loop the loader block */ 00602 for (NextEntry = LoaderBlock->LoadOrderListHead.Flink; 00603 NextEntry != &LoaderBlock->LoadOrderListHead; 00604 NextEntry = NextEntry->Flink) 00605 { 00606 /* Get the loader entry */ 00607 LdrEntry = CONTAINING_RECORD(NextEntry, 00608 LDR_DATA_TABLE_ENTRY, 00609 InLoadOrderLinks); 00610 #ifdef _WORKING_LINKER_ 00611 /* Get the IAT */ 00612 ImageThunk = RtlImageDirectoryEntryToData(LdrEntry->DllBase, 00613 TRUE, 00614 IMAGE_DIRECTORY_ENTRY_IAT, 00615 &ImportSize); 00616 if (!ImageThunk) continue; 00617 00618 /* Make sure we have an IAT */ 00619 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry->BaseDllName); 00620 for (i = 0; i < ImportSize; i++, ImageThunk++) 00621 { 00622 /* Check if it's within this module */ 00623 if ((*ImageThunk >= (ULONG_PTR)OldBase) && (*ImageThunk <= OldBaseTop)) 00624 { 00625 /* Relocate it */ 00626 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n", 00627 ImageThunk, *ImageThunk, *ImageThunk + Delta); 00628 *ImageThunk += Delta; 00629 } 00630 } 00631 #else 00632 /* Get the import table */ 00633 ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase, 00634 TRUE, 00635 IMAGE_DIRECTORY_ENTRY_IMPORT, 00636 &ImportSize); 00637 if (!ImportDescriptor) continue; 00638 00639 /* Make sure we have an IAT */ 00640 DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry->BaseDllName); 00641 while ((ImportDescriptor->Name) && 00642 (ImportDescriptor->OriginalFirstThunk)) 00643 { 00644 /* Get the image thunk */ 00645 ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase + 00646 ImportDescriptor->FirstThunk); 00647 while (*ImageThunk) 00648 { 00649 /* Check if it's within this module */ 00650 if ((*ImageThunk >= (ULONG_PTR)OldBase) && (*ImageThunk <= OldBaseTop)) 00651 { 00652 /* Relocate it */ 00653 DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n", 00654 ImageThunk, *ImageThunk, *ImageThunk + Delta); 00655 *ImageThunk += Delta; 00656 } 00657 00658 /* Go to the next thunk */ 00659 ImageThunk++; 00660 } 00661 00662 /* Go to the next import */ 00663 ImportDescriptor++; 00664 } 00665 #endif 00666 } 00667 } 00668 00669 NTSTATUS 00670 NTAPI 00671 MiSnapThunk(IN PVOID DllBase, 00672 IN PVOID ImageBase, 00673 IN PIMAGE_THUNK_DATA Name, 00674 IN PIMAGE_THUNK_DATA Address, 00675 IN PIMAGE_EXPORT_DIRECTORY ExportDirectory, 00676 IN ULONG ExportSize, 00677 IN BOOLEAN SnapForwarder, 00678 OUT PCHAR *MissingApi) 00679 { 00680 BOOLEAN IsOrdinal; 00681 USHORT Ordinal; 00682 PULONG NameTable; 00683 PUSHORT OrdinalTable; 00684 PIMAGE_IMPORT_BY_NAME NameImport; 00685 USHORT Hint; 00686 ULONG Low = 0, Mid = 0, High; 00687 LONG Ret; 00688 NTSTATUS Status; 00689 PCHAR MissingForwarder; 00690 CHAR NameBuffer[MAXIMUM_FILENAME_LENGTH]; 00691 PULONG ExportTable; 00692 ANSI_STRING DllName; 00693 UNICODE_STRING ForwarderName; 00694 PLIST_ENTRY NextEntry; 00695 PLDR_DATA_TABLE_ENTRY LdrEntry; 00696 ULONG ForwardExportSize; 00697 PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory; 00698 PIMAGE_IMPORT_BY_NAME ForwardName; 00699 SIZE_T ForwardLength; 00700 IMAGE_THUNK_DATA ForwardThunk; 00701 PAGED_CODE(); 00702 00703 /* Check if this is an ordinal */ 00704 IsOrdinal = IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal); 00705 if ((IsOrdinal) && !(SnapForwarder)) 00706 { 00707 /* Get the ordinal number and set it as missing */ 00708 Ordinal = (USHORT)(IMAGE_ORDINAL(Name->u1.Ordinal) - 00709 ExportDirectory->Base); 00710 *MissingApi = (PCHAR)(ULONG_PTR)Ordinal; 00711 } 00712 else 00713 { 00714 /* Get the VA if we don't have to snap */ 00715 if (!SnapForwarder) Name->u1.AddressOfData += (ULONG_PTR)ImageBase; 00716 NameImport = (PIMAGE_IMPORT_BY_NAME)Name->u1.AddressOfData; 00717 00718 /* Copy the procedure name */ 00719 RtlStringCbCopyA(*MissingApi, 00720 MAXIMUM_FILENAME_LENGTH, 00721 (PCHAR)&NameImport->Name[0]); 00722 00723 /* Setup name tables */ 00724 DPRINT("Import name: %s\n", NameImport->Name); 00725 NameTable = (PULONG)((ULONG_PTR)DllBase + 00726 ExportDirectory->AddressOfNames); 00727 OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase + 00728 ExportDirectory->AddressOfNameOrdinals); 00729 00730 /* Get the hint and check if it's valid */ 00731 Hint = NameImport->Hint; 00732 if ((Hint < ExportDirectory->NumberOfNames) && 00733 !(strcmp((PCHAR)NameImport->Name, (PCHAR)DllBase + NameTable[Hint]))) 00734 { 00735 /* We have a match, get the ordinal number from here */ 00736 Ordinal = OrdinalTable[Hint]; 00737 } 00738 else 00739 { 00740 /* Do a binary search */ 00741 High = ExportDirectory->NumberOfNames - 1; 00742 while (High >= Low) 00743 { 00744 /* Get new middle value */ 00745 Mid = (Low + High) >> 1; 00746 00747 /* Compare name */ 00748 Ret = strcmp((PCHAR)NameImport->Name, (PCHAR)DllBase + NameTable[Mid]); 00749 if (Ret < 0) 00750 { 00751 /* Update high */ 00752 High = Mid - 1; 00753 } 00754 else if (Ret > 0) 00755 { 00756 /* Update low */ 00757 Low = Mid + 1; 00758 } 00759 else 00760 { 00761 /* We got it */ 00762 break; 00763 } 00764 } 00765 00766 /* Check if we couldn't find it */ 00767 if (High < Low) 00768 { 00769 DPRINT1("Warning: Driver failed to load, %s not found\n", NameImport->Name); 00770 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND; 00771 } 00772 00773 /* Otherwise, this is the ordinal */ 00774 Ordinal = OrdinalTable[Mid]; 00775 } 00776 } 00777 00778 /* Check if the ordinal is invalid */ 00779 if (Ordinal >= ExportDirectory->NumberOfFunctions) 00780 { 00781 /* Fail */ 00782 Status = STATUS_DRIVER_ORDINAL_NOT_FOUND; 00783 } 00784 else 00785 { 00786 /* In case the forwarder is missing */ 00787 MissingForwarder = NameBuffer; 00788 00789 /* Resolve the address and write it */ 00790 ExportTable = (PULONG)((ULONG_PTR)DllBase + 00791 ExportDirectory->AddressOfFunctions); 00792 Address->u1.Function = (ULONG_PTR)DllBase + ExportTable[Ordinal]; 00793 00794 /* Assume success from now on */ 00795 Status = STATUS_SUCCESS; 00796 00797 /* Check if the function is actually a forwarder */ 00798 if ((Address->u1.Function > (ULONG_PTR)ExportDirectory) && 00799 (Address->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize))) 00800 { 00801 /* Now assume failure in case the forwarder doesn't exist */ 00802 Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND; 00803 00804 /* Build the forwarder name */ 00805 DllName.Buffer = (PCHAR)Address->u1.Function; 00806 DllName.Length = (USHORT)(strchr(DllName.Buffer, '.') - 00807 DllName.Buffer) + 00808 sizeof(ANSI_NULL); 00809 DllName.MaximumLength = DllName.Length; 00810 00811 /* Convert it */ 00812 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName, 00813 &DllName, 00814 TRUE))) 00815 { 00816 /* We failed, just return an error */ 00817 return Status; 00818 } 00819 00820 /* Loop the module list */ 00821 NextEntry = PsLoadedModuleList.Flink; 00822 while (NextEntry != &PsLoadedModuleList) 00823 { 00824 /* Get the loader entry */ 00825 LdrEntry = CONTAINING_RECORD(NextEntry, 00826 LDR_DATA_TABLE_ENTRY, 00827 InLoadOrderLinks); 00828 00829 /* Check if it matches */ 00830 if (RtlPrefixString((PSTRING)&ForwarderName, 00831 (PSTRING)&LdrEntry->BaseDllName, 00832 TRUE)) 00833 { 00834 /* Get the forwarder export directory */ 00835 ForwardExportDirectory = 00836 RtlImageDirectoryEntryToData(LdrEntry->DllBase, 00837 TRUE, 00838 IMAGE_DIRECTORY_ENTRY_EXPORT, 00839 &ForwardExportSize); 00840 if (!ForwardExportDirectory) break; 00841 00842 /* Allocate a name entry */ 00843 ForwardLength = strlen(DllName.Buffer + DllName.Length) + 00844 sizeof(ANSI_NULL); 00845 ForwardName = ExAllocatePoolWithTag(PagedPool, 00846 sizeof(*ForwardName) + 00847 ForwardLength, 00848 TAG_LDR_WSTR); 00849 if (!ForwardName) break; 00850 00851 /* Copy the data */ 00852 RtlCopyMemory(&ForwardName->Name[0], 00853 DllName.Buffer + DllName.Length, 00854 ForwardLength); 00855 ForwardName->Hint = 0; 00856 00857 /* Set the new address */ 00858 ForwardThunk.u1.AddressOfData = (ULONG_PTR)ForwardName; 00859 00860 /* Snap the forwarder */ 00861 Status = MiSnapThunk(LdrEntry->DllBase, 00862 ImageBase, 00863 &ForwardThunk, 00864 &ForwardThunk, 00865 ForwardExportDirectory, 00866 ForwardExportSize, 00867 TRUE, 00868 &MissingForwarder); 00869 00870 /* Free the forwarder name and set the thunk */ 00871 ExFreePoolWithTag(ForwardName, TAG_LDR_WSTR); 00872 Address->u1 = ForwardThunk.u1; 00873 break; 00874 } 00875 00876 /* Go to the next entry */ 00877 NextEntry = NextEntry->Flink; 00878 } 00879 00880 /* Free the name */ 00881 RtlFreeUnicodeString(&ForwarderName); 00882 } 00883 } 00884 00885 /* Return status */ 00886 return Status; 00887 } 00888 00889 NTSTATUS 00890 NTAPI 00891 MmUnloadSystemImage(IN PVOID ImageHandle) 00892 { 00893 PLDR_DATA_TABLE_ENTRY LdrEntry = ImageHandle; 00894 PVOID BaseAddress = LdrEntry->DllBase; 00895 NTSTATUS Status; 00896 STRING TempName; 00897 BOOLEAN HadEntry = FALSE; 00898 00899 /* Acquire the loader lock */ 00900 KeEnterCriticalRegion(); 00901 KeWaitForSingleObject(&MmSystemLoadLock, 00902 WrVirtualMemory, 00903 KernelMode, 00904 FALSE, 00905 NULL); 00906 00907 /* Check if this driver was loaded at boot and didn't get imports parsed */ 00908 if (LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) goto Done; 00909 00910 /* We should still be alive */ 00911 ASSERT(LdrEntry->LoadCount != 0); 00912 LdrEntry->LoadCount--; 00913 00914 /* Check if we're still loaded */ 00915 if (LdrEntry->LoadCount) goto Done; 00916 00917 /* We should cleanup... are symbols loaded */ 00918 if (LdrEntry->Flags & LDRP_DEBUG_SYMBOLS_LOADED) 00919 { 00920 /* Create the ANSI name */ 00921 Status = RtlUnicodeStringToAnsiString(&TempName, 00922 &LdrEntry->BaseDllName, 00923 TRUE); 00924 if (NT_SUCCESS(Status)) 00925 { 00926 /* Unload the symbols */ 00927 DbgUnLoadImageSymbols(&TempName, 00928 BaseAddress, 00929 (ULONG_PTR)ZwCurrentProcess()); 00930 RtlFreeAnsiString(&TempName); 00931 } 00932 } 00933 00934 /* FIXME: Free the driver */ 00935 DPRINT1("Leaking driver: %wZ\n", &LdrEntry->BaseDllName); 00936 //MmFreeSection(LdrEntry->DllBase); 00937 00938 /* Check if we're linked in */ 00939 if (LdrEntry->InLoadOrderLinks.Flink) 00940 { 00941 /* Remove us */ 00942 MiProcessLoaderEntry(LdrEntry, FALSE); 00943 HadEntry = TRUE; 00944 } 00945 00946 /* Dereference and clear the imports */ 00947 MiDereferenceImports(LdrEntry->LoadedImports); 00948 MiClearImports(LdrEntry); 00949 00950 /* Check if the entry needs to go away */ 00951 if (HadEntry) 00952 { 00953 /* Check if it had a name */ 00954 if (LdrEntry->FullDllName.Buffer) 00955 { 00956 /* Free it */ 00957 ExFreePoolWithTag(LdrEntry->FullDllName.Buffer, TAG_LDR_WSTR); 00958 } 00959 00960 /* Check if we had a section */ 00961 if (LdrEntry->SectionPointer) 00962 { 00963 /* Dereference it */ 00964 ObDereferenceObject(LdrEntry->SectionPointer); 00965 } 00966 00967 /* Free the entry */ 00968 ExFreePoolWithTag(LdrEntry, TAG_MODULE_OBJECT); 00969 } 00970 00971 /* Release the system lock and return */ 00972 Done: 00973 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE); 00974 KeLeaveCriticalRegion(); 00975 return STATUS_SUCCESS; 00976 } 00977 00978 NTSTATUS 00979 NTAPI 00980 MiResolveImageReferences(IN PVOID ImageBase, 00981 IN PUNICODE_STRING ImageFileDirectory, 00982 IN PUNICODE_STRING NamePrefix OPTIONAL, 00983 OUT PCHAR *MissingApi, 00984 OUT PWCHAR *MissingDriver, 00985 OUT PLOAD_IMPORTS *LoadImports) 00986 { 00987 PCHAR MissingApiBuffer = *MissingApi, ImportName; 00988 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor, CurrentImport; 00989 ULONG ImportSize, ImportCount = 0, LoadedImportsSize, ExportSize; 00990 PLOAD_IMPORTS LoadedImports, NewImports; 00991 ULONG GdiLink, NormalLink, i; 00992 BOOLEAN ReferenceNeeded, Loaded; 00993 ANSI_STRING TempString; 00994 UNICODE_STRING NameString, DllName; 00995 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL, DllEntry, ImportEntry = NULL; 00996 PVOID ImportBase, DllBase; 00997 PLIST_ENTRY NextEntry; 00998 PIMAGE_EXPORT_DIRECTORY ExportDirectory; 00999 NTSTATUS Status; 01000 PIMAGE_THUNK_DATA OrigThunk, FirstThunk; 01001 PAGED_CODE(); 01002 DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n", 01003 __FUNCTION__, ImageBase, ImageFileDirectory); 01004 01005 /* Assume no imports */ 01006 *LoadImports = MM_SYSLDR_NO_IMPORTS; 01007 01008 /* Get the import descriptor */ 01009 ImportDescriptor = RtlImageDirectoryEntryToData(ImageBase, 01010 TRUE, 01011 IMAGE_DIRECTORY_ENTRY_IMPORT, 01012 &ImportSize); 01013 if (!ImportDescriptor) return STATUS_SUCCESS; 01014 01015 /* Loop all imports to count them */ 01016 for (CurrentImport = ImportDescriptor; 01017 (CurrentImport->Name) && (CurrentImport->OriginalFirstThunk); 01018 CurrentImport++) 01019 { 01020 /* One more */ 01021 ImportCount++; 01022 } 01023 01024 /* Make sure we have non-zero imports */ 01025 if (ImportCount) 01026 { 01027 /* Calculate and allocate the list we'll need */ 01028 LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T); 01029 LoadedImports = ExAllocatePoolWithTag(PagedPool, 01030 LoadedImportsSize, 01031 TAG_LDR_IMPORTS); 01032 if (LoadedImports) 01033 { 01034 /* Zero it */ 01035 RtlZeroMemory(LoadedImports, LoadedImportsSize); 01036 LoadedImports->Count = ImportCount; 01037 } 01038 } 01039 else 01040 { 01041 /* No table */ 01042 LoadedImports = NULL; 01043 } 01044 01045 /* Reset the import count and loop descriptors again */ 01046 ImportCount = GdiLink = NormalLink = 0; 01047 while ((ImportDescriptor->Name) && (ImportDescriptor->OriginalFirstThunk)) 01048 { 01049 /* Get the name */ 01050 ImportName = (PCHAR)((ULONG_PTR)ImageBase + ImportDescriptor->Name); 01051 01052 /* Check if this is a GDI driver */ 01053 GdiLink = GdiLink | 01054 !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)); 01055 01056 /* We can also allow dxapi (for Windows compat, allow IRT and coverage )*/ 01057 NormalLink = NormalLink | 01058 ((_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) && 01059 (_strnicmp(ImportName, "dxapi", sizeof("dxapi") - 1)) && 01060 (_strnicmp(ImportName, "coverage", sizeof("coverage") - 1)) && 01061 (_strnicmp(ImportName, "irt", sizeof("irt") - 1))); 01062 01063 /* Check if this is a valid GDI driver */ 01064 if ((GdiLink) && (NormalLink)) 01065 { 01066 /* It's not, it's importing stuff it shouldn't be! */ 01067 MiDereferenceImports(LoadedImports); 01068 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS); 01069 return STATUS_PROCEDURE_NOT_FOUND; 01070 } 01071 01072 /* Check for user-mode printer or video card drivers, which don't belong */ 01073 if (!(_strnicmp(ImportName, "ntdll", sizeof("ntdll") - 1)) || 01074 !(_strnicmp(ImportName, "winsrv", sizeof("winsrv") - 1)) || 01075 !(_strnicmp(ImportName, "advapi32", sizeof("advapi32") - 1)) || 01076 !(_strnicmp(ImportName, "kernel32", sizeof("kernel32") - 1)) || 01077 !(_strnicmp(ImportName, "user32", sizeof("user32") - 1)) || 01078 !(_strnicmp(ImportName, "gdi32", sizeof("gdi32") - 1))) 01079 { 01080 /* This is not kernel code */ 01081 MiDereferenceImports(LoadedImports); 01082 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS); 01083 return STATUS_PROCEDURE_NOT_FOUND; 01084 } 01085 01086 /* Check if this is a "core" import, which doesn't get referenced */ 01087 if (!(_strnicmp(ImportName, "ntoskrnl", sizeof("ntoskrnl") - 1)) || 01088 !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) || 01089 !(_strnicmp(ImportName, "hal", sizeof("hal") - 1))) 01090 { 01091 /* Don't reference this */ 01092 ReferenceNeeded = FALSE; 01093 } 01094 else 01095 { 01096 /* Reference these modules */ 01097 ReferenceNeeded = TRUE; 01098 } 01099 01100 /* Now setup a unicode string for the import */ 01101 RtlInitAnsiString(&TempString, ImportName); 01102 Status = RtlAnsiStringToUnicodeString(&NameString, &TempString, TRUE); 01103 if (!NT_SUCCESS(Status)) 01104 { 01105 /* Failed */ 01106 MiDereferenceImports(LoadedImports); 01107 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS); 01108 return Status; 01109 } 01110 01111 /* We don't support name prefixes yet */ 01112 if (NamePrefix) DPRINT1("Name Prefix not yet supported!\n"); 01113 01114 /* Remember that we haven't loaded the import at this point */ 01115 CheckDllState: 01116 Loaded = FALSE; 01117 ImportBase = NULL; 01118 01119 /* Loop the driver list */ 01120 NextEntry = PsLoadedModuleList.Flink; 01121 while (NextEntry != &PsLoadedModuleList) 01122 { 01123 /* Get the loader entry and compare the name */ 01124 LdrEntry = CONTAINING_RECORD(NextEntry, 01125 LDR_DATA_TABLE_ENTRY, 01126 InLoadOrderLinks); 01127 if (RtlEqualUnicodeString(&NameString, 01128 &LdrEntry->BaseDllName, 01129 TRUE)) 01130 { 01131 /* Get the base address */ 01132 ImportBase = LdrEntry->DllBase; 01133 01134 /* Check if we haven't loaded yet, and we need references */ 01135 if (!(Loaded) && (ReferenceNeeded)) 01136 { 01137 /* Make sure we're not already loading */ 01138 if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS)) 01139 { 01140 /* Increase the load count */ 01141 LdrEntry->LoadCount++; 01142 } 01143 } 01144 01145 /* Done, break out */ 01146 break; 01147 } 01148 01149 /* Go to the next entry */ 01150 NextEntry = NextEntry->Flink; 01151 } 01152 01153 /* Check if we haven't loaded the import yet */ 01154 if (!ImportBase) 01155 { 01156 /* Setup the import DLL name */ 01157 DllName.MaximumLength = NameString.Length + 01158 ImageFileDirectory->Length + 01159 sizeof(UNICODE_NULL); 01160 DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool, 01161 DllName.MaximumLength, 01162 TAG_LDR_WSTR); 01163 if (DllName.Buffer) 01164 { 01165 /* Setup the base length and copy it */ 01166 DllName.Length = ImageFileDirectory->Length; 01167 RtlCopyMemory(DllName.Buffer, 01168 ImageFileDirectory->Buffer, 01169 ImageFileDirectory->Length); 01170 01171 /* Now add the import name and null-terminate it */ 01172 RtlAppendUnicodeStringToString(&DllName, 01173 &NameString); 01174 DllName.Buffer[DllName.Length / sizeof(WCHAR)] = UNICODE_NULL; 01175 01176 /* Load the image */ 01177 Status = MmLoadSystemImage(&DllName, 01178 NamePrefix, 01179 NULL, 01180 FALSE, 01181 (PVOID)&DllEntry, 01182 &DllBase); 01183 if (NT_SUCCESS(Status)) 01184 { 01185 /* We can free the DLL Name */ 01186 ExFreePoolWithTag(DllName.Buffer, TAG_LDR_WSTR); 01187 } 01188 else 01189 { 01190 /* Fill out the information for the error */ 01191 *MissingDriver = DllName.Buffer; 01192 *(PULONG)MissingDriver |= 1; 01193 *MissingApi = NULL; 01194 01195 DPRINT1("Failed to load dependency: %wZ\n", &DllName); 01196 } 01197 } 01198 else 01199 { 01200 /* We're out of resources */ 01201 Status = STATUS_INSUFFICIENT_RESOURCES; 01202 } 01203 01204 /* Check if we're OK until now */ 01205 if (NT_SUCCESS(Status)) 01206 { 01207 /* We're now loaded */ 01208 Loaded = TRUE; 01209 01210 /* Sanity check */ 01211 ASSERT(DllBase == DllEntry->DllBase); 01212 01213 /* Call the initialization routines */ 01214 Status = MmCallDllInitialize(DllEntry, &PsLoadedModuleList); 01215 if (!NT_SUCCESS(Status)) 01216 { 01217 /* We failed, unload the image */ 01218 MmUnloadSystemImage(DllEntry); 01219 DPRINT1("MmCallDllInitialize failed with status 0x%x\n", Status); 01220 while (TRUE); 01221 Loaded = FALSE; 01222 } 01223 } 01224 01225 /* Check if we failed by here */ 01226 if (!NT_SUCCESS(Status)) 01227 { 01228 /* Cleanup and return */ 01229 RtlFreeUnicodeString(&NameString); 01230 MiDereferenceImports(LoadedImports); 01231 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS); 01232 return Status; 01233 } 01234 01235 /* Loop again to make sure that everything is OK */ 01236 goto CheckDllState; 01237 } 01238 01239 /* Check if we're support to reference this import */ 01240 if ((ReferenceNeeded) && (LoadedImports)) 01241 { 01242 /* Make sure we're not already loading */ 01243 if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS)) 01244 { 01245 /* Add the entry */ 01246 LoadedImports->Entry[ImportCount] = LdrEntry; 01247 ImportCount++; 01248 } 01249 } 01250 01251 /* Free the import name */ 01252 RtlFreeUnicodeString(&NameString); 01253 01254 /* Set the missing driver name and get the export directory */ 01255 *MissingDriver = LdrEntry->BaseDllName.Buffer; 01256 ExportDirectory = RtlImageDirectoryEntryToData(ImportBase, 01257 TRUE, 01258 IMAGE_DIRECTORY_ENTRY_EXPORT, 01259 &ExportSize); 01260 if (!ExportDirectory) 01261 { 01262 /* Cleanup and return */ 01263 MiDereferenceImports(LoadedImports); 01264 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS); 01265 DPRINT1("Warning: Driver failed to load, %S not found\n", *MissingDriver); 01266 return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND; 01267 } 01268 01269 /* Make sure we have an IAT */ 01270 if (ImportDescriptor->OriginalFirstThunk) 01271 { 01272 /* Get the first thunks */ 01273 OrigThunk = (PVOID)((ULONG_PTR)ImageBase + 01274 ImportDescriptor->OriginalFirstThunk); 01275 FirstThunk = (PVOID)((ULONG_PTR)ImageBase + 01276 ImportDescriptor->FirstThunk); 01277 01278 /* Loop the IAT */ 01279 while (OrigThunk->u1.AddressOfData) 01280 { 01281 /* Snap thunk */ 01282 Status = MiSnapThunk(ImportBase, 01283 ImageBase, 01284 OrigThunk++, 01285 FirstThunk++, 01286 ExportDirectory, 01287 ExportSize, 01288 FALSE, 01289 MissingApi); 01290 if (!NT_SUCCESS(Status)) 01291 { 01292 /* Cleanup and return */ 01293 MiDereferenceImports(LoadedImports); 01294 if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS); 01295 return Status; 01296 } 01297 01298 /* Reset the buffer */ 01299 *MissingApi = MissingApiBuffer; 01300 } 01301 } 01302 01303 /* Go to the next import */ 01304 ImportDescriptor++; 01305 } 01306 01307 /* Check if we have an import list */ 01308 if (LoadedImports) 01309 { 01310 /* Reset the count again, and loop entries */ 01311 ImportCount = 0; 01312 for (i = 0; i < LoadedImports->Count; i++) 01313 { 01314 if (LoadedImports->Entry[i]) 01315 { 01316 /* Got an entry, OR it with 1 in case it's the single entry */ 01317 ImportEntry = (PVOID)((ULONG_PTR)LoadedImports->Entry[i] | 01318 MM_SYSLDR_SINGLE_ENTRY); 01319 ImportCount++; 01320 } 01321 } 01322 01323 /* Check if we had no imports */ 01324 if (!ImportCount) 01325 { 01326 /* Free the list and set it to no imports */ 01327 ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS); 01328 LoadedImports = MM_SYSLDR_NO_IMPORTS; 01329 } 01330 else if (ImportCount == 1) 01331 { 01332 /* Just one entry, we can free the table and only use our entry */ 01333 ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS); 01334 LoadedImports = (PLOAD_IMPORTS)ImportEntry; 01335 } 01336 else if (ImportCount != LoadedImports->Count) 01337 { 01338 /* Allocate a new list */ 01339 LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T); 01340 NewImports = ExAllocatePoolWithTag(PagedPool, 01341 LoadedImportsSize, 01342 TAG_LDR_IMPORTS); 01343 if (NewImports) 01344 { 01345 /* Set count */ 01346 NewImports->Count = 0; 01347 01348 /* Loop all the imports */ 01349 for (i = 0; i < LoadedImports->Count; i++) 01350 { 01351 /* Make sure it's valid */ 01352 if (LoadedImports->Entry[i]) 01353 { 01354 /* Copy it */ 01355 NewImports->Entry[NewImports->Count] = LoadedImports->Entry[i]; 01356 NewImports->Count++; 01357 } 01358 } 01359 01360 /* Free the old copy */ 01361 ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS); 01362 LoadedImports = NewImports; 01363 } 01364 } 01365 01366 /* Return the list */ 01367 *LoadImports = LoadedImports; 01368 } 01369 01370 /* Return success */ 01371 return STATUS_SUCCESS; 01372 } 01373 01374 VOID 01375 NTAPI 01376 MiFreeInitializationCode(IN PVOID InitStart, 01377 IN PVOID InitEnd) 01378 { 01379 PMMPTE PointerPte; 01380 PFN_NUMBER PagesFreed; 01381 01382 /* Get the start PTE */ 01383 PointerPte = MiAddressToPte(InitStart); 01384 ASSERT(MI_IS_PHYSICAL_ADDRESS(InitStart) == FALSE); 01385 01386 /* Compute the number of pages we expect to free */ 01387 PagesFreed = (PFN_NUMBER)(MiAddressToPte(InitEnd) - PointerPte + 1); 01388 01389 /* Try to actually free them */ 01390 PagesFreed = MiDeleteSystemPageableVm(PointerPte, 01391 PagesFreed, 01392 0, 01393 NULL); 01394 } 01395 01396 VOID 01397 NTAPI 01398 INIT_FUNCTION 01399 MiFindInitializationCode(OUT PVOID *StartVa, 01400 OUT PVOID *EndVa) 01401 { 01402 ULONG Size, SectionCount, Alignment; 01403 PLDR_DATA_TABLE_ENTRY LdrEntry; 01404 ULONG_PTR DllBase, InitStart, InitEnd, ImageEnd, InitCode; 01405 PLIST_ENTRY NextEntry; 01406 PIMAGE_NT_HEADERS NtHeader; 01407 PIMAGE_SECTION_HEADER Section, LastSection; 01408 BOOLEAN InitFound; 01409 01410 /* So we don't free our own code yet */ 01411 InitCode = (ULONG_PTR)&MiFindInitializationCode; 01412 01413 /* Assume failure */ 01414 *StartVa = NULL; 01415 01416 /* Enter a critical region while we loop the list */ 01417 KeEnterCriticalRegion(); 01418 01419 /* Loop all loaded modules */ 01420 NextEntry = PsLoadedModuleList.Flink; 01421 while (NextEntry != &PsLoadedModuleList) 01422 { 01423 /* Get the loader entry and its DLL base */ 01424 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); 01425 DllBase = (ULONG_PTR)LdrEntry->DllBase; 01426 01427 /* Get the NT header */ 01428 NtHeader = RtlImageNtHeader((PVOID)DllBase); 01429 if (!NtHeader) 01430 { 01431 /* Keep going */ 01432 NextEntry = NextEntry->Flink; 01433 continue; 01434 } 01435 01436 /* Get the first section, the section count, and scan them all */ 01437 Section = IMAGE_FIRST_SECTION(NtHeader); 01438 SectionCount = NtHeader->FileHeader.NumberOfSections; 01439 InitStart = 0; 01440 while (SectionCount > 0) 01441 { 01442 /* Assume failure */ 01443 InitFound = FALSE; 01444 01445 /* Is this the INIT section or a discardable section? */ 01446 if ((*(PULONG)Section->Name == 'TINI') || 01447 ((Section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE))) 01448 { 01449 /* Remember this */ 01450 InitFound = TRUE; 01451 } 01452 01453 if (InitFound) 01454 { 01455 /* Pick the biggest size -- either raw or virtual */ 01456 Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize); 01457 01458 /* Read the section alignment */ 01459 Alignment = NtHeader->OptionalHeader.SectionAlignment; 01460 01461 /* Align the start and end addresses appropriately */ 01462 InitStart = DllBase + Section->VirtualAddress; 01463 InitEnd = ((Alignment + InitStart + Size - 2) & 0xFFFFF000) - 1; 01464 InitStart = (InitStart + (PAGE_SIZE - 1)) & 0xFFFFF000; 01465 01466 /* Have we reached the last section? */ 01467 if (SectionCount == 1) 01468 { 01469 /* Remember this */ 01470 LastSection = Section; 01471 } 01472 else 01473 { 01474 /* We have not, loop all the sections */ 01475 LastSection = NULL; 01476 do 01477 { 01478 /* Keep going until we find a non-discardable section range */ 01479 SectionCount--; 01480 Section++; 01481 if (Section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) 01482 { 01483 /* Discardable, so record it, then keep going */ 01484 LastSection = Section; 01485 } 01486 else 01487 { 01488 /* Non-contigous discard flag, or no flag, break out */ 01489 break; 01490 } 01491 } 01492 while (SectionCount > 1); 01493 } 01494 01495 /* Have we found a discardable or init section? */ 01496 if (LastSection) 01497 { 01498 /* Pick the biggest size -- either raw or virtual */ 01499 Size = max(LastSection->SizeOfRawData, LastSection->Misc.VirtualSize); 01500 01501 /* Use this as the end of the section address */ 01502 InitEnd = DllBase + LastSection->VirtualAddress + Size - 1; 01503 01504 /* Have we reached the last section yet? */ 01505 if (SectionCount != 1) 01506 { 01507 /* Then align this accross the session boundary */ 01508 InitEnd = ((Alignment + InitEnd - 1) & 0XFFFFF000) - 1; 01509 } 01510 } 01511 01512 /* Make sure we don't let the init section go past the image */ 01513 ImageEnd = DllBase + LdrEntry->SizeOfImage; 01514 if (InitEnd > ImageEnd) InitEnd = (ImageEnd - 1) | (PAGE_SIZE - 1); 01515 01516 /* Make sure we have a valid, non-zero init section */ 01517 if (InitStart <= InitEnd) 01518 { 01519 /* Make sure we are not within this code itself */ 01520 if ((InitCode >= InitStart) && (InitCode <= InitEnd)) 01521 { 01522 /* Return it, we can't free ourselves now */ 01523 ASSERT(*StartVa == 0); 01524 *StartVa = (PVOID)InitStart; 01525 *EndVa = (PVOID)InitEnd; 01526 } 01527 else 01528 { 01529 /* This isn't us -- go ahead and free it */ 01530 ASSERT(MI_IS_PHYSICAL_ADDRESS((PVOID)InitStart) == FALSE); 01531 MiFreeInitializationCode((PVOID)InitStart, (PVOID)InitEnd); 01532 } 01533 } 01534 } 01535 01536 /* Move to the next section */ 01537 SectionCount--; 01538 Section++; 01539 } 01540 01541 /* Move to the next module */ 01542 NextEntry = NextEntry->Flink; 01543 } 01544 01545 /* Leave the critical region and return */ 01546 KeLeaveCriticalRegion(); 01547 } 01548 01549 /* 01550 * Note: This function assumes that all discardable sections are at the end of 01551 * the PE file. It searches backwards until it finds the non-discardable section 01552 */ 01553 VOID 01554 NTAPI 01555 MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry) 01556 { 01557 PMMPTE StartPte, EndPte; 01558 PFN_NUMBER PageCount; 01559 PVOID DllBase; 01560 ULONG i; 01561 PIMAGE_NT_HEADERS NtHeader; 01562 PIMAGE_SECTION_HEADER Section, DiscardSection; 01563 ULONG PagesDeleted; 01564 01565 /* Get the base address and the page count */ 01566 DllBase = LdrEntry->DllBase; 01567 PageCount = LdrEntry->SizeOfImage >> PAGE_SHIFT; 01568 01569 /* Get the last PTE in this image */ 01570 EndPte = MiAddressToPte(DllBase) + PageCount; 01571 01572 /* Get the NT header */ 01573 NtHeader = RtlImageNtHeader(DllBase); 01574 if (!NtHeader) return; 01575 01576 /* Get the last section and loop each section backwards */ 01577 Section = IMAGE_FIRST_SECTION(NtHeader) + NtHeader->FileHeader.NumberOfSections; 01578 DiscardSection = NULL; 01579 for (i = 0; i < NtHeader->FileHeader.NumberOfSections; i++) 01580 { 01581 /* Go back a section and check if it's discardable */ 01582 Section--; 01583 if (Section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) 01584 { 01585 /* It is, select it for freeing */ 01586 DiscardSection = Section; 01587 } 01588 else 01589 { 01590 /* No more discardable sections exist, bail out */ 01591 break; 01592 } 01593 } 01594 01595 /* Bail out if there's nothing to free */ 01596 if (!DiscardSection) return; 01597 01598 /* Push the DLL base to the first disacrable section, and get its PTE */ 01599 DllBase = (PVOID)ROUND_TO_PAGES((ULONG_PTR)DllBase + DiscardSection->VirtualAddress); 01600 ASSERT(MI_IS_PHYSICAL_ADDRESS(DllBase) == FALSE); 01601 StartPte = MiAddressToPte(DllBase); 01602 01603 /* Check how many pages to free total */ 01604 PageCount = (PFN_NUMBER)(EndPte - StartPte); 01605 if (!PageCount) return; 01606 01607 /* Delete this many PTEs */ 01608 PagesDeleted = MiDeleteSystemPageableVm(StartPte, PageCount, 0, NULL); 01609 } 01610 01611 VOID 01612 NTAPI 01613 INIT_FUNCTION 01614 MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 01615 { 01616 PLIST_ENTRY NextEntry; 01617 ULONG i = 0; 01618 PIMAGE_NT_HEADERS NtHeader; 01619 PLDR_DATA_TABLE_ENTRY LdrEntry; 01620 PIMAGE_FILE_HEADER FileHeader; 01621 BOOLEAN ValidRelocs; 01622 PIMAGE_DATA_DIRECTORY DataDirectory; 01623 PVOID DllBase, NewImageAddress; 01624 NTSTATUS Status; 01625 PMMPTE PointerPte, StartPte, LastPte; 01626 PFN_COUNT PteCount; 01627 PMMPFN Pfn1; 01628 MMPTE TempPte, OldPte; 01629 01630 /* Loop driver list */ 01631 for (NextEntry = LoaderBlock->LoadOrderListHead.Flink; 01632 NextEntry != &LoaderBlock->LoadOrderListHead; 01633 NextEntry = NextEntry->Flink) 01634 { 01635 /* Get the loader entry and NT header */ 01636 LdrEntry = CONTAINING_RECORD(NextEntry, 01637 LDR_DATA_TABLE_ENTRY, 01638 InLoadOrderLinks); 01639 NtHeader = RtlImageNtHeader(LdrEntry->DllBase); 01640 01641 /* Debug info */ 01642 DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n", 01643 LdrEntry->DllBase, 01644 (ULONG_PTR)LdrEntry->DllBase + LdrEntry->SizeOfImage, 01645 &LdrEntry->FullDllName); 01646 01647 /* Get the first PTE and the number of PTEs we'll need */ 01648 PointerPte = StartPte = MiAddressToPte(LdrEntry->DllBase); 01649 PteCount = ROUND_TO_PAGES(LdrEntry->SizeOfImage) >> PAGE_SHIFT; 01650 LastPte = StartPte + PteCount; 01651 01652 #if MI_TRACE_PFNS 01653 /* Loop the PTEs */ 01654 while (PointerPte < LastPte) 01655 { 01656 ULONG len; 01657 ASSERT(PointerPte->u.Hard.Valid == 1); 01658 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte)); 01659 len = wcslen(LdrEntry->BaseDllName.Buffer) * sizeof(WCHAR); 01660 snprintf(Pfn1->ProcessName, min(16, len), "%S", LdrEntry->BaseDllName.Buffer); 01661 PointerPte++; 01662 } 01663 #endif 01664 /* Skip kernel and HAL */ 01665 /* ROS HACK: Skip BOOTVID/KDCOM too */ 01666 i++; 01667 if (i <= 4) continue; 01668 01669 /* Skip non-drivers */ 01670 if (!NtHeader) continue; 01671 01672 /* Get the file header and make sure we can relocate */ 01673 FileHeader = &NtHeader->FileHeader; 01674 if (FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) continue; 01675 if (NtHeader->OptionalHeader.NumberOfRvaAndSizes < 01676 IMAGE_DIRECTORY_ENTRY_BASERELOC) continue; 01677 01678 /* Everything made sense until now, check the relocation section too */ 01679 DataDirectory = &NtHeader->OptionalHeader. 01680 DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; 01681 if (!DataDirectory->VirtualAddress) 01682 { 01683 /* We don't really have relocations */ 01684 ValidRelocs = FALSE; 01685 } 01686 else 01687 { 01688 /* Make sure the size is valid */ 01689 if ((DataDirectory->VirtualAddress + DataDirectory->Size) > 01690 LdrEntry->SizeOfImage) 01691 { 01692 /* They're not, skip */ 01693 continue; 01694 } 01695 01696 /* We have relocations */ 01697 ValidRelocs = TRUE; 01698 } 01699 01700 /* Remember the original address */ 01701 DllBase = LdrEntry->DllBase; 01702 01703 /* Loop the PTEs */ 01704 PointerPte = StartPte; 01705 while (PointerPte < LastPte) 01706 { 01707 /* Mark the page modified in the PFN database */ 01708 ASSERT(PointerPte->u.Hard.Valid == 1); 01709 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte)); 01710 ASSERT(Pfn1->u3.e1.Rom == 0); 01711 Pfn1->u3.e1.Modified = TRUE; 01712 01713 /* Next */ 01714 PointerPte++; 01715 } 01716 01717 /* Now reserve system PTEs for the image */ 01718 PointerPte = MiReserveSystemPtes(PteCount, SystemPteSpace); 01719 if (!PointerPte) 01720 { 01721 /* Shouldn't happen */ 01722 DPRINT1("[Mm0]: Couldn't allocate driver section!\n"); 01723 while (TRUE); 01724 } 01725 01726 /* This is the new virtual address for the module */ 01727 LastPte = PointerPte + PteCount; 01728 NewImageAddress = MiPteToAddress(PointerPte); 01729 01730 /* Sanity check */ 01731 DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase, NewImageAddress); 01732 ASSERT(ExpInitializationPhase == 0); 01733 01734 /* Loop the new driver PTEs */ 01735 TempPte = ValidKernelPte; 01736 while (PointerPte < LastPte) 01737 { 01738 /* Copy the old data */ 01739 OldPte = *StartPte; 01740 ASSERT(OldPte.u.Hard.Valid == 1); 01741 01742 /* Set page number from the loader's memory */ 01743 TempPte.u.Hard.PageFrameNumber = OldPte.u.Hard.PageFrameNumber; 01744 01745 /* Write it */ 01746 MI_WRITE_VALID_PTE(PointerPte, TempPte); 01747 01748 /* Move on */ 01749 PointerPte++; 01750 StartPte++; 01751 } 01752 01753 /* Update position */ 01754 PointerPte -= PteCount; 01755 01756 /* Sanity check */ 01757 ASSERT(*(PULONG)NewImageAddress == *(PULONG)DllBase); 01758 01759 /* Set the image base to the address where the loader put it */ 01760 NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase; 01761 01762 /* Check if we had relocations */ 01763 if (ValidRelocs) 01764 { 01765 /* Relocate the image */ 01766 Status = LdrRelocateImageWithBias(NewImageAddress, 01767 0, 01768 "SYSLDR", 01769 STATUS_SUCCESS, 01770 STATUS_CONFLICTING_ADDRESSES, 01771 STATUS_INVALID_IMAGE_FORMAT); 01772 if (!NT_SUCCESS(Status)) 01773 { 01774 /* This shouldn't happen */ 01775 DPRINT1("Relocations failed!\n"); 01776 while (TRUE); 01777 } 01778 } 01779 01780 /* Update the loader entry */ 01781 LdrEntry->DllBase = NewImageAddress; 01782 01783 /* Update the thunks */ 01784 DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry->BaseDllName); 01785 MiUpdateThunks(LoaderBlock, 01786 DllBase, 01787 NewImageAddress, 01788 LdrEntry->SizeOfImage); 01789 01790 /* Update the loader entry */ 01791 LdrEntry->Flags |= LDRP_SYSTEM_MAPPED; 01792 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)NewImageAddress + 01793 NtHeader->OptionalHeader.AddressOfEntryPoint); 01794 LdrEntry->SizeOfImage = PteCount << PAGE_SHIFT; 01795 01796 /* FIXME: We'll need to fixup the PFN linkage when switching to ARM3 */ 01797 } 01798 } 01799 01800 NTSTATUS 01801 NTAPI 01802 INIT_FUNCTION 01803 MiBuildImportsForBootDrivers(VOID) 01804 { 01805 PLIST_ENTRY NextEntry, NextEntry2; 01806 PLDR_DATA_TABLE_ENTRY LdrEntry, KernelEntry, HalEntry, LdrEntry2, LastEntry; 01807 PLDR_DATA_TABLE_ENTRY* EntryArray; 01808 UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe"); 01809 UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll"); 01810 PLOAD_IMPORTS LoadedImports; 01811 ULONG LoadedImportsSize, ImportSize; 01812 PULONG_PTR ImageThunk; 01813 ULONG_PTR DllBase, DllEnd; 01814 ULONG Modules = 0, i, j = 0; 01815 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor; 01816 01817 /* Initialize variables */ 01818 KernelEntry = HalEntry = LastEntry = NULL; 01819 01820 /* Loop the loaded module list... we are early enough that no lock is needed */ 01821 NextEntry = PsLoadedModuleList.Flink; 01822 while (NextEntry != &PsLoadedModuleList) 01823 { 01824 /* Get the entry */ 01825 LdrEntry = CONTAINING_RECORD(NextEntry, 01826 LDR_DATA_TABLE_ENTRY, 01827 InLoadOrderLinks); 01828 01829 /* Check if it's the kernel or HAL */ 01830 if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE)) 01831 { 01832 /* Found it */ 01833 KernelEntry = LdrEntry; 01834 } 01835 else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE)) 01836 { 01837 /* Found it */ 01838 HalEntry = LdrEntry; 01839 } 01840 01841 /* Check if this is a driver DLL */ 01842 if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL) 01843 { 01844 /* Check if this is the HAL or kernel */ 01845 if ((LdrEntry == HalEntry) || (LdrEntry == KernelEntry)) 01846 { 01847 /* Add a reference */ 01848 LdrEntry->LoadCount = 1; 01849 } 01850 else 01851 { 01852 /* No referencing needed */ 01853 LdrEntry->LoadCount = 0; 01854 } 01855 } 01856 else 01857 { 01858 /* No referencing needed */ 01859 LdrEntry->LoadCount = 0; 01860 } 01861 01862 /* Remember this came from the loader */ 01863 LdrEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED; 01864 01865 /* Keep looping */ 01866 NextEntry = NextEntry->Flink; 01867 Modules++; 01868 } 01869 01870 /* We must have at least found the kernel and HAL */ 01871 if (!(HalEntry) || (!KernelEntry)) return STATUS_NOT_FOUND; 01872 01873 /* Allocate the list */ 01874 EntryArray = ExAllocatePoolWithTag(PagedPool, Modules * sizeof(PVOID), TAG_LDR_IMPORTS); 01875 if (!EntryArray) return STATUS_INSUFFICIENT_RESOURCES; 01876 01877 /* Loop the loaded module list again */ 01878 NextEntry = PsLoadedModuleList.Flink; 01879 while (NextEntry != &PsLoadedModuleList) 01880 { 01881 /* Get the entry */ 01882 LdrEntry = CONTAINING_RECORD(NextEntry, 01883 LDR_DATA_TABLE_ENTRY, 01884 InLoadOrderLinks); 01885 #ifdef _WORKING_LOADER_ 01886 /* Get its imports */ 01887 ImageThunk = RtlImageDirectoryEntryToData(LdrEntry->DllBase, 01888 TRUE, 01889 IMAGE_DIRECTORY_ENTRY_IAT, 01890 &ImportSize); 01891 if (!ImageThunk) 01892 #else 01893 /* Get its imports */ 01894 ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase, 01895 TRUE, 01896 IMAGE_DIRECTORY_ENTRY_IMPORT, 01897 &ImportSize); 01898 if (!ImportDescriptor) 01899 #endif 01900 { 01901 /* None present */ 01902 LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS; 01903 NextEntry = NextEntry->Flink; 01904 continue; 01905 } 01906 01907 /* Clear the list and count the number of IAT thunks */ 01908 RtlZeroMemory(EntryArray, Modules * sizeof(PVOID)); 01909 #ifdef _WORKING_LOADER_ 01910 ImportSize /= sizeof(ULONG_PTR); 01911 01912 /* Scan the thunks */ 01913 for (i = 0, DllBase = 0, DllEnd = 0; i < ImportSize; i++, ImageThunk++) 01914 #else 01915 DllBase = DllEnd = i = 0; 01916 while ((ImportDescriptor->Name) && 01917 (ImportDescriptor->OriginalFirstThunk)) 01918 { 01919 /* Get the image thunk */ 01920 ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase + 01921 ImportDescriptor->FirstThunk); 01922 while (*ImageThunk) 01923 #endif 01924 { 01925 /* Do we already have an address? */ 01926 if (DllBase) 01927 { 01928 /* Is the thunk in the same address? */ 01929 if ((*ImageThunk >= DllBase) && (*ImageThunk < DllEnd)) 01930 { 01931 /* Skip it, we already have a reference for it */ 01932 ASSERT(EntryArray[j]); 01933 ImageThunk++; 01934 continue; 01935 } 01936 } 01937 01938 /* Loop the loaded module list to locate this address owner */ 01939 j = 0; 01940 NextEntry2 = PsLoadedModuleList.Flink; 01941 while (NextEntry2 != &PsLoadedModuleList) 01942 { 01943 /* Get the entry */ 01944 LdrEntry2 = CONTAINING_RECORD(NextEntry2, 01945 LDR_DATA_TABLE_ENTRY, 01946 InLoadOrderLinks); 01947 01948 /* Get the address range for this module */ 01949 DllBase = (ULONG_PTR)LdrEntry2->DllBase; 01950 DllEnd = DllBase + LdrEntry2->SizeOfImage; 01951 01952 /* Check if this IAT entry matches it */ 01953 if ((*ImageThunk >= DllBase) && (*ImageThunk < DllEnd)) 01954 { 01955 /* Save it */ 01956 //DPRINT1("Found imported dll: %wZ\n", &LdrEntry2->BaseDllName); 01957 EntryArray[j] = LdrEntry2; 01958 break; 01959 } 01960 01961 /* Keep searching */ 01962 NextEntry2 = NextEntry2->Flink; 01963 j++; 01964 } 01965 01966 /* Do we have a thunk outside the range? */ 01967 if ((*ImageThunk < DllBase) || (*ImageThunk >= DllEnd)) 01968 { 01969 /* Could be 0... */ 01970 if (*ImageThunk) 01971 { 01972 /* Should not be happening */ 01973 DPRINT1("Broken IAT entry for %p at %p (%lx)\n", 01974 LdrEntry, ImageThunk, *ImageThunk); 01975 ASSERT(FALSE); 01976 } 01977 01978 /* Reset if we hit this */ 01979 DllBase = 0; 01980 } 01981 #ifndef _WORKING_LOADER_ 01982 ImageThunk++; 01983 } 01984 01985 i++; 01986 ImportDescriptor++; 01987 #endif 01988 } 01989 01990 /* Now scan how many imports we really have */ 01991 for (i = 0, ImportSize = 0; i < Modules; i++) 01992 { 01993 /* Skip HAL and kernel */ 01994 if ((EntryArray[i]) && 01995 (EntryArray[i] != HalEntry) && 01996 (EntryArray[i] != KernelEntry)) 01997 { 01998 /* A valid reference */ 01999 LastEntry = EntryArray[i]; 02000 ImportSize++; 02001 } 02002 } 02003 02004 /* Do we have any imports after all? */ 02005 if (!ImportSize) 02006 { 02007 /* No */ 02008 LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS; 02009 } 02010 else if (ImportSize == 1) 02011 { 02012 /* A single entry import */ 02013 LdrEntry->LoadedImports = (PVOID)((ULONG_PTR)LastEntry | MM_SYSLDR_SINGLE_ENTRY); 02014 LastEntry->LoadCount++; 02015 } 02016 else 02017 { 02018 /* We need an import table */ 02019 LoadedImportsSize = ImportSize * sizeof(PVOID) + sizeof(SIZE_T); 02020 LoadedImports = ExAllocatePoolWithTag(PagedPool, 02021 LoadedImportsSize, 02022 TAG_LDR_IMPORTS); 02023 ASSERT(LoadedImports); 02024 02025 /* Save the count */ 02026 LoadedImports->Count = ImportSize; 02027 02028 /* Now copy all imports */ 02029 for (i = 0, j = 0; i < Modules; i++) 02030 { 02031 /* Skip HAL and kernel */ 02032 if ((EntryArray[i]) && 02033 (EntryArray[i] != HalEntry) && 02034 (EntryArray[i] != KernelEntry)) 02035 { 02036 /* A valid reference */ 02037 //DPRINT1("Found valid entry: %p\n", EntryArray[i]); 02038 LoadedImports->Entry[j] = EntryArray[i]; 02039 EntryArray[i]->LoadCount++; 02040 j++; 02041 } 02042 } 02043 02044 /* Should had as many entries as we expected */ 02045 ASSERT(j == ImportSize); 02046 LdrEntry->LoadedImports = LoadedImports; 02047 } 02048 02049 /* Next */ 02050 NextEntry = NextEntry->Flink; 02051 } 02052 02053 /* Free the initial array */ 02054 ExFreePoolWithTag(EntryArray, TAG_LDR_IMPORTS); 02055 02056 /* FIXME: Might not need to keep the HAL/Kernel imports around */ 02057 02058 /* Kernel and HAL are loaded at boot */ 02059 KernelEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED; 02060 HalEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED; 02061 02062 /* All worked well */ 02063 return STATUS_SUCCESS; 02064 } 02065 02066 VOID 02067 NTAPI 02068 INIT_FUNCTION 02069 MiLocateKernelSections(IN PLDR_DATA_TABLE_ENTRY LdrEntry) 02070 { 02071 ULONG_PTR DllBase; 02072 PIMAGE_NT_HEADERS NtHeaders; 02073 PIMAGE_SECTION_HEADER SectionHeader; 02074 ULONG Sections, Size; 02075 02076 /* Get the kernel section header */ 02077 DllBase = (ULONG_PTR)LdrEntry->DllBase; 02078 NtHeaders = RtlImageNtHeader((PVOID)DllBase); 02079 SectionHeader = IMAGE_FIRST_SECTION(NtHeaders); 02080 02081 /* Loop all the sections */ 02082 Sections = NtHeaders->FileHeader.NumberOfSections; 02083 while (Sections) 02084 { 02085 /* Grab the size of the section */ 02086 Size = max(SectionHeader->SizeOfRawData, SectionHeader->Misc.VirtualSize); 02087 02088 /* Check for .RSRC section */ 02089 if (*(PULONG)SectionHeader->Name == 'rsr.') 02090 { 02091 /* Remember the PTEs so we can modify them later */ 02092 MiKernelResourceStartPte = MiAddressToPte(DllBase + 02093 SectionHeader->VirtualAddress); 02094 MiKernelResourceEndPte = MiKernelResourceStartPte + 02095 BYTES_TO_PAGES(SectionHeader->VirtualAddress + Size); 02096 } 02097 else if (*(PULONG)SectionHeader->Name == 'LOOP') 02098 { 02099 /* POOLCODE vs. POOLMI */ 02100 if (*(PULONG)&SectionHeader->Name[4] == 'EDOC') 02101 { 02102 /* Found Ex* Pool code */ 02103 ExPoolCodeStart = DllBase + SectionHeader->VirtualAddress; 02104 ExPoolCodeEnd = ExPoolCodeStart + Size; 02105 } 02106 else if (*(PUSHORT)&SectionHeader->Name[4] == 'MI') 02107 { 02108 /* Found Mm* Pool code */ 02109 MmPoolCodeStart = DllBase + SectionHeader->VirtualAddress; 02110 MmPoolCodeEnd = ExPoolCodeStart + Size; 02111 } 02112 } 02113 else if ((*(PULONG)SectionHeader->Name == 'YSIM') && 02114 (*(PULONG)&SectionHeader->Name[4] == 'ETPS')) 02115 { 02116 /* Found MISYSPTE (Mm System PTE code)*/ 02117 MmPteCodeStart = DllBase + SectionHeader->VirtualAddress; 02118 MmPteCodeEnd = ExPoolCodeStart + Size; 02119 } 02120 02121 /* Keep going */ 02122 Sections--; 02123 SectionHeader++; 02124 } 02125 } 02126 02127 BOOLEAN 02128 NTAPI 02129 INIT_FUNCTION 02130 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 02131 { 02132 PLDR_DATA_TABLE_ENTRY LdrEntry, NewEntry; 02133 PLIST_ENTRY ListHead, NextEntry; 02134 ULONG EntrySize; 02135 02136 /* Setup the loaded module list and locks */ 02137 ExInitializeResourceLite(&PsLoadedModuleResource); 02138 KeInitializeSpinLock(&PsLoadedModuleSpinLock); 02139 InitializeListHead(&PsLoadedModuleList); 02140 02141 /* Get loop variables and the kernel entry */ 02142 ListHead = &LoaderBlock->LoadOrderListHead; 02143 NextEntry = ListHead->Flink; 02144 LdrEntry = CONTAINING_RECORD(NextEntry, 02145 LDR_DATA_TABLE_ENTRY, 02146 InLoadOrderLinks); 02147 PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase; 02148 02149 /* Locate resource section, pool code, and system pte code */ 02150 MiLocateKernelSections(LdrEntry); 02151 02152 /* Loop the loader block */ 02153 while (NextEntry != ListHead) 02154 { 02155 /* Get the loader entry */ 02156 LdrEntry = CONTAINING_RECORD(NextEntry, 02157 LDR_DATA_TABLE_ENTRY, 02158 InLoadOrderLinks); 02159 02160 /* FIXME: ROS HACK. Make sure this is a driver */ 02161 if (!RtlImageNtHeader(LdrEntry->DllBase)) 02162 { 02163 /* Skip this entry */ 02164 NextEntry = NextEntry->Flink; 02165 continue; 02166 } 02167 02168 /* Calculate the size we'll need and allocate a copy */ 02169 EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) + 02170 LdrEntry->BaseDllName.MaximumLength + 02171 sizeof(UNICODE_NULL); 02172 NewEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT); 02173 if (!NewEntry) return FALSE; 02174 02175 /* Copy the entry over */ 02176 *NewEntry = *LdrEntry; 02177 02178 /* Allocate the name */ 02179 NewEntry->FullDllName.Buffer = 02180 ExAllocatePoolWithTag(PagedPool, 02181 LdrEntry->FullDllName.MaximumLength + 02182 sizeof(UNICODE_NULL), 02183 TAG_LDR_WSTR); 02184 if (!NewEntry->FullDllName.Buffer) return FALSE; 02185 02186 /* Set the base name */ 02187 NewEntry->BaseDllName.Buffer = (PVOID)(NewEntry + 1); 02188 02189 /* Copy the full and base name */ 02190 RtlCopyMemory(NewEntry->FullDllName.Buffer, 02191 LdrEntry->FullDllName.Buffer, 02192 LdrEntry->FullDllName.MaximumLength); 02193 RtlCopyMemory(NewEntry->BaseDllName.Buffer, 02194 LdrEntry->BaseDllName.Buffer, 02195 LdrEntry->BaseDllName.MaximumLength); 02196 02197 /* Null-terminate the base name */ 02198 NewEntry->BaseDllName.Buffer[NewEntry->BaseDllName.Length / 02199 sizeof(WCHAR)] = UNICODE_NULL; 02200 02201 /* Insert the entry into the list */ 02202 InsertTailList(&PsLoadedModuleList, &NewEntry->InLoadOrderLinks); 02203 NextEntry = NextEntry->Flink; 02204 } 02205 02206 /* Build the import lists for the boot drivers */ 02207 MiBuildImportsForBootDrivers(); 02208 02209 /* We're done */ 02210 return TRUE; 02211 } 02212 02213 LOGICAL 02214 NTAPI 02215 MiUseLargeDriverPage(IN ULONG NumberOfPtes, 02216 IN OUT PVOID *ImageBaseAddress, 02217 IN PUNICODE_STRING BaseImageName, 02218 IN BOOLEAN BootDriver) 02219 { 02220 PLIST_ENTRY NextEntry; 02221 BOOLEAN DriverFound = FALSE; 02222 PMI_LARGE_PAGE_DRIVER_ENTRY LargePageDriverEntry; 02223 ASSERT(KeGetCurrentIrql () <= APC_LEVEL); 02224 ASSERT(*ImageBaseAddress >= MmSystemRangeStart); 02225 02226 #ifdef _X86_ 02227 if (!(KeFeatureBits & KF_LARGE_PAGE)) return FALSE; 02228 if (!(__readcr4() & CR4_PSE)) return FALSE; 02229 #endif 02230 02231 /* Make sure there's enough system PTEs for a large page driver */ 02232 if (MmTotalFreeSystemPtes[SystemPteSpace] < (16 * (PDE_MAPPED_VA >> PAGE_SHIFT))) 02233 { 02234 return FALSE; 02235 } 02236 02237 /* This happens if the registry key had a "*" (wildcard) in it */ 02238 if (MiLargePageAllDrivers == 0) 02239 { 02240 /* It didn't, so scan the list */ 02241 NextEntry = MiLargePageDriverList.Flink; 02242 while (NextEntry != &MiLargePageDriverList) 02243 { 02244 /* Check if the driver name matches */ 02245 LargePageDriverEntry = CONTAINING_RECORD(NextEntry, 02246 MI_LARGE_PAGE_DRIVER_ENTRY, 02247 Links); 02248 if (RtlEqualUnicodeString(BaseImageName, 02249 &LargePageDriverEntry->BaseName, 02250 TRUE)) 02251 { 02252 /* Enable large pages for this driver */ 02253 DriverFound = TRUE; 02254 break; 02255 } 02256 02257 /* Keep trying */ 02258 NextEntry = NextEntry->Flink; 02259 } 02260 02261 /* If we didn't find the driver, it doesn't need large pages */ 02262 if (DriverFound == FALSE) return FALSE; 02263 } 02264 02265 /* Nothing to do yet */ 02266 DPRINT1("Large pages not supported!\n"); 02267 return FALSE; 02268 } 02269 02270 ULONG 02271 NTAPI 02272 MiComputeDriverProtection(IN BOOLEAN SessionSpace, 02273 IN ULONG SectionProtection) 02274 { 02275 ULONG Protection = MM_ZERO_ACCESS; 02276 02277 /* Check if the caller gave anything */ 02278 if (SectionProtection) 02279 { 02280 /* Always turn on execute access */ 02281 SectionProtection |= IMAGE_SCN_MEM_EXECUTE; 02282 02283 /* Check if the registry setting is on or not */ 02284 if (!MmEnforceWriteProtection) 02285 { 02286 /* Turn on write access too */ 02287 SectionProtection |= (IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE); 02288 } 02289 } 02290 02291 /* Convert to internal PTE flags */ 02292 if (SectionProtection & IMAGE_SCN_MEM_EXECUTE) Protection |= MM_EXECUTE; 02293 if (SectionProtection & IMAGE_SCN_MEM_READ) Protection |= MM_READONLY; 02294 02295 /* Check for write access */ 02296 if (SectionProtection & IMAGE_SCN_MEM_WRITE) 02297 { 02298 /* Session space is not supported */ 02299 if (SessionSpace) 02300 { 02301 DPRINT1("Session drivers not supported\n"); 02302 ASSERT(SessionSpace == FALSE); 02303 } 02304 else 02305 { 02306 /* Convert to internal PTE flag */ 02307 Protection = (Protection & MM_EXECUTE) ? MM_EXECUTE_READWRITE : MM_READWRITE; 02308 } 02309 } 02310 02311 /* If there's no access at all by now, convert to internal no access flag */ 02312 if (Protection == MM_ZERO_ACCESS) Protection = MM_NOACCESS; 02313 02314 /* Return the computed PTE protection */ 02315 return Protection; 02316 } 02317 02318 VOID 02319 NTAPI 02320 MiSetSystemCodeProtection(IN PMMPTE FirstPte, 02321 IN PMMPTE LastPte, 02322 IN ULONG ProtectionMask) 02323 { 02324 /* I'm afraid to introduce regressions at the moment... */ 02325 return; 02326 } 02327 02328 VOID 02329 NTAPI 02330 MiWriteProtectSystemImage(IN PVOID ImageBase) 02331 { 02332 PIMAGE_NT_HEADERS NtHeaders; 02333 PIMAGE_SECTION_HEADER Section; 02334 PFN_NUMBER DriverPages; 02335 ULONG CurrentProtection, SectionProtection, CombinedProtection = 0, ProtectionMask; 02336 ULONG Sections, Size; 02337 ULONG_PTR BaseAddress, CurrentAddress; 02338 PMMPTE PointerPte, StartPte, LastPte, CurrentPte, ComboPte = NULL; 02339 ULONG CurrentMask, CombinedMask = 0; 02340 PAGED_CODE(); 02341 02342 /* No need to write protect physical memory-backed drivers (large pages) */ 02343 if (MI_IS_PHYSICAL_ADDRESS(ImageBase)) return; 02344 02345 /* Get the image headers */ 02346 NtHeaders = RtlImageNtHeader(ImageBase); 02347 if (!NtHeaders) return; 02348 02349 /* Check if this is a session driver or not */ 02350 if (!MI_IS_SESSION_ADDRESS(ImageBase)) 02351 { 02352 /* Don't touch NT4 drivers */ 02353 if (NtHeaders->OptionalHeader.MajorOperatingSystemVersion < 5) return; 02354 if (NtHeaders->OptionalHeader.MajorImageVersion < 5) return; 02355 } 02356 else 02357 { 02358 /* Not supported */ 02359 DPRINT1("Session drivers not supported\n"); 02360 ASSERT(FALSE); 02361 } 02362 02363 /* These are the only protection masks we care about */ 02364 ProtectionMask = IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE; 02365 02366 /* Calculate the number of pages this driver is occupying */ 02367 DriverPages = BYTES_TO_PAGES(NtHeaders->OptionalHeader.SizeOfImage); 02368 02369 /* Get the number of sections and the first section header */ 02370 Sections = NtHeaders->FileHeader.NumberOfSections; 02371 ASSERT(Sections != 0); 02372 Section = IMAGE_FIRST_SECTION(NtHeaders); 02373 02374 /* Loop all the sections */ 02375 CurrentAddress = (ULONG_PTR)ImageBase; 02376 while (Sections) 02377 { 02378 /* Get the section size */ 02379 Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize); 02380 02381 /* Get its virtual address */ 02382 BaseAddress = (ULONG_PTR)ImageBase + Section->VirtualAddress; 02383 if (BaseAddress < CurrentAddress) 02384 { 02385 /* Windows doesn't like these */ 02386 DPRINT1("Badly linked image!\n"); 02387 return; 02388 } 02389 02390 /* Remember the current address */ 02391 CurrentAddress = BaseAddress + Size - 1; 02392 02393 /* Next */ 02394 Sections--; 02395 Section++; 02396 } 02397 02398 /* Get the number of sections and the first section header */ 02399 Sections = NtHeaders->FileHeader.NumberOfSections; 02400 ASSERT(Sections != 0); 02401 Section = IMAGE_FIRST_SECTION(NtHeaders); 02402 02403 /* Set the address at the end to initialize the loop */ 02404 CurrentAddress = (ULONG_PTR)Section + Sections - 1; 02405 CurrentProtection = IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ; 02406 02407 /* Set the PTE points for the image, and loop its sections */ 02408 StartPte = MiAddressToPte(ImageBase); 02409 LastPte = StartPte + DriverPages; 02410 while (Sections) 02411 { 02412 /* Get the section size */ 02413 Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize); 02414 02415 /* Get its virtual address and PTE */ 02416 BaseAddress = (ULONG_PTR)ImageBase + Section->VirtualAddress; 02417 PointerPte = MiAddressToPte(BaseAddress); 02418 02419 /* Check if we were already protecting a run, and found a new run */ 02420 if ((ComboPte) && (PointerPte > ComboPte)) 02421 { 02422 /* Compute protection */ 02423 CombinedMask = MiComputeDriverProtection(FALSE, CombinedProtection); 02424 02425 /* Set it */ 02426 MiSetSystemCodeProtection(ComboPte, ComboPte, CombinedMask); 02427 02428 /* Check for overlap */ 02429 if (ComboPte == StartPte) StartPte++; 02430 02431 /* One done, reset variables */ 02432 ComboPte = NULL; 02433 CombinedProtection = 0; 02434 } 02435 02436 /* Break out when needed */ 02437 if (PointerPte >= LastPte) break; 02438 02439 /* Get the requested protection from the image header */ 02440 SectionProtection = Section->Characteristics & ProtectionMask; 02441 if (SectionProtection == CurrentProtection) 02442 { 02443 /* Same protection, so merge the request */ 02444 CurrentAddress = BaseAddress + Size - 1; 02445 02446 /* Next */ 02447 Sections--; 02448 Section++; 02449 continue; 02450 } 02451 02452 /* This is now a new section, so close up the old one */ 02453 CurrentPte = MiAddressToPte(CurrentAddress); 02454 02455 /* Check for overlap */ 02456 if (CurrentPte == PointerPte) 02457 { 02458 /* Skip the last PTE, since it overlaps with us */ 02459 CurrentPte--; 02460 02461 /* And set the PTE we will merge with */ 02462 ASSERT((ComboPte == NULL) || (ComboPte == PointerPte)); 02463 ComboPte = PointerPte; 02464 02465 /* Get the most flexible protection by merging both */ 02466 CombinedMask |= (SectionProtection | CurrentProtection); 02467 } 02468 02469 /* Loop any PTEs left */ 02470 if (CurrentPte >= StartPte) 02471 { 02472 /* Sanity check */ 02473 ASSERT(StartPte < LastPte); 02474 02475 /* Make sure we don't overflow past the last PTE in the driver */ 02476 if (CurrentPte >= LastPte) CurrentPte = LastPte - 1; 02477 ASSERT(CurrentPte >= StartPte); 02478 02479 /* Compute the protection and set it */ 02480 CurrentMask = MiComputeDriverProtection(FALSE, CurrentProtection); 02481 MiSetSystemCodeProtection(StartPte, CurrentPte, CurrentMask); 02482 } 02483 02484 /* Set new state */ 02485 StartPte = PointerPte; 02486 CurrentAddress = BaseAddress + Size - 1; 02487 CurrentProtection = SectionProtection; 02488 02489 /* Next */ 02490 Sections--; 02491 Section++; 02492 } 02493 02494 /* Is there a leftover section to merge? */ 02495 if (ComboPte) 02496 { 02497 /* Compute and set the protection */ 02498 CombinedMask = MiComputeDriverProtection(FALSE, CombinedProtection); 02499 MiSetSystemCodeProtection(ComboPte, ComboPte, CombinedMask); 02500 02501 /* Handle overlap */ 02502 if (ComboPte == StartPte) StartPte++; 02503 } 02504 02505 /* Finally, handle the last section */ 02506 CurrentPte = MiAddressToPte(CurrentAddress); 02507 if ((StartPte < LastPte) && (CurrentPte >= StartPte)) 02508 { 02509 /* Handle overlap */ 02510 if (CurrentPte >= LastPte) CurrentPte = LastPte - 1; 02511 ASSERT(CurrentPte >= StartPte); 02512 02513 /* Compute and set the protection */ 02514 CurrentMask = MiComputeDriverProtection(FALSE, CurrentProtection); 02515 MiSetSystemCodeProtection(StartPte, CurrentPte, CurrentMask); 02516 } 02517 } 02518 02519 VOID 02520 NTAPI 02521 MiSetPagingOfDriver(IN PMMPTE PointerPte, 02522 IN PMMPTE LastPte) 02523 { 02524 PVOID ImageBase; 02525 PETHREAD CurrentThread = PsGetCurrentThread(); 02526 PFN_COUNT PageCount = 0; 02527 PFN_NUMBER PageFrameIndex; 02528 PMMPFN Pfn1; 02529 PAGED_CODE(); 02530 02531 /* Get the driver's base address */ 02532 ImageBase = MiPteToAddress(PointerPte); 02533 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase) == FALSE); 02534 02535 /* If this is a large page, it's stuck in physical memory */ 02536 if (MI_IS_PHYSICAL_ADDRESS(ImageBase)) return; 02537 02538 /* Lock the working set */ 02539 MiLockWorkingSet(CurrentThread, &MmSystemCacheWs); 02540 02541 /* Loop the PTEs */ 02542 while (PointerPte <= LastPte) 02543 { 02544 /* Check for valid PTE */ 02545 if (PointerPte->u.Hard.Valid == 1) 02546 { 02547 PageFrameIndex = PFN_FROM_PTE(PointerPte); 02548 Pfn1 = MiGetPfnEntry(PageFrameIndex); 02549 ASSERT(Pfn1->u2.ShareCount == 1); 02550 02551 /* No working sets in ReactOS yet */ 02552 PageCount++; 02553 } 02554 02555 ImageBase = (PVOID)((ULONG_PTR)ImageBase + PAGE_SIZE); 02556 PointerPte++; 02557 } 02558 02559 /* Release the working set */ 02560 MiUnlockWorkingSet(CurrentThread, &MmSystemCacheWs); 02561 02562 /* Do we have any driver pages? */ 02563 if (PageCount) 02564 { 02565 /* Update counters */ 02566 InterlockedExchangeAdd((PLONG)&MmTotalSystemDriverPages, PageCount); 02567 } 02568 } 02569 02570 VOID 02571 NTAPI 02572 MiEnablePagingOfDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry) 02573 { 02574 ULONG_PTR ImageBase; 02575 PIMAGE_NT_HEADERS NtHeaders; 02576 ULONG Sections, Alignment, Size; 02577 PIMAGE_SECTION_HEADER Section; 02578 PMMPTE PointerPte = NULL, LastPte = NULL; 02579 if (MmDisablePagingExecutive) return; 02580 02581 /* Get the driver base address and its NT header */ 02582 ImageBase = (ULONG_PTR)LdrEntry->DllBase; 02583 NtHeaders = RtlImageNtHeader((PVOID)ImageBase); 02584 if (!NtHeaders) return; 02585 02586 /* Get the sections and their alignment */ 02587 Sections = NtHeaders->FileHeader.NumberOfSections; 02588 Alignment = NtHeaders->OptionalHeader.SectionAlignment - 1; 02589 02590 /* Loop each section */ 02591 Section = IMAGE_FIRST_SECTION(NtHeaders); 02592 while (Sections) 02593 { 02594 /* Find PAGE or .edata */ 02595 if ((*(PULONG)Section->Name == 'EGAP') || 02596 (*(PULONG)Section->Name == 'ade.')) 02597 { 02598 /* Had we already done some work? */ 02599 if (!PointerPte) 02600 { 02601 /* Nope, setup the first PTE address */ 02602 PointerPte = MiAddressToPte(ROUND_TO_PAGES(ImageBase + 02603 Section-> 02604 VirtualAddress)); 02605 } 02606 02607 /* Compute the size */ 02608 Size = max(Section->SizeOfRawData, Section->Misc.VirtualSize); 02609 02610 /* Find the last PTE that maps this section */ 02611 LastPte = MiAddressToPte(ImageBase + 02612 Section->VirtualAddress + 02613 Alignment + 02614 Size - 02615 PAGE_SIZE); 02616 } 02617 else 02618 { 02619 /* Had we found a section before? */ 02620 if (PointerPte) 02621 { 02622 /* Mark it as pageable */ 02623 MiSetPagingOfDriver(PointerPte, LastPte); 02624 PointerPte = NULL; 02625 } 02626 } 02627 02628 /* Keep searching */ 02629 Sections--; 02630 Section++; 02631 } 02632 02633 /* Handle the straggler */ 02634 if (PointerPte) MiSetPagingOfDriver(PointerPte, LastPte); 02635 } 02636 02637 BOOLEAN 02638 NTAPI 02639 MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress) 02640 { 02641 PIMAGE_NT_HEADERS NtHeader; 02642 PAGED_CODE(); 02643 02644 /* Get NT Headers */ 02645 NtHeader = RtlImageNtHeader(BaseAddress); 02646 if (NtHeader) 02647 { 02648 /* Check if this image is only safe for UP while we have 2+ CPUs */ 02649 if ((KeNumberProcessors > 1) && 02650 (NtHeader->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)) 02651 { 02652 /* Fail */ 02653 return FALSE; 02654 } 02655 } 02656 02657 /* Otherwise, it's safe */ 02658 return TRUE; 02659 } 02660 02661 NTSTATUS 02662 NTAPI 02663 MmCheckSystemImage(IN HANDLE ImageHandle, 02664 IN BOOLEAN PurgeSection) 02665 { 02666 NTSTATUS Status; 02667 HANDLE SectionHandle; 02668 PVOID ViewBase = NULL; 02669 SIZE_T ViewSize = 0; 02670 IO_STATUS_BLOCK IoStatusBlock; 02671 FILE_STANDARD_INFORMATION FileStandardInfo; 02672 KAPC_STATE ApcState; 02673 PIMAGE_NT_HEADERS NtHeaders; 02674 OBJECT_ATTRIBUTES ObjectAttributes; 02675 PAGED_CODE(); 02676 02677 /* Setup the object attributes */ 02678 InitializeObjectAttributes(&ObjectAttributes, 02679 NULL, 02680 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 02681 NULL, 02682 NULL); 02683 02684 /* Create a section for the DLL */ 02685 Status = ZwCreateSection(&SectionHandle, 02686 SECTION_MAP_EXECUTE, 02687 &ObjectAttributes, 02688 NULL, 02689 PAGE_EXECUTE, 02690 SEC_IMAGE, 02691 ImageHandle); 02692 if (!NT_SUCCESS(Status)) 02693 { 02694 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status); 02695 return Status; 02696 } 02697 02698 /* Make sure we're in the system process */ 02699 KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState); 02700 02701 /* Map it */ 02702 Status = ZwMapViewOfSection(SectionHandle, 02703 NtCurrentProcess(), 02704 &ViewBase, 02705 0, 02706 0, 02707 NULL, 02708 &ViewSize, 02709 ViewShare, 02710 0, 02711 PAGE_EXECUTE); 02712 if (!NT_SUCCESS(Status)) 02713 { 02714 /* We failed, close the handle and return */ 02715 DPRINT1("ZwMapViewOfSection failed with status 0x%x\n", Status); 02716 KeUnstackDetachProcess(&ApcState); 02717 ZwClose(SectionHandle); 02718 return Status; 02719 } 02720 02721 /* Now query image information */ 02722 Status = ZwQueryInformationFile(ImageHandle, 02723 &IoStatusBlock, 02724 &FileStandardInfo, 02725 sizeof(FileStandardInfo), 02726 FileStandardInformation); 02727 if (NT_SUCCESS(Status)) 02728 { 02729 /* First, verify the checksum */ 02730 if (!LdrVerifyMappedImageMatchesChecksum(ViewBase, 02731 ViewSize, 02732 FileStandardInfo. 02733 EndOfFile.LowPart)) 02734 { 02735 /* Set checksum failure */ 02736 Status = STATUS_IMAGE_CHECKSUM_MISMATCH; 02737 goto Fail; 02738 } 02739 02740 /* Make sure it's a real image */ 02741 NtHeaders = RtlImageNtHeader(ViewBase); 02742 if (!NtHeaders) 02743 { 02744 /* Set checksum failure */ 02745 Status = STATUS_IMAGE_CHECKSUM_MISMATCH; 02746 goto Fail; 02747 } 02748 02749 /* Make sure it's for the correct architecture */ 02750 if ((NtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_NATIVE) || 02751 (NtHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)) 02752 { 02753 /* Set protection failure */ 02754 Status = STATUS_INVALID_IMAGE_PROTECT; 02755 goto Fail; 02756 } 02757 02758 /* Check that it's a valid SMP image if we have more then one CPU */ 02759 if (!MmVerifyImageIsOkForMpUse(ViewBase)) 02760 { 02761 /* Otherwise it's not the right image */ 02762 Status = STATUS_IMAGE_MP_UP_MISMATCH; 02763 } 02764 } 02765 02766 /* Unmap the section, close the handle, and return status */ 02767 Fail: 02768 ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase); 02769 KeUnstackDetachProcess(&ApcState); 02770 ZwClose(SectionHandle); 02771 return Status; 02772 } 02773 02774 NTSTATUS 02775 NTAPI 02776 MmLoadSystemImage(IN PUNICODE_STRING FileName, 02777 IN PUNICODE_STRING NamePrefix OPTIONAL, 02778 IN PUNICODE_STRING LoadedName OPTIONAL, 02779 IN ULONG Flags, 02780 OUT PVOID *ModuleObject, 02781 OUT PVOID *ImageBaseAddress) 02782 { 02783 PVOID ModuleLoadBase = NULL; 02784 NTSTATUS Status; 02785 HANDLE FileHandle = NULL; 02786 OBJECT_ATTRIBUTES ObjectAttributes; 02787 IO_STATUS_BLOCK IoStatusBlock; 02788 PIMAGE_NT_HEADERS NtHeader; 02789 UNICODE_STRING BaseName, BaseDirectory, PrefixName, UnicodeTemp; 02790 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL; 02791 ULONG EntrySize, DriverSize; 02792 PLOAD_IMPORTS LoadedImports = MM_SYSLDR_NO_IMPORTS; 02793 PCHAR MissingApiName, Buffer; 02794 PWCHAR MissingDriverName; 02795 HANDLE SectionHandle; 02796 ACCESS_MASK DesiredAccess; 02797 PVOID Section = NULL; 02798 BOOLEAN LockOwned = FALSE; 02799 PLIST_ENTRY NextEntry; 02800 IMAGE_INFO ImageInfo; 02801 STRING AnsiTemp; 02802 PAGED_CODE(); 02803 02804 /* Detect session-load */ 02805 if (Flags) 02806 { 02807 /* Sanity checks */ 02808 ASSERT(NamePrefix == NULL); 02809 ASSERT(LoadedName == NULL); 02810 02811 /* Make sure the process is in session too */ 02812 if (!PsGetCurrentProcess()->ProcessInSession) return STATUS_NO_MEMORY; 02813 } 02814 02815 /* Allocate a buffer we'll use for names */ 02816 Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR); 02817 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES; 02818 02819 /* Check for a separator */ 02820 if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) 02821 { 02822 PWCHAR p; 02823 ULONG BaseLength; 02824 02825 /* Loop the path until we get to the base name */ 02826 p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)]; 02827 while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--; 02828 02829 /* Get the length */ 02830 BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p); 02831 BaseLength *= sizeof(WCHAR); 02832 02833 /* Setup the string */ 02834 BaseName.Length = (USHORT)BaseLength; 02835 BaseName.Buffer = p; 02836 } 02837 else 02838 { 02839 /* Otherwise, we already have a base name */ 02840 BaseName.Length = FileName->Length; 02841 BaseName.Buffer = FileName->Buffer; 02842 } 02843 02844 /* Setup the maximum length */ 02845 BaseName.MaximumLength = BaseName.Length; 02846 02847 /* Now compute the base directory */ 02848 BaseDirectory = *FileName; 02849 BaseDirectory.Length -= BaseName.Length; 02850 BaseDirectory.MaximumLength = BaseDirectory.Length; 02851 02852 /* And the prefix, which for now is just the name itself */ 02853 PrefixName = *FileName; 02854 02855 /* Check if we have a prefix */ 02856 if (NamePrefix) DPRINT1("Prefixed images are not yet supported!\n"); 02857 02858 /* Check if we already have a name, use it instead */ 02859 if (LoadedName) BaseName = *LoadedName; 02860 02861 /* Check for loader snap debugging */ 02862 if (NtGlobalFlag & FLG_SHOW_LDR_SNAPS) 02863 { 02864 /* Print out standard string */ 02865 DPRINT1("MM:SYSLDR Loading %wZ (%wZ) %s\n", 02866 &PrefixName, &BaseName, Flags ? "in session space" : ""); 02867 } 02868 02869 /* Acquire the load lock */ 02870 LoaderScan: 02871 ASSERT(LockOwned == FALSE); 02872 LockOwned = TRUE; 02873 KeEnterCriticalRegion(); 02874 KeWaitForSingleObject(&MmSystemLoadLock, 02875 WrVirtualMemory, 02876 KernelMode, 02877 FALSE, 02878 NULL); 02879 02880 /* Scan the module list */ 02881 NextEntry = PsLoadedModuleList.Flink; 02882 while (NextEntry != &PsLoadedModuleList) 02883 { 02884 /* Get the entry and compare the names */ 02885 LdrEntry = CONTAINING_RECORD(NextEntry, 02886 LDR_DATA_TABLE_ENTRY, 02887 InLoadOrderLinks); 02888 if (RtlEqualUnicodeString(&PrefixName, &LdrEntry->FullDllName, TRUE)) 02889 { 02890 /* Found it, break out */ 02891 break; 02892 } 02893 02894 /* Keep scanning */ 02895 NextEntry = NextEntry->Flink; 02896 } 02897 02898 /* Check if we found the image */ 02899 if (NextEntry != &PsLoadedModuleList) 02900 { 02901 /* Check if we had already mapped a section */ 02902 if (Section) 02903 { 02904 /* Dereference and clear */ 02905 ObDereferenceObject(Section); 02906 Section = NULL; 02907 } 02908 02909 /* Check if this was supposed to be a session load */ 02910 if (!Flags) 02911 { 02912 /* It wasn't, so just return the data */ 02913 *ModuleObject = LdrEntry; 02914 *ImageBaseAddress = LdrEntry->DllBase; 02915 Status = STATUS_IMAGE_ALREADY_LOADED; 02916 } 02917 else 02918 { 02919 /* We don't support session loading yet */ 02920 DPRINT1("Unsupported Session-Load!\n"); 02921 while (TRUE); 02922 } 02923 02924 /* Do cleanup */ 02925 goto Quickie; 02926 } 02927 else if (!Section) 02928 { 02929 /* It wasn't loaded, and we didn't have a previous attempt */ 02930 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE); 02931 KeLeaveCriticalRegion(); 02932 LockOwned = FALSE; 02933 02934 /* Check if KD is enabled */ 02935 if ((KdDebuggerEnabled) && !(KdDebuggerNotPresent)) 02936 { 02937 /* FIXME: Attempt to get image from KD */ 02938 } 02939 02940 /* We don't have a valid entry */ 02941 LdrEntry = NULL; 02942 02943 /* Setup image attributes */ 02944 InitializeObjectAttributes(&ObjectAttributes, 02945 FileName, 02946 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 02947 NULL, 02948 NULL); 02949 02950 /* Open the image */ 02951 Status = ZwOpenFile(&FileHandle, 02952 FILE_EXECUTE, 02953 &ObjectAttributes, 02954 &IoStatusBlock, 02955 FILE_SHARE_READ | FILE_SHARE_DELETE, 02956 0); 02957 if (!NT_SUCCESS(Status)) 02958 { 02959 DPRINT1("ZwOpenFile failed with status 0x%x\n", Status); 02960 goto Quickie; 02961 } 02962 02963 /* Validate it */ 02964 Status = MmCheckSystemImage(FileHandle, FALSE); 02965 if ((Status == STATUS_IMAGE_CHECKSUM_MISMATCH) || 02966 (Status == STATUS_IMAGE_MP_UP_MISMATCH) || 02967 (Status == STATUS_INVALID_IMAGE_PROTECT)) 02968 { 02969 /* Fail loading */ 02970 goto Quickie; 02971 } 02972 02973 /* Check if this is a session-load */ 02974 if (Flags) 02975 { 02976 /* Then we only need read and execute */ 02977 DesiredAccess = SECTION_MAP_READ | SECTION_MAP_EXECUTE; 02978 } 02979 else 02980 { 02981 /* Otherwise, we can allow write access */ 02982 DesiredAccess = SECTION_ALL_ACCESS; 02983 } 02984 02985 /* Initialize the attributes for the section */ 02986 InitializeObjectAttributes(&ObjectAttributes, 02987 NULL, 02988 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 02989 NULL, 02990 NULL); 02991 02992 /* Create the section */ 02993 Status = ZwCreateSection(&SectionHandle, 02994 DesiredAccess, 02995 &ObjectAttributes, 02996 NULL, 02997 PAGE_EXECUTE, 02998 SEC_IMAGE, 02999 FileHandle); 03000 if (!NT_SUCCESS(Status)) 03001 { 03002 DPRINT1("ZwCreateSection failed with status 0x%x\n", Status); 03003 goto Quickie; 03004 } 03005 03006 /* Now get the section pointer */ 03007 Status = ObReferenceObjectByHandle(SectionHandle, 03008 SECTION_MAP_EXECUTE, 03009 MmSectionObjectType, 03010 KernelMode, 03011 &Section, 03012 NULL); 03013 ZwClose(SectionHandle); 03014 if (!NT_SUCCESS(Status)) goto Quickie; 03015 03016 /* Check if this was supposed to be a session-load */ 03017 if (Flags) 03018 { 03019 /* We don't support session loading yet */ 03020 DPRINT1("Unsupported Session-Load!\n"); 03021 while (TRUE); 03022 } 03023 03024 /* Check the loader list again, we should end up in the path below */ 03025 goto LoaderScan; 03026 } 03027 else 03028 { 03029 /* We don't have a valid entry */ 03030 LdrEntry = NULL; 03031 } 03032 03033 /* Load the image */ 03034 Status = MiLoadImageSection(&Section, 03035 &ModuleLoadBase, 03036 FileName, 03037 FALSE, 03038 NULL); 03039 ASSERT(Status != STATUS_ALREADY_COMMITTED); 03040 03041 /* Get the size of the driver */ 03042 DriverSize = ((PROS_SECTION_OBJECT)Section)->ImageSection->ImageSize; 03043 03044 /* Make sure we're not being loaded into session space */ 03045 if (!Flags) 03046 { 03047 /* Check for success */ 03048 if (NT_SUCCESS(Status)) 03049 { 03050 /* Support large pages for drivers */ 03051 MiUseLargeDriverPage(DriverSize / PAGE_SIZE, 03052 &ModuleLoadBase, 03053 &BaseName, 03054 TRUE); 03055 } 03056 03057 /* Dereference the section */ 03058 ObDereferenceObject(Section); 03059 Section = NULL; 03060 } 03061 03062 /* Check for failure of the load earlier */ 03063 if (!NT_SUCCESS(Status)) 03064 { 03065 DPRINT1("MiLoadImageSection failed with status 0x%x\n", Status); 03066 goto Quickie; 03067 } 03068 03069 /* Relocate the driver */ 03070 Status = LdrRelocateImageWithBias(ModuleLoadBase, 03071 0, 03072 "SYSLDR", 03073 STATUS_SUCCESS, 03074 STATUS_CONFLICTING_ADDRESSES, 03075 STATUS_INVALID_IMAGE_FORMAT); 03076 if (!NT_SUCCESS(Status)) 03077 { 03078 DPRINT1("LdrRelocateImageWithBias failed with status 0x%x\n", Status); 03079 goto Quickie; 03080 } 03081 03082 /* Get the NT Header */ 03083 NtHeader = RtlImageNtHeader(ModuleLoadBase); 03084 03085 /* Calculate the size we'll need for the entry and allocate it */ 03086 EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) + 03087 BaseName.Length + 03088 sizeof(UNICODE_NULL); 03089 03090 /* Allocate the entry */ 03091 LdrEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT); 03092 if (!LdrEntry) 03093 { 03094 /* Fail */ 03095 Status = STATUS_INSUFFICIENT_RESOURCES; 03096 goto Quickie; 03097 } 03098 03099 /* Setup the entry */ 03100 LdrEntry->Flags = LDRP_LOAD_IN_PROGRESS; 03101 LdrEntry->LoadCount = 1; 03102 LdrEntry->LoadedImports = LoadedImports; 03103 LdrEntry->PatchInformation = NULL; 03104 03105 /* Check the version */ 03106 if ((NtHeader->OptionalHeader.MajorOperatingSystemVersion >= 5) && 03107 (NtHeader->OptionalHeader.MajorImageVersion >= 5)) 03108 { 03109 /* Mark this image as a native image */ 03110 LdrEntry->Flags |= LDRP_ENTRY_NATIVE; 03111 } 03112 03113 /* Setup the rest of the entry */ 03114 LdrEntry->DllBase = ModuleLoadBase; 03115 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)ModuleLoadBase + 03116 NtHeader->OptionalHeader.AddressOfEntryPoint); 03117 LdrEntry->SizeOfImage = DriverSize; 03118 LdrEntry->CheckSum = NtHeader->OptionalHeader.CheckSum; 03119 LdrEntry->SectionPointer = Section; 03120 03121 /* Now write the DLL name */ 03122 LdrEntry->BaseDllName.Buffer = (PVOID)(LdrEntry + 1); 03123 LdrEntry->BaseDllName.Length = BaseName.Length; 03124 LdrEntry->BaseDllName.MaximumLength = BaseName.Length; 03125 03126 /* Copy and null-terminate it */ 03127 RtlCopyMemory(LdrEntry->BaseDllName.Buffer, 03128 BaseName.Buffer, 03129 BaseName.Length); 03130 LdrEntry->BaseDllName.Buffer[BaseName.Length / sizeof(WCHAR)] = UNICODE_NULL; 03131 03132 /* Now allocate the full name */ 03133 LdrEntry->FullDllName.Buffer = ExAllocatePoolWithTag(PagedPool, 03134 PrefixName.Length + 03135 sizeof(UNICODE_NULL), 03136 TAG_LDR_WSTR); 03137 if (!LdrEntry->FullDllName.Buffer) 03138 { 03139 /* Don't fail, just set it to zero */ 03140 LdrEntry->FullDllName.Length = 0; 03141 LdrEntry->FullDllName.MaximumLength = 0; 03142 } 03143 else 03144 { 03145 /* Set it up */ 03146 LdrEntry->FullDllName.Length = PrefixName.Length; 03147 LdrEntry->FullDllName.MaximumLength = PrefixName.Length; 03148 03149 /* Copy and null-terminate */ 03150 RtlCopyMemory(LdrEntry->FullDllName.Buffer, 03151 PrefixName.Buffer, 03152 PrefixName.Length); 03153 LdrEntry->FullDllName.Buffer[PrefixName.Length / sizeof(WCHAR)] = UNICODE_NULL; 03154 } 03155 03156 /* Add the entry */ 03157 MiProcessLoaderEntry(LdrEntry, TRUE); 03158 03159 /* Resolve imports */ 03160 MissingApiName = Buffer; 03161 Status = MiResolveImageReferences(ModuleLoadBase, 03162 &BaseDirectory, 03163 NULL, 03164 &MissingApiName, 03165 &MissingDriverName, 03166 &LoadedImports); 03167 if (!NT_SUCCESS(Status)) 03168 { 03169 DPRINT1("MiResolveImageReferences failed with status 0x%x\n", Status); 03170 03171 /* Fail */ 03172 MiProcessLoaderEntry(LdrEntry, FALSE); 03173 03174 /* Check if we need to free the name */ 03175 if (LdrEntry->FullDllName.Buffer) 03176 { 03177 /* Free it */ 03178 ExFreePoolWithTag(LdrEntry->FullDllName.Buffer, TAG_LDR_WSTR); 03179 } 03180 03181 /* Free the entry itself */ 03182 ExFreePoolWithTag(LdrEntry, TAG_MODULE_OBJECT); 03183 LdrEntry = NULL; 03184 goto Quickie; 03185 } 03186 03187 /* Update the loader entry */ 03188 LdrEntry->Flags |= (LDRP_SYSTEM_MAPPED | 03189 LDRP_ENTRY_PROCESSED | 03190 LDRP_MM_LOADED); 03191 LdrEntry->Flags &= ~LDRP_LOAD_IN_PROGRESS; 03192 LdrEntry->LoadedImports = LoadedImports; 03193 03194 /* FIXME: Call driver verifier's loader function */ 03195 03196 /* Write-protect the system image */ 03197 MiWriteProtectSystemImage(LdrEntry->DllBase); 03198 03199 /* Check if notifications are enabled */ 03200 if (PsImageNotifyEnabled) 03201 { 03202 /* Fill out the notification data */ 03203 ImageInfo.Properties = 0; 03204 ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT; 03205 ImageInfo.SystemModeImage = TRUE; 03206 ImageInfo.ImageSize = LdrEntry->SizeOfImage; 03207 ImageInfo.ImageBase = LdrEntry->DllBase; 03208 ImageInfo.ImageSectionNumber = ImageInfo.ImageSelector = 0; 03209 03210 /* Send the notification */ 03211 PspRunLoadImageNotifyRoutines(FileName, NULL, &ImageInfo); 03212 } 03213 03214 #if defined(KDBG) || defined(_WINKD_) 03215 /* MiCacheImageSymbols doesn't detect rossym */ 03216 if (TRUE) 03217 #else 03218 /* Check if there's symbols */ 03219 if (MiCacheImageSymbols(LdrEntry->DllBase)) 03220 #endif 03221 { 03222 /* Check if the system root is present */ 03223 if ((PrefixName.Length > (11 * sizeof(WCHAR))) && 03224 !(_wcsnicmp(PrefixName.Buffer, L"\\SystemRoot", 11))) 03225 { 03226 /* Add the system root */ 03227 UnicodeTemp = PrefixName; 03228 UnicodeTemp.Buffer += 11; 03229 UnicodeTemp.Length -= (11 * sizeof(WCHAR)); 03230 sprintf_nt(Buffer, 03231 "%ws%wZ", 03232 &SharedUserData->NtSystemRoot[2], 03233 &UnicodeTemp); 03234 } 03235 else 03236 { 03237 /* Build the name */ 03238 sprintf_nt(Buffer, "%wZ", &BaseName); 03239 } 03240 03241 /* Setup the ansi string */ 03242 RtlInitString(&AnsiTemp, Buffer); 03243 03244 /* Notify the debugger */ 03245 DbgLoadImageSymbols(&AnsiTemp, 03246 LdrEntry->DllBase, 03247 (ULONG_PTR)ZwCurrentProcess()); 03248 LdrEntry->Flags |= LDRP_DEBUG_SYMBOLS_LOADED; 03249 } 03250 03251 /* Page the driver */ 03252 ASSERT(Section == NULL); 03253 MiEnablePagingOfDriver(LdrEntry); 03254 03255 /* Return pointers */ 03256 *ModuleObject = LdrEntry; 03257 *ImageBaseAddress = LdrEntry->DllBase; 03258 03259 Quickie: 03260 /* Check if we have the lock acquired */ 03261 if (LockOwned) 03262 { 03263 /* Release the lock */ 03264 KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE); 03265 KeLeaveCriticalRegion(); 03266 LockOwned = FALSE; 03267 } 03268 03269 /* If we have a file handle, close it */ 03270 if (FileHandle) ZwClose(FileHandle); 03271 03272 /* Check if we had a prefix (not supported yet - PrefixName == *FileName now) */ 03273 /* if (NamePrefix) ExFreePool(PrefixName.Buffer); */ 03274 03275 /* Free the name buffer and return status */ 03276 ExFreePoolWithTag(Buffer, TAG_LDR_WSTR); 03277 return Status; 03278 } 03279 03280 PLDR_DATA_TABLE_ENTRY 03281 NTAPI 03282 MiLookupDataTableEntry(IN PVOID Address) 03283 { 03284 PLDR_DATA_TABLE_ENTRY LdrEntry, FoundEntry = NULL; 03285 PLIST_ENTRY NextEntry; 03286 PAGED_CODE(); 03287 03288 /* Loop entries */ 03289 NextEntry = PsLoadedModuleList.Flink; 03290 do 03291 { 03292 /* Get the loader entry */ 03293 LdrEntry = CONTAINING_RECORD(NextEntry, 03294 LDR_DATA_TABLE_ENTRY, 03295 InLoadOrderLinks); 03296 03297 /* Check if the address matches */ 03298 if ((Address >= LdrEntry->DllBase) && 03299 (Address < (PVOID)((ULONG_PTR)LdrEntry->DllBase + 03300 LdrEntry->SizeOfImage))) 03301 { 03302 /* Found a match */ 03303 FoundEntry = LdrEntry; 03304 break; 03305 } 03306 03307 /* Move on */ 03308 NextEntry = NextEntry->Flink; 03309 } while(NextEntry != &PsLoadedModuleList); 03310 03311 /* Return the entry */ 03312 return FoundEntry; 03313 } 03314 03315 /* PUBLIC FUNCTIONS ***********************************************************/ 03316 03317 /* 03318 * @implemented 03319 */ 03320 PVOID 03321 NTAPI 03322 MmPageEntireDriver(IN PVOID AddressWithinSection) 03323 { 03324 PMMPTE StartPte, EndPte; 03325 PLDR_DATA_TABLE_ENTRY LdrEntry; 03326 PAGED_CODE(); 03327 03328 /* Get the loader entry */ 03329 LdrEntry = MiLookupDataTableEntry(AddressWithinSection); 03330 if (!LdrEntry) return NULL; 03331 03332 /* Check if paging of kernel mode is disabled or if the driver is mapped as an image */ 03333 if ((MmDisablePagingExecutive) || (LdrEntry->SectionPointer)) 03334 { 03335 /* Don't do anything, just return the base address */ 03336 return LdrEntry->DllBase; 03337 } 03338 03339 /* Wait for active DPCs to finish before we page out the driver */ 03340 KeFlushQueuedDpcs(); 03341 03342 /* Get the PTE range for the whole driver image */ 03343 StartPte = MiAddressToPte((ULONG_PTR)LdrEntry->DllBase); 03344 EndPte = MiAddressToPte((ULONG_PTR)LdrEntry->DllBase + LdrEntry->SizeOfImage); 03345 03346 /* Enable paging for the PTE range */ 03347 ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(AddressWithinSection) == FALSE); 03348 MiSetPagingOfDriver(StartPte, EndPte); 03349 03350 /* Return the base address */ 03351 return LdrEntry->DllBase; 03352 } 03353 03354 /* 03355 * @unimplemented 03356 */ 03357 VOID 03358 NTAPI 03359 MmResetDriverPaging(IN PVOID AddressWithinSection) 03360 { 03361 UNIMPLEMENTED; 03362 } 03363 03364 /* 03365 * @implemented 03366 */ 03367 PVOID 03368 NTAPI 03369 MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName) 03370 { 03371 PVOID ProcAddress = NULL; 03372 ANSI_STRING AnsiRoutineName; 03373 NTSTATUS Status; 03374 PLIST_ENTRY NextEntry; 03375 PLDR_DATA_TABLE_ENTRY LdrEntry; 03376 BOOLEAN Found = FALSE; 03377 UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe"); 03378 UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll"); 03379 ULONG Modules = 0; 03380 03381 /* Convert routine to ansi name */ 03382 Status = RtlUnicodeStringToAnsiString(&AnsiRoutineName, 03383 SystemRoutineName, 03384 TRUE); 03385 if (!NT_SUCCESS(Status)) return NULL; 03386 03387 /* Lock the list */ 03388 KeEnterCriticalRegion(); 03389 ExAcquireResourceSharedLite(&PsLoadedModuleResource, TRUE); 03390 03391 /* Loop the loaded module list */ 03392 NextEntry = PsLoadedModuleList.Flink; 03393 while (NextEntry != &PsLoadedModuleList) 03394 { 03395 /* Get the entry */ 03396 LdrEntry = CONTAINING_RECORD(NextEntry, 03397 LDR_DATA_TABLE_ENTRY, 03398 InLoadOrderLinks); 03399 03400 /* Check if it's the kernel or HAL */ 03401 if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE)) 03402 { 03403 /* Found it */ 03404 Found = TRUE; 03405 Modules++; 03406 } 03407 else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE)) 03408 { 03409 /* Found it */ 03410 Found = TRUE; 03411 Modules++; 03412 } 03413 03414 /* Check if we found a valid binary */ 03415 if (Found) 03416 { 03417 /* Find the procedure name */ 03418 ProcAddress = MiFindExportedRoutineByName(LdrEntry->DllBase, 03419 &AnsiRoutineName); 03420 03421 /* Break out if we found it or if we already tried both modules */ 03422 if (ProcAddress) break; 03423 if (Modules == 2) break; 03424 } 03425 03426 /* Keep looping */ 03427 NextEntry = NextEntry->Flink; 03428 } 03429 03430 /* Release the lock */ 03431 ExReleaseResourceLite(&PsLoadedModuleResource); 03432 KeLeaveCriticalRegion(); 03433 03434 /* Free the string and return */ 03435 RtlFreeAnsiString(&AnsiRoutineName); 03436 return ProcAddress; 03437 } 03438 Generated on Sat May 26 2012 04:36:25 for ReactOS by
1.7.6.1
|