Simplified executable file formats

This commit is contained in:
Eduard Urbach 2024-08-15 00:46:49 +02:00
parent 1cb93b39a7
commit 999e60e294
Signed by: eduard
GPG key ID: 49226B848C78F6C8
29 changed files with 236 additions and 218 deletions

119
src/exe/pe/EXE.go Normal file
View file

@ -0,0 +1,119 @@
package pe
import (
"bytes"
"encoding/binary"
"io"
"git.akyoto.dev/cli/q/src/config"
"git.akyoto.dev/cli/q/src/exe"
)
const NumSections = 2
// EXE is the portable executable format used on Windows.
type EXE struct {
DOSHeader
NTHeader
OptionalHeader64
Sections [NumSections]SectionHeader
}
// Write writes the EXE file to the given writer.
func Write(writer io.Writer, code []byte, data []byte) {
const (
HeaderEnd = DOSHeaderSize + NTHeaderSize + OptionalHeader64Size + SectionHeaderSize*NumSections
)
var (
codePadding = exe.Padding(HeaderEnd, config.Align)
codeEnd = config.CodeOffset + len(code)
dataPadding = exe.Padding(codeEnd, config.Align)
dataStart = codeEnd + dataPadding
)
imageSize := dataStart + len(data)
imageSize += exe.Padding(imageSize, config.Align)
pe := &EXE{
DOSHeader: DOSHeader{
Magic: [4]byte{'M', 'Z', 0, 0},
NTHeaderOffset: DOSHeaderSize,
},
NTHeader: NTHeader{
Signature: [4]byte{'P', 'E', 0, 0},
Machine: IMAGE_FILE_MACHINE_AMD64,
NumberOfSections: NumSections,
SizeOfOptionalHeader: OptionalHeader64Size,
Characteristics: IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE,
},
OptionalHeader64: OptionalHeader64{
Magic: 0x020B, // PE32+ executable
MajorLinkerVersion: 0x0E,
MinorLinkerVersion: 0x16,
SizeOfCode: uint32(len(code)),
AddressOfEntryPoint: config.CodeOffset,
BaseOfCode: config.CodeOffset,
ImageBase: config.BaseAddress,
SectionAlignment: config.Align, // power of 2, must be greater than or equal to FileAlignment
FileAlignment: config.Align, // power of 2
MajorOperatingSystemVersion: 0x06,
MajorSubsystemVersion: 0x06,
SizeOfImage: uint32(imageSize),
SizeOfHeaders: config.CodeOffset, // section bodies begin here
Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI,
DllCharacteristics: IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE,
SizeOfStackReserve: 0x100000,
SizeOfStackCommit: 0x1000,
SizeOfHeapReserve: 0x100000,
SizeOfHeapCommit: 0x1000,
NumberOfRvaAndSizes: 16,
DataDirectory: [16]DataDirectory{
{VirtualAddress: 0, Size: 0},
{VirtualAddress: 0, Size: 0},
{VirtualAddress: 0, Size: 0},
{VirtualAddress: 0, Size: 0},
{VirtualAddress: 0, Size: 0},
{VirtualAddress: 0, Size: 0},
{VirtualAddress: 0, Size: 0},
{VirtualAddress: 0, Size: 0},
{VirtualAddress: 0, Size: 0},
{VirtualAddress: 0, Size: 0},
{VirtualAddress: 0, Size: 0},
{VirtualAddress: 0, Size: 0},
{VirtualAddress: 0, Size: 0},
{VirtualAddress: 0, Size: 0},
{VirtualAddress: 0, Size: 0},
{VirtualAddress: 0, Size: 0},
},
},
Sections: [NumSections]SectionHeader{
{
Name: [8]byte{'.', 't', 'e', 'x', 't'},
VirtualSize: uint32(len(code)),
VirtualAddress: config.CodeOffset,
RawSize: uint32(len(code)), // must be a multiple of FileAlignment
RawAddress: config.CodeOffset, // must be a multiple of FileAlignment
Characteristics: IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ,
},
{
Name: [8]byte{'.', 'r', 'd', 'a', 't', 'a'},
VirtualSize: uint32(len(data)),
VirtualAddress: uint32(dataStart),
RawSize: uint32(len(data)), // must be a multiple of FileAlignment
RawAddress: uint32(dataStart), // must be a multiple of FileAlignment
Characteristics: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ,
},
},
}
binary.Write(writer, binary.LittleEndian, &pe.DOSHeader)
binary.Write(writer, binary.LittleEndian, &pe.NTHeader)
binary.Write(writer, binary.LittleEndian, &pe.OptionalHeader64)
binary.Write(writer, binary.LittleEndian, &pe.Sections)
writer.Write(bytes.Repeat([]byte{0}, int(codePadding)))
writer.Write(code)
writer.Write(bytes.Repeat([]byte{0}, int(dataPadding)))
writer.Write(data)
}