Geoff Chappell, Software Analyst
This function opens the registry key for reading a given executable’s Image File Execution Options.
NTSTATUS LdrOpenImageFileOptionsKey ( PUNICODE_STRING lpImageFile, BOOLEAN bWow64, HANDLE *phKey);
The lpImageFile argument names the executable image for which the key is sought.
The bWow64 argument is non-zero to get the key from the Wow6432Node branch. This argument is ignored in version 6.1 and higher.
The phKey argument is the address of a variable that is to receive a handle to the opened key.
The function returns STATUS_SUCCESS if successful, else a negative error code.
The LdrOpenImageFileOptionsKey function is exported by name from NTDLL.DLL in version 5.2 starting from Windows Server 2003 SP1, and higher.
In version 6.0 and higher, the name LdrOpenImageFileOptionsKey exists just for export. Were the function not exported, it would be an internal routine whose only name is RtlOpenImageFileOptionsKey. As usual for Run Time Library (RTL) routines, the code is written for both kernel and user modes. The kernel has this routine since version 6.0 and exports it without the name change starting with the 1709 release of version 10.0.
The LdrOpenImageFileOptionsKey function is not documented. Neither is it declared in any C-language header that Microsoft is known to have published in any development kit for either user-mode or kernel-mode software. While Microsoft’s names and types for the function’s arguments are not known, this article uses inventions.
From all the way back at version 3.10, NTDLL has provided that executables are subject to Image File Execution Options in the registry. The options for different executables are in different subkeys of a base key named Image File Execution Options. Historically, options apply to all executables that have the same filename. In version 6.1 and higher, subkeys can reach one level deeper to define different options for different executables that have the same filename. The LdrOpenImageFileOptionsKey function opens the appropriate subkey for the named executable without the caller having to know the implementation details of these one or two levels of subkey.
Note that there is no rule that the lpImageFile argument names an executable. Strictly speaking, it just provides input for selecting a subkey of the base key. Flexibility on this point does seem deliberate: as early as the function’s introduction, NTDLL allows that any DLL’s filename can be queried as an Image File Execution Option in a subkey named DllNXOptions.
This function’s introduction for Windows Server 2003 SP1 comes from NTDLL exporting separate functions (that had developed as internal routines in version 5.1) for opening the key and for querying its potentially numerous values. This LdrOpenImageFileOptionsKey function opens the key. The LdrQueryImageFileKeyOption function queries the values. The caller is expected to close the key when done. This separation leaves the ancient LdrQueryImageFileExecutionOptions and the relatively new LdrQueryImageFileExecutionOptionsEx as compounds which open the key, query one value and close the key.
For the purposes of this function, LdrOpenImageFileOptionsKey, all Image File Execution Options are in the registry at least one subkey beneath the one base key, which can be either:
Only the first is recognised in version 6.1 and higher. The second, in the Wow6432Node branch, is selected in versions 5.2 and 6.0 if the bWow64 argument is non-zero. (Remember that to 32-bit processes on 64-bit Windows, this second key appears to be the first.)
Each base key is opened on the first call that has the corresponding bWow64 argument, and is then kept open. If the base key is not already open, then this function’s failure to open it is failure for the function. The required access is KEY_QUERY_VALUE and KEY_ENUMERATE_SUB_KEYS nowadays but only the latter in version 5.2. The addition of KEY_QUERY_VALUE allows version 6.0 and higher to support global options in the base key itself, for although this function, LdrOpenImageFileOptionsKey, does not expose the base key to its callers, the compound functions LdrQueryImageFileExecutionOptions and LdrQueryImageFileExecutionOptionsEx do (by allowing that their lpImageFile argument can be NULL).
The general scheme provides for subkeys in which to specify options for different executables. The subkey for an executable is the executable’s filename. If the given lpImageFile contains a backslash, then the subkey’s name is whatever follows the last backslash. If this is too long for representation in a UNICODE_STRING, the function fails, returning STATUS_BUFFER_TOO_SMALL. Failure to open the subkey (relative to the open base key) is failure for the function. The required access is KEY_QUERY_VALUE and KEY_ENUMERATE_SUB_KEYS nowadays but GENERIC_READ in version 5.2.
In general, and as the only successful outcome in versions 5.2 and 6.0, the subkey as opened for the executable from just its filename is what the function returns at the address given by the phKey argument.
The general scheme has the problem, of course, that the same options apply to all executables that have the same filename. Version 6.1 extends the scheme to differentiate according to the whole name that is supplied for the executable. The extension is a little complicated because, of course, the whole pathname can’t itself be a subkey. If the subkey just for the filename contains a particular value (to show that the extension applies) and a suitable subkey (containing a particular value whose string data matches the executable’s whole name), then the function returns the deeper subkey instead.
Extension to a subkey for the whole name of the executable applies only if the subkey for the filename contains a REG_DWORD value named UseFilter whose dword of data is non-zero:
|Key:||HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\filename|
If the UseFilter value is absent from the subkey for an executable’s filename, or if it is present but has the wrong type or size or is zero, then all executables with this filename have the same Image File Execution Options and the subkey for the filename is what the function sticks with. Note, however, that any other failure when querying for the UseFilter value is failure for the function. (Other failure is specifically anything other than STATUS_OBJECT_NAME_NOT_FOUND, STATUS_BUFFER_TOO_SMALL or STATUS_BUFFER_OVERFLOW.)
Given that the subkey for just the filename has a correctly configured UseFilter, it may have any number of subkeys that are each for a different pathname. The names of the subkeys are immaterial. What matters is whether a subkey has a REG_SZ value named FilterFullPath whose data matches the executable’s whole name:
|Key:||HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\filename\subkey|
|Data:||executable’s case-insensitive name from lpImageFile, less any \??\ prefix|
Subkeys are ignored if they contain a FilterFullPath value that has the wrong type or has data that is too large for representation in a UNICODE_STRING or which does not match the executable. For this purpose, if the given lpImageFile begins with \??\ then what’s matched as the executable’s name is what follows this prefix. Any other error while enumerating or opening subkeys or querying FilterFullPath (once sufficient memory is obtained), including that any subkey has no FilterFullPath, is failure for the function. If every subkey has a FilterFullPath but none matches the executable’s whole name, then the function sticks with the subkey for just the filename.
The function assumes that data for the FilterFullPath value, having been established as having the REG_SZ type, is whole Unicode characters ending with a null. More precisely, it ignores the last two bytes.
When failure while seeking a subkey for the executable’s whole name becomes failure for the whole function, the handle to the subkey for the executable’s filename does not get closed.