static BOOLEAN WinLdrpBindImportName(IN OUT PLIST_ENTRY ModuleListHead, IN PVOID DllBase, IN PVOID ImageBase, IN PIMAGE_THUNK_DATA ThunkData, IN PIMAGE_EXPORT_DIRECTORY ExportDirectory, IN ULONG ExportSize, IN BOOLEAN ProcessForwards, IN PCSTR DirectoryPath) { ULONG Ordinal; PULONG NameTable, FunctionTable; PUSHORT OrdinalTable; LONG High, Low, Middle, Result; ULONG Hint; PIMAGE_IMPORT_BY_NAME ImportData; PCHAR ExportName, ForwarderName; BOOLEAN Success; //TRACE("WinLdrpBindImportName(): DllBase 0x%X, ImageBase 0x%X, ThunkData 0x%X, ExportDirectory 0x%X, ExportSize %d, ProcessForwards 0x%X\n", // DllBase, ImageBase, ThunkData, ExportDirectory, ExportSize, ProcessForwards); /* Check passed DllBase param */ if(DllBase == NULL) { WARN("DllBase == NULL!\n"); return FALSE; } /* Convert all non-critical pointers to PA from VA */ ThunkData = VaToPa(ThunkData); /* Is the reference by ordinal? */ if (IMAGE_SNAP_BY_ORDINAL(ThunkData->u1.Ordinal) && !ProcessForwards) { /* Yes, calculate the ordinal */ Ordinal = (ULONG)(IMAGE_ORDINAL(ThunkData->u1.Ordinal) - (UINT32)ExportDirectory->Base); //TRACE("WinLdrpBindImportName(): Ordinal %d\n", Ordinal); } else { /* It's reference by name, we have to look it up in the export directory */ if (!ProcessForwards) { /* AddressOfData in thunk entry will become a virtual address (from relative) */ //TRACE("WinLdrpBindImportName(): ThunkData->u1.AOD was %p\n", ThunkData->u1.AddressOfData); ThunkData->u1.AddressOfData = (ULONG_PTR)RVA(ImageBase, ThunkData->u1.AddressOfData); //TRACE("WinLdrpBindImportName(): ThunkData->u1.AOD became %p\n", ThunkData->u1.AddressOfData); } /* Get the import name */ ImportData = VaToPa((PVOID)ThunkData->u1.AddressOfData); /* Get pointers to Name and Ordinal tables (RVA -> VA) */ NameTable = VaToPa(RVA(DllBase, ExportDirectory->AddressOfNames)); OrdinalTable = VaToPa(RVA(DllBase, ExportDirectory->AddressOfNameOrdinals)); //TRACE("NameTable 0x%X, OrdinalTable 0x%X, ED->AddressOfNames 0x%X, ED->AOFO 0x%X\n", // NameTable, OrdinalTable, ExportDirectory->AddressOfNames, ExportDirectory->AddressOfNameOrdinals); /* Get the hint, convert it to a physical pointer */ Hint = ((PIMAGE_IMPORT_BY_NAME)VaToPa((PVOID)ThunkData->u1.AddressOfData))->Hint; //TRACE("HintIndex %d\n", Hint); /* Get the export name from the hint */ ExportName = VaToPa(RVA(DllBase, NameTable[Hint])); /* If Hint is less than total number of entries in the export directory, and import name == export name, then we can just get it from the OrdinalTable */ if ((Hint < ExportDirectory->NumberOfNames) && (strcmp(ExportName, (PCHAR)ImportData->Name) == 0)) { Ordinal = OrdinalTable[Hint]; //TRACE("WinLdrpBindImportName(): Ordinal %d\n", Ordinal); } else { /* It's not the easy way, we have to lookup import name in the name table. Let's use a binary search for this task. */ //TRACE("WinLdrpBindImportName() looking up the import name using binary search...\n"); /* Low boundary is set to 0, and high boundary to the maximum index */ Low = 0; High = ExportDirectory->NumberOfNames - 1; /* Perform a binary-search loop */ while (High >= Low) { /* Divide by 2 by shifting to the right once */ Middle = (Low + High) / 2; /* Get the name from the name table */ ExportName = VaToPa(RVA(DllBase, NameTable[Middle])); /* Compare the names */ Result = strcmp(ExportName, (PCHAR)ImportData->Name); /*TRACE("Binary search: comparing Import '__', Export '%s'\n",*/ /*VaToPa(&((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name[0]),*/ /*(PCHAR)VaToPa(RVA(DllBase, NameTable[Middle])));*/ /*TRACE("TE->u1.AOD %p, fulladdr %p\n", ThunkData->u1.AddressOfData, ((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name );*/ /* Depending on result of strcmp, perform different actions */ if (Result > 0) { /* Adjust top boundary */ High = Middle - 1; } else if (Result < 0) { /* Adjust bottom boundary */ Low = Middle + 1; } else { /* Yay, found it! */ break; } } /* If high boundary is less than low boundary, then no result found */ if (High < Low) { //Print(L"Error in binary search\n"); ERR("Did not find export '%s'!\n", (PCHAR)ImportData->Name); return FALSE; } /* Everything alright, get the ordinal */ Ordinal = OrdinalTable[Middle]; //TRACE("WinLdrpBindImportName() found Ordinal %d\n", Ordinal); } } /* Check ordinal number for validity! */ if (Ordinal >= ExportDirectory->NumberOfFunctions) { ERR("Ordinal number is invalid!\n"); return FALSE; } /* Get a pointer to the function table */ FunctionTable = (PULONG)VaToPa(RVA(DllBase, ExportDirectory->AddressOfFunctions)); /* Save a pointer to the function */ ThunkData->u1.Function = (ULONG_PTR)RVA(DllBase, FunctionTable[Ordinal]); /* Is it a forwarder? (function pointer is within the export directory) */ ForwarderName = (PCHAR)VaToPa((PVOID)ThunkData->u1.Function); if (((ULONG_PTR)ForwarderName > (ULONG_PTR)ExportDirectory) && ((ULONG_PTR)ForwarderName < ((ULONG_PTR)ExportDirectory + ExportSize))) { PLDR_DATA_TABLE_ENTRY DataTableEntry; CHAR ForwardDllName[255]; PIMAGE_EXPORT_DIRECTORY RefExportDirectory; ULONG RefExportSize; TRACE("WinLdrpBindImportName(): ForwarderName %s\n", ForwarderName); /* Save the name of the forward dll */ RtlCopyMemory(ForwardDllName, ForwarderName, sizeof(ForwardDllName)); /* Strip out the symbol name */ *strrchr(ForwardDllName,'.') = '\0'; /* Check if the target image is already loaded */ if (!WinLdrCheckForLoadedDll(ModuleListHead, ForwardDllName, &DataTableEntry)) { /* Check if the forward dll name has an extension */ if (strchr(ForwardDllName, '.') == NULL) { /* Name does not have an extension, append '.dll' */ strcat(ForwardDllName, ".dll"); } /* Now let's try to load it! */ Success = WinLdrpLoadAndScanReferencedDll(ModuleListHead, DirectoryPath, ForwardDllName, &DataTableEntry); if (!Success) { ERR("WinLdrpLoadAndScanReferencedDll() failed to load forwarder dll.\n"); return Success; } } /* Get pointer to the export directory of loaded DLL */ RefExportDirectory = (PIMAGE_EXPORT_DIRECTORY) RtlImageDirectoryEntryToData(VaToPa(DataTableEntry->DllBase), TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &RefExportSize); /* Fail if it's NULL */ if (RefExportDirectory) { UCHAR Buffer[128]; IMAGE_THUNK_DATA RefThunkData; PIMAGE_IMPORT_BY_NAME ImportByName; PCHAR ImportName; /* Get pointer to the import name */ ImportName = strrchr(ForwarderName, '.') + 1; /* Create a IMAGE_IMPORT_BY_NAME structure, pointing to the local Buffer */ ImportByName = (PIMAGE_IMPORT_BY_NAME)Buffer; /* Fill the name with the import name */ RtlCopyMemory(ImportByName->Name, ImportName, strlen(ImportName)+1); /* Set Hint to 0 */ ImportByName->Hint = 0; /* And finally point ThunkData's AddressOfData to that structure */ RefThunkData.u1.AddressOfData = (ULONG_PTR)ImportByName; /* And recursively call ourselves */ Success = WinLdrpBindImportName(ModuleListHead, DataTableEntry->DllBase, ImageBase, &RefThunkData, RefExportDirectory, RefExportSize, TRUE, DirectoryPath); /* Fill out the ThunkData with data from RefThunkData */ ThunkData->u1 = RefThunkData.u1; /* Return what we got from the recursive call */ return Success; } else { /* Fail if ExportDirectory is NULL */ return FALSE; } } /* Success! */ return TRUE; }
BOOLEAN WinLdrScanImportDescriptorTable(IN OUT PLIST_ENTRY ModuleListHead, IN PCCH DirectoryPath, IN PLDR_DATA_TABLE_ENTRY ScanDTE) { PLDR_DATA_TABLE_ENTRY DataTableEntry; PIMAGE_IMPORT_DESCRIPTOR ImportTable; ULONG ImportTableSize; PCH ImportName; BOOLEAN Success; /* Get a pointer to the import table of this image */ ImportTable = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(VaToPa(ScanDTE->DllBase), TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ImportTableSize); { UNICODE_STRING BaseName; BaseName.Buffer = VaToPa(ScanDTE->BaseDllName.Buffer); BaseName.MaximumLength = ScanDTE->BaseDllName.MaximumLength; BaseName.Length = ScanDTE->BaseDllName.Length; TRACE("WinLdrScanImportDescriptorTable(): %wZ ImportTable = 0x%X\n", &BaseName, ImportTable); } /* If image doesn't have any import directory - just return success */ if (ImportTable == NULL) return TRUE; /* Loop through all entries */ for (;(ImportTable->Name != 0) && (ImportTable->FirstThunk != 0);ImportTable++) { /* Get pointer to the name */ ImportName = (PCH)VaToPa(RVA(ScanDTE->DllBase, ImportTable->Name)); TRACE("WinLdrScanImportDescriptorTable(): Looking at %s\n", ImportName); /* In case we get a reference to ourselves - just skip it */ if (WinLdrpCompareDllName(ImportName, &ScanDTE->BaseDllName)) continue; /* Load the DLL if it is not already loaded */ if (!WinLdrCheckForLoadedDll(ModuleListHead, ImportName, &DataTableEntry)) { Success = WinLdrpLoadAndScanReferencedDll(ModuleListHead, DirectoryPath, ImportName, &DataTableEntry); if (!Success) { ERR("WinLdrpLoadAndScanReferencedDll() failed\n"); return Success; } } /* Scan its import address table */ Success = WinLdrpScanImportAddressTable(ModuleListHead, DataTableEntry->DllBase, ScanDTE->DllBase, (PIMAGE_THUNK_DATA)RVA(ScanDTE->DllBase, ImportTable->FirstThunk), DirectoryPath); if (!Success) { ERR("WinLdrpScanImportAddressTable() failed: ImportName = '%s', DirectoryPath = '%s'\n", ImportName, DirectoryPath); return Success; } } return TRUE; }
static BOOLEAN WinLdrLoadDeviceDriver(PLIST_ENTRY LoadOrderListHead, LPCSTR BootPath, PUNICODE_STRING FilePath, ULONG Flags, PLDR_DATA_TABLE_ENTRY *DriverDTE) { CHAR FullPath[1024]; CHAR DriverPath[1024]; CHAR DllName[1024]; PCHAR DriverNamePos; BOOLEAN Status; PVOID DriverBase = NULL; // Separate the path to file name and directory path _snprintf(DriverPath, sizeof(DriverPath), "%wZ", FilePath); DriverNamePos = strrchr(DriverPath, '\\'); if (DriverNamePos != NULL) { // Copy the name strcpy(DllName, DriverNamePos+1); // Cut out the name from the path *(DriverNamePos+1) = 0; } else { // There is no directory in the path strcpy(DllName, DriverPath); DriverPath[0] = 0; } TRACE("DriverPath: %s, DllName: %s, LPB\n", DriverPath, DllName); // Check if driver is already loaded Status = WinLdrCheckForLoadedDll(LoadOrderListHead, DllName, DriverDTE); if (Status) { // We've got the pointer to its DTE, just return success return TRUE; } // It's not loaded, we have to load it _snprintf(FullPath, sizeof(FullPath), "%s%wZ", BootPath, FilePath); Status = WinLdrLoadImage(FullPath, LoaderBootDriver, &DriverBase); if (!Status) return FALSE; // Allocate a DTE for it Status = WinLdrAllocateDataTableEntry(LoadOrderListHead, DllName, DllName, DriverBase, DriverDTE); if (!Status) { ERR("WinLdrAllocateDataTableEntry() failed\n"); return FALSE; } // Modify any flags, if needed (*DriverDTE)->Flags |= Flags; // Look for any dependencies it may have, and load them too sprintf(FullPath,"%s%s", BootPath, DriverPath); Status = WinLdrScanImportDescriptorTable(LoadOrderListHead, FullPath, *DriverDTE); if (!Status) { ERR("WinLdrScanImportDescriptorTable() failed for %s\n", FullPath); return FALSE; } return TRUE; }