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:
7
vendor/github.com/jchv/go-winloader/LICENSE.md
generated
vendored
Normal file
7
vendor/github.com/jchv/go-winloader/LICENSE.md
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
# ISC License
|
||||
|
||||
Copyright © 2021, John Chadwick <john@jchw.io>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
124
vendor/github.com/jchv/go-winloader/README.md
generated
vendored
Normal file
124
vendor/github.com/jchv/go-winloader/README.md
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
# go-winloader
|
||||
|
||||
**Note:** This library is still experimental. There are no guarantees of API stability, or runtime stability. Proceed with caution.
|
||||
|
||||
go-winloader is a library that implements the Windows module loader algorithm in pure Go. The actual Windows module loader, accessible via `LoadLibrary`, only supports loading modules from disk, which is sometimes undesirable. With go-winloader, you can load modules directly from memory without needing to write intermediate temporary files to disk.
|
||||
|
||||
This is a bit more versatile than linking directly to object files, since you do not need object files for this approach. As a downside, it is a purely Windows-only approach.
|
||||
|
||||
Note: Unlike native APIs, in place of processor register sized values go-winloader uses `uint64` instead of `uintptr` except when calling native host functions. This allows it to remain neutral to processor architecture at runtime, which in the future may allow for more esoteric use cases. (See TODO for more information on potential future features.)
|
||||
|
||||
## Example
|
||||
|
||||
```go
|
||||
// Load a module off disk (for simplicity; you can pass in any byte slice.)
|
||||
b, _ := ioutil.ReadFile("my.dll")
|
||||
mod, err := winloader.LoadFromMemory(b)
|
||||
if err != nil {
|
||||
log.Fatalln("error loading module:", err)
|
||||
}
|
||||
|
||||
// Get a procedure.
|
||||
addProc := mod.Proc("Add")
|
||||
if proc == nil {
|
||||
log.Fatalln("module my.dll is missing required procedure Add")
|
||||
}
|
||||
|
||||
// Call the procedure!
|
||||
result, _, _ := addProc.Call(1, 2)
|
||||
log.Printf("1 + 2 = %d", result)
|
||||
```
|
||||
|
||||
## TODO
|
||||
|
||||
* WinSXS support
|
||||
|
||||
* Some binaries have manifests requesting a specific version of a library.
|
||||
There is an undocumented library at sxs.dll. Since it's undocumented,
|
||||
it might be difficult to work out how to use it.
|
||||
|
||||
* It'd be nice to have a reimplementation of the whole SXS algorithm, just
|
||||
for completeness sake. (It might even be useful to Wine.)
|
||||
|
||||
* Additional compatibility hacks
|
||||
|
||||
* Because we are not Windows loader, Windows loader's internal structures
|
||||
do not update when we load binaries into the address space.
|
||||
|
||||
* Because of this, our HINSTANCE value may not always work properly.
|
||||
|
||||
* There's a hack that sends the process HINSTANCE instead.
|
||||
|
||||
* There's a stub for a hack that would inject the library into the PEB
|
||||
loader data linked lists.
|
||||
|
||||
* This might fail catastrophically or have worse consequences, but it
|
||||
would be interesting to explore.
|
||||
|
||||
* Another useful hack would be one that can override calls to important
|
||||
Windows functions and implement their functionality for cases when our
|
||||
own false HINSTANCE is used. This could be done on a process-wide level
|
||||
(for best compatibility) or directly on the import table (usually enough,
|
||||
but tricky modules will bypass this.)
|
||||
|
||||
* Better support for loading executable images.
|
||||
|
||||
* Right now, if you attempt to load an executable, it executes the
|
||||
entrypoint eagerly when it tries to send the DLL attach message.
|
||||
|
||||
* Threading support.
|
||||
|
||||
* Perhaps have a helper function that can run a function in a new thread,
|
||||
automatically calling `DLL_THREAD_ATTACH`/`DLL_THREAD_DETACH` as needed
|
||||
on memory loaded modules.
|
||||
|
||||
* While it may not be necessary for all libraries, it is likely necessary
|
||||
for libraries that have statically linked the MSVC runtime, and for
|
||||
libraries that use thread-local storage. Otherwise, calling functions on
|
||||
threads other than the initial one is likely to crash.
|
||||
|
||||
* Even better: if we can find a place to hook new threads, this would be a
|
||||
nice hack to support.
|
||||
|
||||
* Versatility
|
||||
|
||||
* Operating systems other than Windows:
|
||||
|
||||
* Need to figure out how to make MSABI calls. Maybe CGo with msabi
|
||||
function pointers, or maybe we need to write out the asm by hand.
|
||||
|
||||
* Emulator would need the ability to generate stub addresses that call
|
||||
back into Go code, so we can use them to handle imports and whatnot.
|
||||
|
||||
* Would need a custom loader that lets you emulate calls to other
|
||||
libraries.
|
||||
|
||||
* CPU emulation
|
||||
|
||||
* Should be possible implement virtual machines with emulated CPUs.
|
||||
|
||||
* Similar to the outside Windows case, we need a custom loader to
|
||||
emulate library calls. Although we *can* use the host system's
|
||||
libraries, we need to translate API calls so that they work
|
||||
correctly, like translating addresses and marshaling/unmarshaling
|
||||
data as necessary, and of course calling conventions are entirely
|
||||
different.
|
||||
|
||||
* We should provide shims at least for running 32-bit binaries in
|
||||
64-bit processes using emulation. How much of the API to emulate
|
||||
would be hard to guage, but at least for documented APIs it should
|
||||
be relatively straightforward work.
|
||||
|
||||
* Legacy formats
|
||||
|
||||
* Currently go-winloader only supports loading PE32 or PE64 binaries.
|
||||
|
||||
* It might be useful to someone to implement loading very old legacy
|
||||
binaries, like NE or LX.
|
||||
|
||||
* Expose lower level APIs
|
||||
|
||||
* In order to allow this library to be useful while it is still in
|
||||
heavy flux, a very small surface area is exposed today. As it
|
||||
matures, more of these internal libraries should be exposed as
|
||||
public API.
|
||||
11
vendor/github.com/jchv/go-winloader/common.go
generated
vendored
Normal file
11
vendor/github.com/jchv/go-winloader/common.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package winloader
|
||||
|
||||
import (
|
||||
"github.com/jchv/go-winloader/internal/loader"
|
||||
)
|
||||
|
||||
// Proc represents a proc of a module.
|
||||
type Proc = loader.Proc
|
||||
|
||||
// Module represents a loaded module.
|
||||
type Module = loader.Module
|
||||
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
|
||||
23
vendor/github.com/jchv/go-winloader/loader_other.go
generated
vendored
Normal file
23
vendor/github.com/jchv/go-winloader/loader_other.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
// +build !windows
|
||||
|
||||
package winloader
|
||||
|
||||
import "fmt"
|
||||
|
||||
// LoadFromFile loads a Windows module from file using the native Windows
|
||||
// loader.
|
||||
func LoadFromFile(name string) (Module, error) {
|
||||
return nil, fmt.Errorf("unsupported platform")
|
||||
}
|
||||
|
||||
// LoadFromMemory loads a Windows module from memory.
|
||||
func LoadFromMemory(data []byte) (Module, error) {
|
||||
return nil, fmt.Errorf("unsupported platform")
|
||||
}
|
||||
|
||||
// AddToCache adds a module to the loader cache, allowing in-memory libraries
|
||||
// to link to it. Note that modules in the cache must exist in the same
|
||||
// address space.
|
||||
func AddToCache(name string, module Module) error {
|
||||
return nil
|
||||
}
|
||||
33
vendor/github.com/jchv/go-winloader/loader_windows.go
generated
vendored
Normal file
33
vendor/github.com/jchv/go-winloader/loader_windows.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
package winloader
|
||||
|
||||
import (
|
||||
"github.com/jchv/go-winloader/internal/memloader"
|
||||
"github.com/jchv/go-winloader/internal/winloader"
|
||||
)
|
||||
|
||||
var native = winloader.Loader{}
|
||||
|
||||
var cache = memloader.NewCache(native)
|
||||
|
||||
var ldr = memloader.New(memloader.Options{
|
||||
Next: cache,
|
||||
Machine: winloader.NativeMachine{},
|
||||
})
|
||||
|
||||
// LoadFromFile loads a Windows module from file using the native Windows
|
||||
// loader.
|
||||
func LoadFromFile(name string) (Module, error) {
|
||||
return native.Load(name)
|
||||
}
|
||||
|
||||
// LoadFromMemory loads a Windows module from memory.
|
||||
func LoadFromMemory(data []byte) (Module, error) {
|
||||
return ldr.LoadMem(data)
|
||||
}
|
||||
|
||||
// AddToCache adds a module to the loader cache, allowing in-memory libraries
|
||||
// to link to it. Note that modules in the cache must exist in the same
|
||||
// address space.
|
||||
func AddToCache(name string, module Module) error {
|
||||
return cache.Add(name, module)
|
||||
}
|
||||
Reference in New Issue
Block a user