github.com/gidoBOSSftw5731/go/src@v0.0.0-20210226122457-d24b0edbf019/syscall/dll_windows.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package syscall 6 7 import ( 8 "internal/syscall/windows/sysdll" 9 "sync" 10 "sync/atomic" 11 "unsafe" 12 ) 13 14 // DLLError describes reasons for DLL load failures. 15 type DLLError struct { 16 Err error 17 ObjName string 18 Msg string 19 } 20 21 func (e *DLLError) Error() string { return e.Msg } 22 23 func (e *DLLError) Unwrap() error { return e.Err } 24 25 // Implemented in ../runtime/syscall_windows.go. 26 27 func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) 28 func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) 29 func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) 30 func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno) 31 func Syscall15(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2 uintptr, err Errno) 32 func Syscall18(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 uintptr) (r1, r2 uintptr, err Errno) 33 func loadlibrary(filename *uint16) (handle uintptr, err Errno) 34 func loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle uintptr, err Errno) 35 func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno) 36 37 // A DLL implements access to a single DLL. 38 type DLL struct { 39 Name string 40 Handle Handle 41 } 42 43 // We use this for computing the absolute path for system DLLs on systems 44 // where SEARCH_SYSTEM32 is not available. 45 var systemDirectoryPrefix string 46 47 func init() { 48 n := uint32(MAX_PATH) 49 for { 50 b := make([]uint16, n) 51 l, e := getSystemDirectory(&b[0], n) 52 if e != nil { 53 panic("Unable to determine system directory: " + e.Error()) 54 } 55 if l <= n { 56 systemDirectoryPrefix = UTF16ToString(b[:l]) + "\\" 57 break 58 } 59 n = l 60 } 61 } 62 63 // LoadDLL loads the named DLL file into memory. 64 // 65 // If name is not an absolute path and is not a known system DLL used by 66 // Go, Windows will search for the named DLL in many locations, causing 67 // potential DLL preloading attacks. 68 // 69 // Use LazyDLL in golang.org/x/sys/windows for a secure way to 70 // load system DLLs. 71 func LoadDLL(name string) (*DLL, error) { 72 namep, err := UTF16PtrFromString(name) 73 if err != nil { 74 return nil, err 75 } 76 var h uintptr 77 var e Errno 78 if sysdll.IsSystemDLL[name] { 79 absoluteFilepathp, err := UTF16PtrFromString(systemDirectoryPrefix + name) 80 if err != nil { 81 return nil, err 82 } 83 h, e = loadsystemlibrary(namep, absoluteFilepathp) 84 } else { 85 h, e = loadlibrary(namep) 86 } 87 if e != 0 { 88 return nil, &DLLError{ 89 Err: e, 90 ObjName: name, 91 Msg: "Failed to load " + name + ": " + e.Error(), 92 } 93 } 94 d := &DLL{ 95 Name: name, 96 Handle: Handle(h), 97 } 98 return d, nil 99 } 100 101 // MustLoadDLL is like LoadDLL but panics if load operation fails. 102 func MustLoadDLL(name string) *DLL { 103 d, e := LoadDLL(name) 104 if e != nil { 105 panic(e) 106 } 107 return d 108 } 109 110 // FindProc searches DLL d for procedure named name and returns *Proc 111 // if found. It returns an error if search fails. 112 func (d *DLL) FindProc(name string) (proc *Proc, err error) { 113 namep, err := BytePtrFromString(name) 114 if err != nil { 115 return nil, err 116 } 117 a, e := getprocaddress(uintptr(d.Handle), namep) 118 if e != 0 { 119 return nil, &DLLError{ 120 Err: e, 121 ObjName: name, 122 Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(), 123 } 124 } 125 p := &Proc{ 126 Dll: d, 127 Name: name, 128 addr: a, 129 } 130 return p, nil 131 } 132 133 // MustFindProc is like FindProc but panics if search fails. 134 func (d *DLL) MustFindProc(name string) *Proc { 135 p, e := d.FindProc(name) 136 if e != nil { 137 panic(e) 138 } 139 return p 140 } 141 142 // Release unloads DLL d from memory. 143 func (d *DLL) Release() (err error) { 144 return FreeLibrary(d.Handle) 145 } 146 147 // A Proc implements access to a procedure inside a DLL. 148 type Proc struct { 149 Dll *DLL 150 Name string 151 addr uintptr 152 } 153 154 // Addr returns the address of the procedure represented by p. 155 // The return value can be passed to Syscall to run the procedure. 156 func (p *Proc) Addr() uintptr { 157 return p.addr 158 } 159 160 //go:uintptrescapes 161 162 // Call executes procedure p with arguments a. It will panic if more than 18 arguments 163 // are supplied. 164 // 165 // The returned error is always non-nil, constructed from the result of GetLastError. 166 // Callers must inspect the primary return value to decide whether an error occurred 167 // (according to the semantics of the specific function being called) before consulting 168 // the error. The error always has type syscall.Errno. 169 // 170 // On amd64, Call can pass and return floating-point values. To pass 171 // an argument x with C type "float", use 172 // uintptr(math.Float32bits(x)). To pass an argument with C type 173 // "double", use uintptr(math.Float64bits(x)). Floating-point return 174 // values are returned in r2. The return value for C type "float" is 175 // math.Float32frombits(uint32(r2)). For C type "double", it is 176 // math.Float64frombits(uint64(r2)). 177 func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) { 178 switch len(a) { 179 case 0: 180 return Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0) 181 case 1: 182 return Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0) 183 case 2: 184 return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0) 185 case 3: 186 return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2]) 187 case 4: 188 return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0) 189 case 5: 190 return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0) 191 case 6: 192 return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5]) 193 case 7: 194 return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0) 195 case 8: 196 return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0) 197 case 9: 198 return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]) 199 case 10: 200 return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0) 201 case 11: 202 return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0) 203 case 12: 204 return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11]) 205 case 13: 206 return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], 0, 0) 207 case 14: 208 return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], 0) 209 case 15: 210 return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14]) 211 case 16: 212 return Syscall18(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], 0, 0) 213 case 17: 214 return Syscall18(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], a[16], 0) 215 case 18: 216 return Syscall18(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], a[16], a[17]) 217 default: 218 panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".") 219 } 220 } 221 222 // A LazyDLL implements access to a single DLL. 223 // It will delay the load of the DLL until the first 224 // call to its Handle method or to one of its 225 // LazyProc's Addr method. 226 // 227 // LazyDLL is subject to the same DLL preloading attacks as documented 228 // on LoadDLL. 229 // 230 // Use LazyDLL in golang.org/x/sys/windows for a secure way to 231 // load system DLLs. 232 type LazyDLL struct { 233 mu sync.Mutex 234 dll *DLL // non nil once DLL is loaded 235 Name string 236 } 237 238 // Load loads DLL file d.Name into memory. It returns an error if fails. 239 // Load will not try to load DLL, if it is already loaded into memory. 240 func (d *LazyDLL) Load() error { 241 // Non-racy version of: 242 // if d.dll == nil { 243 if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) == nil { 244 d.mu.Lock() 245 defer d.mu.Unlock() 246 if d.dll == nil { 247 dll, e := LoadDLL(d.Name) 248 if e != nil { 249 return e 250 } 251 // Non-racy version of: 252 // d.dll = dll 253 atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll)) 254 } 255 } 256 return nil 257 } 258 259 // mustLoad is like Load but panics if search fails. 260 func (d *LazyDLL) mustLoad() { 261 e := d.Load() 262 if e != nil { 263 panic(e) 264 } 265 } 266 267 // Handle returns d's module handle. 268 func (d *LazyDLL) Handle() uintptr { 269 d.mustLoad() 270 return uintptr(d.dll.Handle) 271 } 272 273 // NewProc returns a LazyProc for accessing the named procedure in the DLL d. 274 func (d *LazyDLL) NewProc(name string) *LazyProc { 275 return &LazyProc{l: d, Name: name} 276 } 277 278 // NewLazyDLL creates new LazyDLL associated with DLL file. 279 func NewLazyDLL(name string) *LazyDLL { 280 return &LazyDLL{Name: name} 281 } 282 283 // A LazyProc implements access to a procedure inside a LazyDLL. 284 // It delays the lookup until the Addr, Call, or Find method is called. 285 type LazyProc struct { 286 mu sync.Mutex 287 Name string 288 l *LazyDLL 289 proc *Proc 290 } 291 292 // Find searches DLL for procedure named p.Name. It returns 293 // an error if search fails. Find will not search procedure, 294 // if it is already found and loaded into memory. 295 func (p *LazyProc) Find() error { 296 // Non-racy version of: 297 // if p.proc == nil { 298 if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil { 299 p.mu.Lock() 300 defer p.mu.Unlock() 301 if p.proc == nil { 302 e := p.l.Load() 303 if e != nil { 304 return e 305 } 306 proc, e := p.l.dll.FindProc(p.Name) 307 if e != nil { 308 return e 309 } 310 // Non-racy version of: 311 // p.proc = proc 312 atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc)) 313 } 314 } 315 return nil 316 } 317 318 // mustFind is like Find but panics if search fails. 319 func (p *LazyProc) mustFind() { 320 e := p.Find() 321 if e != nil { 322 panic(e) 323 } 324 } 325 326 // Addr returns the address of the procedure represented by p. 327 // The return value can be passed to Syscall to run the procedure. 328 func (p *LazyProc) Addr() uintptr { 329 p.mustFind() 330 return p.proc.Addr() 331 } 332 333 //go:uintptrescapes 334 335 // Call executes procedure p with arguments a. See the documentation of 336 // Proc.Call for more information. 337 func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) { 338 p.mustFind() 339 return p.proc.Call(a...) 340 }