Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The current DLL hijacking prevention code in Squirrel isn't effective enough.
How do we know
So how do we know that we are vulnerable and which DLLs are a vector to attack? A simple look into ProcMon reveals the loading attempts of DLL from the local folder. Its best to set filter for the name of our executable, Paths that end with DLL and Results of NAME NOT FOUND.
In order to avoid the local DLL loading on all platforms and each code path I had to deploy all the following techniques. 😭
Static linking
Enabling static linked reduced the number of local DLL loading already. However, this was not full enabled for our binary. While Multi-Threaded (/MT) was enabled we missed the Static Library setting for Use of MFC. Why do we need both. Because SO says so https://stackoverflow.com/questions/37398/how-do-i-make-a-fully-statically-linked-exe-with-visual-studio-express-2005
Setting the default DLL directory
Squirrel already had an attempt to fix DLL hijacking. First code in Setup was this:
Basically we telling the kernel32.dll to look first into the System32 folder. However, in my experimentations this had no effect. I also tried calling SetDefaultDllDirectories() directly on Setup.exe and other DLLs that get loaded.
Delayed DLL loading
As mentioned in the previous paragraph SetDefaultDllDirectories() had no effect. The reason for this is that by default DLL are loaded at load-time of the module. So before any code runs we are already doomed. Luckily there is way to tell the linker to change this behavior to runtime loading via the /DelayLoad switch. This way DLLs will only be loaded if they are accessed. This gives us a chance to run code very early in the main function before any DDL is loaded and therefor SetDefaultDllDirectories() offers salvation.
Preloading DLLs
While the previous steps were good enough for Windows 10, we still see DLLs loaded from the current folder on Windows 7. Since we have delayed loading enabled we are in luck and can use some trickery. If we load the libraries in question with a full path to System32 before the actual code that needs them then we no new attempt is made to load them because they are already in memory.