mirror of
https://github.com/rwinkhart/sys.git
synced 2026-09-01 06:46:44 -04:00
windows: add LoadLibraryEx, add LazyDLL.System
Updates golang/go#14959 Change-Id: Ib91c359c3df919df0b30e584d38e56f79f3e3dc9 Reviewed-on: https://go-review.googlesource.com/21388 Reviewed-by: Russ Cox <rsc@golang.org> Reviewed-by: Alex Brainman <alex.brainman@gmail.com> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
+108
-16
@@ -31,6 +31,10 @@ type DLL struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LoadDLL loads DLL file into memory.
|
// LoadDLL loads DLL file into memory.
|
||||||
|
//
|
||||||
|
// Warning: using LoadDLL without an absolute path name is subject to
|
||||||
|
// DLL preloading attacks. To safely load a system DLL, use LazyDLL
|
||||||
|
// with System set to true, or use LoadLibraryEx directly.
|
||||||
func LoadDLL(name string) (dll *DLL, err error) {
|
func LoadDLL(name string) (dll *DLL, err error) {
|
||||||
namep, err := UTF16PtrFromString(name)
|
namep, err := UTF16PtrFromString(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -162,29 +166,48 @@ func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
|||||||
// call to its Handle method or to one of its
|
// call to its Handle method or to one of its
|
||||||
// LazyProc's Addr method.
|
// LazyProc's Addr method.
|
||||||
type LazyDLL struct {
|
type LazyDLL struct {
|
||||||
mu sync.Mutex
|
|
||||||
dll *DLL // non nil once DLL is loaded
|
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
|
// System determines whether the DLL must be loaded from the
|
||||||
|
// Windows System directory, bypassing the normal DLL search
|
||||||
|
// path.
|
||||||
|
System bool
|
||||||
|
|
||||||
|
mu sync.Mutex
|
||||||
|
dll *DLL // non nil once DLL is loaded
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load loads DLL file d.Name into memory. It returns an error if fails.
|
// Load loads DLL file d.Name into memory. It returns an error if fails.
|
||||||
// Load will not try to load DLL, if it is already loaded into memory.
|
// Load will not try to load DLL, if it is already loaded into memory.
|
||||||
func (d *LazyDLL) Load() error {
|
func (d *LazyDLL) Load() error {
|
||||||
// Non-racy version of:
|
// Non-racy version of:
|
||||||
// if d.dll == nil {
|
// if d.dll != nil {
|
||||||
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) == nil {
|
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) != nil {
|
||||||
d.mu.Lock()
|
return nil
|
||||||
defer d.mu.Unlock()
|
|
||||||
if d.dll == nil {
|
|
||||||
dll, e := LoadDLL(d.Name)
|
|
||||||
if e != nil {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
// Non-racy version of:
|
|
||||||
// d.dll = dll
|
|
||||||
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
if d.dll != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// kernel32.dll is special, since it's where LoadLibraryEx comes from.
|
||||||
|
// The kernel already special-cases its name, so it's always
|
||||||
|
// loaded from system32.
|
||||||
|
var dll *DLL
|
||||||
|
var err error
|
||||||
|
if d.Name == "kernel32.dll" {
|
||||||
|
dll, err = LoadDLL(d.Name)
|
||||||
|
} else {
|
||||||
|
dll, err = loadLibraryEx(d.Name, d.System)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-racy version of:
|
||||||
|
// d.dll = dll
|
||||||
|
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,8 +238,9 @@ func NewLazyDLL(name string) *LazyDLL {
|
|||||||
// A LazyProc implements access to a procedure inside a LazyDLL.
|
// A LazyProc implements access to a procedure inside a LazyDLL.
|
||||||
// It delays the lookup until the Addr method is called.
|
// It delays the lookup until the Addr method is called.
|
||||||
type LazyProc struct {
|
type LazyProc struct {
|
||||||
mu sync.Mutex
|
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
|
mu sync.Mutex
|
||||||
l *LazyDLL
|
l *LazyDLL
|
||||||
proc *Proc
|
proc *Proc
|
||||||
}
|
}
|
||||||
@@ -273,3 +297,71 @@ func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
|||||||
p.mustFind()
|
p.mustFind()
|
||||||
return p.proc.Call(a...)
|
return p.proc.Call(a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var canDoSearchSystem32Once struct {
|
||||||
|
sync.Once
|
||||||
|
v bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func initCanDoSearchSystem32() {
|
||||||
|
// https://msdn.microsoft.com/en-us/library/ms684179(v=vs.85).aspx says:
|
||||||
|
// "Windows 7, Windows Server 2008 R2, Windows Vista, and Windows
|
||||||
|
// Server 2008: The LOAD_LIBRARY_SEARCH_* flags are available on
|
||||||
|
// systems that have KB2533623 installed. To determine whether the
|
||||||
|
// flags are available, use GetProcAddress to get the address of the
|
||||||
|
// AddDllDirectory, RemoveDllDirectory, or SetDefaultDllDirectories
|
||||||
|
// function. If GetProcAddress succeeds, the LOAD_LIBRARY_SEARCH_*
|
||||||
|
// flags can be used with LoadLibraryEx."
|
||||||
|
canDoSearchSystem32Once.v = (modkernel32.NewProc("AddDllDirectory").Find() == nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func canDoSearchSystem32() bool {
|
||||||
|
canDoSearchSystem32Once.Do(initCanDoSearchSystem32)
|
||||||
|
return canDoSearchSystem32Once.v
|
||||||
|
}
|
||||||
|
|
||||||
|
func isBaseName(name string) bool {
|
||||||
|
for _, c := range name {
|
||||||
|
if c == ':' || c == '/' || c == '\\' {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadLibraryEx wraps the Windows LoadLibraryEx function.
|
||||||
|
//
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx
|
||||||
|
//
|
||||||
|
// If name is not an absolute path, LoadLibraryEx searches for the DLL
|
||||||
|
// in a variety of automatic locations unless constrained by flags.
|
||||||
|
// See: https://msdn.microsoft.com/en-us/library/ff919712%28VS.85%29.aspx
|
||||||
|
func loadLibraryEx(name string, system bool) (*DLL, error) {
|
||||||
|
loadDLL := name
|
||||||
|
var flags uintptr
|
||||||
|
if system {
|
||||||
|
if canDoSearchSystem32() {
|
||||||
|
const LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
|
||||||
|
flags = LOAD_LIBRARY_SEARCH_SYSTEM32
|
||||||
|
} else if isBaseName(name) {
|
||||||
|
// WindowsXP or unpatched Windows machine
|
||||||
|
// 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")
|
||||||
|
}
|
||||||
|
loadDLL = windir + "\\System32\\" + name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h, err := LoadLibraryEx(loadDLL, 0, flags)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &DLL{Name: name, Handle: h}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type errString string
|
||||||
|
|
||||||
|
func (s errString) Error() string { return string(s) }
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ package registry
|
|||||||
|
|
||||||
import "syscall"
|
import "syscall"
|
||||||
|
|
||||||
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go
|
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -xsys -output zsyscall_windows.go syscall.go
|
||||||
|
|
||||||
const (
|
const (
|
||||||
_REG_OPTION_NON_VOLATILE = 0
|
_REG_OPTION_NON_VOLATILE = 0
|
||||||
|
|||||||
@@ -2,14 +2,17 @@
|
|||||||
|
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
import "unsafe"
|
import (
|
||||||
import "syscall"
|
"golang.org/x/sys/windows"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
var _ unsafe.Pointer
|
var _ unsafe.Pointer
|
||||||
|
|
||||||
var (
|
var (
|
||||||
modadvapi32 = syscall.NewLazyDLL("advapi32.dll")
|
modadvapi32 = &windows.LazyDLL{Name: "advapi32.dll", System: true}
|
||||||
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
modkernel32 = &windows.LazyDLL{Name: "kernel32.dll", System: true}
|
||||||
|
|
||||||
procRegCreateKeyExW = modadvapi32.NewProc("RegCreateKeyExW")
|
procRegCreateKeyExW = modadvapi32.NewProc("RegCreateKeyExW")
|
||||||
procRegDeleteKeyW = modadvapi32.NewProc("RegDeleteKeyW")
|
procRegDeleteKeyW = modadvapi32.NewProc("RegDeleteKeyW")
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go eventlog.go service.go syscall_windows.go security_windows.go
|
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -xsys -output zsyscall_windows.go eventlog.go service.go syscall_windows.go security_windows.go
|
||||||
|
|
||||||
type Handle uintptr
|
type Handle uintptr
|
||||||
|
|
||||||
@@ -84,6 +84,7 @@ func NewCallbackCDecl(fn interface{}) uintptr
|
|||||||
|
|
||||||
//sys GetLastError() (lasterr error)
|
//sys GetLastError() (lasterr error)
|
||||||
//sys LoadLibrary(libname string) (handle Handle, err error) = LoadLibraryW
|
//sys LoadLibrary(libname string) (handle Handle, err error) = LoadLibraryW
|
||||||
|
//sys LoadLibraryEx(libname string, zero Handle, flags uintptr) (handle Handle, err error) = LoadLibraryExW
|
||||||
//sys FreeLibrary(handle Handle) (err error)
|
//sys FreeLibrary(handle Handle) (err error)
|
||||||
//sys GetProcAddress(module Handle, procname string) (proc uintptr, err error)
|
//sys GetProcAddress(module Handle, procname string) (proc uintptr, err error)
|
||||||
//sys GetVersion() (ver uint32, err error)
|
//sys GetVersion() (ver uint32, err error)
|
||||||
|
|||||||
+38
-13
@@ -2,23 +2,25 @@
|
|||||||
|
|
||||||
package windows
|
package windows
|
||||||
|
|
||||||
import "unsafe"
|
import (
|
||||||
import "syscall"
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
var _ unsafe.Pointer
|
var _ unsafe.Pointer
|
||||||
|
|
||||||
var (
|
var (
|
||||||
modadvapi32 = syscall.NewLazyDLL("advapi32.dll")
|
modadvapi32 = &LazyDLL{Name: "advapi32.dll", System: true}
|
||||||
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
modkernel32 = &LazyDLL{Name: "kernel32.dll", System: true}
|
||||||
modshell32 = syscall.NewLazyDLL("shell32.dll")
|
modshell32 = &LazyDLL{Name: "shell32.dll", System: true}
|
||||||
modmswsock = syscall.NewLazyDLL("mswsock.dll")
|
modmswsock = &LazyDLL{Name: "mswsock.dll", System: true}
|
||||||
modcrypt32 = syscall.NewLazyDLL("crypt32.dll")
|
modcrypt32 = &LazyDLL{Name: "crypt32.dll", System: true}
|
||||||
modws2_32 = syscall.NewLazyDLL("ws2_32.dll")
|
modws2_32 = &LazyDLL{Name: "ws2_32.dll", System: true}
|
||||||
moddnsapi = syscall.NewLazyDLL("dnsapi.dll")
|
moddnsapi = &LazyDLL{Name: "dnsapi.dll", System: true}
|
||||||
modiphlpapi = syscall.NewLazyDLL("iphlpapi.dll")
|
modiphlpapi = &LazyDLL{Name: "iphlpapi.dll", System: true}
|
||||||
modsecur32 = syscall.NewLazyDLL("secur32.dll")
|
modsecur32 = &LazyDLL{Name: "secur32.dll", System: true}
|
||||||
modnetapi32 = syscall.NewLazyDLL("netapi32.dll")
|
modnetapi32 = &LazyDLL{Name: "netapi32.dll", System: true}
|
||||||
moduserenv = syscall.NewLazyDLL("userenv.dll")
|
moduserenv = &LazyDLL{Name: "userenv.dll", System: true}
|
||||||
|
|
||||||
procRegisterEventSourceW = modadvapi32.NewProc("RegisterEventSourceW")
|
procRegisterEventSourceW = modadvapi32.NewProc("RegisterEventSourceW")
|
||||||
procDeregisterEventSource = modadvapi32.NewProc("DeregisterEventSource")
|
procDeregisterEventSource = modadvapi32.NewProc("DeregisterEventSource")
|
||||||
@@ -39,6 +41,7 @@ var (
|
|||||||
procQueryServiceConfig2W = modadvapi32.NewProc("QueryServiceConfig2W")
|
procQueryServiceConfig2W = modadvapi32.NewProc("QueryServiceConfig2W")
|
||||||
procGetLastError = modkernel32.NewProc("GetLastError")
|
procGetLastError = modkernel32.NewProc("GetLastError")
|
||||||
procLoadLibraryW = modkernel32.NewProc("LoadLibraryW")
|
procLoadLibraryW = modkernel32.NewProc("LoadLibraryW")
|
||||||
|
procLoadLibraryExW = modkernel32.NewProc("LoadLibraryExW")
|
||||||
procFreeLibrary = modkernel32.NewProc("FreeLibrary")
|
procFreeLibrary = modkernel32.NewProc("FreeLibrary")
|
||||||
procGetProcAddress = modkernel32.NewProc("GetProcAddress")
|
procGetProcAddress = modkernel32.NewProc("GetProcAddress")
|
||||||
procGetVersion = modkernel32.NewProc("GetVersion")
|
procGetVersion = modkernel32.NewProc("GetVersion")
|
||||||
@@ -430,6 +433,28 @@ func _LoadLibrary(libname *uint16) (handle Handle, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LoadLibraryEx(libname string, zero Handle, flags uintptr) (handle Handle, err error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, err = syscall.UTF16PtrFromString(libname)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _LoadLibraryEx(_p0, zero, flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _LoadLibraryEx(libname *uint16, zero Handle, flags uintptr) (handle Handle, err error) {
|
||||||
|
r0, _, e1 := syscall.Syscall(procLoadLibraryExW.Addr(), 3, uintptr(unsafe.Pointer(libname)), uintptr(zero), uintptr(flags))
|
||||||
|
handle = Handle(r0)
|
||||||
|
if handle == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = error(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func FreeLibrary(handle Handle) (err error) {
|
func FreeLibrary(handle Handle) (err error) {
|
||||||
r1, _, e1 := syscall.Syscall(procFreeLibrary.Addr(), 1, uintptr(handle), 0, 0)
|
r1, _, e1 := syscall.Syscall(procFreeLibrary.Addr(), 1, uintptr(handle), 0, 0)
|
||||||
if r1 == 0 {
|
if r1 == 0 {
|
||||||
|
|||||||
Reference in New Issue
Block a user