Switch remote deploy to vendored source builds
Move remote deployment to a vendored source bundle built on the target host via Docker so redeploys no longer require local cross-compilation or host Go installation. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
25
vendor/github.com/jchv/go-winloader/internal/loader/loader.go
generated
vendored
Normal file
25
vendor/github.com/jchv/go-winloader/internal/loader/loader.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
package loader
|
||||
|
||||
// Module represents a loaded Windows module.
|
||||
type Module interface {
|
||||
// Proc returns a procedure by symbol name. Returns nil if the symbol is
|
||||
// not found.
|
||||
Proc(name string) Proc
|
||||
|
||||
// Ordinal returns a procedure by ordinal.
|
||||
Ordinal(ordinal uint64) Proc
|
||||
|
||||
// Free closes the module and frees the memory. After this, GetProcAddress
|
||||
// will stop working and procedures will no longer function.
|
||||
Free() error
|
||||
}
|
||||
|
||||
// Loader represents a named module loader implementation.
|
||||
type Loader interface {
|
||||
Load(libname string) (Module, error)
|
||||
}
|
||||
|
||||
// MemLoader represents a memory module loader implementation.
|
||||
type MemLoader interface {
|
||||
LoadMem(module []byte) (Module, error)
|
||||
}
|
||||
53
vendor/github.com/jchv/go-winloader/internal/loader/machine.go
generated
vendored
Normal file
53
vendor/github.com/jchv/go-winloader/internal/loader/machine.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
package loader
|
||||
|
||||
import "io"
|
||||
|
||||
// Proc represents a procedure in memory.
|
||||
type Proc interface {
|
||||
// Call calls the procedure. r1 and r2 contain the return value. lastErr
|
||||
// contains the Windows error value after calling.
|
||||
Call(a ...uint64) (r1, r2 uint64, lastErr error)
|
||||
|
||||
// Returns the raw address of this function.
|
||||
Addr() uint64
|
||||
}
|
||||
|
||||
// Memory is an interface for a block of allocated virtual memory.
|
||||
type Memory interface {
|
||||
io.ReadWriteSeeker
|
||||
io.ReaderAt
|
||||
io.WriterAt
|
||||
|
||||
// Free frees the virtual memory region.
|
||||
Free()
|
||||
|
||||
// Addr returns the address of the region of memory in the virtual address
|
||||
// space.
|
||||
Addr() uint64
|
||||
|
||||
// Clear zeros the entire region of memory.
|
||||
Clear()
|
||||
|
||||
// Protect changes the memory protection for a subregion of this allocated
|
||||
// block. It should match the semantics of the VirtualProtect function on
|
||||
// Windows.
|
||||
Protect(addr, size uint64, protect int) error
|
||||
}
|
||||
|
||||
// Machine is an abstract machine interface.
|
||||
type Machine interface {
|
||||
// IsArchitectureSupported returns whether or not an architecture is
|
||||
// supported by this abstract machine. Machine is a PE machine ID.
|
||||
IsArchitectureSupported(machine int) bool
|
||||
|
||||
// GetPageSize returns the size of a memory page on this abstract machine.
|
||||
GetPageSize() uint64
|
||||
|
||||
// Alloc performs virtual memory allocation. It should match the semantics
|
||||
// of VirtualAlloc/VirtualFree on Windows.
|
||||
Alloc(addr, size uint64, allocType, protect int) Memory
|
||||
|
||||
// MemProc returns an object for interfacing with a procedure at addr in
|
||||
// the abstract machine's virtual memory space.
|
||||
MemProc(addr uint64) Proc
|
||||
}
|
||||
42
vendor/github.com/jchv/go-winloader/internal/memloader/cache.go
generated
vendored
Normal file
42
vendor/github.com/jchv/go-winloader/internal/memloader/cache.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package memloader
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/jchv/go-winloader/internal/loader"
|
||||
)
|
||||
|
||||
// Cache implements a memory cache for PE modules.
|
||||
type Cache struct {
|
||||
next loader.Loader
|
||||
cache map[string]loader.Module
|
||||
}
|
||||
|
||||
// NewCache creates a new cache with the specified options.
|
||||
func NewCache(next loader.Loader) *Cache {
|
||||
return &Cache{
|
||||
next: next,
|
||||
cache: make(map[string]loader.Module),
|
||||
}
|
||||
}
|
||||
|
||||
// Load implements loader.Loader by loading from cache or falling back.
|
||||
func (c *Cache) Load(libname string) (loader.Module, error) {
|
||||
if m, ok := c.cache[strings.ToLower(libname)]; ok {
|
||||
return m, nil
|
||||
}
|
||||
if m, ok := c.cache[strings.ToLower(libname)+".dll"]; ok {
|
||||
return m, nil
|
||||
}
|
||||
return c.next.Load(libname)
|
||||
}
|
||||
|
||||
// Add adds a module to the cache.
|
||||
func (c *Cache) Add(libname string, m loader.Module) error {
|
||||
libname = strings.ToLower(libname)
|
||||
if strings.HasSuffix(libname, ".dll") {
|
||||
libname = libname[0 : len(libname)-4]
|
||||
}
|
||||
c.cache[libname] = m
|
||||
return nil
|
||||
}
|
||||
253
vendor/github.com/jchv/go-winloader/internal/memloader/loader.go
generated
vendored
Normal file
253
vendor/github.com/jchv/go-winloader/internal/memloader/loader.go
generated
vendored
Normal file
@@ -0,0 +1,253 @@
|
||||
package memloader
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/jchv/go-winloader/internal/loader"
|
||||
"github.com/jchv/go-winloader/internal/pe"
|
||||
"github.com/jchv/go-winloader/internal/vmem"
|
||||
"github.com/jchv/go-winloader/internal/winloader"
|
||||
)
|
||||
|
||||
// module implements a module for the memory loader.
|
||||
type module struct {
|
||||
machine loader.Machine
|
||||
memory loader.Memory
|
||||
pemod *pe.Module
|
||||
exports *pe.ExportTable
|
||||
hinstance uint64
|
||||
}
|
||||
|
||||
// Proc implements loader.Module
|
||||
func (m *module) Proc(name string) loader.Proc {
|
||||
addr := m.exports.Proc(name)
|
||||
if addr == 0 {
|
||||
return nil
|
||||
}
|
||||
return m.machine.MemProc(addr)
|
||||
}
|
||||
|
||||
// Ordinal implements loader.Module
|
||||
func (m *module) Ordinal(ordinal uint64) loader.Proc {
|
||||
addr := m.exports.Ordinal(uint16(ordinal))
|
||||
if addr == 0 {
|
||||
return nil
|
||||
}
|
||||
return m.machine.MemProc(addr)
|
||||
}
|
||||
|
||||
// Free implements loader.Module
|
||||
func (m *module) Free() error {
|
||||
// Execute entrypoint for detach.
|
||||
entry := m.machine.MemProc(m.memory.Addr() + uint64(m.pemod.Header.OptionalHeader.AddressOfEntryPoint))
|
||||
entry.Call(uint64(m.memory.Addr()), 0, 0)
|
||||
|
||||
// Free memory.
|
||||
m.memory.Free()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Loader implements a memory loader for PE files.
|
||||
type Loader struct {
|
||||
next loader.Loader
|
||||
machine loader.Machine
|
||||
pebhacks bool
|
||||
prochinst bool
|
||||
}
|
||||
|
||||
// Options contains the options for creating a new memory loader.
|
||||
type Options struct {
|
||||
// Next specifies the loader to use for recursing to resolve modules by
|
||||
// name.
|
||||
Next loader.Loader
|
||||
|
||||
// Machine specifies the machine the module should be loaded into.
|
||||
Machine loader.Machine
|
||||
|
||||
// HintAddModuleToPEB specifies that the memory loader should try to add
|
||||
// the loaded module into the PEB so that certain things function as
|
||||
// expected.
|
||||
// NOTE: This is not implemented yet and may not be possible.
|
||||
HintAddModuleToPEB bool
|
||||
|
||||
// HintUseProcessHInstance specifies that the memory loader should use the
|
||||
// host process's HINSTANCE value for calling into entrypoints.
|
||||
HintUseProcessHInstance bool
|
||||
}
|
||||
|
||||
// New creates a new loader with the specified options.
|
||||
func New(opts Options) loader.MemLoader {
|
||||
return &Loader{
|
||||
next: opts.Next,
|
||||
machine: opts.Machine,
|
||||
}
|
||||
}
|
||||
|
||||
// LoadMem implements the loader.MemLoader interface.
|
||||
func (l *Loader) LoadMem(data []byte) (loader.Module, error) {
|
||||
bin, err := pe.LoadModule(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !l.machine.IsArchitectureSupported(int(bin.Header.FileHeader.Machine)) {
|
||||
return nil, fmt.Errorf("image architecture not %04x not supported by this machine", bin.Header.FileHeader.Machine)
|
||||
}
|
||||
|
||||
pageSize := l.machine.GetPageSize()
|
||||
imageSize := vmem.RoundUp(uint64(bin.Header.OptionalHeader.SizeOfImage), pageSize)
|
||||
|
||||
var mem loader.Memory
|
||||
|
||||
// If the image is not movable, allocate it at its preferred address.
|
||||
if bin.Header.OptionalHeader.DllCharacteristics&pe.ImageDLLCharacteristicsDynamicBase == 0 {
|
||||
mem = l.machine.Alloc(bin.Header.OptionalHeader.ImageBase, imageSize, vmem.MemCommit|vmem.MemReserve, vmem.PageExecuteReadWrite)
|
||||
if mem == nil {
|
||||
return nil, fmt.Errorf("image could not be mapped at preferred base 0x%08x and cannot be relocated", bin.Header.OptionalHeader.ImageBase)
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate anywhere, so as long as the image won't span a 4 GiB
|
||||
// alignment boundary.
|
||||
failedAllocs := []loader.Memory{}
|
||||
for mem == nil || mem.Addr()>>32 != (mem.Addr()+imageSize)>>32 {
|
||||
if mem != nil {
|
||||
failedAllocs = append(failedAllocs, mem)
|
||||
}
|
||||
if mem = l.machine.Alloc(0, imageSize, vmem.MemCommit|vmem.MemReserve, vmem.PageExecuteReadWrite); mem == nil {
|
||||
return nil, fmt.Errorf("allocation of %d bytes failed", imageSize)
|
||||
}
|
||||
}
|
||||
for _, i := range failedAllocs {
|
||||
i.Free()
|
||||
}
|
||||
|
||||
realBase := mem.Addr()
|
||||
hdrsize := uint64(bin.Header.OptionalHeader.SizeOfHeaders)
|
||||
vmem.Alloc(realBase, hdrsize, vmem.MemCommit, vmem.PageReadWrite).Write(data[0:hdrsize])
|
||||
|
||||
// Map sections into memory
|
||||
for _, section := range bin.Sections {
|
||||
addr := realBase + uint64(section.VirtualAddress)
|
||||
if section.SizeOfRawData == 0 {
|
||||
size := uint64(bin.Header.OptionalHeader.SectionAlignment)
|
||||
if size != 0 {
|
||||
vmem.Alloc(addr, size, vmem.MemCommit, vmem.PageReadWrite).Clear()
|
||||
}
|
||||
} else {
|
||||
sectionData := data[section.PointerToRawData : section.PointerToRawData+section.SizeOfRawData]
|
||||
vmem.Alloc(addr, uint64(section.SizeOfRawData), vmem.MemCommit, vmem.PageReadWrite).Write(sectionData)
|
||||
}
|
||||
// TODO: need to set Misc.PhysicalAddress?
|
||||
}
|
||||
|
||||
// TODO: Detect native byte order for relocations.
|
||||
order := binary.LittleEndian
|
||||
machine := int(bin.Header.FileHeader.Machine)
|
||||
|
||||
// Perform relocations
|
||||
relocs := pe.LoadBaseRelocs(bin, mem)
|
||||
if err := pe.Relocate(machine, relocs, uint64(realBase), bin.Header.OptionalHeader.ImageBase, mem, order); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Perform runtime linking
|
||||
if err := pe.LinkModule(bin, mem, l.next); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Set access flags.
|
||||
for _, section := range bin.Sections {
|
||||
executable := section.Characteristics&pe.ImageSectionCharacteristicsMemoryExecute != 0
|
||||
readable := section.Characteristics&pe.ImageSectionCharacteristicsMemoryRead != 0
|
||||
writable := section.Characteristics&pe.ImageSectionCharacteristicsMemoryWrite != 0
|
||||
protect := vmem.PageNoAccess
|
||||
switch {
|
||||
case !executable && !readable && !writable:
|
||||
protect = vmem.PageNoAccess
|
||||
case !executable && !readable && writable:
|
||||
protect = vmem.PageWriteCopy
|
||||
case !executable && readable && !writable:
|
||||
protect = vmem.PageReadOnly
|
||||
case !executable && readable && writable:
|
||||
protect = vmem.PageReadWrite
|
||||
case executable && !readable && !writable:
|
||||
protect = vmem.PageExecute
|
||||
case executable && !readable && writable:
|
||||
protect = vmem.PageExecuteWriteCopy
|
||||
case executable && readable && !writable:
|
||||
protect = vmem.PageExecuteRead
|
||||
case executable && readable && writable:
|
||||
protect = vmem.PageExecuteReadWrite
|
||||
}
|
||||
size := uint64(section.SizeOfRawData)
|
||||
if size == 0 {
|
||||
size = uint64(bin.Header.OptionalHeader.SectionAlignment)
|
||||
}
|
||||
err := mem.Protect(uint64(section.VirtualAddress), size, protect)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Handle HINSTANCE setup.
|
||||
hinstance := realBase
|
||||
if l.pebhacks {
|
||||
// TODO: implement PEB loader hacks, see if it works.
|
||||
}
|
||||
if l.prochinst {
|
||||
if prochinst, err := winloader.GetProcessHInstance(); err == nil {
|
||||
hinstance = uint64(prochinst)
|
||||
}
|
||||
}
|
||||
|
||||
m := &module{
|
||||
machine: l.machine,
|
||||
memory: mem,
|
||||
pemod: bin,
|
||||
hinstance: hinstance,
|
||||
}
|
||||
|
||||
// Execute TLS callbacks.
|
||||
tlsdir := bin.Header.OptionalHeader.DataDirectory[pe.ImageDirectoryEntryTLS]
|
||||
if tlsdir.Size > 0 {
|
||||
mem.Seek(int64(tlsdir.VirtualAddress), io.SeekStart)
|
||||
dir := pe.ImageTLSDirectory64{}
|
||||
b := [8]byte{}
|
||||
psize := 4
|
||||
if bin.IsPE64 {
|
||||
psize = 8
|
||||
binary.Read(mem, binary.LittleEndian, &dir)
|
||||
} else {
|
||||
dir32 := pe.ImageTLSDirectory32{}
|
||||
binary.Read(mem, binary.LittleEndian, &dir32)
|
||||
dir = dir32.To64()
|
||||
}
|
||||
mem.Seek(int64(dir.AddressOfCallBacks), io.SeekStart)
|
||||
if dir.AddressOfCallBacks != 0 {
|
||||
for {
|
||||
mem.Read(b[:psize])
|
||||
addr := binary.LittleEndian.Uint64(b[:])
|
||||
if addr == 0 {
|
||||
break
|
||||
}
|
||||
cb := l.machine.MemProc(realBase + addr)
|
||||
cb.Call(hinstance, 1, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute entrypoint for attach.
|
||||
entry := l.machine.MemProc(realBase + uint64(bin.Header.OptionalHeader.AddressOfEntryPoint))
|
||||
entry.Call(hinstance, 1, 0)
|
||||
|
||||
m.exports, err = pe.LoadExports(bin, mem, realBase)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
76
vendor/github.com/jchv/go-winloader/internal/pe/export.go
generated
vendored
Normal file
76
vendor/github.com/jchv/go-winloader/internal/pe/export.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
package pe
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
)
|
||||
|
||||
// ExportTable is a table of module exports.
|
||||
type ExportTable struct {
|
||||
symbols map[string]uint64
|
||||
ordinals map[uint16]uint64
|
||||
}
|
||||
|
||||
// Proc returns an exported function address by symbol, or 0 if it is not found.
|
||||
func (t *ExportTable) Proc(symbol string) (addr uint64) {
|
||||
return t.symbols[symbol]
|
||||
}
|
||||
|
||||
// Ordinal returns an exported function address by ordinal, or 0 if it is not found.
|
||||
func (t *ExportTable) Ordinal(ordinal uint16) (addr uint64) {
|
||||
return t.ordinals[ordinal]
|
||||
}
|
||||
|
||||
// LoadExports returns a symbol table.
|
||||
func LoadExports(m *Module, mem io.ReadWriteSeeker, base uint64) (*ExportTable, error) {
|
||||
table := &ExportTable{
|
||||
symbols: map[string]uint64{},
|
||||
ordinals: map[uint16]uint64{},
|
||||
}
|
||||
|
||||
dir := m.Header.OptionalHeader.DataDirectory[ImageDirectoryEntryExport]
|
||||
if dir.Size == 0 {
|
||||
return table, nil
|
||||
}
|
||||
|
||||
// Load export directory header
|
||||
header := ImageExportDirectory{}
|
||||
mem.Seek(int64(dir.VirtualAddress), io.SeekStart)
|
||||
binary.Read(mem, binary.LittleEndian, &header)
|
||||
|
||||
// Load addresses
|
||||
addresses := make([]uint32, header.NumberOfFunctions)
|
||||
mem.Seek(int64(header.AddressOfFunctions), io.SeekStart)
|
||||
for i := range addresses {
|
||||
b := [4]byte{}
|
||||
mem.Read(b[:])
|
||||
addresses[i] = binary.LittleEndian.Uint32(b[:])
|
||||
table.ordinals[uint16(i)] = base + uint64(addresses[i])
|
||||
}
|
||||
|
||||
// Load name ordinals
|
||||
nameords := make([]uint16, header.NumberOfNames)
|
||||
mem.Seek(int64(header.AddressOfNameOrdinals), io.SeekStart)
|
||||
for i := range nameords {
|
||||
b := [2]byte{}
|
||||
mem.Read(b[:])
|
||||
nameords[i] = binary.LittleEndian.Uint16(b[:])
|
||||
}
|
||||
|
||||
// Load name addresses
|
||||
nameaddrs := make([]uint32, header.NumberOfNames)
|
||||
mem.Seek(int64(header.AddressOfNames), io.SeekStart)
|
||||
for i := range nameaddrs {
|
||||
b := [4]byte{}
|
||||
mem.Read(b[:])
|
||||
nameaddrs[i] = binary.LittleEndian.Uint32(b[:])
|
||||
}
|
||||
|
||||
// Load names
|
||||
for i, nameaddr := range nameaddrs {
|
||||
mem.Seek(int64(nameaddr), io.SeekStart)
|
||||
table.symbols[readsz(mem)] = base + uint64(addresses[nameords[i]])
|
||||
}
|
||||
|
||||
return table, nil
|
||||
}
|
||||
522
vendor/github.com/jchv/go-winloader/internal/pe/format.go
generated
vendored
Normal file
522
vendor/github.com/jchv/go-winloader/internal/pe/format.go
generated
vendored
Normal file
@@ -0,0 +1,522 @@
|
||||
package pe
|
||||
|
||||
// CONSTANTS / MAGIC NUMBERS
|
||||
|
||||
// MZSignature is the signature of the MZ format. This is the value of the
|
||||
// Signature field in ImageDOSHeader.
|
||||
var MZSignature = [2]byte{'M', 'Z'}
|
||||
|
||||
// PESignature is the signature of the PE format. This is the value of the
|
||||
// Signature field in ImageNTHeaders32 and ImageNTHeaders64.
|
||||
var PESignature = [4]byte{'P', 'E', 0, 0}
|
||||
|
||||
// Enumeration of magic numbers
|
||||
const (
|
||||
// ImageNTOptionalHeader32Magic is the magic number for 32-bit optional
|
||||
// header (ImageOptionalHeader32)
|
||||
ImageNTOptionalHeader32Magic = 0x010b
|
||||
|
||||
// ImageNTOptionalHeader64Magic is the magic number for 64-bit optional
|
||||
// header (ImageOptionalHeader64)
|
||||
ImageNTOptionalHeader64Magic = 0x020b
|
||||
)
|
||||
|
||||
// Enumeration of structure lengths.
|
||||
const (
|
||||
// SizeOfImageDOSHeader is the on-disk size of the ImageDOSHeader
|
||||
// structure.
|
||||
SizeOfImageDOSHeader = 64
|
||||
|
||||
// SizeOfImageFileHeader is the on-disk size of the ImageFileHeader
|
||||
// structure.
|
||||
SizeOfImageFileHeader = 20
|
||||
|
||||
// SizeOfImageOptionalHeader32 is the on-disk size of the
|
||||
// ImageOptionalHeader32 structure.
|
||||
SizeOfImageOptionalHeader32 = 224
|
||||
|
||||
// SizeOfImageOptionalHeader64 is the on-disk size of the
|
||||
// ImageOptionalHeader64 structure.
|
||||
SizeOfImageOptionalHeader64 = 240
|
||||
|
||||
// SizeOfImageNTHeaders32 is the on-disk size of the ImageNTHeaders32
|
||||
// structure.
|
||||
SizeOfImageNTHeaders32 = 248
|
||||
|
||||
// SizeOfImageNTHeaders64 is the on-disk size of the ImageNTHeaders64
|
||||
// structure.
|
||||
SizeOfImageNTHeaders64 = 264
|
||||
|
||||
// SizeOfImageDataDirectory is the on-disk size of the ImageDataDirectory
|
||||
// structure.
|
||||
SizeOfImageDataDirectory = 8
|
||||
)
|
||||
|
||||
// Enumeration of useful field offsets.
|
||||
const (
|
||||
// OffsetOfOptionalHeaderFromNTHeader is the offset from the start of
|
||||
// the NT header to the optional header magic value. This is helpful for
|
||||
// determining if the PE file is PE32 or PE64.
|
||||
OffsetOfOptionalHeaderFromNTHeader = 0x18
|
||||
)
|
||||
|
||||
// Enumeration of fixed-size array lengths in PE
|
||||
const (
|
||||
// NumDirectoryEntries specifies the number of data directory entries.
|
||||
NumDirectoryEntries = 16
|
||||
|
||||
// SectionNameLength is the size of a section short name.
|
||||
SectionNameLength = 8
|
||||
)
|
||||
|
||||
// Enumeration of known Windows Loader limits. (Some of these may not be
|
||||
// imposed by the format itself and purely by Windows runtime.)
|
||||
const (
|
||||
// MaxNumSections specifies the maximum number of sections that are
|
||||
// allowed. This is imposed by Windows Loader.
|
||||
MaxNumSections = 96
|
||||
)
|
||||
|
||||
// ENUMERATION VALUES
|
||||
|
||||
// Enumeration of machine values for the file header.
|
||||
const (
|
||||
ImageFileMachineUnknown = 0x0000
|
||||
ImageFileMachineTargetHost = 0x0001
|
||||
ImageFileMachinei386 = 0x014c
|
||||
ImageFileMachineR3000BE = 0x0160
|
||||
ImageFileMachineR3000 = 0x0162
|
||||
ImageFileMachineR4000 = 0x0166
|
||||
ImageFileMachineR10000 = 0x0168
|
||||
ImageFileMachineWCEMIPSv2 = 0x0169
|
||||
ImageFileMachineAlpha = 0x0184
|
||||
ImageFileMachineSH3 = 0x01a2
|
||||
ImageFileMachineSH3DSP = 0x01a3
|
||||
ImageFileMachineSH3E = 0x01a4
|
||||
ImageFileMachineSH4 = 0x01a6
|
||||
ImageFileMachineSH5 = 0x01a8
|
||||
ImageFileMachineARM = 0x01c0
|
||||
ImageFileMachineTHUMB = 0x01c2
|
||||
ImageFileMachineARMNT = 0x01c4
|
||||
ImageFileMachineAM33 = 0x01d3
|
||||
ImageFileMachinePowerPC = 0x01F0
|
||||
ImageFileMachinePowerPCFP = 0x01f1
|
||||
ImageFileMachineIA64 = 0x0200
|
||||
ImageFileMachineMIPS16 = 0x0266
|
||||
ImageFileMachineAlpha64 = 0x0284
|
||||
ImageFileMachineMIPSFPU = 0x0366
|
||||
ImageFileMachineMIPSFPU16 = 0x0466
|
||||
ImageFileMachineAXP64 = ImageFileMachineAlpha64
|
||||
ImageFileMachineTricore = 0x0520
|
||||
ImageFileMachineCEF = 0x00CE
|
||||
ImageFileMachineEBC = 0x0EBC
|
||||
ImageFileMachineAMD64 = 0x8664
|
||||
ImageFileMachineM32R = 0x9041
|
||||
ImageFileMachineARM64 = 0xAA64
|
||||
ImageFileMachineCEE = 0x0C0E
|
||||
ImageFileMachineRISCV32 = 0x5032
|
||||
ImageFileMachineRISCV64 = 0x5064
|
||||
ImageFileMachineRISCV128 = 0x5128
|
||||
)
|
||||
|
||||
// Enumeration of charateristics values for the file header.
|
||||
const (
|
||||
ImageFileRelocsStripped = 0x0001
|
||||
ImageFileExecutableImage = 0x0002
|
||||
ImageFileLineNumsStripped = 0x0004
|
||||
ImageFileLocalSymsStripped = 0x0008
|
||||
ImageFileAggressiveWSTrim = 0x0010
|
||||
ImageFileLargeAddressAware = 0x0020
|
||||
ImageFileBytesReversedLo = 0x0080
|
||||
ImageFile32BitMachine = 0x0100
|
||||
ImageFileDebugStripped = 0x0200
|
||||
ImageFileRemovableRunFromSwap = 0x0400
|
||||
ImageFileNetRunFromSwap = 0x0800
|
||||
ImageFileSystem = 0x1000
|
||||
ImageFileDLL = 0x2000
|
||||
ImageFileUPSystemOnly = 0x4000
|
||||
ImageFileBytesReversedHi = 0x8000
|
||||
)
|
||||
|
||||
// Enumeration of image subsystem values.
|
||||
const (
|
||||
ImageSubsystemUnknown = 0
|
||||
ImageSubsystemNative = 1
|
||||
ImageSubsystemWindowsGUI = 2
|
||||
ImageSubsystemWindowsCUI = 3
|
||||
ImageSubsystemOS2CUI = 5
|
||||
ImageSubsystemPOSIXCUI = 7
|
||||
ImageSubsystemNativeWindows = 8
|
||||
ImageSubsystemWindowsCEGUI = 9
|
||||
ImageSubsystemEFIApplication = 10
|
||||
ImageSubsystemEFIBootServiceDriver = 11
|
||||
ImageSubsystemEFIRuntimeDriver = 12
|
||||
ImageSubsystemEFIROM = 13
|
||||
ImageSubsystemXBox = 14
|
||||
ImageSubsystemWindowsBootApplication = 16
|
||||
ImageSubsystemXBoxCodeCatalog = 17
|
||||
)
|
||||
|
||||
// Enumeration of DLL characteristics values.
|
||||
const (
|
||||
ImageDLLCharacteristicsHighEntropyVA = 0x0020
|
||||
ImageDLLCharacteristicsDynamicBase = 0x0040
|
||||
ImageDLLCharacteristicsForceIntegrity = 0x0080
|
||||
ImageDLLCharacteristicsNXCompat = 0x0100
|
||||
ImageDLLCharacteristicsNoIsolation = 0x0200
|
||||
ImageDLLCharacteristicsNoSEH = 0x0400
|
||||
ImageDLLCharacteristicsNoBind = 0x0800
|
||||
ImageDLLCharacteristicsAppContainer = 0x1000
|
||||
ImageDLLCharacteristicsWDMDriver = 0x2000
|
||||
ImageDLLCharacteristicsGuardCF = 0x4000
|
||||
ImageDLLCharacteristicsTerminalServerAware = 0x8000
|
||||
)
|
||||
|
||||
// Enumeration of image directory entry indexes. These represent indices into
|
||||
// the data directory array of the optional header.
|
||||
const (
|
||||
ImageDirectoryEntryExport = 0
|
||||
ImageDirectoryEntryImport = 1
|
||||
ImageDirectoryEntryResource = 2
|
||||
ImageDirectoryEntryException = 3
|
||||
ImageDirectoryEntrySecurity = 4
|
||||
ImageDirectoryEntryBaseReloc = 5
|
||||
ImageDirectoryEntryDebug = 6
|
||||
ImageDirectoryEntryCopyright = 7
|
||||
ImageDirectoryEntryArchitecture = 7
|
||||
ImageDirectoryEntryGlobalPtr = 8
|
||||
ImageDirectoryEntryTLS = 9
|
||||
ImageDirectoryEntryLoadConfig = 10
|
||||
ImageDirectoryEntryBoundImport = 11
|
||||
ImageDirectoryEntryIAT = 12
|
||||
ImageDirectoryEntryDelayImport = 13
|
||||
ImageDirectoryEntryCOMDescriptor = 14
|
||||
)
|
||||
|
||||
// Enumeration of image section characteristics.
|
||||
const (
|
||||
ImageSectionCharacteristicsNoPad = 0x00000008
|
||||
ImageSectionCharacteristicsContainsCode = 0x00000020
|
||||
ImageSectionCharacteristicsContainsInitializedData = 0x00000040
|
||||
ImageSectionCharacteristicsContainsUninitailizedData = 0x00000080
|
||||
ImageSectionCharacteristicsLinkOther = 0x00000100
|
||||
ImageSectionCharacteristicsLinkInfo = 0x00000200
|
||||
ImageSectionCharacteristicsLinkRemove = 0x00000800
|
||||
ImageSectionCharacteristicsLinkCOMDAT = 0x00001000
|
||||
ImageSectionCharacteristicsNoDeferSpecExc = 0x00004000
|
||||
ImageSectionCharacteristicsGPRel = 0x00008000
|
||||
ImageSectionCharacteristicsMemoryFarData = 0x00008000
|
||||
ImageSectionCharacteristicsMemoryPurgeable = 0x00020000
|
||||
ImageSectionCharacteristicsMemory16Bit = 0x00020000
|
||||
ImageSectionCharacteristicsMemoryLocked = 0x00040000
|
||||
ImageSectionCharacteristicsMemoryPreload = 0x00080000
|
||||
ImageSectionCharacteristicsAlign1Bytes = 0x00100000
|
||||
ImageSectionCharacteristicsAlign2Bytes = 0x00200000
|
||||
ImageSectionCharacteristicsAlign4Bytes = 0x00300000
|
||||
ImageSectionCharacteristicsAlign8Bytes = 0x00400000
|
||||
ImageSectionCharacteristicsAlign16Bytes = 0x00500000
|
||||
ImageSectionCharacteristicsAlign32Bytes = 0x00600000
|
||||
ImageSectionCharacteristicsAlign64Bytes = 0x00700000
|
||||
ImageSectionCharacteristicsAlign128Bytes = 0x00800000
|
||||
ImageSectionCharacteristicsAlign256Bytes = 0x00900000
|
||||
ImageSectionCharacteristicsAlign512Bytes = 0x00A00000
|
||||
ImageSectionCharacteristicsAlign1024Bytes = 0x00B00000
|
||||
ImageSectionCharacteristicsAlign2048Bytes = 0x00C00000
|
||||
ImageSectionCharacteristicsAlign4096Bytes = 0x00D00000
|
||||
ImageSectionCharacteristicsAlign8192Bytes = 0x00E00000
|
||||
ImageSectionCharacteristicsAlignMask = 0x00F00000
|
||||
ImageSectionCharacteristicsLinkNumRelocOverflow = 0x01000000
|
||||
ImageSectionCharacteristicsMemoryDiscardable = 0x02000000
|
||||
ImageSectionCharacteristicsMemoryNotCached = 0x04000000
|
||||
ImageSectionCharacteristicsMemoryNotPaged = 0x08000000
|
||||
ImageSectionCharacteristicsMemoryShared = 0x10000000
|
||||
ImageSectionCharacteristicsMemoryExecute = 0x20000000
|
||||
ImageSectionCharacteristicsMemoryRead = 0x40000000
|
||||
ImageSectionCharacteristicsMemoryWrite = 0x80000000
|
||||
)
|
||||
|
||||
// Enumeration of TLS characteristics.
|
||||
const (
|
||||
ImageSectionTLSCharacteristicsScaleIndex = 0x00000001
|
||||
)
|
||||
|
||||
// Enumeration of relocation types.
|
||||
const (
|
||||
ImageRelBasedAbsolute = 0
|
||||
ImageRelBasedHigh = 1
|
||||
ImageRelBasedLow = 2
|
||||
ImageRelBasedHighLow = 3
|
||||
ImageRelBasedHighAdj = 4
|
||||
ImageRelBasedMachineSpecific5 = 5
|
||||
ImageRelBasedReserved = 6
|
||||
ImageRelBasedMachineSpecific7 = 7
|
||||
ImageRelBasedMachineSpecific8 = 8
|
||||
ImageRelBasedMachineSpecific9 = 9
|
||||
ImageRelBasedDir64 = 10
|
||||
)
|
||||
|
||||
// ImageDOSHeader is the structure of the DOS MZ Executable format. All PE
|
||||
// files contain at least a valid stub DOS MZ executable at the top; the PE
|
||||
// format itself starts at the address specified by NewHeaderAddr.
|
||||
type ImageDOSHeader struct {
|
||||
Signature [2]byte
|
||||
LastPageBytes uint16
|
||||
CountPages uint16
|
||||
CountRelocs uint16
|
||||
HeaderLen uint16
|
||||
MinAlloc uint16
|
||||
MaxAlloc uint16
|
||||
InitialSS uint16
|
||||
InitialSP uint16
|
||||
Checksum uint16
|
||||
InitialIP uint16
|
||||
InitialCS uint16
|
||||
RelocAddr uint16
|
||||
OverlayNum uint16
|
||||
Reserved [4]uint16
|
||||
OEMID uint16
|
||||
OEMInfo uint16
|
||||
Reserved2 [10]uint16
|
||||
NewHeaderAddr uint32
|
||||
}
|
||||
|
||||
// ImageFileHeader contains some of the basic attributes about the PE/COFF
|
||||
// file, including the number of sections and the machine type.
|
||||
type ImageFileHeader struct {
|
||||
Machine uint16
|
||||
NumberOfSections uint16
|
||||
TimeDateStamp uint32
|
||||
PointerToSymbolTable uint32
|
||||
NumberOfSymbols uint32
|
||||
SizeOfOptionalHeader uint16
|
||||
Characteristics uint16
|
||||
}
|
||||
|
||||
// ImageOptionalHeader32 contains the optional header for 32-bit PE images. It
|
||||
// is only 'optional' in the sense that not all PE/COFF binaries have it,
|
||||
// however it is required for executables and DLLs.
|
||||
type ImageOptionalHeader32 struct {
|
||||
Magic uint16
|
||||
MajorLinkerVersion uint8
|
||||
MinorLinkerVersion uint8
|
||||
SizeOfCode uint32
|
||||
SizeOfInitializedData uint32
|
||||
SizeOfUninitializedData uint32
|
||||
AddressOfEntryPoint uint32
|
||||
BaseOfCode uint32
|
||||
BaseOfData uint32
|
||||
|
||||
ImageBase uint32
|
||||
SectionAlignment uint32
|
||||
FileAlignment uint32
|
||||
MajorOperatingSystemVersion uint16
|
||||
MinorOperatingSystemVersion uint16
|
||||
MajorImageVersion uint16
|
||||
MinorImageVersion uint16
|
||||
MajorSubsystemVersion uint16
|
||||
MinorSubsystemVersion uint16
|
||||
Win32VersionValue uint32
|
||||
SizeOfImage uint32
|
||||
SizeOfHeaders uint32
|
||||
CheckSum uint32
|
||||
Subsystem uint16
|
||||
DllCharacteristics uint16
|
||||
SizeOfStackReserve uint32
|
||||
SizeOfStackCommit uint32
|
||||
SizeOfHeapReserve uint32
|
||||
SizeOfHeapCommit uint32
|
||||
LoaderFlags uint32
|
||||
NumberOfRvaAndSizes uint32
|
||||
DataDirectory [NumDirectoryEntries]ImageDataDirectory
|
||||
}
|
||||
|
||||
// ImageOptionalHeader64 contains the optional header for 64-bit PE images.
|
||||
type ImageOptionalHeader64 struct {
|
||||
Magic uint16
|
||||
MajorLinkerVersion uint8
|
||||
MinorLinkerVersion uint8
|
||||
SizeOfCode uint32
|
||||
SizeOfInitializedData uint32
|
||||
SizeOfUninitializedData uint32
|
||||
AddressOfEntryPoint uint32
|
||||
BaseOfCode uint32
|
||||
ImageBase uint64
|
||||
SectionAlignment uint32
|
||||
FileAlignment uint32
|
||||
MajorOperatingSystemVersion uint16
|
||||
MinorOperatingSystemVersion uint16
|
||||
MajorImageVersion uint16
|
||||
MinorImageVersion uint16
|
||||
MajorSubsystemVersion uint16
|
||||
MinorSubsystemVersion uint16
|
||||
Win32VersionValue uint32
|
||||
SizeOfImage uint32
|
||||
SizeOfHeaders uint32
|
||||
CheckSum uint32
|
||||
Subsystem uint16
|
||||
DllCharacteristics uint16
|
||||
SizeOfStackReserve uint64
|
||||
SizeOfStackCommit uint64
|
||||
SizeOfHeapReserve uint64
|
||||
SizeOfHeapCommit uint64
|
||||
LoaderFlags uint32
|
||||
NumberOfRvaAndSizes uint32
|
||||
DataDirectory [NumDirectoryEntries]ImageDataDirectory
|
||||
}
|
||||
|
||||
// To64 converts the ImageOptionalHeader32 to an ImageOptionalHeader64.
|
||||
func (i ImageOptionalHeader32) To64() ImageOptionalHeader64 {
|
||||
return ImageOptionalHeader64{
|
||||
Magic: i.Magic,
|
||||
MajorLinkerVersion: i.MajorLinkerVersion,
|
||||
MinorLinkerVersion: i.MinorLinkerVersion,
|
||||
SizeOfCode: i.SizeOfCode,
|
||||
SizeOfInitializedData: i.SizeOfInitializedData,
|
||||
SizeOfUninitializedData: i.SizeOfUninitializedData,
|
||||
AddressOfEntryPoint: i.AddressOfEntryPoint,
|
||||
BaseOfCode: i.BaseOfCode,
|
||||
ImageBase: uint64(i.ImageBase),
|
||||
SectionAlignment: i.SectionAlignment,
|
||||
FileAlignment: i.FileAlignment,
|
||||
MajorOperatingSystemVersion: i.MajorOperatingSystemVersion,
|
||||
MinorOperatingSystemVersion: i.MinorOperatingSystemVersion,
|
||||
MajorImageVersion: i.MajorImageVersion,
|
||||
MinorImageVersion: i.MinorImageVersion,
|
||||
MajorSubsystemVersion: i.MajorSubsystemVersion,
|
||||
MinorSubsystemVersion: i.MinorSubsystemVersion,
|
||||
Win32VersionValue: i.Win32VersionValue,
|
||||
SizeOfImage: i.SizeOfImage,
|
||||
SizeOfHeaders: i.SizeOfHeaders,
|
||||
CheckSum: i.CheckSum,
|
||||
Subsystem: i.Subsystem,
|
||||
DllCharacteristics: i.DllCharacteristics,
|
||||
SizeOfStackReserve: uint64(i.SizeOfStackReserve),
|
||||
SizeOfStackCommit: uint64(i.SizeOfStackCommit),
|
||||
SizeOfHeapReserve: uint64(i.SizeOfHeapReserve),
|
||||
SizeOfHeapCommit: uint64(i.SizeOfHeapCommit),
|
||||
LoaderFlags: i.LoaderFlags,
|
||||
NumberOfRvaAndSizes: i.NumberOfRvaAndSizes,
|
||||
DataDirectory: i.DataDirectory,
|
||||
}
|
||||
}
|
||||
|
||||
// ImageNTHeaders32 contains the PE file headers for 32-bit PE images.
|
||||
type ImageNTHeaders32 struct {
|
||||
// Signature identifies the PE format; Always "PE\0\0".
|
||||
Signature [4]byte
|
||||
FileHeader ImageFileHeader
|
||||
OptionalHeader ImageOptionalHeader32
|
||||
}
|
||||
|
||||
// ImageNTHeaders64 contains the PE file headers for 64-bit PE images.
|
||||
type ImageNTHeaders64 struct {
|
||||
// Signature identifies the PE format; Always "PE\0\0".
|
||||
Signature [4]byte
|
||||
FileHeader ImageFileHeader
|
||||
OptionalHeader ImageOptionalHeader64
|
||||
}
|
||||
|
||||
// To64 converts the ImageNTHeaders32 to an ImageNTHeaders64.
|
||||
func (i ImageNTHeaders32) To64() ImageNTHeaders64 {
|
||||
return ImageNTHeaders64{
|
||||
Signature: i.Signature,
|
||||
FileHeader: i.FileHeader,
|
||||
OptionalHeader: i.OptionalHeader.To64(),
|
||||
}
|
||||
}
|
||||
|
||||
// ImageDataDirectory holds a record for the given data directory. Each data
|
||||
// directory contains information about another section, such as the import
|
||||
// table. The index of the directory entry determines which section it
|
||||
// pertains to.
|
||||
type ImageDataDirectory struct {
|
||||
VirtualAddress uint32
|
||||
Size uint32
|
||||
}
|
||||
|
||||
// ImageSectionHeader is the header for a section. Windows Loader uses these
|
||||
// entries to configure the memory mapping of the executable. A series of
|
||||
// these structures immediately follow the headers.
|
||||
type ImageSectionHeader struct {
|
||||
Name [SectionNameLength]byte
|
||||
PhysicalAddressOrVirtualSize uint32
|
||||
VirtualAddress uint32
|
||||
SizeOfRawData uint32
|
||||
PointerToRawData uint32
|
||||
PointerToRelocations uint32
|
||||
PointerToLinenumbers uint32
|
||||
NumberOfRelocations uint16
|
||||
NumberOfLinenumbers uint16
|
||||
Characteristics uint32
|
||||
}
|
||||
|
||||
// ImageBaseRelocation holds the header for a single page of base relocation
|
||||
// data. The .reloc section of the binary contains a series of blocks of
|
||||
// base relocation data, each starting with this header and followed by n
|
||||
// 16-bit values that each represent a single relocation. The 4 most
|
||||
// significant bits specify the type of relocation, while the 12 least
|
||||
// significant bits contain the lower bits of the address (which is combined
|
||||
// with the virtual address of the page.) The SizeOfBlock value specifies the
|
||||
// size of an entire block, in bytes, including its header.
|
||||
type ImageBaseRelocation struct {
|
||||
VirtualAddress uint32
|
||||
SizeOfBlock uint32
|
||||
}
|
||||
|
||||
// The ImageImportDescriptor contains information about an imported module.
|
||||
type ImageImportDescriptor struct {
|
||||
OriginalFirstThunk uint32
|
||||
TimeDateStamp uint32
|
||||
ForwarderChain uint32
|
||||
Name uint32
|
||||
FirstThunk uint32
|
||||
}
|
||||
|
||||
// The ImageExportDirectory contains information about the module's exports.
|
||||
type ImageExportDirectory struct {
|
||||
Characteristics uint32
|
||||
TimeDateStamp uint32
|
||||
MajorVersion uint16
|
||||
MinorVersion uint16
|
||||
Name uint32
|
||||
Base uint32
|
||||
NumberOfFunctions uint32
|
||||
NumberOfNames uint32
|
||||
AddressOfFunctions uint32
|
||||
AddressOfNames uint32
|
||||
AddressOfNameOrdinals uint32
|
||||
}
|
||||
|
||||
// ImageTLSDirectory32 contains information about the module's thread local
|
||||
// storage callbacks (in PE32)
|
||||
type ImageTLSDirectory32 struct {
|
||||
StartAddressOfRawData uint32
|
||||
EndAddressOfRawData uint32
|
||||
AddressOfIndex uint32
|
||||
AddressOfCallBacks uint32
|
||||
SizeOfZeroFill uint32
|
||||
Characteristics uint32
|
||||
}
|
||||
|
||||
// ImageTLSDirectory64 contains information about the module's thread local
|
||||
// storage callbacks (in PE64)
|
||||
type ImageTLSDirectory64 struct {
|
||||
StartAddressOfRawData uint64
|
||||
EndAddressOfRawData uint64
|
||||
AddressOfIndex uint64
|
||||
AddressOfCallBacks uint64
|
||||
SizeOfZeroFill uint32
|
||||
Characteristics uint32
|
||||
}
|
||||
|
||||
// To64 converts the ImageTLSDirectory32 to an ImageTLSDirectory64.
|
||||
func (i ImageTLSDirectory32) To64() ImageTLSDirectory64 {
|
||||
return ImageTLSDirectory64{
|
||||
StartAddressOfRawData: uint64(i.StartAddressOfRawData),
|
||||
EndAddressOfRawData: uint64(i.EndAddressOfRawData),
|
||||
AddressOfIndex: uint64(i.AddressOfIndex),
|
||||
AddressOfCallBacks: uint64(i.AddressOfCallBacks),
|
||||
SizeOfZeroFill: i.SizeOfZeroFill,
|
||||
Characteristics: i.Characteristics,
|
||||
}
|
||||
}
|
||||
106
vendor/github.com/jchv/go-winloader/internal/pe/import.go
generated
vendored
Normal file
106
vendor/github.com/jchv/go-winloader/internal/pe/import.go
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
package pe
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/jchv/go-winloader/internal/loader"
|
||||
)
|
||||
|
||||
// LinkModule links a PE module in-memory.
|
||||
func LinkModule(m *Module, mem io.ReadWriteSeeker, ldr loader.Loader) error {
|
||||
dir := m.Header.OptionalHeader.DataDirectory[ImageDirectoryEntryImport]
|
||||
if dir.Size == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Determine pointer size based on whether we're PE32 or PE64.
|
||||
psize := 4
|
||||
if m.IsPE64 {
|
||||
psize = 8
|
||||
}
|
||||
|
||||
// Load import descriptors
|
||||
descs := []ImageImportDescriptor{}
|
||||
mem.Seek(int64(dir.VirtualAddress), io.SeekStart)
|
||||
for {
|
||||
desc := ImageImportDescriptor{}
|
||||
binary.Read(mem, binary.LittleEndian, &desc)
|
||||
|
||||
if desc.Name == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
descs = append(descs, desc)
|
||||
}
|
||||
|
||||
// Load modules.
|
||||
for _, desc := range descs {
|
||||
thunk := int64(desc.OriginalFirstThunk)
|
||||
iat := int64(desc.FirstThunk)
|
||||
if thunk == 0 {
|
||||
thunk = iat
|
||||
}
|
||||
|
||||
// Read module name
|
||||
mem.Seek(int64(desc.Name), io.SeekStart)
|
||||
|
||||
// Load library
|
||||
libname := readsz(mem)
|
||||
lib, err := ldr.Load(libname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read thunk addrs
|
||||
b := [8]byte{}
|
||||
thunks := []uint64{}
|
||||
mem.Seek(thunk, io.SeekStart)
|
||||
for {
|
||||
mem.Read(b[:psize])
|
||||
thunk := binary.LittleEndian.Uint64(b[:])
|
||||
if thunk == 0 {
|
||||
break
|
||||
}
|
||||
thunks = append(thunks, thunk)
|
||||
}
|
||||
|
||||
// Resolve thunks
|
||||
resolved := []uint64{}
|
||||
for _, thunk := range thunks {
|
||||
thunkord := int64(-1)
|
||||
if (m.IsPE64 && thunk&0x8000000000000000 != 0) || (!m.IsPE64 && thunk&0x80000000 != 0) {
|
||||
thunkord = int64(thunk & 0xFFFF)
|
||||
}
|
||||
if thunkord != -1 {
|
||||
// Import by ordinal
|
||||
if proc := lib.Ordinal(uint64(thunkord)); proc != nil {
|
||||
resolved = append(resolved, proc.Addr())
|
||||
} else {
|
||||
return fmt.Errorf("could not resolve ordinal %d in module %q", thunkord, libname)
|
||||
}
|
||||
} else {
|
||||
// Read name
|
||||
mem.Seek(int64(thunk+2), io.SeekStart)
|
||||
fnname := readsz(mem)
|
||||
|
||||
// Import by name
|
||||
if proc := lib.Proc(fnname); proc != nil {
|
||||
resolved = append(resolved, proc.Addr())
|
||||
} else {
|
||||
return fmt.Errorf("could not resolve symbol %q in module %q", fnname, libname)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write resolved IAT
|
||||
mem.Seek(iat, io.SeekStart)
|
||||
for _, fn := range resolved {
|
||||
binary.LittleEndian.PutUint64(b[:], uint64(fn))
|
||||
mem.Write(b[:psize])
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
91
vendor/github.com/jchv/go-winloader/internal/pe/module.go
generated
vendored
Normal file
91
vendor/github.com/jchv/go-winloader/internal/pe/module.go
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
package pe
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrBadMZSignature is returned when the MZ signature is invalid.
|
||||
ErrBadMZSignature = errors.New("mz: bad signature")
|
||||
|
||||
// ErrBadPESignature is returned when the PE signature is invalid.
|
||||
ErrBadPESignature = errors.New("pe: bad signature")
|
||||
|
||||
// ErrUnknownOptionalHeaderMagic is returned when the optional header
|
||||
// magic field has an unknown value.
|
||||
ErrUnknownOptionalHeaderMagic = errors.New("pe: unknown optional header magic")
|
||||
)
|
||||
|
||||
// Module contains a parsed and loaded PE file.
|
||||
type Module struct {
|
||||
IsPE64 bool
|
||||
DOSHeader ImageDOSHeader
|
||||
Header ImageNTHeaders64
|
||||
Sections []ImageSectionHeader
|
||||
}
|
||||
|
||||
// LoadModule loads a PE module into memory.
|
||||
func LoadModule(r io.ReadSeeker) (*Module, error) {
|
||||
m := &Module{}
|
||||
|
||||
r.Seek(0, io.SeekStart)
|
||||
dos := ImageDOSHeader{}
|
||||
if err := binary.Read(r, binary.LittleEndian, &dos); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if dos.Signature != MZSignature {
|
||||
return nil, ErrBadMZSignature
|
||||
}
|
||||
m.DOSHeader = dos
|
||||
|
||||
r.Seek(int64(dos.NewHeaderAddr), io.SeekStart)
|
||||
pesig := [4]byte{}
|
||||
if err := binary.Read(r, binary.LittleEndian, &pesig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if pesig != PESignature {
|
||||
return nil, ErrBadPESignature
|
||||
}
|
||||
|
||||
optmagic := uint16(0)
|
||||
r.Seek(int64(dos.NewHeaderAddr)+OffsetOfOptionalHeaderFromNTHeader, io.SeekStart)
|
||||
if err := binary.Read(r, binary.LittleEndian, &optmagic); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r.Seek(int64(dos.NewHeaderAddr), io.SeekStart)
|
||||
switch optmagic {
|
||||
case ImageNTOptionalHeader32Magic:
|
||||
m.IsPE64 = false
|
||||
nt := ImageNTHeaders32{}
|
||||
if err := binary.Read(r, binary.LittleEndian, &nt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.Header = nt.To64()
|
||||
case ImageNTOptionalHeader64Magic:
|
||||
m.IsPE64 = true
|
||||
nt := ImageNTHeaders64{}
|
||||
if err := binary.Read(r, binary.LittleEndian, &nt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.Header = nt
|
||||
default:
|
||||
return nil, ErrUnknownOptionalHeaderMagic
|
||||
}
|
||||
|
||||
// Seek past end of optional headers.
|
||||
r.Seek(int64(dos.NewHeaderAddr)+OffsetOfOptionalHeaderFromNTHeader+int64(m.Header.FileHeader.SizeOfOptionalHeader), io.SeekStart)
|
||||
|
||||
for i := uint16(0); i < m.Header.FileHeader.NumberOfSections; i++ {
|
||||
section := ImageSectionHeader{}
|
||||
if err := binary.Read(r, binary.LittleEndian, §ion); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.Sections = append(m.Sections, section)
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
177
vendor/github.com/jchv/go-winloader/internal/pe/reloc.go
generated
vendored
Normal file
177
vendor/github.com/jchv/go-winloader/internal/pe/reloc.go
generated
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
package pe
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// BaseRelocation is a parsed PE base relocation.
|
||||
type BaseRelocation struct {
|
||||
// Relative virtual address of offset (that is, 0 == first byte of PE.)
|
||||
Offset uint64
|
||||
|
||||
// Type of base relocation using the ImageRelBased* constants.
|
||||
Type int
|
||||
}
|
||||
|
||||
// LoadBaseRelocs loads relocations from memory.
|
||||
func LoadBaseRelocs(m *Module, mem io.ReadSeeker) []BaseRelocation {
|
||||
relocs := []BaseRelocation{}
|
||||
dir := m.Header.OptionalHeader.DataDirectory[ImageDirectoryEntryBaseReloc]
|
||||
if dir.Size == 0 {
|
||||
return relocs
|
||||
}
|
||||
n := uint32(0)
|
||||
mem.Seek(int64(dir.VirtualAddress), io.SeekStart)
|
||||
for n < dir.Size {
|
||||
hdr := ImageBaseRelocation{}
|
||||
binary.Read(mem, binary.LittleEndian, &hdr)
|
||||
data := make([]uint16, hdr.SizeOfBlock/2-4)
|
||||
binary.Read(mem, binary.LittleEndian, &data)
|
||||
for _, i := range data {
|
||||
relocs = append(relocs, BaseRelocation{
|
||||
Offset: uint64(hdr.VirtualAddress) + uint64(i&0xFFF),
|
||||
Type: int(i >> 12),
|
||||
})
|
||||
}
|
||||
n += hdr.SizeOfBlock
|
||||
}
|
||||
return relocs
|
||||
}
|
||||
|
||||
// Relocate performs a series of relocations on m, where address is the load
|
||||
// address and original is the original address. The ReadWriteSeeker is
|
||||
// assumed to have the PE image at offset 0.
|
||||
func Relocate(machine int, rels []BaseRelocation, address uint64, original uint64, m io.ReadWriteSeeker, o binary.ByteOrder) error {
|
||||
b := [8]byte{}
|
||||
delta := address - original
|
||||
|
||||
if delta == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
read := func(off uint64, cb int) error {
|
||||
m.Seek(int64(off), io.SeekStart)
|
||||
err := readfully(m, b[0:cb])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.Seek(int64(-cb), io.SeekCurrent)
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, rel := range rels {
|
||||
switch rel.Type {
|
||||
case ImageRelBasedAbsolute:
|
||||
break
|
||||
|
||||
case ImageRelBasedHigh:
|
||||
if err := read(rel.Offset, 2); err != nil {
|
||||
return err
|
||||
}
|
||||
o.PutUint16(b[0:2], uint16(uint64(o.Uint16(b[:2]))+(delta>>16)))
|
||||
if _, err := m.Write(b[0:2]); err != nil {
|
||||
return err
|
||||
}
|
||||
break
|
||||
|
||||
case ImageRelBasedLow:
|
||||
if err := read(rel.Offset, 2); err != nil {
|
||||
return err
|
||||
}
|
||||
o.PutUint16(b[0:2], uint16(uint64(o.Uint16(b[:2]))+(delta>>0)))
|
||||
if _, err := m.Write(b[0:2]); err != nil {
|
||||
return err
|
||||
}
|
||||
break
|
||||
|
||||
case ImageRelBasedHighLow:
|
||||
if err := read(rel.Offset, 4); err != nil {
|
||||
return err
|
||||
}
|
||||
o.PutUint32(b[0:4], uint32(uint64(o.Uint32(b[:4]))+delta))
|
||||
if _, err := m.Write(b[0:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
break
|
||||
|
||||
case ImageRelBasedDir64:
|
||||
if err := read(rel.Offset, 8); err != nil {
|
||||
return err
|
||||
}
|
||||
o.PutUint64(b[0:8], uint64(o.Uint64(b[:8]))+delta)
|
||||
if _, err := m.Write(b[0:8]); err != nil {
|
||||
return err
|
||||
}
|
||||
break
|
||||
|
||||
// Could use some help for ensuring we have proper support for
|
||||
// machine-specific relocations. If you are interested in this
|
||||
// use case for some reason, feel free to send PRs. -- john
|
||||
case ImageRelBasedMachineSpecific5:
|
||||
switch machine {
|
||||
// MIPS: JMP reloc
|
||||
case ImageFileMachineR3000, ImageFileMachineR3000BE,
|
||||
ImageFileMachineR4000, ImageFileMachineR10000,
|
||||
ImageFileMachineWCEMIPSv2, ImageFileMachineMIPS16,
|
||||
ImageFileMachineMIPSFPU, ImageFileMachineMIPSFPU16:
|
||||
return errors.New("MIPS JMP reloc not implemented")
|
||||
// ARM: MOV32 reloc
|
||||
case ImageFileMachineARM, ImageFileMachineTHUMB,
|
||||
ImageFileMachineARMNT:
|
||||
return errors.New("ARM MOV32 reloc not implemented")
|
||||
// RISC-V: HI20 reloc
|
||||
case ImageFileMachineRISCV32, ImageFileMachineRISCV64,
|
||||
ImageFileMachineRISCV128:
|
||||
return errors.New("RISC-V HI20 reloc not implemented")
|
||||
default:
|
||||
return fmt.Errorf("unknown machine-specific relocation type %d on machine type %04x", rel.Type, machine)
|
||||
}
|
||||
|
||||
case ImageRelBasedMachineSpecific7:
|
||||
switch machine {
|
||||
// THUMB: MOV32 reloc
|
||||
case ImageFileMachineARM, ImageFileMachineTHUMB,
|
||||
ImageFileMachineARMNT:
|
||||
return errors.New("THUMB MOV32 reloc not implemented")
|
||||
// RISC-V: LOW12I reloc
|
||||
case ImageFileMachineRISCV32, ImageFileMachineRISCV64,
|
||||
ImageFileMachineRISCV128:
|
||||
return errors.New("RISC-V LOW12I reloc not implemented")
|
||||
default:
|
||||
return fmt.Errorf("unknown machine-specific relocation type %d on machine type %04x", rel.Type, machine)
|
||||
}
|
||||
|
||||
case ImageRelBasedMachineSpecific8:
|
||||
switch machine {
|
||||
// RISC-V: LOW12S reloc
|
||||
case ImageFileMachineRISCV32, ImageFileMachineRISCV64,
|
||||
ImageFileMachineRISCV128:
|
||||
return errors.New("RISC-V LOW12S reloc not implemented")
|
||||
default:
|
||||
return fmt.Errorf("unknown machine-specific relocation type %d on machine type %04x", rel.Type, machine)
|
||||
}
|
||||
|
||||
case ImageRelBasedMachineSpecific9:
|
||||
switch machine {
|
||||
// MIPS: JMP16 reloc
|
||||
case ImageFileMachineR3000, ImageFileMachineR3000BE,
|
||||
ImageFileMachineR4000, ImageFileMachineR10000,
|
||||
ImageFileMachineWCEMIPSv2, ImageFileMachineMIPS16,
|
||||
ImageFileMachineMIPSFPU, ImageFileMachineMIPSFPU16:
|
||||
return errors.New("MIPS JMP16 reloc not implemented")
|
||||
// Itanium: Imm64 reloc
|
||||
case ImageFileMachineIA64:
|
||||
return errors.New("Itanium Imm64 reloc not implemented")
|
||||
default:
|
||||
return fmt.Errorf("unknown machine-specific relocation type %d on machine type %04x", rel.Type, machine)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown relocation type %d", rel.Type)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
40
vendor/github.com/jchv/go-winloader/internal/pe/util.go
generated
vendored
Normal file
40
vendor/github.com/jchv/go-winloader/internal/pe/util.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
package pe
|
||||
|
||||
import "io"
|
||||
|
||||
func readfully(r io.Reader, p []byte) error {
|
||||
n, err := r.Read(p)
|
||||
if n < 0 || n > len(p) {
|
||||
panic("invalid read length")
|
||||
}
|
||||
if err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
for n < len(p) {
|
||||
m, err := r.Read(p[n:])
|
||||
if m < 0 || m > len(p[n:]) {
|
||||
panic("invalid read length")
|
||||
}
|
||||
n += m
|
||||
if n < len(p) && err != nil {
|
||||
return err
|
||||
}
|
||||
if n >= len(p) && err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readsz(r io.Reader) string {
|
||||
name := []byte{}
|
||||
for {
|
||||
b := [1]byte{}
|
||||
r.Read(b[:])
|
||||
if b[0] == 0 {
|
||||
break
|
||||
}
|
||||
name = append(name, b[0])
|
||||
}
|
||||
return string(name)
|
||||
}
|
||||
55
vendor/github.com/jchv/go-winloader/internal/vmem/common.go
generated
vendored
Normal file
55
vendor/github.com/jchv/go-winloader/internal/vmem/common.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
package vmem
|
||||
|
||||
const (
|
||||
memDecommit = 0x4000
|
||||
memRelease = 0x8000
|
||||
)
|
||||
|
||||
type systemInfo struct {
|
||||
wProcessorArchitecture uint16
|
||||
wReserved uint16
|
||||
dwPageSize uint32
|
||||
lpMinimumApplicationAddress uintptr
|
||||
lpMaximumApplicationAddress uintptr
|
||||
dwActiveProcessorMask uintptr
|
||||
dwNumberOfProcessors uint32
|
||||
dwProcessorType uint32
|
||||
dwAllocationGranularity uint32
|
||||
wProcessorLevel uint16
|
||||
wProcessorRevision uint16
|
||||
}
|
||||
|
||||
// Enumeration of allocation type values.
|
||||
const (
|
||||
MemCommit = 0x00001000
|
||||
MemReserve = 0x00002000
|
||||
MemReset = 0x00080000
|
||||
MemResetUndo = 0x10000000
|
||||
)
|
||||
|
||||
// Enumeration of protection levels.
|
||||
const (
|
||||
PageNoAccess = 0x01
|
||||
PageReadOnly = 0x02
|
||||
PageReadWrite = 0x04
|
||||
PageWriteCopy = 0x08
|
||||
PageExecute = 0x10
|
||||
PageExecuteRead = 0x20
|
||||
PageExecuteReadWrite = 0x40
|
||||
PageExecuteWriteCopy = 0x80
|
||||
)
|
||||
|
||||
// RoundDown rounds an address up to a given multiple of size. Size must be a
|
||||
// power of two.
|
||||
func RoundDown(addr uint64, size uint64) uint64 {
|
||||
if size&(size-1) != 0 {
|
||||
panic("alignment size is not a power of two")
|
||||
}
|
||||
return addr &^ (size - 1)
|
||||
}
|
||||
|
||||
// RoundUp rounds an address up to a given multiple of size. Size must be a
|
||||
// power of two.
|
||||
func RoundUp(addr uint64, size uint64) uint64 {
|
||||
return RoundDown(addr+size-1, size)
|
||||
}
|
||||
70
vendor/github.com/jchv/go-winloader/internal/vmem/memory_other.go
generated
vendored
Normal file
70
vendor/github.com/jchv/go-winloader/internal/vmem/memory_other.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
// +build !windows
|
||||
|
||||
package vmem
|
||||
|
||||
// Memory represents a raw block of memory.
|
||||
type Memory struct {
|
||||
data []byte
|
||||
}
|
||||
|
||||
// GetPageSize returns the size of a memory page.
|
||||
func GetPageSize() uint64 {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// Alloc allocates memory at addr of size with allocType and protect.
|
||||
// It returns nil if it fails.
|
||||
func Alloc(addr, size uint64, allocType, protect int) *Memory {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// Get returns a range of existing memory. If the range is not a block of
|
||||
// allocated memory, the returned memory will pagefault when accessed.
|
||||
func Get(addr, size uint64) *Memory {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// Free frees the block of memory.
|
||||
func (m *Memory) Free() {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// Addr returns the actual address of the memory.
|
||||
func (m *Memory) Addr() uint64 {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// Read implements the io.Reader interface.
|
||||
func (m *Memory) Read(b []byte) (n int, err error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// ReadAt implements the io.ReaderAt interface.
|
||||
func (m *Memory) ReadAt(b []byte, off int64) (n int, err error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// Write implements the io.Writer interface.
|
||||
func (m *Memory) Write(b []byte) (n int, err error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// WriteAt implements the io.WriterAt interface.
|
||||
func (m *Memory) WriteAt(b []byte, off int64) (n int, err error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// Seek implements the io.Seeker interface.
|
||||
func (m *Memory) Seek(offset int64, whence int) (int64, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// Protect changes the memory protection for a range of memory.
|
||||
func (m *Memory) Protect(addr, size uint64, protect int) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// Clear sets all bytes in the memory block to zero.
|
||||
func (m *Memory) Clear() {
|
||||
panic("not implemented")
|
||||
}
|
||||
178
vendor/github.com/jchv/go-winloader/internal/vmem/memory_windows.go
generated
vendored
Normal file
178
vendor/github.com/jchv/go-winloader/internal/vmem/memory_windows.go
generated
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
// +build windows
|
||||
|
||||
package vmem
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"reflect"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
kernel32 = windows.NewLazySystemDLL("kernel32")
|
||||
kernel32VirtualAlloc = kernel32.NewProc("VirtualAlloc")
|
||||
kernel32VirtualFree = kernel32.NewProc("VirtualFree")
|
||||
kernel32VirtualProtect = kernel32.NewProc("VirtualProtect")
|
||||
kernel32GetNativeSystemInfo = kernel32.NewProc("GetNativeSystemInfo")
|
||||
kernel32FlushInstructionCache = kernel32.NewProc("FlushInstructionCache")
|
||||
kernel32GetCurrentProcess = kernel32.NewProc("GetCurrentProcess")
|
||||
|
||||
pageSize uint64
|
||||
pageSizeOnce sync.Once
|
||||
)
|
||||
|
||||
// getCurrentProcess returns the current process handle.
|
||||
func getCurrentProcess() uintptr {
|
||||
r, _, _ := kernel32GetCurrentProcess.Call()
|
||||
return uintptr(r)
|
||||
}
|
||||
|
||||
// GetPageSize returns the size of a memory page.
|
||||
func GetPageSize() uint64 {
|
||||
pageSizeOnce.Do(func() {
|
||||
if kernel32GetNativeSystemInfo.Find() != nil {
|
||||
pageSize = 0x1000
|
||||
}
|
||||
info := systemInfo{}
|
||||
kernel32GetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&info)))
|
||||
pageSize = uint64(info.dwPageSize)
|
||||
})
|
||||
return pageSize
|
||||
}
|
||||
|
||||
// Memory represents a raw block of memory.
|
||||
type Memory struct {
|
||||
data []byte
|
||||
i int64
|
||||
}
|
||||
|
||||
// Alloc allocates memory at addr of size with allocType and protect.
|
||||
// It returns nil if it fails.
|
||||
func Alloc(addr, size uint64, allocType, protect int) *Memory {
|
||||
r, _, _ := kernel32VirtualAlloc.Call(uintptr(addr), uintptr(size), uintptr(allocType), uintptr(protect))
|
||||
if r == 0 {
|
||||
return nil
|
||||
}
|
||||
return Get(uint64(r), size)
|
||||
}
|
||||
|
||||
// Get returns a range of existing memory. If the range is not a block of
|
||||
// allocated memory, the returned memory will pagefault when accessed.
|
||||
func Get(addr, size uint64) *Memory {
|
||||
m := &Memory{}
|
||||
sh := (*reflect.SliceHeader)(unsafe.Pointer(&m.data))
|
||||
sh.Data = uintptr(addr)
|
||||
sh.Len = int(size)
|
||||
sh.Cap = int(size)
|
||||
return m
|
||||
}
|
||||
|
||||
// Free frees the block of memory.
|
||||
func (m *Memory) Free() {
|
||||
sh := (*reflect.SliceHeader)(unsafe.Pointer(&m.data))
|
||||
kernel32VirtualFree.Call(sh.Data, 0, memRelease)
|
||||
m.data = nil
|
||||
}
|
||||
|
||||
// Addr returns the actual address of the memory.
|
||||
func (m *Memory) Addr() uint64 {
|
||||
return uint64((*reflect.SliceHeader)(unsafe.Pointer(&m.data)).Data)
|
||||
}
|
||||
|
||||
// Read implements the io.Reader interface.
|
||||
func (m *Memory) Read(b []byte) (n int, err error) {
|
||||
if m.i >= int64(len(m.data)) {
|
||||
return 0, io.EOF
|
||||
}
|
||||
n = copy(b, m.data[m.i:])
|
||||
m.i += int64(n)
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// ReadAt implements the io.ReaderAt interface.
|
||||
func (m *Memory) ReadAt(b []byte, off int64) (n int, err error) {
|
||||
if off < 0 {
|
||||
return 0, errors.New("negative offset")
|
||||
}
|
||||
if off >= int64(len(m.data)) {
|
||||
return 0, io.EOF
|
||||
}
|
||||
n = copy(b, m.data[off:])
|
||||
if n < len(b) {
|
||||
return n, io.EOF
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Write implements the io.Writer interface.
|
||||
func (m *Memory) Write(b []byte) (n int, err error) {
|
||||
if m.i >= int64(len(m.data)) {
|
||||
return 0, io.ErrShortWrite
|
||||
}
|
||||
n = copy(m.data[m.i:], b)
|
||||
if kernel32FlushInstructionCache.Find() == nil {
|
||||
kernel32FlushInstructionCache.Call(getCurrentProcess(), uintptr(unsafe.Pointer(&m.data[m.i])), uintptr(n))
|
||||
}
|
||||
m.i += int64(n)
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// WriteAt implements the io.WriterAt interface.
|
||||
func (m *Memory) WriteAt(b []byte, off int64) (n int, err error) {
|
||||
if off < 0 {
|
||||
return 0, errors.New("negative offset")
|
||||
}
|
||||
if off >= int64(len(m.data)) {
|
||||
return 0, io.ErrShortWrite
|
||||
}
|
||||
n = copy(m.data[off:], b)
|
||||
if kernel32FlushInstructionCache.Find() == nil {
|
||||
kernel32FlushInstructionCache.Call(getCurrentProcess(), uintptr(unsafe.Pointer(&m.data[off])), uintptr(n))
|
||||
}
|
||||
if n < len(b) {
|
||||
return n, io.ErrShortWrite
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Seek implements the io.Seeker interface.
|
||||
func (m *Memory) Seek(offset int64, whence int) (int64, error) {
|
||||
var n int64
|
||||
switch whence {
|
||||
case io.SeekStart:
|
||||
n = offset
|
||||
case io.SeekCurrent:
|
||||
n = m.i + offset
|
||||
case io.SeekEnd:
|
||||
n = int64(len(m.data)) + offset
|
||||
default:
|
||||
return 0, errors.New("invalid whence")
|
||||
}
|
||||
if n < 0 {
|
||||
return 0, errors.New("negative position")
|
||||
}
|
||||
m.i = n
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Clear sets all bytes in the memory block to zero.
|
||||
func (m *Memory) Clear() {
|
||||
for i := range m.data {
|
||||
m.data[i] = 0
|
||||
}
|
||||
if kernel32FlushInstructionCache.Find() == nil {
|
||||
kernel32FlushInstructionCache.Call(getCurrentProcess(), uintptr(unsafe.Pointer(&m.data[0])), uintptr(len(m.data)))
|
||||
}
|
||||
}
|
||||
|
||||
// Protect changes the memory protection for a range of memory.
|
||||
func (m *Memory) Protect(addr, size uint64, protect int) error {
|
||||
// TODO: error handling
|
||||
oldProtect := uint32(0)
|
||||
kernel32VirtualProtect.Call(uintptr(m.Addr()+addr), uintptr(size), uintptr(protect), uintptr(unsafe.Pointer(&oldProtect)))
|
||||
return nil
|
||||
}
|
||||
16
vendor/github.com/jchv/go-winloader/internal/winloader/hacks_other.go
generated
vendored
Normal file
16
vendor/github.com/jchv/go-winloader/internal/winloader/hacks_other.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// +build !windows
|
||||
|
||||
package winloader
|
||||
|
||||
import "errors"
|
||||
|
||||
// MakePEBEntryForModule is a hack that inserts an entry for the loaded module
|
||||
// into the PEB loader data to make it appear to Windows functions.
|
||||
func MakePEBEntryForModule() error {
|
||||
return errors.New("platform not supported")
|
||||
}
|
||||
|
||||
// GetProcessHInstance gets the HINSTANCE for the current process.
|
||||
func GetProcessHInstance() (uintptr, error) {
|
||||
return errors.New("platform not supported")
|
||||
}
|
||||
73
vendor/github.com/jchv/go-winloader/internal/winloader/hacks_windows.go
generated
vendored
Normal file
73
vendor/github.com/jchv/go-winloader/internal/winloader/hacks_windows.go
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
package winloader
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
ntdllModule = windows.NewLazySystemDLL("ntdll")
|
||||
ntdllNtQueryInformationProcess = ntdllModule.NewProc("NtQueryInformationProcess")
|
||||
)
|
||||
|
||||
type _ProcessBasicInformation struct {
|
||||
Reserved1 uintptr
|
||||
PebBaseAddress uintptr
|
||||
Reserved2 [2]uintptr
|
||||
UniqueProcessID uintptr
|
||||
Reserved3 uintptr
|
||||
}
|
||||
|
||||
type _PEB struct {
|
||||
Reserved1 [2]byte
|
||||
BeingDebugged byte
|
||||
Reserved2 [1]byte
|
||||
Reserved3 [2]uintptr
|
||||
Ldr uintptr
|
||||
}
|
||||
|
||||
type _List struct {
|
||||
Front uintptr
|
||||
Back uintptr
|
||||
}
|
||||
|
||||
type _PEBLoaderData struct {
|
||||
Length uint32
|
||||
Initialized uint8
|
||||
Padding [3]uint8
|
||||
SsHandle uintptr
|
||||
InLoadOrderModuleList _List
|
||||
InMemoryOrderModuleList _List
|
||||
InInitializationOrderModuleList _List
|
||||
}
|
||||
|
||||
// MakePEBEntryForModule is a hack that inserts an entry for the loaded module
|
||||
// into the PEB loader data to make it appear to Windows functions.
|
||||
func MakePEBEntryForModule() error {
|
||||
process := -1
|
||||
sizeNeeded := uint32(0)
|
||||
pbi := _ProcessBasicInformation{}
|
||||
status, _, _ := ntdllNtQueryInformationProcess.Call(
|
||||
uintptr(process),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&pbi)),
|
||||
unsafe.Sizeof(pbi),
|
||||
uintptr(unsafe.Pointer(&sizeNeeded)),
|
||||
)
|
||||
if status != 0 {
|
||||
return fmt.Errorf("NtQueryInformationProcess failed: %08x", status)
|
||||
}
|
||||
|
||||
// TODO: Implement attempt to insert module entry.
|
||||
return errors.New("unimplemented")
|
||||
}
|
||||
|
||||
// GetProcessHInstance gets the HINSTANCE for the current process.
|
||||
func GetProcessHInstance() (uintptr, error) {
|
||||
var hinstance windows.Handle
|
||||
windows.GetModuleHandleEx(0, nil, &hinstance)
|
||||
return uintptr(hinstance), nil
|
||||
}
|
||||
96
vendor/github.com/jchv/go-winloader/internal/winloader/loader_windows.go
generated
vendored
Normal file
96
vendor/github.com/jchv/go-winloader/internal/winloader/loader_windows.go
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
package winloader
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"github.com/jchv/go-winloader/internal/loader"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// Proc is a Proc implementation using a native procedure.
|
||||
type Proc uintptr
|
||||
|
||||
// Call calls a native procedure.
|
||||
func (p Proc) Call(a ...uint64) (r1, r2 uint64, lastErr error) {
|
||||
var n1, n2 uintptr
|
||||
switch len(a) {
|
||||
case 0:
|
||||
n1, n2, lastErr = syscall.Syscall(uintptr(p), 0, 0, 0, 0)
|
||||
case 1:
|
||||
n1, n2, lastErr = syscall.Syscall(uintptr(p), 1, uintptr(a[0]), 0, 0)
|
||||
case 2:
|
||||
n1, n2, lastErr = syscall.Syscall(uintptr(p), 2, uintptr(a[0]), uintptr(a[1]), 0)
|
||||
case 3:
|
||||
n1, n2, lastErr = syscall.Syscall(uintptr(p), 3, uintptr(a[0]), uintptr(a[1]), uintptr(a[2]))
|
||||
case 4:
|
||||
n1, n2, lastErr = syscall.Syscall6(uintptr(p), 4, uintptr(a[0]), uintptr(a[1]), uintptr(a[2]), uintptr(a[3]), 0, 0)
|
||||
case 5:
|
||||
n1, n2, lastErr = syscall.Syscall6(uintptr(p), 5, uintptr(a[0]), uintptr(a[1]), uintptr(a[2]), uintptr(a[3]), uintptr(a[4]), 0)
|
||||
case 6:
|
||||
n1, n2, lastErr = syscall.Syscall6(uintptr(p), 6, uintptr(a[0]), uintptr(a[1]), uintptr(a[2]), uintptr(a[3]), uintptr(a[4]), uintptr(a[5]))
|
||||
case 7:
|
||||
n1, n2, lastErr = syscall.Syscall9(uintptr(p), 7, uintptr(a[0]), uintptr(a[1]), uintptr(a[2]), uintptr(a[3]), uintptr(a[4]), uintptr(a[5]), uintptr(a[6]), 0, 0)
|
||||
case 8:
|
||||
n1, n2, lastErr = syscall.Syscall9(uintptr(p), 8, uintptr(a[0]), uintptr(a[1]), uintptr(a[2]), uintptr(a[3]), uintptr(a[4]), uintptr(a[5]), uintptr(a[6]), uintptr(a[7]), 0)
|
||||
case 9:
|
||||
n1, n2, lastErr = syscall.Syscall9(uintptr(p), 9, uintptr(a[0]), uintptr(a[1]), uintptr(a[2]), uintptr(a[3]), uintptr(a[4]), uintptr(a[5]), uintptr(a[6]), uintptr(a[7]), uintptr(a[8]))
|
||||
case 10:
|
||||
n1, n2, lastErr = syscall.Syscall12(uintptr(p), 10, uintptr(a[0]), uintptr(a[1]), uintptr(a[2]), uintptr(a[3]), uintptr(a[4]), uintptr(a[5]), uintptr(a[6]), uintptr(a[7]), uintptr(a[8]), uintptr(a[9]), 0, 0)
|
||||
case 11:
|
||||
n1, n2, lastErr = syscall.Syscall12(uintptr(p), 11, uintptr(a[0]), uintptr(a[1]), uintptr(a[2]), uintptr(a[3]), uintptr(a[4]), uintptr(a[5]), uintptr(a[6]), uintptr(a[7]), uintptr(a[8]), uintptr(a[9]), uintptr(a[10]), 0)
|
||||
case 12:
|
||||
n1, n2, lastErr = syscall.Syscall12(uintptr(p), 12, uintptr(a[0]), uintptr(a[1]), uintptr(a[2]), uintptr(a[3]), uintptr(a[4]), uintptr(a[5]), uintptr(a[6]), uintptr(a[7]), uintptr(a[8]), uintptr(a[9]), uintptr(a[10]), uintptr(a[11]))
|
||||
case 13:
|
||||
n1, n2, lastErr = syscall.Syscall15(uintptr(p), 13, uintptr(a[0]), uintptr(a[1]), uintptr(a[2]), uintptr(a[3]), uintptr(a[4]), uintptr(a[5]), uintptr(a[6]), uintptr(a[7]), uintptr(a[8]), uintptr(a[9]), uintptr(a[10]), uintptr(a[11]), uintptr(a[12]), 0, 0)
|
||||
case 14:
|
||||
n1, n2, lastErr = syscall.Syscall15(uintptr(p), 14, uintptr(a[0]), uintptr(a[1]), uintptr(a[2]), uintptr(a[3]), uintptr(a[4]), uintptr(a[5]), uintptr(a[6]), uintptr(a[7]), uintptr(a[8]), uintptr(a[9]), uintptr(a[10]), uintptr(a[11]), uintptr(a[12]), uintptr(a[13]), 0)
|
||||
case 15:
|
||||
n1, n2, lastErr = syscall.Syscall15(uintptr(p), 15, uintptr(a[0]), uintptr(a[1]), uintptr(a[2]), uintptr(a[3]), uintptr(a[4]), uintptr(a[5]), uintptr(a[6]), uintptr(a[7]), uintptr(a[8]), uintptr(a[9]), uintptr(a[10]), uintptr(a[11]), uintptr(a[12]), uintptr(a[13]), uintptr(a[14]))
|
||||
default:
|
||||
panic("too many arguments")
|
||||
}
|
||||
return uint64(n1), uint64(n2), lastErr
|
||||
}
|
||||
|
||||
// Addr gets the native address of the procedure.
|
||||
func (p Proc) Addr() uint64 {
|
||||
return uint64(p)
|
||||
}
|
||||
|
||||
// Library is a module implementation using the native Windows loader.
|
||||
type Library windows.Handle
|
||||
|
||||
// Proc implements loader.Module
|
||||
func (l Library) Proc(name string) loader.Proc {
|
||||
proc, _ := windows.GetProcAddress(windows.Handle(l), name)
|
||||
if proc == 0 {
|
||||
return nil
|
||||
}
|
||||
return Proc(proc)
|
||||
}
|
||||
|
||||
// Ordinal implements loader.Module
|
||||
func (l Library) Ordinal(ordinal uint64) loader.Proc {
|
||||
proc, _ := windows.GetProcAddressByOrdinal(windows.Handle(l), uintptr(ordinal))
|
||||
if proc == 0 {
|
||||
return nil
|
||||
}
|
||||
return Proc(proc)
|
||||
}
|
||||
|
||||
// Free implements loader.Module
|
||||
func (l Library) Free() error {
|
||||
return windows.FreeLibrary(windows.Handle(l))
|
||||
}
|
||||
|
||||
// Loader is a loader that uses the native Windows library loader.
|
||||
type Loader struct{}
|
||||
|
||||
// Load loads a module into memory.
|
||||
func (Loader) Load(libname string) (loader.Module, error) {
|
||||
handle, err := windows.LoadLibrary(libname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Library(handle), nil
|
||||
}
|
||||
32
vendor/github.com/jchv/go-winloader/internal/winloader/machine_windows.go
generated
vendored
Normal file
32
vendor/github.com/jchv/go-winloader/internal/winloader/machine_windows.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
package winloader
|
||||
|
||||
import (
|
||||
"github.com/jchv/go-winloader/internal/loader"
|
||||
"github.com/jchv/go-winloader/internal/vmem"
|
||||
)
|
||||
|
||||
// NativeMachine is a loader.Machine implementation that uses the native
|
||||
// machine the binary is running on.
|
||||
type NativeMachine struct{}
|
||||
|
||||
// IsArchitectureSupported implements loader.Machine.
|
||||
func (NativeMachine) IsArchitectureSupported(machine int) bool {
|
||||
return machine == NativeArch
|
||||
}
|
||||
|
||||
func (NativeMachine) GetPageSize() uint64 {
|
||||
return vmem.GetPageSize()
|
||||
}
|
||||
|
||||
// Alloc implements loader.Machine.
|
||||
func (NativeMachine) Alloc(addr, size uint64, allocType, protect int) loader.Memory {
|
||||
if mem := vmem.Alloc(addr, size, allocType, protect); mem != nil {
|
||||
return mem
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MemProc implements loader.MemProc.
|
||||
func (NativeMachine) MemProc(addr uint64) loader.Proc {
|
||||
return Proc(addr)
|
||||
}
|
||||
9
vendor/github.com/jchv/go-winloader/internal/winloader/nativearch_386.go
generated
vendored
Normal file
9
vendor/github.com/jchv/go-winloader/internal/winloader/nativearch_386.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package winloader
|
||||
|
||||
import (
|
||||
"github.com/jchv/go-winloader/internal/pe"
|
||||
)
|
||||
|
||||
// NativeArch is a constant that will be equal to the PE machine type
|
||||
// enumeration value that corresponds to the arch the binary is running as.
|
||||
const NativeArch = pe.ImageFileMachinei386
|
||||
9
vendor/github.com/jchv/go-winloader/internal/winloader/nativearch_amd64.go
generated
vendored
Normal file
9
vendor/github.com/jchv/go-winloader/internal/winloader/nativearch_amd64.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package winloader
|
||||
|
||||
import (
|
||||
"github.com/jchv/go-winloader/internal/pe"
|
||||
)
|
||||
|
||||
// NativeArch is a constant that will be equal to the PE machine type
|
||||
// enumeration value that corresponds to the arch the binary is running as.
|
||||
const NativeArch = pe.ImageFileMachineAMD64
|
||||
9
vendor/github.com/jchv/go-winloader/internal/winloader/nativearch_arm64.go
generated
vendored
Normal file
9
vendor/github.com/jchv/go-winloader/internal/winloader/nativearch_arm64.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package winloader
|
||||
|
||||
import (
|
||||
"github.com/jchv/go-winloader/internal/pe"
|
||||
)
|
||||
|
||||
// NativeArch is a constant that will be equal to the PE machine type
|
||||
// enumeration value that corresponds to the arch the binary is running as.
|
||||
const NativeArch = pe.ImageFileMachineARM64
|
||||
Reference in New Issue
Block a user