如何调整Delphi应用的系统DLL搜索方式,避免加载伪系统DLL?
Great question! This is a classic Windows DLL loading pitfall—by default, Windows checks the app's current directory first before system folders, which lets rogue copies of system DLLs hijack the load and throw errors like the 0xc0000020 status you're seeing. Here are several practical, reliable ways to resolve this:
1. Adjust DLL Search Order via Initialization Code
The simplest and most effective fix for modern Windows versions is to modify the DLL search path early in your app's lifecycle. Use Windows API functions to prioritize system directories over your app's folder:
uses Windows; initialization // Target Windows Vista and later (most systems today) if Win32MajorVersion >= 6 then // Restrict DLL searches to the System32 folder for system DLLs SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32) else // For Windows XP and older, remove current directory from search path SetDllDirectory('');
How it works:
SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32)tells Windows to only look in the System32 directory for system DLLs, skipping the app's current folder entirely.- For older systems,
SetDllDirectory('')clears the current directory from the DLL search order, forcing Windows to use the standard system path.
2. Use an Application Manifest to Redirect System DLLs
You can add a manifest file to your Delphi project that explicitly instructs Windows to load specified system DLLs from the system directory, overriding the default search order.
- Create a file named
app.manifestwith this content:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <!-- Optional: Include common controls manifest if needed --> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/> </dependentAssembly> </dependency> <!-- List system DLLs you want to protect; add more as needed --> <file name="version.dll" /> <file name="kernel32.dll" /> <file name="user32.dll" /> </assembly>
- Link it to your Delphi project:
- Go to Project > Options > Application > Manifest
- Select "Custom manifest" and browse to your
app.manifestfile
This tells Windows to load the listed DLLs directly from the system location, ignoring any copies in your app's directory.
3. Static Link Critical System Functions (Advanced)
For core system functions you rely on, you can statically link them instead of using dynamic loading. In Delphi, you can use the {$LINK} directive to link against import libraries directly. This is more work, but it eliminates the risk of DLL hijacking for those specific functions.
For example, to statically link a function from kernel32.dll:
{$LINK 'kernel32.lib'} function GetSystemDirectory(lpBuffer: LPTSTR; uSize: UINT): UINT; stdcall;
Note: This method only works for individual functions, not entire DLLs, so it's best for critical, frequently used functions.
4. Hook LoadLibrary to Validate DLL Sources (High Security)
If you need maximum control, you can hook the LoadLibrary/LoadLibraryEx functions in your app to validate that system DLLs are loaded from the system directory. This requires using a detour library like Microsoft Detours to intercept the calls.
Here's a simplified example:
uses Windows; type TLoadLibraryW = function(lpLibFileName: PWideChar): HMODULE; stdcall; var OriginalLoadLibraryW: TLoadLibraryW; function HookedLoadLibraryW(lpLibFileName: PWideChar): HMODULE; stdcall; var SystemDir: array[0..MAX_PATH] of WideChar; FullSystemPath: array[0..MAX_PATH] of WideChar; begin // Check if we're loading a system DLL (customize this list as needed) if SameText(lpLibFileName, 'version.dll') then begin GetSystemDirectoryW(SystemDir, MAX_PATH); wsprintfW(FullSystemPath, '%s\%s', [SystemDir, lpLibFileName]); Result := OriginalLoadLibraryW(FullSystemPath); end else // For non-system DLLs, use the original load logic Result := OriginalLoadLibraryW(lpLibFileName); end; initialization // Get pointer to original LoadLibraryW OriginalLoadLibraryW := GetProcAddress(GetModuleHandleW('kernel32.dll'), 'LoadLibraryW'); // Install detour (requires Microsoft Detours library) // DetourAttach(PVOID(@OriginalLoadLibraryW), PVOID(@HookedLoadLibraryW)); finalization // Remove detour when app exits // DetourDetach(PVOID(@OriginalLoadLibraryW), PVOID(@HookedLoadLibraryW));
Important Considerations:
- The
SetDefaultDllDirectoriesmethod is the most recommended for modern apps—it's lightweight, OS-native, and covers all system DLLs without needing to list them individually. - Always test your app on all target Windows versions to ensure compatibility, especially if you support older systems like Windows XP.
- Avoid breaking legitimate DLLs your app needs to load from its own directory—these methods target system DLLs, but double-check your app's dependencies to ensure you don't block required files.
内容的提问来源于stack exchange,提问作者Anto Raja Prakash

