I need to use a windows function like GetModuleHandle or GetModuleFileName to find out if a specific dll is loaded in the same process where my code is executing.
One module I'm looking for is System.Windows.Forms.dll, but even when it is loaded in process... (Here you can see it using Process Explorer)
GetModuleHandle still will not find it!
HMODULE modHandle = GetModuleHandle(L"System.Windows.Forms.dll");
GetLastError() returns ERROR_MOD_NOT_FOUND
If the function succeeds, the return value is a handle to the specified module.
If the function fails, the return value is NULL.
I think it may be something to do with how the CLR loads these dlls. I see a note on LoadLibraryEx that if the LOAD_LIBRARY_AS_DATAFILE flag is used then:
If this value is used, the system maps the file into the calling
process's virtual address space as if it were a data file. Nothing is
done to execute or prepare to execute the mapped file. Therefore, you
cannot call functions like GetModuleFileName, GetModuleHandle or
GetProcAddress with this DLL.
Maybe this is my problem, but regardless of the cause - does anyone know a way to find a managed DotNet dll in a process using native / c++ code?
Thanks!
EDIT:
Based on suggestions from Castorix in the comments I tried to use EnumProcessModules:
HMODULE modules[100];
void* hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, GetCurrentProcessId());
if (hProcess)
{
DWORD bytesNeeded;
BOOL rc = EnumProcessModules(hProcess, modules, sizeof(modules), &bytesNeeded);
if (rc)
{
int count = (int)(bytesNeeded / sizeof(HMODULE));
for (int i = 0; i < count; i++)
{
wchar_t moduleName[260];
GetModuleFileName(modules[i], moduleName, 260);
}
}
}
CloseHandle(hProcess);
This code finds a lot of the modules but not System.Windows.Forms.dll
OK, this is an attempt to an answer (or really just a too long comment, sorry).
Personally, I have never seen managed .NET DLLs in the Process Explorer pane, but might not have been looking hard / often enough. However, what I can (and always could) see are the NGENed images (*.ni.dll).
Note also the presence of System.Data.dll here, which is not NGENed, but is a mixed mode assembly and contains native code as well as managed code.
So one could conclude, that you can only see NGENed and mixed mode "assemblies" here, because they are still loaded by LoadLibrary or LoadLibraryEx.
Also note my comment, which I reproduce here for easier access:
I think the CLR does not use LoadLibrary, which would explain why you
cannot "see" them using the APIs you described. In fact,
CLR 4 Does Not Use LoadLibrary to Load Assemblies
is a blog entry that is relevant. You could always check the sources
(CoreCLR, but shouldn't matter), about how it is done in particular. I
have no really good place, but you could start
here
and then go from it. Use the ICorDebug interface instead.
Here are some relevant quotes from the blog entry linked above:
You may be asking yourself: …who cares? Well, first of all it’s good
to know. I haven’t noticed a public service announcement to the above.
It is an implementation detail, however—CLR assemblies are not even
guaranteed to be implemented using files, not to mention DLL files in
a specific format that are loaded using the LoadLibrary Win32 API.
However, there are several tools and scenarios which have come to rely
on the fact the CLR loads assemblies using LoadLibrary. For example,
up to CLR 4, if you wanted to know which .NET assemblies were loaded
in your process, a fairly reliable heuristic would be to fire up
Sysinternals Process Explorer and look at the DLLs view of a given
process. This doesn’t work for CLR 4, as you can see here:
Frankly, I don't know how Process Explorer manages to show assemblies (not NGENed and not mixed mode) in your case - appart from you are watching a CLR2 process. However, mind you that PE does not only use Win32 APIs. It also uses WMI and probably also uses the CLR directly for more information. For example, the "Process Properties/.NET Assemblies" and "Process Properties/.NET Performance" tabs most likely use ICorDebug/ICorProfile and performance counters/ETW respectively.
You might need to use on of those interfaces as well, or something else from the unmanaged Debugging API or the unmanaged API in general.
Whatever it is, I don't think that EnumProcessModules, etc. will get you there for reasons above.
To add to the above answer and provide relevant code; it was not possible to use a native function like EnumProcessModules to detect the non-ngen'ed DotNet dlls and instead I had to use c++ interfaces to the CLR.
There is a lot more info here: https://blogs.msdn.microsoft.com/calvin_hsia/2013/12/05/use-reflection-from-native-c-code-to-run-managed-code/ The code most relevant to this particular question was:
HRESULT GetAssemblyFromAppDomain(_AppDomain* pAppDomain, LPCWSTR wszAssemblyName, _Deref_out_opt_ _Assembly **ppAssembly)
{
*ppAssembly = NULL;
// get the assemblies into a safearray
SAFEARRAY *pAssemblyArray = NULL;
HRESULT hr = pAppDomain->GetAssemblies(&pAssemblyArray);
if (FAILED(hr))
{
return hr;
}
// put the safearray into a smart ptr, so it gets released
CComSafeArray<IUnknown*> csaAssemblies;
csaAssemblies.Attach(pAssemblyArray);
size_t cchAssemblyName = wcslen(wszAssemblyName);
long cAssemblies = csaAssemblies.GetCount();
for (long i=0; i<cAssemblies; i++)
{
CComPtr<_Assembly> spAssembly;
spAssembly = csaAssemblies[i];
if (spAssembly == NULL)
continue;
CComBSTR cbstrAssemblyFullName;
hr = spAssembly->get_FullName(&cbstrAssemblyFullName);
if (FAILED(hr))
continue;
// is it the one we want?
if (cbstrAssemblyFullName != NULL &&
_wcsnicmp(cbstrAssemblyFullName,
wszAssemblyName,
cchAssemblyName) == 0)
{
*ppAssembly = spAssembly.Detach();
hr = S_OK;
break;
}
}
if (*ppAssembly == 0)
{
hr = E_FAIL;
}
return hr;
}
There's some information on the CLR interfaces here:
ICLRMetaHost
ICLRRuntimeInfo
ICorRuntimeHost
_AppDomain
_Assembly
Related
If I do
LoadLibrary("MyTest.dll")
Windows will locate and load it from "C:\TestFolder\Test\MyTest.dll", because "C:\TestFolder\Test\" is in %PATH% folder.
How can I emulate same function? I need to locate C:\TestFolder\Test\MyTest.dll (C:\TestFolder\Test\ is in %PATH%) by passing MyTest.dll as an argument to a function. Is there such an API? or a function?
P.S. I can't do LoadLibrary and then GetModuleHandle and finding Path, sometimes this DLL could be malicious DLL and I can't load it. So I need to find PATH without having to load it.
To load the DLL without running any malicious code inside, use LoadLibraryEx with the DONT_RESOLVE_DLL_REFERENCES and LOAD_LIBRARY_AS_DATAFILE flags.
Then you can use GetModuleFileName.
You should also read about all the other flags, which allow you to perform all the various searches Windows is capable of.
The accepted answer to this question will not work in all scenarios. More specifically, using GetModuleFileName together with LOAD_LIBRARY_AS_DATAFILE will only work if the library was already loaded prior without this flag. For example, it will work for a library like KERNEL32.DLL which is already loaded by the process, but it will not work with your own library being loaded into the process for the first time.
This is because, to quote The Old New Thing, a library loaded via LOAD_LIBRARY_AS_DATAFILE (or similar flags) doesn't get to play in any reindeer module games.
If you load a library with the LOAD_LIBRARY_AS_DATAFILE flag, then it
isn’t really loaded in any normal sense. In fact, it’s kept completely
off the books. If you load a library with the
LOAD_LIBRARY_AS_DATAFILE, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE, or
LOAD_LIBRARY_AS_IMAGE_RESOURCE flag (or any similar flag added in the
future), then the library gets mapped into the process address space,
but it is not a true module. Functions like GetModuleHandle,
GetModuleFileName, EnumProcessModules and
CreateToolhelp32Snapshot will not see the library, because it was
never entered into the database of loaded modules.
At that point, you might as well just use GetModuleHandle, since it'll only work with previously loaded libraries. Obviously not ideal, and doesn't actually answer the question of getting the path without executing DllMain.
What about the other flag, DONT_RESOLVE_DLL_REFERENCES? Well, technically yes it will work. However, you'll notice in the Microsoft documentation the following note.
Do not use this value; it is provided only for backward compatibility.
If you are planning to access only data or resources in the DLL, use
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE or LOAD_LIBRARY_AS_IMAGE_RESOURCE
or both.
The flag is only provided for backwards compatibility, and that is for good reason. To quote The Old New Thing a second time, DONT_RESOLVE_DLL_REFERENCES is a time bomb.
It is common for somebody to call GetModuleHandle to see if a DLL is
loaded, and if so, use GetProcAddress to get a procedure address and
call it. If the DLL had been loaded with DONT_RESOLVE_DLL_REFERENCES,
both the GetModuleHandle will succeed, but the resulting function will
crash when called. The code doing this has no idea that the DLL was
loaded with DONT_RESOLVE_DLL_REFERENCES; it has no way of protecting
itself.
Other threads will see the library is loaded. If they attempt to use the loaded library, as would be entirely normal to do, they will crash the program because it has not actually been initialized. So this flag, while it does work with GetModuleFileName, will cause instability in the program. Still not ideal.
So then, if we can't use DONT_RESOLVE_DLL_REFERENCES or LOAD_LIBRARY_AS_DATAFILE with GetModuleFileName, then what is the solution? Well, the solution is to not use GetModuleFileName - and instead use GetMappedFileName.
At this point, if you know what GetMappedFileName does, you may be confused. Normally, GetMappedFileName is used to get a filename from a File Mapping, created with the File Mapping API. Well, the secret is that under the hood, image loading is accomplished with MapViewOfFile. This is subtly hinted at by the Dbghelp documentation - for example, the ImageNtHeader documentation which states an image base must be...
The base address of an image that is mapped into memory by a call to
the MapViewOfFile function.
This means that not only is a module handle a pointer to a module, but also a mapped file pointer. Unlike GetModuleFileName however, GetMappedFileName has no concept of "the reindeer module games," so it works even with the LOAD_LIBARY_AS_DATAFILE flag of LoadLibraryEx. Not only that, but GetMappedFileName has an additional benefit over GetModuleFileName.
Something you might not know is that simply loading a library with LoadLibrary does not exclusively lock the DLL file. Try it yourself: write a simple program which loads your own library with LoadLibrary, and then while the program is running, cut and paste the DLL file to a different location. This will work (and yes, has always worked regardless of Windows version) so long as no other application has a lock on the DLL file. The File Mapping API just keeps on chugging, regardless of the DLL file's new location.
However, when you call GetModuleFileName, it will always return the path of the DLL file as of whenever the library was loaded with LoadLibrary. This has security ramifications. It would be possible to cut and paste the DLL file to a new location, and put a different one at the old location. If the path returned by GetModuleFileName is used to load the library again, it could actually result in loading a different DLL file altogether. As such, GetModuleFileName is only useful for the purpose of displaying the name or getting the DLL file name passed to LoadLibrary, and can't be depended upon for the current file path.
GetMappedFileName has no such issue, because it has no concept of when LoadLibrary was called. It returns an up to date path to the file, even if it has been moved while it's loaded.
There is one minor downside though: GetMappedFileName returns a device path, in the format of \Device\HarddiskVolume1\Example.DLL. This appears to be due to the File Mapping API originally being from DOS - why a "GetMappedFileNameEx" that returns a drive path doesn't exist is beyond me.
Thankfully, it's a resolvable issue. We can use QueryDosDevice to turn the device path into a drive path.
bool getFilePathNameFromMappedView(HANDLE process, LPVOID mappedView, std::string &filePathName) {
if (!process) {
return false;
}
if (!mappedView) {
return false;
}
CHAR mappedFileName[MAX_PATH] = "";
if (!GetMappedFileName(process, mappedView, mappedFileName, MAX_PATH - 1)) {
return false;
}
// the mapped file name is a device path, we need a drive path
// https://learn.microsoft.com/en-us/windows/win32/fileio/defining-an-ms-dos-device-name
const SIZE_T DEVICE_NAME_SIZE = 3;
CHAR deviceName[DEVICE_NAME_SIZE] = "A:";
// the additional character is for the trailing slash we add
size_t targetPathLength = 0;
CHAR targetPath[MAX_PATH + 1] = "";
// find the MS-DOS Device Name
DWORD logicalDrives = GetLogicalDrives();
do {
if (logicalDrives & 1) {
if (!QueryDosDevice(deviceName, targetPath, MAX_PATH - 1)) {
return false;
}
// add a trailing slash
targetPathLength = strnlen_s(targetPath, MAX_PATH);
targetPath[targetPathLength++] = '\\';
// compare the Target Path to the Device Object Name in the Mapped File Name
// case insensitive
// https://flylib.com/books/en/4.168.1.23/1/
if (!_strnicmp(targetPath, mappedFileName, targetPathLength)) {
break;
}
}
deviceName[0]++;
} while (logicalDrives >>= 1);
if (!logicalDrives) {
return false;
}
// get the drive path
filePathName = std::string(deviceName) + "\\" + (mappedFileName + targetPathLength);
return true;
}
GetLogicalDrives just gets a list of which drives are available (like C:, D:, etc.) in the form of a bitmask (where the first bit corresponds to A:, the second bit corresponds to B:, etc.) We then loop through the available drives, getting their paths, and comparing them against the one in the Mapped File Name. The result of this function is a path that could be passed to the CreateFile function.
The only source I could find for whether these device paths are case-insensitive or not was this book claiming that they used to be case-sensitive, but are case-insensitive as of Windows XP. I'm going to assume you are not targeting Windows 9x anymore, so I just compare them case-insensitively.
Hold on a second though: this still may not be enough. If your intention is, as mine was, to try and get a file handle to the DLL file, but using the DLL search path, then just getting the path and passing it to CreateFile opens us up to a filesystem race condition, like the kind explained in this LiveOverflow video. A technique like this could be abused by a hacker so the handle doesn't actually point to the file we want. There isn't any GetMappedFileHandle function, so what can we do?
I thought about this for a while, and here is the workaround I came up with. The idea is that we call our own getFilePathNameFromMappedView function once just to get the path to pass to CreateFile, and exclusively lock the file in place with the FILE_SHARE_READ flag. However, we then confirm, with a second call to getFilePathNameFromMappedView, that the file is still actually there. If the paths match, knowing that the file at that path is now locked, we can know for sure the handle we got is to the library that was actually loaded. If the file was moved before the call to CreateFile finished, however, the paths will not match, because GetMappedFileName returns the up to date path to the file. At that point, we can try again. I decided to do this as a recursive function, but you could decide to throw an error and have the caller handle it.
inline bool stringsCaseInsensitiveEqual(const char* leftHandSide, const char* rightHandSide) {
return !_stricmp(leftHandSide, rightHandSide);
}
bool getHandleFromModuleHandle(HMODULE moduleHandle, HANDLE &file) {
if (!moduleHandle) {
return false;
}
HANDLE currentProcess = GetCurrentProcess();
// pass the Module Handle as a Mapped View
// to get its current path
std::string filePathName = "";
if (!getFilePathNameFromMappedView(currentProcess, moduleHandle, filePathName)) {
return false;
}
// prevent the Example File from being written to, moved, renamed, or deleted
// by acquiring it and effectively locking it from other processes
file = CreateFile(filePathName.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (!file || file == INVALID_HANDLE_VALUE) {
return false;
}
bool recursive = false;
{
// we now know this path is now protected against race conditions
// but the path may have changed before we acquired it
// so ensure the File Path Name is the same as before
// so that we know the path we protected is for the Mapped View
std::string _filePathName = "";
if (!getFilePathNameFromMappedView(currentProcess, moduleHandle, _filePathName)) {
goto error;
}
if (!stringsCaseInsensitiveEqual(filePathName.c_str(), _filePathName.c_str())) {
// race condition occured
recursive = true;
goto error;
}
}
return true;
error:
if (file && file != INVALID_HANDLE_VALUE) {
if (!CloseHandle(file)) {
return false;
}
file = NULL;
}
if (recursive) {
return getHandleFromModuleHandle(moduleHandle, file);
}
return false;
}
Then we can call it like this...
HMODULE exampleModuleHandle = LoadLibraryEx("Example.DLL", NULL, LOAD_LIBRARY_AS_DATAFILE);
if (!exampleModuleHandle) {
return false;
}
// we want this to be a handle to the Example File
HANDLE exampleFile = NULL;
if (!getHandleFromModuleHandle(exampleModuleHandle, exampleFile)) {
return false;
}
This is just something I thought of, so let me know in the responses if there are issues with it.
Once you have a handle to the file, it can then be passed to GetFileInformationByHandle to confirm it is the same library as is loaded in another process, and subsequently closed with CloseHandle.
Short:
In my c++ project i need to read/write extended file properties. I managed it with using alternate data streams (ADS). My problem is, for opening the ADS i need to use the CreateFile API. But it is not fulfilling my needs. NtCreateFile will fullfill all my needs. (Or alternatively NtSetEaFile and NtQueryEaFile) But NtCreateFile is not directly accessible from a win32 console application.
I know i can use this function easily via GetProcAdress. But i like to know the opinion of you all, if i did miss something? Some other libs are using this pattern already, for example Chromium (https://github.com/chromium-googlesource-mirror/chromium/blob/1c1996b75d3611f56d14e2b30e7ae4eabc101486/src/sandbox/src/win_utils.cc function: ResolveNTFunctionPtr)
But im uncertain, because the c++ project is not a hobby project and i ask myself if it is dangerous or not.
I guess NtCreateFile is maybe the securest way to do, because it is well documented and supported by winternl.h header. Especially because this method is unchanged since windows 2000. But what is with NtSetEaFile, NtQueryEaFile which are fitting my needs perfectly. They are only half documented. A documentation for ZwSetEaFile and ZwQueryEaFile exist (unchanged since windows 2000).
Reason why i want to do that:
I want to write and read extended properties from files via ADS. But in case of writing the extended property of a given file the first time, i need to open the file with OPEN_ALWAYS. In case of file is not existing it will create a new file, even if i only access not the content stream of the file. To avoid this i get first the handle of the original file and check with this HANDLE if the file still exist.
But i dont want to blog any file with reduced access rights, because from my point of view that is a very bad pattern. The user needs to have full access to any file any time. Because of that we open all HANDLES with the flag FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE. And now i have the race.
auto hFile = CreateFileW(originalPath, …, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, …).
// this is the little race: if somebody at least rename originalPath the
// second CreateFileW call will cause the creation of a empty file with the
// path originalPath (the old path).
auto hADS = CreateFileW(originalPath + adsName, …, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_ALWAYS, …).
This is a main issue, especially because this happens from time to time in our tests. NtCreateFile will fix it, because i can create the second HANDLE with the help of the first HANDLE. Because of that no race. Or NtSetEaFile and NtQueryEaFile will help, because i only need one HANDLE.
The thing is, that the application needs not to be save for the future, because ADS works only on NTFS anyway. And who knows when NTFS will be exchanged. But i dont want a flaky behaviour. I want to trust this Methods. I I am fine if the API will change in the future and the software needs to adapt to it. But i want to be sure, that all Windows higher or equal then 7 can deal with it. Somebody some experience to share? I would like to hear them very much.
This question is wrong. Your proposed solution for your problem, is not using NtCreateFile, but use CreateFile with dwCreationDisposition set to the OPEN_EXISTING.
From documentation:
OPEN_EXISTING
Opens a file or device, only if it exists. If the specified file or
device does not exist, the function fails and the last-error code is
set to ERROR_FILE_NOT_FOUND.
Simply open file if exists and set whatever you want. If file is renamed, CreateFile returns ERROR_FILE_NOT_FOUND.
THE PROBLEM
Now, to your proposed solution, what is better method or why is not possible use ntdll.dll in win32 console application (???).
Again, your "better" method - GetProcAddress is "wrong" same as using linking against ntdll.dll. In Windows 11, or Windows 12 or Windows 3030 the function may be removed and both solutions (statical vs. dynamical import) will be fail.
It is not really unsecure to use this kind of APIs if their is a documentation. In case of NtSetEaFile, NtQueryEaFile and NtCreateFile you can find a description inside of Microsoft's Doc. (keep in mind NtXxx == ZwXxx)
But this API can change in the future and Microsoft does not guarantee that it will provides the same methods in the next Windows version. If you can, use the public API, because then you are safe. If not it is a case by case decision. In this case the three methods from the API are unchanged since Windows2000. Plus for example NtSetEaFile and NtQueryEaFile is used by Microsoft for WSL (Windows Subsystem for Linux). And especially NtCreateFile is used by a wide range of OpenSource Projects. So it is very unlikely that this API will change.
In my use case another aspect is important. Because I wanted to use ADS, but ADS is only supported by NTFS. So using ADS does not ensure future compatibility as well. So it was very clear for me using NtSetEaFile and NtQueryEaFile.
But how you can use this kind of APIs? Dynamic or static linking is possible. It depends on your needs what is better. In case of static linking you need to download the last WDK (Windows Driver Kit) and link against the ntdll.lib. In case of dynamic linking you can access the dll directly via GetModuleHandle and finding out the address of the method with GetProcAddress. Under Windows ntdll.dll is accessible from any application. In both cases you don't have directly a header file. You have to define the header file by yourself or use WDK to get them.
In my project dynamic linking was the best choice. The reason was, that on every windows the right implementation will be choosen and in case the method is not available i have the chance to deactivate the feature in my software instead of crash. Microsoft is recommending the dynamic way, because of the last reason.
Simple PseudoCode (dynamic case):
typedef struct _FILE_FULL_EA_INFORMATION {
ULONG NextEntryOffset;
UCHAR Flags;
UCHAR EaNameLength;
USHORT EaValueLength;
CHAR EaName[1];
} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION;
typedef struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status;
PVOID Pointer;
};
ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
typedef NTSTATUS(WINAPI *NtSetEaFileFunction)(IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK
IoStatusBlock,
IN PVOID Buffer,
IN ULONG Length);
HMODULE ntdll = GetModuleHandle(L"ntdll.dll");
NtSetEaFileFunction function = nullptr;
FARPROC *function_ptr = reinterpret_cast<FARPROC *>(&function);
*function_ptr = GetProcAddress(ntdll, "NtQueryEaFile");
// function could be used normally.
The other answer is incorrect. The reason is that the reason of my problem is, that I need to use OPEN_ALWAYS. Of course, if you don't need this flag, everything is fine. But in my case there is a point where I needed to create the ADS. And it will not be created without the OPEN_ALWAYS flag.
Sorry, if it's too broad of a question. I'm trying to see what exactly SetProcessMitigationPolicy function does in Windows 10, but I can't find much about it online (besides my previous forays into this subject.) I'm testing its PROCESS_MITIGATION_POLICY options one-by-one, and I have some questions about these:
ProcessSystemCallDisablePolicy states that it "Disables the ability to use NTUser/GDI functions at the lowest layer.". So I'm testing it as such:
PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY pmscdp = {0};
pmscdp.DisallowWin32kSystemCalls = 1;
BOOL bR = ::SetProcessMitigationPolicy(ProcessSystemCallDisablePolicy, &pmscdp, sizeof(pmscdp));
int err = ::GetLastError();
::GdiFlush(); //Try to trip it here
But it always fails with error code 19, or ERROR_WRITE_PROTECT.
So what exactly is it supposed to do and how do I set it?
ProcessExtensionPointDisablePolicy states that it "... prevents legacy extension point DLLs from being loaded into the process."
PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY pmepdp = {0};
pmepdp.DisableExtensionPoints = 1;
BOOL bR = ::SetProcessMitigationPolicy(ProcessExtensionPointDisablePolicy, &pmepdp, sizeof(pmepdp));
int err = ::GetLastError();
Sorry for my naivete, but what is the extension point DLL? And how can I test one?
ProcessSignaturePolicy states that it can "restrict image loading to those images that are either signed by Microsoft, by the Windows Store, or by Microsoft, the Windows Store and the Windows Hardware Quality Labs (WHQL)".
First off, it seems to have no effect on CreateProcess and only works with LoadLibrary-type functions. So if I do this:
PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY pmbsp = {0};
pmbsp.MicrosoftSignedOnly = 1;
//pmbsp.StoreSignedOnly = 1; //always seems to fail with this flag
//pmbsp.MitigationOptIn = 1; //Doesn't seem to have any effect
BOOL bR = ::SetProcessMitigationPolicy(ProcessSignaturePolicy, &pmbsp, sizeof(pmbsp));
BOOL err = ::GetLastError();
And then try to load some of my test DLLs:
HMODULE hModDll = ::LoadLibrary(L".\\Dll1.dll");
The LoadLibrary function fails with the MessageBox that reads:
Bad Image
Dll-Name is either not designed to run on Windows or it
contains an error. Try installing the program again using the original
installation media or contact your system administrator or the
software vendor for support. Error status 0xc0000428.
Interestingly, if I call it on some System32 DLL that is not signed:
HMODULE hModDll = ::LoadLibrary(L"iologmsg.dll");
it seems to work fine. But if I place a copy of my test Dll1.dll into System32 folder and load it this way:
HMODULE hModDll = ::LoadLibrary(L"Dll1_.dll");
it still fails with the same message box:
This is interesting. How can it tell the difference between iologmsg.dll and Dll1_.dll? Both files aren't signed.
PS. And that modal message box can throw in a really nasty wrench into the mix if the app (or the service) does not expect any UI to be shown there.
ProcessFontDisablePolicy lastly, I'm totally lost about this one. It states that it "turns off the ability of the process to load non-system fonts."
So after I enable it in my MFC GUI app:
PROCESS_MITIGATION_FONT_DISABLE_POLICY pmfdp = {0};
pmfdp.DisableNonSystemFonts = 1;
BOOL bR = ::SetProcessMitigationPolicy(ProcessFontDisablePolicy, &pmfdp, sizeof(pmfdp));
int err = ::GetLastError();
the app has a Richedit control that I can load a custom font in. So I went online and downloaded a totally random font. Then installed it in Windows Explorer and tried to use it from the app after that policy has been enabled:
//Set format for the text window
CHARFORMAT cf = { 0 };
cf.cbSize = sizeof(cf);
cf.dwMask = CFM_FACE | CFM_SIZE;
cf.yHeight = 18 * 20;
VERIFY(SUCCEEDED(::StringCchCopy(cf.szFaceName, _countof(cf.szFaceName), L"Action Man")));
VERIFY(SetDefaultCharFormat(cf));
The app was able to display and use that (clearly non-system) font without any issues:
So what am I missing here in that policy?
This is guessing, but since many links in the function's documentation are 404s, I believe that the following would be valid:
1.Probably not implemented, yet.
2.Only a guess (since the link is also 404), but it might refer to DLLs used in obsolete situtations (like the XP and below login DLL, replaced in Vista with Credential Providers).
3.Windows DLLs are treated as signed (without actually having a digital signature attached), not only because they reside in System32, but because Windows keeps internally a map for them. For your DLLs, it won't work. Also, this has no point in CreateProcess() because the new process cannot interact with yours (without your knowledge) and, therefore, cannot hijack it, where a DLL loaded with LoadLibrary can do anything to ruin your process.
4.It probably refers to fonts not installed by Explorer, but fonts added with AddFontResource.
I have an application that relies heavily on plugins.
On startup it scans a directory for DLLs and loads them one by one, looking for ones that implement a certain exported function. However - if someone were to rename a different type of file to *.dll and put it in the directory, that file would then also be loaded by LoadLibrary(). LoadLibrary() doesn't like that and produces an error [dialog].
Is there a way to simply ignore invalid / incompatible .dll files (either detecting them prior to the call or have LoadLibrary() return NULL rather than throwing a fit)?
You need to set the error mode for your process. Do this once and for all at startup:
UINT oldMode = SetErrorMode(0);
SetErrorMode(oldMode | SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
After you've set the process error mode, when LoadLibrary fails no dialog box will be displayed and LoadLibrary will return NULL.
The documentation says:
Best practice is that all applications call the process-wide SetErrorMode function with a parameter of SEM_FAILCRITICALERRORS at startup. This is to prevent error mode dialogs from hanging the application.
I also recommend adding SEM_NOOPENFILEERRORBOX for reasons that I guess should be obvious.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms684175%28v=vs.85%29.aspx
Remarks
To enable or disable error messages displayed by the loader during DLL loads, use the SetErrorMode function.
Don't forget to restore the error mode after you are finished.
If you wanted to do this yourself, in a primitive manner you could parse the PE header to identify obvious cases of bad DLL files, however it is not really possible to determine if a DLL is valid and loadable without a full PE loader which requires a lot of work and is already built into the operating system.
Updated answer after feedback in comments from djgandy and Remy Lebeau. Now a complete
function, better preservation of error mode at entry:
// This function will load the DLL named by pszPath if it is a valid library.
// If the function succeeds, it will return a valid HMODULE for the DLL. This
// handle should be passed to FreeLibrary when it is no longer needed.
// If the function fails, it will return NULL and no annoying dialog boxes will
// be displayed. It is therefore up to the caller to notify the user about what
// happened or take any other appropriate action. The reason for failure can
// be obtained from GetLastError(). Common problems:
// ERROR_BAD_EXE_FORMAT - Bad DLL (tested function with text file)
// ERROR_MOD_NOT_FOUND - Missing DLL (tested with file that did not exist)
//
// Module-loading functions can return several other errors, look at winerror.h
// list starting at ERROR_INVALID_MODULETYPE
//
// Obviously, since it's just a wrapper around LoadLibrary this function is not
// safe to call from DllMain.
//
// NB: GetErrorMode() is only available on Vista / Server 2003 or later.
HMODULE LoadLibraryIfValid(LPCTSTR pszPath)
{
HMODULE hModule = NULL;
UINT prevErrorMode = GetErrorMode();
SetErrorMode(prevErrorMode | SEM_FAILCRITICALERRORS);
hModule = LoadLibrary(pszPath);
SetErrorMode(prevErrorMode);
return hModule;
}
If targeting Windows 7 / Server 2008 R2 or later, the Get/SetThreadErrorMode()
functions are available, but might not be worth it or even a good alternative
(discussion in comments, below)
If anyone cared enough to put the time into it (I sure don't), a version of
this function could easily be written using GetModuleHandle for kernel32 and
GetProcAddress to be compatible with earlier versions of Windows as well as
provide a global/per-thread error mode option for platforms that support it
(truly pointless because it's only changed for the duration of one call anyway).
This is the largest commentary-to-code ratio in my life.
If I do
LoadLibrary("MyTest.dll")
Windows will locate and load it from "C:\TestFolder\Test\MyTest.dll", because "C:\TestFolder\Test\" is in %PATH% folder.
How can I emulate same function? I need to locate C:\TestFolder\Test\MyTest.dll (C:\TestFolder\Test\ is in %PATH%) by passing MyTest.dll as an argument to a function. Is there such an API? or a function?
P.S. I can't do LoadLibrary and then GetModuleHandle and finding Path, sometimes this DLL could be malicious DLL and I can't load it. So I need to find PATH without having to load it.
To load the DLL without running any malicious code inside, use LoadLibraryEx with the DONT_RESOLVE_DLL_REFERENCES and LOAD_LIBRARY_AS_DATAFILE flags.
Then you can use GetModuleFileName.
You should also read about all the other flags, which allow you to perform all the various searches Windows is capable of.
The accepted answer to this question will not work in all scenarios. More specifically, using GetModuleFileName together with LOAD_LIBRARY_AS_DATAFILE will only work if the library was already loaded prior without this flag. For example, it will work for a library like KERNEL32.DLL which is already loaded by the process, but it will not work with your own library being loaded into the process for the first time.
This is because, to quote The Old New Thing, a library loaded via LOAD_LIBRARY_AS_DATAFILE (or similar flags) doesn't get to play in any reindeer module games.
If you load a library with the LOAD_LIBRARY_AS_DATAFILE flag, then it
isn’t really loaded in any normal sense. In fact, it’s kept completely
off the books. If you load a library with the
LOAD_LIBRARY_AS_DATAFILE, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE, or
LOAD_LIBRARY_AS_IMAGE_RESOURCE flag (or any similar flag added in the
future), then the library gets mapped into the process address space,
but it is not a true module. Functions like GetModuleHandle,
GetModuleFileName, EnumProcessModules and
CreateToolhelp32Snapshot will not see the library, because it was
never entered into the database of loaded modules.
At that point, you might as well just use GetModuleHandle, since it'll only work with previously loaded libraries. Obviously not ideal, and doesn't actually answer the question of getting the path without executing DllMain.
What about the other flag, DONT_RESOLVE_DLL_REFERENCES? Well, technically yes it will work. However, you'll notice in the Microsoft documentation the following note.
Do not use this value; it is provided only for backward compatibility.
If you are planning to access only data or resources in the DLL, use
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE or LOAD_LIBRARY_AS_IMAGE_RESOURCE
or both.
The flag is only provided for backwards compatibility, and that is for good reason. To quote The Old New Thing a second time, DONT_RESOLVE_DLL_REFERENCES is a time bomb.
It is common for somebody to call GetModuleHandle to see if a DLL is
loaded, and if so, use GetProcAddress to get a procedure address and
call it. If the DLL had been loaded with DONT_RESOLVE_DLL_REFERENCES,
both the GetModuleHandle will succeed, but the resulting function will
crash when called. The code doing this has no idea that the DLL was
loaded with DONT_RESOLVE_DLL_REFERENCES; it has no way of protecting
itself.
Other threads will see the library is loaded. If they attempt to use the loaded library, as would be entirely normal to do, they will crash the program because it has not actually been initialized. So this flag, while it does work with GetModuleFileName, will cause instability in the program. Still not ideal.
So then, if we can't use DONT_RESOLVE_DLL_REFERENCES or LOAD_LIBRARY_AS_DATAFILE with GetModuleFileName, then what is the solution? Well, the solution is to not use GetModuleFileName - and instead use GetMappedFileName.
At this point, if you know what GetMappedFileName does, you may be confused. Normally, GetMappedFileName is used to get a filename from a File Mapping, created with the File Mapping API. Well, the secret is that under the hood, image loading is accomplished with MapViewOfFile. This is subtly hinted at by the Dbghelp documentation - for example, the ImageNtHeader documentation which states an image base must be...
The base address of an image that is mapped into memory by a call to
the MapViewOfFile function.
This means that not only is a module handle a pointer to a module, but also a mapped file pointer. Unlike GetModuleFileName however, GetMappedFileName has no concept of "the reindeer module games," so it works even with the LOAD_LIBARY_AS_DATAFILE flag of LoadLibraryEx. Not only that, but GetMappedFileName has an additional benefit over GetModuleFileName.
Something you might not know is that simply loading a library with LoadLibrary does not exclusively lock the DLL file. Try it yourself: write a simple program which loads your own library with LoadLibrary, and then while the program is running, cut and paste the DLL file to a different location. This will work (and yes, has always worked regardless of Windows version) so long as no other application has a lock on the DLL file. The File Mapping API just keeps on chugging, regardless of the DLL file's new location.
However, when you call GetModuleFileName, it will always return the path of the DLL file as of whenever the library was loaded with LoadLibrary. This has security ramifications. It would be possible to cut and paste the DLL file to a new location, and put a different one at the old location. If the path returned by GetModuleFileName is used to load the library again, it could actually result in loading a different DLL file altogether. As such, GetModuleFileName is only useful for the purpose of displaying the name or getting the DLL file name passed to LoadLibrary, and can't be depended upon for the current file path.
GetMappedFileName has no such issue, because it has no concept of when LoadLibrary was called. It returns an up to date path to the file, even if it has been moved while it's loaded.
There is one minor downside though: GetMappedFileName returns a device path, in the format of \Device\HarddiskVolume1\Example.DLL. This appears to be due to the File Mapping API originally being from DOS - why a "GetMappedFileNameEx" that returns a drive path doesn't exist is beyond me.
Thankfully, it's a resolvable issue. We can use QueryDosDevice to turn the device path into a drive path.
bool getFilePathNameFromMappedView(HANDLE process, LPVOID mappedView, std::string &filePathName) {
if (!process) {
return false;
}
if (!mappedView) {
return false;
}
CHAR mappedFileName[MAX_PATH] = "";
if (!GetMappedFileName(process, mappedView, mappedFileName, MAX_PATH - 1)) {
return false;
}
// the mapped file name is a device path, we need a drive path
// https://learn.microsoft.com/en-us/windows/win32/fileio/defining-an-ms-dos-device-name
const SIZE_T DEVICE_NAME_SIZE = 3;
CHAR deviceName[DEVICE_NAME_SIZE] = "A:";
// the additional character is for the trailing slash we add
size_t targetPathLength = 0;
CHAR targetPath[MAX_PATH + 1] = "";
// find the MS-DOS Device Name
DWORD logicalDrives = GetLogicalDrives();
do {
if (logicalDrives & 1) {
if (!QueryDosDevice(deviceName, targetPath, MAX_PATH - 1)) {
return false;
}
// add a trailing slash
targetPathLength = strnlen_s(targetPath, MAX_PATH);
targetPath[targetPathLength++] = '\\';
// compare the Target Path to the Device Object Name in the Mapped File Name
// case insensitive
// https://flylib.com/books/en/4.168.1.23/1/
if (!_strnicmp(targetPath, mappedFileName, targetPathLength)) {
break;
}
}
deviceName[0]++;
} while (logicalDrives >>= 1);
if (!logicalDrives) {
return false;
}
// get the drive path
filePathName = std::string(deviceName) + "\\" + (mappedFileName + targetPathLength);
return true;
}
GetLogicalDrives just gets a list of which drives are available (like C:, D:, etc.) in the form of a bitmask (where the first bit corresponds to A:, the second bit corresponds to B:, etc.) We then loop through the available drives, getting their paths, and comparing them against the one in the Mapped File Name. The result of this function is a path that could be passed to the CreateFile function.
The only source I could find for whether these device paths are case-insensitive or not was this book claiming that they used to be case-sensitive, but are case-insensitive as of Windows XP. I'm going to assume you are not targeting Windows 9x anymore, so I just compare them case-insensitively.
Hold on a second though: this still may not be enough. If your intention is, as mine was, to try and get a file handle to the DLL file, but using the DLL search path, then just getting the path and passing it to CreateFile opens us up to a filesystem race condition, like the kind explained in this LiveOverflow video. A technique like this could be abused by a hacker so the handle doesn't actually point to the file we want. There isn't any GetMappedFileHandle function, so what can we do?
I thought about this for a while, and here is the workaround I came up with. The idea is that we call our own getFilePathNameFromMappedView function once just to get the path to pass to CreateFile, and exclusively lock the file in place with the FILE_SHARE_READ flag. However, we then confirm, with a second call to getFilePathNameFromMappedView, that the file is still actually there. If the paths match, knowing that the file at that path is now locked, we can know for sure the handle we got is to the library that was actually loaded. If the file was moved before the call to CreateFile finished, however, the paths will not match, because GetMappedFileName returns the up to date path to the file. At that point, we can try again. I decided to do this as a recursive function, but you could decide to throw an error and have the caller handle it.
inline bool stringsCaseInsensitiveEqual(const char* leftHandSide, const char* rightHandSide) {
return !_stricmp(leftHandSide, rightHandSide);
}
bool getHandleFromModuleHandle(HMODULE moduleHandle, HANDLE &file) {
if (!moduleHandle) {
return false;
}
HANDLE currentProcess = GetCurrentProcess();
// pass the Module Handle as a Mapped View
// to get its current path
std::string filePathName = "";
if (!getFilePathNameFromMappedView(currentProcess, moduleHandle, filePathName)) {
return false;
}
// prevent the Example File from being written to, moved, renamed, or deleted
// by acquiring it and effectively locking it from other processes
file = CreateFile(filePathName.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (!file || file == INVALID_HANDLE_VALUE) {
return false;
}
bool recursive = false;
{
// we now know this path is now protected against race conditions
// but the path may have changed before we acquired it
// so ensure the File Path Name is the same as before
// so that we know the path we protected is for the Mapped View
std::string _filePathName = "";
if (!getFilePathNameFromMappedView(currentProcess, moduleHandle, _filePathName)) {
goto error;
}
if (!stringsCaseInsensitiveEqual(filePathName.c_str(), _filePathName.c_str())) {
// race condition occured
recursive = true;
goto error;
}
}
return true;
error:
if (file && file != INVALID_HANDLE_VALUE) {
if (!CloseHandle(file)) {
return false;
}
file = NULL;
}
if (recursive) {
return getHandleFromModuleHandle(moduleHandle, file);
}
return false;
}
Then we can call it like this...
HMODULE exampleModuleHandle = LoadLibraryEx("Example.DLL", NULL, LOAD_LIBRARY_AS_DATAFILE);
if (!exampleModuleHandle) {
return false;
}
// we want this to be a handle to the Example File
HANDLE exampleFile = NULL;
if (!getHandleFromModuleHandle(exampleModuleHandle, exampleFile)) {
return false;
}
This is just something I thought of, so let me know in the responses if there are issues with it.
Once you have a handle to the file, it can then be passed to GetFileInformationByHandle to confirm it is the same library as is loaded in another process, and subsequently closed with CloseHandle.