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  }