github.com/tailscale/wireguard-go@v0.0.20201119-0.20210522003738-46b531feb08a/tun/wintun/memmod/memmod_windows.go (about)

     1  /* SPDX-License-Identifier: MIT
     2   *
     3   * Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
     4   */
     5  
     6  package memmod
     7  
     8  import (
     9  	"errors"
    10  	"fmt"
    11  	"syscall"
    12  	"unsafe"
    13  
    14  	"golang.org/x/sys/windows"
    15  )
    16  
    17  type addressList struct {
    18  	next    *addressList
    19  	address uintptr
    20  }
    21  
    22  func (head *addressList) free() {
    23  	for node := head; node != nil; node = node.next {
    24  		windows.VirtualFree(node.address, 0, windows.MEM_RELEASE)
    25  	}
    26  }
    27  
    28  type Module struct {
    29  	headers       *IMAGE_NT_HEADERS
    30  	codeBase      uintptr
    31  	modules       []windows.Handle
    32  	initialized   bool
    33  	isDLL         bool
    34  	isRelocated   bool
    35  	nameExports   map[string]uint16
    36  	entry         uintptr
    37  	blockedMemory *addressList
    38  }
    39  
    40  func (module *Module) headerDirectory(idx int) *IMAGE_DATA_DIRECTORY {
    41  	return &module.headers.OptionalHeader.DataDirectory[idx]
    42  }
    43  
    44  func (module *Module) copySections(address uintptr, size uintptr, old_headers *IMAGE_NT_HEADERS) error {
    45  	sections := module.headers.Sections()
    46  	for i := range sections {
    47  		if sections[i].SizeOfRawData == 0 {
    48  			// Section doesn't contain data in the dll itself, but may define uninitialized data.
    49  			sectionSize := old_headers.OptionalHeader.SectionAlignment
    50  			if sectionSize == 0 {
    51  				continue
    52  			}
    53  			dest, err := windows.VirtualAlloc(module.codeBase+uintptr(sections[i].VirtualAddress),
    54  				uintptr(sectionSize),
    55  				windows.MEM_COMMIT,
    56  				windows.PAGE_READWRITE)
    57  			if err != nil {
    58  				return fmt.Errorf("Error allocating section: %w", err)
    59  			}
    60  
    61  			// Always use position from file to support alignments smaller than page size (allocation above will align to page size).
    62  			dest = module.codeBase + uintptr(sections[i].VirtualAddress)
    63  			// NOTE: On 64bit systems we truncate to 32bit here but expand again later when "PhysicalAddress" is used.
    64  			sections[i].SetPhysicalAddress((uint32)(dest & 0xffffffff))
    65  			var dst []byte
    66  			unsafeSlice(unsafe.Pointer(&dst), a2p(dest), int(sectionSize))
    67  			for j := range dst {
    68  				dst[j] = 0
    69  			}
    70  			continue
    71  		}
    72  
    73  		if size < uintptr(sections[i].PointerToRawData+sections[i].SizeOfRawData) {
    74  			return errors.New("Incomplete section")
    75  		}
    76  
    77  		// Commit memory block and copy data from dll.
    78  		dest, err := windows.VirtualAlloc(module.codeBase+uintptr(sections[i].VirtualAddress),
    79  			uintptr(sections[i].SizeOfRawData),
    80  			windows.MEM_COMMIT,
    81  			windows.PAGE_READWRITE)
    82  		if err != nil {
    83  			return fmt.Errorf("Error allocating memory block: %w", err)
    84  		}
    85  
    86  		// Always use position from file to support alignments smaller than page size (allocation above will align to page size).
    87  		memcpy(
    88  			module.codeBase+uintptr(sections[i].VirtualAddress),
    89  			address+uintptr(sections[i].PointerToRawData),
    90  			uintptr(sections[i].SizeOfRawData))
    91  		// NOTE: On 64bit systems we truncate to 32bit here but expand again later when "PhysicalAddress" is used.
    92  		sections[i].SetPhysicalAddress((uint32)(dest & 0xffffffff))
    93  	}
    94  
    95  	return nil
    96  }
    97  
    98  func (module *Module) realSectionSize(section *IMAGE_SECTION_HEADER) uintptr {
    99  	size := section.SizeOfRawData
   100  	if size != 0 {
   101  		return uintptr(size)
   102  	}
   103  	if (section.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) != 0 {
   104  		return uintptr(module.headers.OptionalHeader.SizeOfInitializedData)
   105  	}
   106  	if (section.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) != 0 {
   107  		return uintptr(module.headers.OptionalHeader.SizeOfUninitializedData)
   108  	}
   109  	return 0
   110  }
   111  
   112  type sectionFinalizeData struct {
   113  	address         uintptr
   114  	alignedAddress  uintptr
   115  	size            uintptr
   116  	characteristics uint32
   117  	last            bool
   118  }
   119  
   120  func (module *Module) finalizeSection(sectionData *sectionFinalizeData) error {
   121  	if sectionData.size == 0 {
   122  		return nil
   123  	}
   124  
   125  	if (sectionData.characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0 {
   126  		// Section is not needed any more and can safely be freed.
   127  		if sectionData.address == sectionData.alignedAddress &&
   128  			(sectionData.last ||
   129  				(sectionData.size%uintptr(module.headers.OptionalHeader.SectionAlignment)) == 0) {
   130  			// Only allowed to decommit whole pages.
   131  			windows.VirtualFree(sectionData.address, sectionData.size, windows.MEM_DECOMMIT)
   132  		}
   133  		return nil
   134  	}
   135  
   136  	// determine protection flags based on characteristics
   137  	var ProtectionFlags = [8]uint32{
   138  		windows.PAGE_NOACCESS,          // not writeable, not readable, not executable
   139  		windows.PAGE_EXECUTE,           // not writeable, not readable, executable
   140  		windows.PAGE_READONLY,          // not writeable, readable, not executable
   141  		windows.PAGE_EXECUTE_READ,      // not writeable, readable, executable
   142  		windows.PAGE_WRITECOPY,         // writeable, not readable, not executable
   143  		windows.PAGE_EXECUTE_WRITECOPY, // writeable, not readable, executable
   144  		windows.PAGE_READWRITE,         // writeable, readable, not executable
   145  		windows.PAGE_EXECUTE_READWRITE, // writeable, readable, executable
   146  	}
   147  	protect := ProtectionFlags[sectionData.characteristics>>29]
   148  	if (sectionData.characteristics & IMAGE_SCN_MEM_NOT_CACHED) != 0 {
   149  		protect |= windows.PAGE_NOCACHE
   150  	}
   151  
   152  	// Change memory access flags.
   153  	var oldProtect uint32
   154  	err := windows.VirtualProtect(sectionData.address, sectionData.size, protect, &oldProtect)
   155  	if err != nil {
   156  		return fmt.Errorf("Error protecting memory page: %w", err)
   157  	}
   158  
   159  	return nil
   160  }
   161  
   162  func (module *Module) finalizeSections() error {
   163  	sections := module.headers.Sections()
   164  	imageOffset := module.headers.OptionalHeader.imageOffset()
   165  	sectionData := sectionFinalizeData{}
   166  	sectionData.address = uintptr(sections[0].PhysicalAddress()) | imageOffset
   167  	sectionData.alignedAddress = alignDown(sectionData.address, uintptr(module.headers.OptionalHeader.SectionAlignment))
   168  	sectionData.size = module.realSectionSize(&sections[0])
   169  	sectionData.characteristics = sections[0].Characteristics
   170  
   171  	// Loop through all sections and change access flags.
   172  	for i := uint16(1); i < module.headers.FileHeader.NumberOfSections; i++ {
   173  		sectionAddress := uintptr(sections[i].PhysicalAddress()) | imageOffset
   174  		alignedAddress := alignDown(sectionAddress, uintptr(module.headers.OptionalHeader.SectionAlignment))
   175  		sectionSize := module.realSectionSize(&sections[i])
   176  		// Combine access flags of all sections that share a page.
   177  		// TODO: We currently share flags of a trailing large section with the page of a first small section. This should be optimized.
   178  		if sectionData.alignedAddress == alignedAddress || sectionData.address+sectionData.size > alignedAddress {
   179  			// Section shares page with previous.
   180  			if (sections[i].Characteristics&IMAGE_SCN_MEM_DISCARDABLE) == 0 || (sectionData.characteristics&IMAGE_SCN_MEM_DISCARDABLE) == 0 {
   181  				sectionData.characteristics = (sectionData.characteristics | sections[i].Characteristics) &^ IMAGE_SCN_MEM_DISCARDABLE
   182  			} else {
   183  				sectionData.characteristics |= sections[i].Characteristics
   184  			}
   185  			sectionData.size = sectionAddress + sectionSize - sectionData.address
   186  			continue
   187  		}
   188  
   189  		err := module.finalizeSection(&sectionData)
   190  		if err != nil {
   191  			return fmt.Errorf("Error finalizing section: %w", err)
   192  		}
   193  		sectionData.address = sectionAddress
   194  		sectionData.alignedAddress = alignedAddress
   195  		sectionData.size = sectionSize
   196  		sectionData.characteristics = sections[i].Characteristics
   197  	}
   198  	sectionData.last = true
   199  	err := module.finalizeSection(&sectionData)
   200  	if err != nil {
   201  		return fmt.Errorf("Error finalizing section: %w", err)
   202  	}
   203  	return nil
   204  }
   205  
   206  func (module *Module) executeTLS() {
   207  	directory := module.headerDirectory(IMAGE_DIRECTORY_ENTRY_TLS)
   208  	if directory.VirtualAddress == 0 {
   209  		return
   210  	}
   211  
   212  	tls := (*IMAGE_TLS_DIRECTORY)(a2p(module.codeBase + uintptr(directory.VirtualAddress)))
   213  	callback := tls.AddressOfCallbacks
   214  	if callback != 0 {
   215  		for {
   216  			f := *(*uintptr)(a2p(callback))
   217  			if f == 0 {
   218  				break
   219  			}
   220  			syscall.Syscall(f, 3, module.codeBase, uintptr(DLL_PROCESS_ATTACH), uintptr(0))
   221  			callback += unsafe.Sizeof(f)
   222  		}
   223  	}
   224  }
   225  
   226  func (module *Module) performBaseRelocation(delta uintptr) (relocated bool, err error) {
   227  	directory := module.headerDirectory(IMAGE_DIRECTORY_ENTRY_BASERELOC)
   228  	if directory.Size == 0 {
   229  		return delta == 0, nil
   230  	}
   231  
   232  	relocationHdr := (*IMAGE_BASE_RELOCATION)(a2p(module.codeBase + uintptr(directory.VirtualAddress)))
   233  	for relocationHdr.VirtualAddress > 0 {
   234  		dest := module.codeBase + uintptr(relocationHdr.VirtualAddress)
   235  
   236  		var relInfos []uint16
   237  		unsafeSlice(
   238  			unsafe.Pointer(&relInfos),
   239  			a2p(uintptr(unsafe.Pointer(relocationHdr))+unsafe.Sizeof(*relocationHdr)),
   240  			int((uintptr(relocationHdr.SizeOfBlock)-unsafe.Sizeof(*relocationHdr))/unsafe.Sizeof(relInfos[0])))
   241  		for _, relInfo := range relInfos {
   242  			// The upper 4 bits define the type of relocation.
   243  			relType := relInfo >> 12
   244  			// The lower 12 bits define the offset.
   245  			relOffset := uintptr(relInfo & 0xfff)
   246  
   247  			switch relType {
   248  			case IMAGE_REL_BASED_ABSOLUTE:
   249  				// Skip relocation.
   250  
   251  			case IMAGE_REL_BASED_LOW:
   252  				*(*uint16)(a2p(dest + relOffset)) += uint16(delta & 0xffff)
   253  				break
   254  
   255  			case IMAGE_REL_BASED_HIGH:
   256  				*(*uint16)(a2p(dest + relOffset)) += uint16(uint32(delta) >> 16)
   257  				break
   258  
   259  			case IMAGE_REL_BASED_HIGHLOW:
   260  				*(*uint32)(a2p(dest + relOffset)) += uint32(delta)
   261  
   262  			case IMAGE_REL_BASED_DIR64:
   263  				*(*uint64)(a2p(dest + relOffset)) += uint64(delta)
   264  
   265  			case IMAGE_REL_BASED_THUMB_MOV32:
   266  				inst := *(*uint32)(a2p(dest + relOffset))
   267  				imm16 := ((inst << 1) & 0x0800) + ((inst << 12) & 0xf000) +
   268  					((inst >> 20) & 0x0700) + ((inst >> 16) & 0x00ff)
   269  				if (inst & 0x8000fbf0) != 0x0000f240 {
   270  					return false, fmt.Errorf("Wrong Thumb2 instruction %08x, expected MOVW", inst)
   271  				}
   272  				imm16 += uint32(delta) & 0xffff
   273  				hiDelta := (uint32(delta&0xffff0000) >> 16) + ((imm16 & 0xffff0000) >> 16)
   274  				*(*uint32)(a2p(dest + relOffset)) = (inst & 0x8f00fbf0) + ((imm16 >> 1) & 0x0400) +
   275  					((imm16 >> 12) & 0x000f) +
   276  					((imm16 << 20) & 0x70000000) +
   277  					((imm16 << 16) & 0xff0000)
   278  				if hiDelta != 0 {
   279  					inst = *(*uint32)(a2p(dest + relOffset + 4))
   280  					imm16 = ((inst << 1) & 0x0800) + ((inst << 12) & 0xf000) +
   281  						((inst >> 20) & 0x0700) + ((inst >> 16) & 0x00ff)
   282  					if (inst & 0x8000fbf0) != 0x0000f2c0 {
   283  						return false, fmt.Errorf("Wrong Thumb2 instruction %08x, expected MOVT", inst)
   284  					}
   285  					imm16 += hiDelta
   286  					if imm16 > 0xffff {
   287  						return false, fmt.Errorf("Resulting immediate value won't fit: %08x", imm16)
   288  					}
   289  					*(*uint32)(a2p(dest + relOffset + 4)) = (inst & 0x8f00fbf0) +
   290  						((imm16 >> 1) & 0x0400) +
   291  						((imm16 >> 12) & 0x000f) +
   292  						((imm16 << 20) & 0x70000000) +
   293  						((imm16 << 16) & 0xff0000)
   294  				}
   295  
   296  			default:
   297  				return false, fmt.Errorf("Unsupported relocation: %v", relType)
   298  			}
   299  		}
   300  
   301  		// Advance to next relocation block.
   302  		relocationHdr = (*IMAGE_BASE_RELOCATION)(a2p(uintptr(unsafe.Pointer(relocationHdr)) + uintptr(relocationHdr.SizeOfBlock)))
   303  	}
   304  	return true, nil
   305  }
   306  
   307  func (module *Module) buildImportTable() error {
   308  	directory := module.headerDirectory(IMAGE_DIRECTORY_ENTRY_IMPORT)
   309  	if directory.Size == 0 {
   310  		return nil
   311  	}
   312  
   313  	module.modules = make([]windows.Handle, 0, 16)
   314  	importDesc := (*IMAGE_IMPORT_DESCRIPTOR)(a2p(module.codeBase + uintptr(directory.VirtualAddress)))
   315  	for importDesc.Name != 0 {
   316  		handle, err := windows.LoadLibraryEx(windows.BytePtrToString((*byte)(a2p(module.codeBase+uintptr(importDesc.Name)))), 0, windows.LOAD_LIBRARY_SEARCH_SYSTEM32)
   317  		if err != nil {
   318  			return fmt.Errorf("Error loading module: %w", err)
   319  		}
   320  		var thunkRef, funcRef *uintptr
   321  		if importDesc.OriginalFirstThunk() != 0 {
   322  			thunkRef = (*uintptr)(a2p(module.codeBase + uintptr(importDesc.OriginalFirstThunk())))
   323  			funcRef = (*uintptr)(a2p(module.codeBase + uintptr(importDesc.FirstThunk)))
   324  		} else {
   325  			// No hint table.
   326  			thunkRef = (*uintptr)(a2p(module.codeBase + uintptr(importDesc.FirstThunk)))
   327  			funcRef = (*uintptr)(a2p(module.codeBase + uintptr(importDesc.FirstThunk)))
   328  		}
   329  		for *thunkRef != 0 {
   330  			if IMAGE_SNAP_BY_ORDINAL(*thunkRef) {
   331  				*funcRef, err = windows.GetProcAddressByOrdinal(handle, IMAGE_ORDINAL(*thunkRef))
   332  			} else {
   333  				thunkData := (*IMAGE_IMPORT_BY_NAME)(a2p(module.codeBase + *thunkRef))
   334  				*funcRef, err = windows.GetProcAddress(handle, windows.BytePtrToString(&thunkData.Name[0]))
   335  			}
   336  			if err != nil {
   337  				windows.FreeLibrary(handle)
   338  				return fmt.Errorf("Error getting function address: %w", err)
   339  			}
   340  			thunkRef = (*uintptr)(a2p(uintptr(unsafe.Pointer(thunkRef)) + unsafe.Sizeof(*thunkRef)))
   341  			funcRef = (*uintptr)(a2p(uintptr(unsafe.Pointer(funcRef)) + unsafe.Sizeof(*funcRef)))
   342  		}
   343  		module.modules = append(module.modules, handle)
   344  		importDesc = (*IMAGE_IMPORT_DESCRIPTOR)(a2p(uintptr(unsafe.Pointer(importDesc)) + unsafe.Sizeof(*importDesc)))
   345  	}
   346  	return nil
   347  }
   348  
   349  func (module *Module) buildNameExports() error {
   350  	directory := module.headerDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT)
   351  	if directory.Size == 0 {
   352  		return errors.New("No export table found")
   353  	}
   354  	exports := (*IMAGE_EXPORT_DIRECTORY)(a2p(module.codeBase + uintptr(directory.VirtualAddress)))
   355  	if exports.NumberOfNames == 0 || exports.NumberOfFunctions == 0 {
   356  		return errors.New("No functions exported")
   357  	}
   358  	if exports.NumberOfNames == 0 {
   359  		return errors.New("No functions exported by name")
   360  	}
   361  	var nameRefs []uint32
   362  	unsafeSlice(unsafe.Pointer(&nameRefs), a2p(module.codeBase+uintptr(exports.AddressOfNames)), int(exports.NumberOfNames))
   363  	var ordinals []uint16
   364  	unsafeSlice(unsafe.Pointer(&ordinals), a2p(module.codeBase+uintptr(exports.AddressOfNameOrdinals)), int(exports.NumberOfNames))
   365  	module.nameExports = make(map[string]uint16)
   366  	for i := range nameRefs {
   367  		nameArray := windows.BytePtrToString((*byte)(a2p(module.codeBase + uintptr(nameRefs[i]))))
   368  		module.nameExports[nameArray] = ordinals[i]
   369  	}
   370  	return nil
   371  }
   372  
   373  // LoadLibrary loads module image to memory.
   374  func LoadLibrary(data []byte) (module *Module, err error) {
   375  	addr := uintptr(unsafe.Pointer(&data[0]))
   376  	size := uintptr(len(data))
   377  	if size < unsafe.Sizeof(IMAGE_DOS_HEADER{}) {
   378  		return nil, errors.New("Incomplete IMAGE_DOS_HEADER")
   379  	}
   380  	dosHeader := (*IMAGE_DOS_HEADER)(a2p(addr))
   381  	if dosHeader.E_magic != IMAGE_DOS_SIGNATURE {
   382  		return nil, fmt.Errorf("Not an MS-DOS binary (provided: %x, expected: %x)", dosHeader.E_magic, IMAGE_DOS_SIGNATURE)
   383  	}
   384  	if (size < uintptr(dosHeader.E_lfanew)+unsafe.Sizeof(IMAGE_NT_HEADERS{})) {
   385  		return nil, errors.New("Incomplete IMAGE_NT_HEADERS")
   386  	}
   387  	oldHeader := (*IMAGE_NT_HEADERS)(a2p(addr + uintptr(dosHeader.E_lfanew)))
   388  	if oldHeader.Signature != IMAGE_NT_SIGNATURE {
   389  		return nil, fmt.Errorf("Not an NT binary (provided: %x, expected: %x)", oldHeader.Signature, IMAGE_NT_SIGNATURE)
   390  	}
   391  	if oldHeader.FileHeader.Machine != imageFileProcess {
   392  		return nil, fmt.Errorf("Foreign platform (provided: %x, expected: %x)", oldHeader.FileHeader.Machine, imageFileProcess)
   393  	}
   394  	if (oldHeader.OptionalHeader.SectionAlignment & 1) != 0 {
   395  		return nil, errors.New("Unaligned section")
   396  	}
   397  	lastSectionEnd := uintptr(0)
   398  	sections := oldHeader.Sections()
   399  	optionalSectionSize := oldHeader.OptionalHeader.SectionAlignment
   400  	for i := range sections {
   401  		var endOfSection uintptr
   402  		if sections[i].SizeOfRawData == 0 {
   403  			// Section without data in the DLL
   404  			endOfSection = uintptr(sections[i].VirtualAddress) + uintptr(optionalSectionSize)
   405  		} else {
   406  			endOfSection = uintptr(sections[i].VirtualAddress) + uintptr(sections[i].SizeOfRawData)
   407  		}
   408  		if endOfSection > lastSectionEnd {
   409  			lastSectionEnd = endOfSection
   410  		}
   411  	}
   412  	alignedImageSize := alignUp(uintptr(oldHeader.OptionalHeader.SizeOfImage), uintptr(oldHeader.OptionalHeader.SectionAlignment))
   413  	if alignedImageSize != alignUp(lastSectionEnd, uintptr(oldHeader.OptionalHeader.SectionAlignment)) {
   414  		return nil, errors.New("Section is not page-aligned")
   415  	}
   416  
   417  	module = &Module{isDLL: (oldHeader.FileHeader.Characteristics & IMAGE_FILE_DLL) != 0}
   418  	defer func() {
   419  		if err != nil {
   420  			module.Free()
   421  			module = nil
   422  		}
   423  	}()
   424  
   425  	// Reserve memory for image of library.
   426  	// TODO: Is it correct to commit the complete memory region at once? Calling DllEntry raises an exception if we don't.
   427  	module.codeBase, err = windows.VirtualAlloc(oldHeader.OptionalHeader.ImageBase,
   428  		alignedImageSize,
   429  		windows.MEM_RESERVE|windows.MEM_COMMIT,
   430  		windows.PAGE_READWRITE)
   431  	if err != nil {
   432  		// Try to allocate memory at arbitrary position.
   433  		module.codeBase, err = windows.VirtualAlloc(0,
   434  			alignedImageSize,
   435  			windows.MEM_RESERVE|windows.MEM_COMMIT,
   436  			windows.PAGE_READWRITE)
   437  		if err != nil {
   438  			err = fmt.Errorf("Error allocating code: %w", err)
   439  			return
   440  		}
   441  	}
   442  	err = module.check4GBBoundaries(alignedImageSize)
   443  	if err != nil {
   444  		err = fmt.Errorf("Error reallocating code: %w", err)
   445  		return
   446  	}
   447  
   448  	if size < uintptr(oldHeader.OptionalHeader.SizeOfHeaders) {
   449  		err = errors.New("Incomplete headers")
   450  		return
   451  	}
   452  	// Commit memory for headers.
   453  	headers, err := windows.VirtualAlloc(module.codeBase,
   454  		uintptr(oldHeader.OptionalHeader.SizeOfHeaders),
   455  		windows.MEM_COMMIT,
   456  		windows.PAGE_READWRITE)
   457  	if err != nil {
   458  		err = fmt.Errorf("Error allocating headers: %w", err)
   459  		return
   460  	}
   461  	// Copy PE header to code.
   462  	memcpy(headers, addr, uintptr(oldHeader.OptionalHeader.SizeOfHeaders))
   463  	module.headers = (*IMAGE_NT_HEADERS)(a2p(headers + uintptr(dosHeader.E_lfanew)))
   464  
   465  	// Update position.
   466  	module.headers.OptionalHeader.ImageBase = module.codeBase
   467  
   468  	// Copy sections from DLL file block to new memory location.
   469  	err = module.copySections(addr, size, oldHeader)
   470  	if err != nil {
   471  		err = fmt.Errorf("Error copying sections: %w", err)
   472  		return
   473  	}
   474  
   475  	// Adjust base address of imported data.
   476  	locationDelta := module.headers.OptionalHeader.ImageBase - oldHeader.OptionalHeader.ImageBase
   477  	if locationDelta != 0 {
   478  		module.isRelocated, err = module.performBaseRelocation(locationDelta)
   479  		if err != nil {
   480  			err = fmt.Errorf("Error relocating module: %w", err)
   481  			return
   482  		}
   483  	} else {
   484  		module.isRelocated = true
   485  	}
   486  
   487  	// Load required dlls and adjust function table of imports.
   488  	err = module.buildImportTable()
   489  	if err != nil {
   490  		err = fmt.Errorf("Error building import table: %w", err)
   491  		return
   492  	}
   493  
   494  	// Mark memory pages depending on section headers and release sections that are marked as "discardable".
   495  	err = module.finalizeSections()
   496  	if err != nil {
   497  		err = fmt.Errorf("Error finalizing sections: %w", err)
   498  		return
   499  	}
   500  
   501  	// TLS callbacks are executed BEFORE the main loading.
   502  	module.executeTLS()
   503  
   504  	// Get entry point of loaded module.
   505  	if module.headers.OptionalHeader.AddressOfEntryPoint != 0 {
   506  		module.entry = module.codeBase + uintptr(module.headers.OptionalHeader.AddressOfEntryPoint)
   507  		if module.isDLL {
   508  			// Notify library about attaching to process.
   509  			r0, _, _ := syscall.Syscall(module.entry, 3, module.codeBase, uintptr(DLL_PROCESS_ATTACH), 0)
   510  			successful := r0 != 0
   511  			if !successful {
   512  				err = windows.ERROR_DLL_INIT_FAILED
   513  				return
   514  			}
   515  			module.initialized = true
   516  		}
   517  	}
   518  
   519  	module.buildNameExports()
   520  	return
   521  }
   522  
   523  // Free releases module resources and unloads it.
   524  func (module *Module) Free() {
   525  	if module.initialized {
   526  		// Notify library about detaching from process.
   527  		syscall.Syscall(module.entry, 3, module.codeBase, uintptr(DLL_PROCESS_DETACH), 0)
   528  		module.initialized = false
   529  	}
   530  	if module.modules != nil {
   531  		// Free previously opened libraries.
   532  		for _, handle := range module.modules {
   533  			windows.FreeLibrary(handle)
   534  		}
   535  		module.modules = nil
   536  	}
   537  	if module.codeBase != 0 {
   538  		windows.VirtualFree(module.codeBase, 0, windows.MEM_RELEASE)
   539  		module.codeBase = 0
   540  	}
   541  	if module.blockedMemory != nil {
   542  		module.blockedMemory.free()
   543  		module.blockedMemory = nil
   544  	}
   545  }
   546  
   547  // ProcAddressByName returns function address by exported name.
   548  func (module *Module) ProcAddressByName(name string) (uintptr, error) {
   549  	directory := module.headerDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT)
   550  	if directory.Size == 0 {
   551  		return 0, errors.New("No export table found")
   552  	}
   553  	exports := (*IMAGE_EXPORT_DIRECTORY)(a2p(module.codeBase + uintptr(directory.VirtualAddress)))
   554  	if module.nameExports == nil {
   555  		return 0, errors.New("No functions exported by name")
   556  	}
   557  	if idx, ok := module.nameExports[name]; ok {
   558  		if uint32(idx) > exports.NumberOfFunctions {
   559  			return 0, errors.New("Ordinal number too high")
   560  		}
   561  		// AddressOfFunctions contains the RVAs to the "real" functions.
   562  		return module.codeBase + uintptr(*(*uint32)(a2p(module.codeBase + uintptr(exports.AddressOfFunctions) + uintptr(idx)*4))), nil
   563  	}
   564  	return 0, errors.New("Function not found by name")
   565  }
   566  
   567  // ProcAddressByOrdinal returns function address by exported ordinal.
   568  func (module *Module) ProcAddressByOrdinal(ordinal uint16) (uintptr, error) {
   569  	directory := module.headerDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT)
   570  	if directory.Size == 0 {
   571  		return 0, errors.New("No export table found")
   572  	}
   573  	exports := (*IMAGE_EXPORT_DIRECTORY)(a2p(module.codeBase + uintptr(directory.VirtualAddress)))
   574  	if uint32(ordinal) < exports.Base {
   575  		return 0, errors.New("Ordinal number too low")
   576  	}
   577  	idx := ordinal - uint16(exports.Base)
   578  	if uint32(idx) > exports.NumberOfFunctions {
   579  		return 0, errors.New("Ordinal number too high")
   580  	}
   581  	// AddressOfFunctions contains the RVAs to the "real" functions.
   582  	return module.codeBase + uintptr(*(*uint32)(a2p(module.codeBase + uintptr(exports.AddressOfFunctions) + uintptr(idx)*4))), nil
   583  }
   584  
   585  func alignDown(value, alignment uintptr) uintptr {
   586  	return value & ^(alignment - 1)
   587  }
   588  
   589  func alignUp(value, alignment uintptr) uintptr {
   590  	return (value + alignment - 1) & ^(alignment - 1)
   591  }
   592  
   593  func a2p(addr uintptr) unsafe.Pointer {
   594  	return unsafe.Pointer(addr)
   595  }
   596  
   597  func memcpy(dst, src, size uintptr) {
   598  	var d, s []byte
   599  	unsafeSlice(unsafe.Pointer(&d), a2p(dst), int(size))
   600  	unsafeSlice(unsafe.Pointer(&s), a2p(src), int(size))
   601  	copy(d, s)
   602  }
   603  
   604  // unsafeSlice updates the slice slicePtr to be a slice
   605  // referencing the provided data with its length & capacity set to
   606  // lenCap.
   607  //
   608  // TODO: when Go 1.16 or Go 1.17 is the minimum supported version,
   609  // update callers to use unsafe.Slice instead of this.
   610  func unsafeSlice(slicePtr, data unsafe.Pointer, lenCap int) {
   611  	type sliceHeader struct {
   612  		Data unsafe.Pointer
   613  		Len  int
   614  		Cap  int
   615  	}
   616  	h := (*sliceHeader)(slicePtr)
   617  	h.Data = data
   618  	h.Len = lenCap
   619  	h.Cap = lenCap
   620  }