Add back LoadLibraryA fallback
This commit is contained in:
@@ -36,3 +36,7 @@ func NewContextStub() *ContextStub {
|
|||||||
ctx.set_fp(getcallerfp())
|
ctx.set_fp(getcallerfp())
|
||||||
return &ContextStub{ctx}
|
return &ContextStub{ctx}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LoadLibraryExStatus() (useEx, haveEx, haveFlags bool) {
|
||||||
|
return useLoadLibraryEx, _LoadLibraryExW != nil, _AddDllDirectory != nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ const (
|
|||||||
//go:cgo_import_dynamic runtime._SetThreadContext SetThreadContext%2 "kernel32.dll"
|
//go:cgo_import_dynamic runtime._SetThreadContext SetThreadContext%2 "kernel32.dll"
|
||||||
//go:cgo_import_dynamic runtime._LoadLibraryExW LoadLibraryExW%3 "kernel32.dll"
|
//go:cgo_import_dynamic runtime._LoadLibraryExW LoadLibraryExW%3 "kernel32.dll"
|
||||||
//go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll"
|
//go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll"
|
||||||
|
//go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA%1 "kernel32.dll"
|
||||||
//go:cgo_import_dynamic runtime._PostQueuedCompletionStatus PostQueuedCompletionStatus%4 "kernel32.dll"
|
//go:cgo_import_dynamic runtime._PostQueuedCompletionStatus PostQueuedCompletionStatus%4 "kernel32.dll"
|
||||||
//go:cgo_import_dynamic runtime._QueryPerformanceCounter QueryPerformanceCounter%1 "kernel32.dll"
|
//go:cgo_import_dynamic runtime._QueryPerformanceCounter QueryPerformanceCounter%1 "kernel32.dll"
|
||||||
//go:cgo_import_dynamic runtime._QueryPerformanceFrequency QueryPerformanceFrequency%1 "kernel32.dll"
|
//go:cgo_import_dynamic runtime._QueryPerformanceFrequency QueryPerformanceFrequency%1 "kernel32.dll"
|
||||||
@@ -74,6 +75,7 @@ var (
|
|||||||
// Following syscalls are available on every Windows PC.
|
// Following syscalls are available on every Windows PC.
|
||||||
// All these variables are set by the Windows executable
|
// All these variables are set by the Windows executable
|
||||||
// loader before the Go program starts.
|
// loader before the Go program starts.
|
||||||
|
_AddDllDirectory,
|
||||||
_AddVectoredContinueHandler,
|
_AddVectoredContinueHandler,
|
||||||
_AddVectoredExceptionHandler,
|
_AddVectoredExceptionHandler,
|
||||||
_CloseHandle,
|
_CloseHandle,
|
||||||
@@ -99,6 +101,7 @@ var (
|
|||||||
_SetThreadContext,
|
_SetThreadContext,
|
||||||
_LoadLibraryExW,
|
_LoadLibraryExW,
|
||||||
_LoadLibraryW,
|
_LoadLibraryW,
|
||||||
|
_LoadLibraryA,
|
||||||
_PostQueuedCompletionStatus,
|
_PostQueuedCompletionStatus,
|
||||||
_QueryPerformanceCounter,
|
_QueryPerformanceCounter,
|
||||||
_QueryPerformanceFrequency,
|
_QueryPerformanceFrequency,
|
||||||
@@ -157,7 +160,6 @@ var (
|
|||||||
ntdlldll = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0}
|
ntdlldll = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0}
|
||||||
powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0}
|
powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0}
|
||||||
winmmdll = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0}
|
winmmdll = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0}
|
||||||
ws2_32dll = [...]uint16{'w', 's', '2', '_', '3', '2', '.', 'd', 'l', 'l', 0}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Function to be called by windows CreateThread
|
// Function to be called by windows CreateThread
|
||||||
@@ -253,7 +255,36 @@ func windows_GetSystemDirectory() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func windowsLoadSystemLib(name []uint16) uintptr {
|
func windowsLoadSystemLib(name []uint16) uintptr {
|
||||||
return stdcall3(_LoadLibraryExW, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
|
if useLoadLibraryEx {
|
||||||
|
return stdcall3(_LoadLibraryExW, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
|
||||||
|
} else {
|
||||||
|
var nameBytes [_MAX_PATH]byte
|
||||||
|
n := len(name)
|
||||||
|
if n > len(nameBytes) {
|
||||||
|
n = len(nameBytes)
|
||||||
|
}
|
||||||
|
for i := 0; i < n && name[i] != 0; i++ {
|
||||||
|
nameBytes[i] = byte(name[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the full path
|
||||||
|
var fullPath [_MAX_PATH]byte
|
||||||
|
copy(fullPath[:], sysDirectory[:sysDirectoryLen])
|
||||||
|
pathLen := sysDirectoryLen
|
||||||
|
for i := 0; i < len(nameBytes) && nameBytes[i] != 0 && pathLen < _MAX_PATH; i++ {
|
||||||
|
fullPath[pathLen] = nameBytes[i]
|
||||||
|
pathLen++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure null-termination
|
||||||
|
if pathLen < _MAX_PATH {
|
||||||
|
fullPath[pathLen] = 0
|
||||||
|
} else {
|
||||||
|
fullPath[_MAX_PATH-1] = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&fullPath[0])))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:linkname windows_QueryPerformanceCounter internal/syscall/windows.QueryPerformanceCounter
|
//go:linkname windows_QueryPerformanceCounter internal/syscall/windows.QueryPerformanceCounter
|
||||||
@@ -271,6 +302,15 @@ func windows_QueryPerformanceFrequency() int64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func loadOptionalSyscalls() {
|
func loadOptionalSyscalls() {
|
||||||
|
var kernel32dll = []byte("kernel32.dll\000")
|
||||||
|
k32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32dll[0])))
|
||||||
|
if k32 == 0 {
|
||||||
|
throw("kernel32.dll not found")
|
||||||
|
}
|
||||||
|
_AddDllDirectory = windowsFindfunc(k32, []byte("AddDllDirectory\000"))
|
||||||
|
_LoadLibraryExW = windowsFindfunc(k32, []byte("LoadLibraryExW\000"))
|
||||||
|
useLoadLibraryEx = (_LoadLibraryExW != nil && _AddDllDirectory != nil)
|
||||||
|
|
||||||
a32 := windowsLoadSystemLib(advapi32dll[:])
|
a32 := windowsLoadSystemLib(advapi32dll[:])
|
||||||
if a32 == 0 {
|
if a32 == 0 {
|
||||||
throw("advapi32.dll not found")
|
throw("advapi32.dll not found")
|
||||||
@@ -365,6 +405,22 @@ const (
|
|||||||
// in sys_windows_386.s and sys_windows_amd64.s:
|
// in sys_windows_386.s and sys_windows_amd64.s:
|
||||||
func getlasterror() uint32
|
func getlasterror() uint32
|
||||||
|
|
||||||
|
// When loading DLLs, we prefer to use LoadLibraryEx with
|
||||||
|
// LOAD_LIBRARY_SEARCH_* flags, if available. LoadLibraryEx is not
|
||||||
|
// available on old Windows, though, and the LOAD_LIBRARY_SEARCH_*
|
||||||
|
// flags are not available on some versions of Windows without a
|
||||||
|
// security patch.
|
||||||
|
//
|
||||||
|
// 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."
|
||||||
|
var useLoadLibraryEx bool
|
||||||
|
|
||||||
var timeBeginPeriodRetValue uint32
|
var timeBeginPeriodRetValue uint32
|
||||||
|
|
||||||
// osRelaxMinNS indicates that sysmon shouldn't osRelax if the next
|
// osRelaxMinNS indicates that sysmon shouldn't osRelax if the next
|
||||||
|
|||||||
@@ -413,10 +413,23 @@ func callbackWrap(a *callbackArgs) {
|
|||||||
|
|
||||||
const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
|
const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
|
||||||
|
|
||||||
|
// When available, this function will use LoadLibraryEx with the filename
|
||||||
|
// parameter and the important SEARCH_SYSTEM32 argument. But on systems that
|
||||||
|
// do not have that option, absoluteFilepath should contain a fallback
|
||||||
|
// to the full path inside of system32 for use with vanilla LoadLibrary.
|
||||||
|
//
|
||||||
//go:linkname syscall_loadsystemlibrary syscall.loadsystemlibrary
|
//go:linkname syscall_loadsystemlibrary syscall.loadsystemlibrary
|
||||||
func syscall_loadsystemlibrary(filename *uint16) (handle, err uintptr) {
|
func syscall_loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle, err uintptr) {
|
||||||
handle, _, err = syscall_SyscallN(uintptr(unsafe.Pointer(_LoadLibraryExW)), uintptr(unsafe.Pointer(filename)), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
|
if useLoadLibraryEx {
|
||||||
|
handle, _, err = syscall_SyscallN(uintptr(unsafe.Pointer(_LoadLibraryExW)), uintptr(unsafe.Pointer(filename)), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
|
||||||
|
} else {
|
||||||
|
handle, _, err = syscall_SyscallN(
|
||||||
|
uintptr(unsafe.Pointer(_LoadLibraryW)),
|
||||||
|
uintptr(unsafe.Pointer(absoluteFilepath)),
|
||||||
|
)
|
||||||
|
}
|
||||||
KeepAlive(filename)
|
KeepAlive(filename)
|
||||||
|
KeepAlive(absoluteFilepath)
|
||||||
if handle != 0 {
|
if handle != 0 {
|
||||||
err = 0
|
err = 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1166,7 +1166,10 @@ uintptr_t cfunc(void) {
|
|||||||
dll, err = syscall.LoadDLL(name)
|
dll, err = syscall.LoadDLL(name)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
dll.Release()
|
dll.Release()
|
||||||
t.Fatalf("Bad: insecure load of DLL by base name %q before sysdll registration: %v", name, err)
|
if wantLoadLibraryEx() {
|
||||||
|
t.Fatalf("Bad: insecure load of DLL by base name %q before sysdll registration: %v", name, err)
|
||||||
|
}
|
||||||
|
t.Skip("insecure load of DLL, but expected")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1212,6 +1215,24 @@ func TestBigStackCallbackSyscall(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wantLoadLibraryEx reports whether we expect LoadLibraryEx to work for tests.
|
||||||
|
func wantLoadLibraryEx() bool {
|
||||||
|
return testenv.Builder() != "" && (runtime.GOARCH == "amd64" || runtime.GOARCH == "386")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoadLibraryEx(t *testing.T) {
|
||||||
|
use, have, flags := runtime.LoadLibraryExStatus()
|
||||||
|
if use {
|
||||||
|
return // success.
|
||||||
|
}
|
||||||
|
if wantLoadLibraryEx() {
|
||||||
|
t.Fatalf("Expected LoadLibraryEx+flags to be available. (LoadLibraryEx=%v; flags=%v)",
|
||||||
|
have, flags)
|
||||||
|
}
|
||||||
|
t.Skipf("LoadLibraryEx not usable, but not expected. (LoadLibraryEx=%v; flags=%v)",
|
||||||
|
have, flags)
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
modwinmm = syscall.NewLazyDLL("winmm.dll")
|
modwinmm = syscall.NewLazyDLL("winmm.dll")
|
||||||
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ func Syscall18(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a
|
|||||||
|
|
||||||
func SyscallN(trap uintptr, args ...uintptr) (r1, r2 uintptr, err Errno)
|
func SyscallN(trap uintptr, args ...uintptr) (r1, r2 uintptr, err Errno)
|
||||||
func loadlibrary(filename *uint16) (handle uintptr, err Errno)
|
func loadlibrary(filename *uint16) (handle uintptr, err Errno)
|
||||||
func loadsystemlibrary(filename *uint16) (handle uintptr, err Errno)
|
func loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle uintptr, err Errno)
|
||||||
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno)
|
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno)
|
||||||
|
|
||||||
// A DLL implements access to a single DLL.
|
// A DLL implements access to a single DLL.
|
||||||
@@ -53,6 +53,26 @@ type DLL struct {
|
|||||||
Handle Handle
|
Handle Handle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We use this for computing the absolute path for system DLLs on systems
|
||||||
|
// where SEARCH_SYSTEM32 is not available.
|
||||||
|
var systemDirectoryPrefix string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
n := uint32(MAX_PATH)
|
||||||
|
for {
|
||||||
|
b := make([]uint16, n)
|
||||||
|
l, e := getSystemDirectory(&b[0], n)
|
||||||
|
if e != nil {
|
||||||
|
panic("Unable to determine system directory: " + e.Error())
|
||||||
|
}
|
||||||
|
if l <= n {
|
||||||
|
systemDirectoryPrefix = UTF16ToString(b[:l]) + "\\"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
n = l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// LoadDLL loads the named DLL file into memory.
|
// LoadDLL loads the named DLL file into memory.
|
||||||
//
|
//
|
||||||
// If name is not an absolute path and is not a known system DLL used by
|
// If name is not an absolute path and is not a known system DLL used by
|
||||||
@@ -69,7 +89,11 @@ func LoadDLL(name string) (*DLL, error) {
|
|||||||
var h uintptr
|
var h uintptr
|
||||||
var e Errno
|
var e Errno
|
||||||
if sysdll.IsSystemDLL[name] {
|
if sysdll.IsSystemDLL[name] {
|
||||||
h, e = loadsystemlibrary(namep)
|
absoluteFilepathp, err := UTF16PtrFromString(systemDirectoryPrefix + name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
h, e = loadsystemlibrary(namep, absoluteFilepathp)
|
||||||
} else {
|
} else {
|
||||||
h, e = loadlibrary(namep)
|
h, e = loadlibrary(namep)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -290,6 +290,7 @@ type Tokenprimarygroup struct {
|
|||||||
//sys OpenProcessToken(h Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken
|
//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 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 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.
|
// An access token contains the security information for a logon session.
|
||||||
// The system creates an access token when a user logs on, and every
|
// The system creates an access token when a user logs on, and every
|
||||||
|
|||||||
@@ -128,6 +128,7 @@ var (
|
|||||||
procGetShortPathNameW = modkernel32.NewProc("GetShortPathNameW")
|
procGetShortPathNameW = modkernel32.NewProc("GetShortPathNameW")
|
||||||
procGetStartupInfoW = modkernel32.NewProc("GetStartupInfoW")
|
procGetStartupInfoW = modkernel32.NewProc("GetStartupInfoW")
|
||||||
procGetStdHandle = modkernel32.NewProc("GetStdHandle")
|
procGetStdHandle = modkernel32.NewProc("GetStdHandle")
|
||||||
|
procGetSystemDirectoryW = modkernel32.NewProc("GetSystemDirectoryW")
|
||||||
procGetSystemTimeAsFileTime = modkernel32.NewProc("GetSystemTimeAsFileTime")
|
procGetSystemTimeAsFileTime = modkernel32.NewProc("GetSystemTimeAsFileTime")
|
||||||
procGetTempPathW = modkernel32.NewProc("GetTempPathW")
|
procGetTempPathW = modkernel32.NewProc("GetTempPathW")
|
||||||
procGetTimeZoneInformation = modkernel32.NewProc("GetTimeZoneInformation")
|
procGetTimeZoneInformation = modkernel32.NewProc("GetTimeZoneInformation")
|
||||||
@@ -870,6 +871,15 @@ func GetStdHandle(stdhandle int) (handle Handle, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getSystemDirectory(dir *uint16, dirLen uint32) (len uint32, err error) {
|
||||||
|
r0, _, e1 := Syscall(procGetSystemDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(dir)), uintptr(dirLen), 0)
|
||||||
|
len = uint32(r0)
|
||||||
|
if len == 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func GetSystemTimeAsFileTime(time *Filetime) {
|
func GetSystemTimeAsFileTime(time *Filetime) {
|
||||||
Syscall(procGetSystemTimeAsFileTime.Addr(), 1, uintptr(unsafe.Pointer(time)), 0, 0)
|
Syscall(procGetSystemTimeAsFileTime.Addr(), 1, uintptr(unsafe.Pointer(time)), 0, 0)
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user