My code is using a library which is a static/implicitly linked DLL (let's call it DLLB) but on runtime it can't find it.
This is despite locating DLLB in the same directory as the code that calls it. (The calling code is itself a DLL, DLLA which is called from python, which is called from arcpy. I'm not quite sure why the python finds DLLA fine but DLLA doesn't find DLLB, despite them being in the same directory).
If I put the library DLL somewhere on the system path, everything works just fine.
But what's the best approach for deployment? Add an entry to the system path on the client machine, at install time? Modify the system path at runtime, from python, before loading the DLL? Something else?
Python must be specifying the full path to the DLL in the LoadLibrary call. This is recommended practice. If you specify only a module name, there is a risk of loading the wrong DLL, possibly introducing a binary planting vulnerability.
Note that although the default search path includes the directory the executable was loaded from, it does not include the directory other DLLs were loaded from. So the behaviour you're seeing is as expected.
If you can use dynamic loading, you can look up the path to DLLA and use it to construct the path to DLLB.
To get a module handle for DLLA, call GetModuleHandleEx. To get the full path to DLLA from the module handle, call GetModuleFileName. Check that the last element is DLLA.dll and replace it with DLLB.dll. You can then call LoadLibrary.
Related
What happens when an executable tries to access a .DLL that isn't loaded ?
Does it try to find it at system32 folder and load it or something else?
Also can someone please explain to me where in the ram .DLL are saved and referenced, I tried researching online but didn't find many good answers...
Thanks in advance
The best description for the search processed used that I've been able to find is in the documentation for LoadLibrary at MSDN. An excerpt from the Remarks section of that documentation:
When no path is specified, the function searches for loaded modules whose base name matches the base name of the module to be loaded. If the name matches, the load succeeds. Otherwise, the function searches for the file.
The first directory searched is the directory containing the image file used to create the calling process (for more information, see the CreateProcess function). Doing this allows private dynamic-link library (DLL) files associated with a process to be found without adding the process's installed directory to the PATH environment variable. If a relative path is specified, the entire relative path is appended to every token in the DLL search path list. To load a module from a relative path without searching any other path, use GetFullPathName to get a nonrelative path and call LoadLibrary with the nonrelative path. For more information on the DLL search order, see Dynamic-Link Library Search Order.
The search path can be altered using the SetDllDirectory function. This solution is recommended instead of using SetCurrentDirectory or hard-coding the full path to the DLL.
If a path is specified and there is a redirection file for the application, the function searches for the module in the application's directory. If the module exists in the application's directory, LoadLibrary ignores the specified path and loads the module from the application's directory. If the module does not exist in the application's directory, LoadLibrary loads the module from the specified directory. For more information, see Dynamic Link Library Redirection.
If you call LoadLibrary with the name of an assembly without a path specification and the assembly is listed in the system compatible manifest, the call is automatically redirected to the side-by-side assembly.
I have a program which stores plugins in multiple directories, like so:
root/
core/bin/
app.exe
core.dll
plugin.dll
support.dll
a/bin/
a.dll
a_support.dll
In this example, a.dll imports core.dll, support.dll, and a_support.dll (they are in that order in the import table). a_support.dll imports support.dll. I can change all but the support modules, those are redists of a third-party library.
My code calls LoadLibraryEx(name, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) to load each plugin. For core.dll and plugin.dll, this works fine.
When I try to load a.dll, it fails saying a_support.dll was not found. No errors about core.dll or support.dll, perhaps because they're already in memory.
My suspicion is that when a_support.dll is loaded, support.dll cannot be found, but this seems unusual as a.dll appears to import support.dll before a_support.dll.
Is this layout of modules even possible to use? Will the system be able to use the already-loaded support DLLs, or will it go searching for them and fail? Would there be a way to handle this through manifests? Is there a way to make this work, or will I have to relocate all modules into a single directory?
Edit: At Adrian McCarthy's suggestion, I ran the loading sequence with Process Monitor tracking, and it seems that when I call LoadLibrary("root/a/bin/a.dll", ...), it starts by searching the root directory, then system directories, then down through the path. For some reason, it never searches a/bin/, which it very much should.
I double-checked the paths, and noticed that my calls to load plugin.dll where using the wrong path (root, instead of root/core/bin). Either way, core.dll was loading correctly. After fixing that, I tried it again and this time a.dll does find a_support.dll and seems to load. However, that makes absolutely no sense, unless the loader is successfully using support.dll from... somewhere. The procmon log doesn't show it even attempting to load support.dll again, so I'm not entirely sure at this point if there actually is a problem (besides behavior from the loader that makes no sense).
I suggest using Process Monitor to see what's really happening. You'll see if it's looking in the right place, whether a_support.dll is opened but not loadable because something else is missing, etc.
Certainly one solution would be to place all DLLs in the same directory, the same directory as the .exe. If you can bring yourself to do that it would be the simplest approach for sure.
If not then you will have a bit more work on your hands. I guess you are expecting that the loader will search in the directory where the DLL lives. Sadly it doesn't. Instead the loader will look first in the executable file's directory, and then the rest of the DLL search order. This is why a_support.dll fails to load, because it is not in the same directory as the executable.
The fact that modules are already in memory is beside the point. The loader goes looking for the file. When it finds the file that it wants it then checks to see if it is already loaded. If so then it simply bumps the reference count to that module. Otherwise it loads it into the process.
You could switch to using LoadLibrary for all DLL loads and always being explicit about the path. That's probably inconvenient.
You could use side-by-side assemblies but that doesn't sound very compatible with a plugin architecture.
So I think the main remaining option is SetDllDirectory. Call this just before you load the plugin. You only need to add a/bin to the search path since the rest of the modules are in the executable directory and so will be found without trouble. Restore this setting to its default by calling SetDllDirectory again, passing NULL, once the plugin has loaded and resolved all of its imports.
If you have multiple sub-directories then use AddDllDirectory.
This is a rather confusing application.
Some questions then:
Which dll's does app.exe implicitly import?
core.dll is both implicitly loaded by a.dll AND as a plugin via LoadLibraryEx?
How was the call to LoadLibraryEx on /plugin.dll ever succeeding? If the path was FQ and did not point at an actual dll, LoadLibrary should have failed outright on that dll.
I can't tell if you're giving sample code or real code. You wrote:
LoadLibrary("root/a/bin/a.dll", ...)
If that's the real code, there are two problems here.
First, LoadLibrary doesn't do what you'd expect with a relative path. From MSDN:
To load a module from a relative path without searching any other
path, use GetFullPathName to get a nonrelative path and call
LoadLibrary with the nonrelative path. For more information on the DLL
search order, see Dynamic-Link Library Search Order.
Basically, you give it a full path and get that file, or you let it search for a name in all the "usual" locations. If you give it a relative path, it basically ignores that path, grabs the name, and looks in the usual locations.
If you really meant LoadLibraryEx, note that when you use LOAD_WITH_ALTERED_SEARCH_PATH you get "undefined behavior" if handed a relative path. Again quoting MSDN:
If this value is used and lpFileName specifies a relative path, the behavior is undefined.
Second, you have forward slashes instead of backslashes. Neither LoadLibrary nor LoadLibraryEx likes those.
I want to make a dll with an exposed C function accessible to applications on the system.
Is there a better way to make it available than modifying %PATH%?
Because people don't like adding it to %PATH% here.
You have three options if you want to allow implicit linking to the dll :-
Create a native Win32 assembly that contains the dll and install it to WinSxS. This requires creating a simple .manifest file, the use of some crypto tools to sign the assembly (being the manifest file and the dll), and creating an MSI installer - or call IAssemblyCache directly to perform the actual install.
Install the dll to System32 - with this option you need to ensure the dll has a relativly unique name.
Ad the path to the dll to the someplace on the PATH (or modify path to point to the dll).
Other options if implicit linking to the C Function isn't critical:-
Create an COM interface that exposes the c-method. Register the path to the dll in the registry and users of the dll use CoCreateInstance to get the interface containing the function.
Store the path to the dll in the registry, and expect users of the dll to use that path with LoadLibrary, and GetProcAddress to load the dll.
Put it somewhere in your PATH. (C:\Windows\System32\ comes to mind). If it's only needed by one application, just stick it in the same directory.
If you call the DLL using an import library, then it looks in the current directory, and then in the PATH.
But, you don't need to call it that way. You can use LoadLibrary() and GetProcAddress() yourself and then do whatever you want. If you call LoadLibrary with just the dll name, it uses the same algorithm as with the import library (current dir + PATH) -- if you pass a full path, it will use it.
COM uses this technique to load a DLL based on a full path to the DLL which is in the registry -- you could do this too without COM.
You could search for it in some other way besides the PATH -- you could call with no path, see if it finds it, and then try the registry, and then look elsewhere (every drive's program files directory, etc).
Basically, if you call LoadLibrary and GetProcAddress yourself, you can do whatever you want.
I guess that it would be best to install it into system32 folder and forget about %PATH% modification...
Simple question: What is dll hijacking?
I read a lot about which applications are vulnerable, but not a lot of depth as to why.
Answers appreciated.
The basics are simple. Windows has a search path for DLLs, much the same way it has a $PATH for finding executables. If you can figure out what DLLs an app requests without an absolute path (triggering this search process), you can then place your hostile DLL somewhere higher up the search path so it'll be found before the real version is, and Windows will happilly feed your attack code to the application.
So, let's pretend your system's DLL search path looks something like this:
a) . <--current working directory of the application, highest priority, first check
b) \windows
c) \windows\system32
d) \windows\syswow64 <-- lowest priority, last check
and some application Foo.exe requests "bar.dll", which happens to live in the syswow64 (d) subdir. This gives you the opportunity to place your malicious version in a), b), or c) and it will be loaded into the app automatically whenever the app requests bar.dll. And now your foo is well and trully bar'd.
As stated before, even an absolute full path can't protect against this, if you can replace the DLL with your own version.
And of course, this isn't really limited to Windows either. Any OS which allows for dynamic linking of external libraries is theoretically vulnerable to this.
DLL Hijacking is really a simple concept.
Applications load external code via DLLs (Dynamic Link Libraries). DLL Highjacking is a process by which malicious code is injected into an application via a malicious DLL with the same name as a DLL used by the application.
An application is vulnerable to DLL hijacking depending on how they reference their DLLs. One example is using relative paths instead of the absolute path to the DLL. Another is loading DLLs using environment variables that may not be set properly in which case the directory defaults to a relative path of the executing application.
I have a question about getting DLL's directory on Windows system.
The situation is like this :
I have a DLL and an EXE file. The exe file must load the DLL to run.
These 2 modules are in different directories.
Moreover, the directory of the DLL is changeable.
Now I have to get the directory of the DLL in "run time".
How could I do this?
Thanks in advance.
Do you need to find where the DLL is to load it or find the the path where it was loaded from?
The DLL path search algorithm is documented on MSDN and you can use the SearchPath function to search the system path.
If you need to find the path where a DLL was loaded, after it was loaded, use the GetModuleFileName function. That takes the module handle that is returned by LoadLibrary, GetModuleHandle, or passed in as hinstDLL to DllMain and returns the full path to the DLL.
I guess you need to implement some custom search algorithm. Only your exe knows which one DLL is needed and where it can be. So find the path and use it with LoadLibrary().
BTW, if possible, I would consider using COM. In this way you will use DLL stuff by some CLSID, which is completely independent from file path.