wails icon indicating copy to clipboard operation
wails copied to clipboard

Prevent DLL hijacking by setting default DLL directories on initialization

Open ansxuman opened this issue 1 year ago • 8 comments

Description

This PR fixes a DLL hijacking vulnerability identified during a VAPT assessment. When the application tries to load certain DLLs from the application directory instead of the system directories, it creates a potential security risk where an attacker could place malicious DLLs in the application directory.

The issue affects several DLLs including:

  • uxtheme.dll
  • WindowsCodecs.dll
  • dwmapi.dll
  • PROPSYS.dll
  • CRYPTBASE.dll
  • Secur32.dll
  • SSPICLI.DLL
  • MLANG.dll
  • WININET.dll

While most DLLs can be fixed by adding windows.SetDefaultDllDirectories(windows.LOAD_LIBRARY_SEARCH_SYSTEM32) in application code, the uxtheme.dll is loaded by the Wails before application initialization. This PR addresses this issue by adding the secure DLL loading directive at the framework level.

Additional Background Information

Our security team recently discovered a DLL hijacking vulnerability in our application. After digging into it, I found that this is actually a common issue in Go applications - there's even a similar bug report in the Go repository (https://github.com/golang/go/issues/64411). Here's what's happening: When Windows looks for DLLs, it first checks the application directory before checking system directories. This creates a security risk where someone could drop malicious versions of these DLLs into our application folder. I initially tried fixing this in our code by adding windows.SetDefaultDllDirectories(windows.LOAD_LIBRARY_SEARCH_SYSTEM32), which tells Windows to prioritize loading DLLs from the System32 directory. This worked for most DLLs, but not for uxtheme.dll, it loaded by Wails before application initialization, so our fix never gets a chance to take effect.It's an important security improvement that protects applications from a potentially serious attack vector where bad actors could execute arbitrary code through fake DLLs.

Type of change

Please select the option that is relevant.

  • [x] Bug fix (non-breaking change which fixes an issue)
  • [ ] New feature (non-breaking change which adds functionality)
  • [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • [ ] This change requires a documentation update

Steps to Reproduce

  1. Create a basic Wails application
  2. Build the application for Windows
  3. Run Process Monitor while launching the application and Filter the PATH to <Application Directory>\uxtheme.dll and observe

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration using wails doctor.

  • [x] Windows
  • [ ] macOS
  • [ ] Linux

If you checked Linux, please specify the distro and version.

Test Configuration

PS C:\Users\DELL\wails\v2\cmd\wails> .\wails.exe doctor       

# Wails
Version  | v2.10.1
Revision | 194b0586ba63b3003bb6f5c3b5bc48f8c84720fc
Modified | true


# System
┌─────────────────────────────────────────────────────────────────────────────────────┐
| OS           | Windows 10 Pro                                                       |
| Version      | 2009 (Build: 19045)                                                  |
| ID           | 22H2                                                                 |
| Branding     | Windows 10 Pro                                                       |
| Go Version   | go1.23.0                                                             |
| Platform     | windows                                                              |
| Architecture | amd64                                                                |
| CPU          | Intel(R) Core(TM) i7-7600U CPU @ 2.80GHz                             |
| GPU          | Intel(R) HD Graphics 620 (Intel Corporation) - Driver: 31.0.101.2127 |
| Memory       | 16GB                                                                 |
└─────────────────────────────────────────────────────────────────────────────────────┘

# Dependencies
┌───────────────────────────────────────────────────────┐
| Dependency | Package Name | Status    | Version       |
| WebView2   | N/A          | Installed | 134.0.3124.93 |
| Nodejs     | N/A          | Installed | 22.14.0       |
| npm        | N/A          | Installed | 10.9.2        |
| *upx       | N/A          | Available |               |
| *nsis      | N/A          | Available |               |
|                                                       |
└─────────────── * - Optional Dependency ───────────────┘

# Diagnosis
Optional package(s) installation details:
  - upx : Available at https://upx.github.io/
  - nsis : More info at https://wails.io/docs/guides/windows-installer/

 SUCCESS  Your system is ready for Wails development!

Checklist:

  • [x] I have updated website/src/pages/changelog.mdx with details of this PR
  • [x] My code follows the general coding style of this project
  • [x] I have performed a self-review of my own code
  • [x] I have commented my code, particularly in hard-to-understand areas
  • [ ] I have made corresponding changes to the documentation
  • [ ] My changes generate no new warnings
  • [ ] I have added tests that prove my fix is effective or that my feature works
  • [ ] New and existing unit tests pass locally with my changes

Summary by CodeRabbit

  • New Features
    • Introduced a new option for Windows users to control DLL search paths, enhancing the application's configurability.
    • Expanded DLL loading settings with advanced controls, allowing for more detailed management of how DLL files are located on Windows platforms.
  • Improvements
    • Updated function visibility for improved accessibility and initialization within the application.

ansxuman avatar Apr 09 '25 15:04 ansxuman

[!CAUTION]

Review failed

The pull request is closed.

Walkthrough

Adds a Windows DLL search-path option and wiring: changelog entry, new constants and DLLSearchPaths option, conditional call to SetDefaultDllDirectories during frontend init, and makes several platform init functions exported for external initialization. No other behavior changes.

Changes

Cohort / File(s) Change Summary
Changelog
website/src/pages/changelog.mdx
Added changelog entry: "Added DLLSearchPaths option to control DLL search paths on Windows" under v2.10.2.
Windows options
v2/pkg/options/windows/windows.go
Added Windows DLL search flag constants (mapped to golang.org/x/sys/windows) and new DLLSearchPaths uint32 field to Options.
Frontend wiring
v2/internal/frontend/desktop/windows/frontend.go
Imported w32consts and golang.org/x/sys/windows as w; in NewFrontend conditionally call w.SetDefaultDllDirectories(appoptions.Windows.DLLSearchPaths) when non-zero and initialize w32/w32consts before constructing the Frontend.
Win32 init exports
v2/internal/frontend/desktop/windows/winc/w32/uxtheme.go, v2/internal/platform/win32/consts.go
Renamed package-local init() functions to exported Init() to allow invocation from other packages; internal logic unchanged.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant Options as AppOptions.Windows
    participant WinSys as golang.org/x/sys/windows (w)
    participant W32 as w32 / w32consts

    App->>Options: Read Windows options
    alt DLLSearchPaths != 0
        App->>WinSys: SetDefaultDllDirectories(DLLSearchPaths)
        WinSys-->>App: success / error
        App->>W32: Init()
        W32-->>App: loaded DLLs
    else DLLSearchPaths == 0
        App-->>App: Skip SetDefaultDllDirectories
        App->>W32: Init()
        W32-->>App: loaded DLLs
    end

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • wailsapp/wails#3713 — Modifies the same winc/w32/uxtheme.go and relates to making initialization and syscall usage changes; likely related to exported init and theme syscall updates.

Suggested labels

Windows, Documentation, go, Bug

Poem

I'm a rabbit in code,
Hopping through DLL lanes so wide,
Flags and paths now mark the tide,
Init is called where shadows hide,
Changelog cheers — I twitch with pride! 🐰✨

✨ Finishing touches
  • [ ] 📝 Generate Docstrings
🧪 Generate unit tests
  • [ ] Create PR with unit tests
  • [ ] Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5d75d08138e4b34519aa61455989509a044286fc and 8746a975f717e9b1431a59a5814e4266ada86786.

📒 Files selected for processing (1)
  • v2/internal/frontend/desktop/windows/frontend.go (2 hunks)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot] avatar Apr 09 '25 15:04 coderabbitai[bot]

Thanks for taking the time to open this 🙏

I absolutely see the need for this but the solution will need to be more flexible to accommodate everyone's use cases. Some people ship DLLs with their binaries using NSIS and this will break their apps in a way they can't fix.

Proposal: create a windows specific application setting that lists the set of search paths. Let's call it DLLSearchPaths. If this is blank, we do nothing and default to Go's defaults. If given, then we set them at application startup. This will mean updating most of the win32 package as you've noted.

Thoughts?

leaanthony avatar Apr 09 '25 20:04 leaanthony

Do you think we need to change func init() { in uxtheme.go to func Init() { and call this manually after setting the DLL search paths? Alternatively, you could try lazy loading the DLL but I'm guessing there's a reason this is being loaded differently.

leaanthony avatar Apr 11 '25 22:04 leaanthony

Do you think we need to change func init() { in uxtheme.go to func Init() { and call this manually after setting the DLL search paths? Alternatively, you could try lazy loading the DLL but I'm guessing there's a reason this is being loaded differently.

Thanks for highlighting this. I didn’t get a chance to test the new changes as my Windows laptop is having some issues. I would prefer changing func init() to func Init() in both uxtheme.go and consts.go for a minimal impact.

ansxuman avatar Apr 12 '25 05:04 ansxuman

Sounds good. Can you please make sure that the changes work correctly and they don't flicker windows when they start up or anything? That is my only concern with converting the init function.

leaanthony avatar Apr 13 '25 03:04 leaanthony

Sounds good. Can you please make sure that the changes work correctly and they don't flicker windows when they start up or anything? That is my only concern with converting the init function.

Sure i will do proper testing and update you here.

ansxuman avatar Apr 13 '25 06:04 ansxuman

Tested on Windows 10, I did not observe any issues.

ansxuman avatar Apr 16 '25 18:04 ansxuman

Documentation Updates

Checked 1 published document(s). No updates required.

You have 2 draft document(s). Publish docs to keep them always up-to-date

How did I do? Any feedback?  Join Discord

dosubot[bot] avatar Sep 24 '25 05:09 dosubot[bot]