diff --git a/windows/dll_windows.go b/windows/dll_windows.go index e92c05b21..ba67658db 100644 --- a/windows/dll_windows.go +++ b/windows/dll_windows.go @@ -359,11 +359,11 @@ func loadLibraryEx(name string, system bool) (*DLL, error) { // trying to load "foo.dll" out of the system // folder, but LoadLibraryEx doesn't support // that yet on their system, so emulate it. - windir, _ := Getenv("WINDIR") // old var; apparently works on XP - if windir == "" { - return nil, errString("%WINDIR% not defined") + systemdir, err := GetSystemDirectory() + if err != nil { + return nil, err } - loadDLL = windir + "\\System32\\" + name + loadDLL = systemdir + "\\" + name } } h, err := LoadLibraryEx(loadDLL, 0, flags) diff --git a/windows/security_windows.go b/windows/security_windows.go index 9f946da6f..f5f2d8bd6 100644 --- a/windows/security_windows.go +++ b/windows/security_windows.go @@ -372,6 +372,7 @@ type Tokengroups struct { //sys OpenProcessToken(h Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken //sys GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) = advapi32.GetTokenInformation //sys GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW +//sys getSystemDirectory(dir *uint16, dirLen uint32) (len uint32, err error) = kernel32.GetSystemDirectoryW // An access token contains the security information for a logon session. // The system creates an access token when a user logs on, and every @@ -468,6 +469,23 @@ func (t Token) GetUserProfileDirectory() (string, error) { } } +// GetSystemDirectory retrieves path to current location of the system +// directory, which is typically, though not always, C:\Windows\System32. +func GetSystemDirectory() (string, error) { + n := uint32(MAX_PATH) + for { + b := make([]uint16, n) + l, e := getSystemDirectory(&b[0], n) + if e != nil { + return "", e + } + if l <= n { + return UTF16ToString(b[:l]), nil + } + n = l + } +} + // IsMember reports whether the access token t is a member of the provided SID. func (t Token) IsMember(sid *SID) (bool, error) { var b int32 diff --git a/windows/syscall_test.go b/windows/syscall_test.go index d7009e44a..f09c6dd5a 100644 --- a/windows/syscall_test.go +++ b/windows/syscall_test.go @@ -7,6 +7,7 @@ package windows_test import ( + "strings" "syscall" "testing" @@ -51,3 +52,13 @@ func TestGetProcAddressByOrdinal(t *testing.T) { t.Error("shlwapi.dll:IsOS(OS_NT) returned 0, expected non-zero value") } } + +func TestGetSystemDirectory(t *testing.T) { + d, err := windows.GetSystemDirectory() + if err != nil { + t.Fatalf("Failed to get system directory: %s", err) + } + if !strings.HasSuffix(strings.ToLower(d), "\\system32") { + t.Fatalf("System directory does not end in system32: %s", d) + } +} diff --git a/windows/zsyscall_windows.go b/windows/zsyscall_windows.go index e4b54e2d9..308c97eec 100644 --- a/windows/zsyscall_windows.go +++ b/windows/zsyscall_windows.go @@ -252,6 +252,7 @@ var ( procOpenProcessToken = modadvapi32.NewProc("OpenProcessToken") procGetTokenInformation = modadvapi32.NewProc("GetTokenInformation") procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW") + procGetSystemDirectoryW = modkernel32.NewProc("GetSystemDirectoryW") ) func RegisterEventSource(uncServerName *uint16, sourceName *uint16) (handle Handle, err error) { @@ -2718,3 +2719,16 @@ func GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) { } return } + +func getSystemDirectory(dir *uint16, dirLen uint32) (len uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetSystemDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(dir)), uintptr(dirLen), 0) + len = uint32(r0) + if len == 0 { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +}