107 lines
2.3 KiB
Go
107 lines
2.3 KiB
Go
|
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
|
||
|
}
|