From b67f3b09775829d608891cc82f8fa6258230682d Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Sat, 8 Mar 2025 22:14:24 +0100 Subject: [PATCH] Added exe package to manage sections --- src/asmc/codeOffset.go | 5 +- src/asmc/compiler.go | 1 + src/asmc/dllCall.go | 10 ++-- src/asmc/resolvePointers.go | 17 +++---- src/config/const.go | 7 ++- src/elf/ELF.go | 60 ++++++++++-------------- src/elf/cpu.go | 15 ++++++ src/exe/Align.go | 12 +++++ src/exe/Executable.go | 31 +++++++++++++ src/exe/Section.go | 9 ++++ src/fs/Align.go | 7 --- src/macho/MachO.go | 45 +++++++----------- src/macho/cpu.go | 15 ++++++ src/pe/EXE.go | 91 ++++++++++++++++++------------------- src/pe/cpu.go | 15 ++++++ src/readme.md | 1 + 16 files changed, 207 insertions(+), 134 deletions(-) create mode 100644 src/elf/cpu.go create mode 100644 src/exe/Align.go create mode 100644 src/exe/Executable.go create mode 100644 src/exe/Section.go delete mode 100644 src/fs/Align.go create mode 100644 src/macho/cpu.go create mode 100644 src/pe/cpu.go diff --git a/src/asmc/codeOffset.go b/src/asmc/codeOffset.go index 9142762..95c03ae 100644 --- a/src/asmc/codeOffset.go +++ b/src/asmc/codeOffset.go @@ -3,7 +3,7 @@ package asmc import ( "git.urbach.dev/cli/q/src/config" "git.urbach.dev/cli/q/src/elf" - "git.urbach.dev/cli/q/src/fs" + "git.urbach.dev/cli/q/src/exe" "git.urbach.dev/cli/q/src/macho" "git.urbach.dev/cli/q/src/pe" ) @@ -21,6 +21,5 @@ func codeOffset() Address { headerEnd = pe.HeaderEnd } - offset, _ := fs.Align(headerEnd, config.Align) - return offset + return exe.Align(headerEnd, config.FileAlign) } diff --git a/src/asmc/compiler.go b/src/asmc/compiler.go index 041e590..056704b 100644 --- a/src/asmc/compiler.go +++ b/src/asmc/compiler.go @@ -13,4 +13,5 @@ type compiler struct { dlls dll.List codeStart Address dataStart Address + importsStart Address } diff --git a/src/asmc/dllCall.go b/src/asmc/dllCall.go index 71d1e0e..22492e8 100644 --- a/src/asmc/dllCall.go +++ b/src/asmc/dllCall.go @@ -8,15 +8,15 @@ import ( ) func (c *compiler) dllCall(x asm.Instruction) { - size := 4 c.code = x86.CallAt(c.code, 0x00_00_00_00) - position := len(c.code) - size + next := Address(len(c.code)) + position := next - 4 label := x.Data.(*asm.Label) pointer := &pointer{ Position: Address(position), OpSize: 2, - Size: uint8(size), + Size: 4, } pointer.Resolve = func() Address { @@ -29,7 +29,9 @@ func (c *compiler) dllCall(x asm.Instruction) { panic("unknown DLL function " + label.Name) } - return Address(index * 8) + destination := c.importsStart + Address(index*8) + from := c.codeStart + next + return destination - from } c.dllPointers = append(c.dllPointers, pointer) diff --git a/src/asmc/resolvePointers.go b/src/asmc/resolvePointers.go index 6e3ac9d..f42c805 100644 --- a/src/asmc/resolvePointers.go +++ b/src/asmc/resolvePointers.go @@ -6,7 +6,7 @@ import ( "slices" "git.urbach.dev/cli/q/src/config" - "git.urbach.dev/cli/q/src/fs" + "git.urbach.dev/cli/q/src/exe" "git.urbach.dev/cli/q/src/sizeof" ) @@ -77,7 +77,9 @@ restart: } } - c.dataStart, _ = fs.Align(c.codeStart+Address(len(c.code)), config.Align) + sections := exe.MakeSections(int(codeOffset()), c.code, c.data, nil) + data := sections[1] + c.dataStart = Address(data.MemoryOffset) for _, pointer := range c.dataPointers { address := pointer.Resolve() @@ -86,14 +88,13 @@ restart: } if config.TargetOS == config.Windows { - importsStart, _ := fs.Align(c.dataStart+Address(len(c.data)), config.Align) + imports := sections[2] + c.importsStart = Address(imports.MemoryOffset) for _, pointer := range c.dllPointers { - destination := importsStart + pointer.Resolve() - from := c.codeStart + pointer.Position + Address(pointer.Size) - offset := destination - from - slice := c.code[pointer.Position : pointer.Position+4] - binary.LittleEndian.PutUint32(slice, uint32(offset)) + address := pointer.Resolve() + slice := c.code[pointer.Position : pointer.Position+Address(pointer.Size)] + binary.LittleEndian.PutUint32(slice, uint32(address)) } } } diff --git a/src/config/const.go b/src/config/const.go index 09d9946..2e683c2 100644 --- a/src/config/const.go +++ b/src/config/const.go @@ -7,6 +7,9 @@ const ( // The base address is the virtual address for our ELF file. BaseAddress = 0x40 * MinAddress - // Align is the alignment of the sections and it must be a multiple of the page size. - Align = 0x1000 + // FileAlign is the alignment of the sections in the file. + FileAlign = 0x4000 + + // MemoryAlign is the alignment of the sections in memory and it must be a multiple of the page size. + MemoryAlign = 0x4000 ) diff --git a/src/elf/ELF.go b/src/elf/ELF.go index 4a36abe..b80978e 100644 --- a/src/elf/ELF.go +++ b/src/elf/ELF.go @@ -6,7 +6,7 @@ import ( "io" "git.urbach.dev/cli/q/src/config" - "git.urbach.dev/cli/q/src/fs" + "git.urbach.dev/cli/q/src/exe" ) const HeaderEnd = HeaderSize + ProgramHeaderSize*2 @@ -21,19 +21,11 @@ type ELF struct { } // Write writes the ELF64 format to the given writer. -func Write(writer io.Writer, code []byte, data []byte) { - var ( - codeStart, codePadding = fs.Align(HeaderEnd, config.Align) - dataStart, dataPadding = fs.Align(codeStart+len(code), config.Align) - arch int16 - ) - - switch config.TargetArch { - case config.ARM: - arch = ArchitectureARM64 - case config.X86: - arch = ArchitectureAMD64 - } +func Write(writer io.Writer, codeBytes []byte, dataBytes []byte) { + sections := exe.MakeSections(HeaderEnd, codeBytes, dataBytes) + code := sections[0] + data := sections[1] + arch := cpu() elf := &ELF{ Header: Header{ @@ -46,7 +38,7 @@ func Write(writer io.Writer, code []byte, data []byte) { Type: TypeExecutable, Architecture: arch, FileVersion: 1, - EntryPointInMemory: int64(config.BaseAddress + codeStart), + EntryPointInMemory: int64(config.BaseAddress + code.MemoryOffset), ProgramHeaderOffset: HeaderSize, SectionHeaderOffset: 0, Flags: 0, @@ -58,24 +50,22 @@ func Write(writer io.Writer, code []byte, data []byte) { SectionNameStringTableIndex: 0, }, CodeHeader: ProgramHeader{ - Type: ProgramTypeLOAD, - Flags: ProgramFlagsExecutable | ProgramFlagsReadable, - Offset: int64(codeStart), - VirtualAddress: int64(config.BaseAddress + codeStart), - PhysicalAddress: int64(config.BaseAddress + codeStart), - SizeInFile: int64(len(code)), - SizeInMemory: int64(len(code)), - Align: config.Align, + Type: ProgramTypeLOAD, + Flags: ProgramFlagsExecutable | ProgramFlagsReadable, + Offset: int64(code.FileOffset), + VirtualAddress: int64(config.BaseAddress + code.MemoryOffset), + SizeInFile: int64(len(code.Bytes)), + SizeInMemory: int64(len(code.Bytes)), + Align: config.MemoryAlign, }, DataHeader: ProgramHeader{ - Type: ProgramTypeLOAD, - Flags: ProgramFlagsReadable, - Offset: int64(dataStart), - VirtualAddress: int64(config.BaseAddress + dataStart), - PhysicalAddress: int64(config.BaseAddress + dataStart), - SizeInFile: int64(len(data)), - SizeInMemory: int64(len(data)), - Align: config.Align, + Type: ProgramTypeLOAD, + Flags: ProgramFlagsReadable, + Offset: int64(data.FileOffset), + VirtualAddress: int64(config.BaseAddress + data.MemoryOffset), + SizeInFile: int64(len(data.Bytes)), + SizeInMemory: int64(len(data.Bytes)), + Align: config.MemoryAlign, }, } @@ -86,10 +76,10 @@ func Write(writer io.Writer, code []byte, data []byte) { binary.Write(writer, binary.LittleEndian, &elf.Header) binary.Write(writer, binary.LittleEndian, &elf.CodeHeader) binary.Write(writer, binary.LittleEndian, &elf.DataHeader) - writer.Write(bytes.Repeat([]byte{0x00}, codePadding)) - writer.Write(code) - writer.Write(bytes.Repeat([]byte{0x00}, dataPadding)) - writer.Write(data) + writer.Write(bytes.Repeat([]byte{0x00}, code.Padding)) + writer.Write(code.Bytes) + writer.Write(bytes.Repeat([]byte{0x00}, data.Padding)) + writer.Write(data.Bytes) if config.Sections { writer.Write(elf.StringTable) diff --git a/src/elf/cpu.go b/src/elf/cpu.go new file mode 100644 index 0000000..53c1e85 --- /dev/null +++ b/src/elf/cpu.go @@ -0,0 +1,15 @@ +package elf + +import "git.urbach.dev/cli/q/src/config" + +// cpu returns the CPU architecture used in the ELF header. +func cpu() int16 { + switch config.TargetArch { + case config.ARM: + return ArchitectureARM64 + case config.X86: + return ArchitectureAMD64 + default: + panic("unknown architecture") + } +} diff --git a/src/exe/Align.go b/src/exe/Align.go new file mode 100644 index 0000000..f7843bd --- /dev/null +++ b/src/exe/Align.go @@ -0,0 +1,12 @@ +package exe + +// Align calculates the next aligned address. +func Align[T int | uint | int64 | uint64 | int32 | uint32](n T, alignment T) T { + return (n + (alignment - 1)) & ^(alignment - 1) +} + +// AlignPad calculates the next aligned address and the padding needed. +func AlignPad[T int | uint | int64 | uint64 | int32 | uint32](n T, alignment T) (T, T) { + aligned := Align(n, alignment) + return aligned, aligned - n +} diff --git a/src/exe/Executable.go b/src/exe/Executable.go new file mode 100644 index 0000000..80e173d --- /dev/null +++ b/src/exe/Executable.go @@ -0,0 +1,31 @@ +package exe + +import "git.urbach.dev/cli/q/src/config" + +// Executable is a generic definition of the binary that later gets translated to OS-specific formats. +type Executable []*Section + +// MakeSections creates new sections. +func MakeSections(headerEnd int, raw ...[]byte) Executable { + sections := make(Executable, len(raw)) + + for i, data := range raw { + sections[i] = &Section{Bytes: data} + } + + sections.Update(headerEnd) + return sections +} + +// Update recalculates all section offsets. +func (sections Executable) Update(headerEnd int) { + first := sections[0] + first.FileOffset, first.Padding = AlignPad(headerEnd, config.FileAlign) + first.MemoryOffset = Align(headerEnd, config.MemoryAlign) + + for i, section := range sections[1:] { + previous := sections[i] + section.FileOffset, section.Padding = AlignPad(previous.FileOffset+len(previous.Bytes), config.FileAlign) + section.MemoryOffset = Align(previous.MemoryOffset+len(previous.Bytes), config.MemoryAlign) + } +} diff --git a/src/exe/Section.go b/src/exe/Section.go new file mode 100644 index 0000000..ba3d384 --- /dev/null +++ b/src/exe/Section.go @@ -0,0 +1,9 @@ +package exe + +// Section represents some data within the executable that will also be loaded into memory. +type Section struct { + Bytes []byte + FileOffset int + Padding int + MemoryOffset int +} diff --git a/src/fs/Align.go b/src/fs/Align.go deleted file mode 100644 index 1ae4f0b..0000000 --- a/src/fs/Align.go +++ /dev/null @@ -1,7 +0,0 @@ -package fs - -// Align calculates the next aligned address and the padding needed. -func Align[T int | uint | int64 | uint64 | int32 | uint32](n T, alignment T) (T, T) { - aligned := (n + (alignment - 1)) & ^(alignment - 1) - return aligned, aligned - n -} diff --git a/src/macho/MachO.go b/src/macho/MachO.go index 4e6ecb7..b305b6a 100644 --- a/src/macho/MachO.go +++ b/src/macho/MachO.go @@ -6,7 +6,7 @@ import ( "io" "git.urbach.dev/cli/q/src/config" - "git.urbach.dev/cli/q/src/fs" + "git.urbach.dev/cli/q/src/exe" ) const ( @@ -24,22 +24,11 @@ type MachO struct { } // Write writes the Mach-O format to the given writer. -func Write(writer io.Writer, code []byte, data []byte) { - var ( - codeStart, codePadding = fs.Align(HeaderEnd, config.Align) - dataStart, dataPadding = fs.Align(codeStart+len(code), config.Align) - arch CPU - microArch uint32 - ) - - switch config.TargetArch { - case config.ARM: - arch = CPU_ARM_64 - microArch = CPU_SUBTYPE_ARM64_ALL | 0x80000000 - case config.X86: - arch = CPU_X86_64 - microArch = CPU_SUBTYPE_X86_64_ALL | 0x80000000 - } +func Write(writer io.Writer, codeBytes []byte, dataBytes []byte) { + sections := exe.MakeSections(HeaderEnd, codeBytes, dataBytes) + code := sections[0] + data := sections[1] + arch, microArch := cpu() m := &MachO{ Header: Header{ @@ -70,9 +59,9 @@ func Write(writer io.Writer, code []byte, data []byte) { Length: Segment64Size, Name: [16]byte{'_', '_', 'T', 'E', 'X', 'T'}, Address: config.BaseAddress, - SizeInMemory: uint64(codeStart + len(code)), + SizeInMemory: uint64(code.MemoryOffset + len(code.Bytes)), Offset: 0, - SizeInFile: uint64(codeStart + len(code)), + SizeInFile: uint64(code.FileOffset + len(code.Bytes)), NumSections: 0, Flag: 0, MaxProt: ProtReadable | ProtExecutable, @@ -82,10 +71,10 @@ func Write(writer io.Writer, code []byte, data []byte) { LoadCommand: LcSegment64, Length: Segment64Size, Name: [16]byte{'_', '_', 'D', 'A', 'T', 'A'}, - Address: uint64(config.BaseAddress + dataStart), - SizeInMemory: uint64(len(data)), - Offset: uint64(dataStart), - SizeInFile: uint64(len(data)), + Address: uint64(config.BaseAddress + data.MemoryOffset), + SizeInMemory: uint64(len(data.Bytes)), + Offset: uint64(data.FileOffset), + SizeInFile: uint64(len(data.Bytes)), NumSections: 0, Flag: 0, MaxProt: ProtReadable, @@ -113,7 +102,7 @@ func Write(writer io.Writer, code []byte, data []byte) { 0, 0, 0, 0, 0, 0, - uint32(config.BaseAddress + codeStart), 0, + uint32(config.BaseAddress + code.MemoryOffset), 0, 0, 0, 0, 0, 0, 0, @@ -127,8 +116,8 @@ func Write(writer io.Writer, code []byte, data []byte) { binary.Write(writer, binary.LittleEndian, &m.CodeHeader) binary.Write(writer, binary.LittleEndian, &m.DataHeader) binary.Write(writer, binary.LittleEndian, &m.UnixThread) - writer.Write(bytes.Repeat([]byte{0x00}, codePadding)) - writer.Write(code) - writer.Write(bytes.Repeat([]byte{0x00}, dataPadding)) - writer.Write(data) + writer.Write(bytes.Repeat([]byte{0x00}, code.Padding)) + writer.Write(code.Bytes) + writer.Write(bytes.Repeat([]byte{0x00}, data.Padding)) + writer.Write(data.Bytes) } diff --git a/src/macho/cpu.go b/src/macho/cpu.go new file mode 100644 index 0000000..35df5c2 --- /dev/null +++ b/src/macho/cpu.go @@ -0,0 +1,15 @@ +package macho + +import "git.urbach.dev/cli/q/src/config" + +// cpu returns the CPU architecture used in the Mach-O header. +func cpu() (CPU, uint32) { + switch config.TargetArch { + case config.ARM: + return CPU_ARM_64, CPU_SUBTYPE_ARM64_ALL | 0x80000000 + case config.X86: + return CPU_X86_64, CPU_SUBTYPE_X86_64_ALL | 0x80000000 + default: + panic("unknown architecture") + } +} diff --git a/src/pe/EXE.go b/src/pe/EXE.go index 579d6a0..8c9473c 100644 --- a/src/pe/EXE.go +++ b/src/pe/EXE.go @@ -7,7 +7,7 @@ import ( "git.urbach.dev/cli/q/src/config" "git.urbach.dev/cli/q/src/dll" - "git.urbach.dev/cli/q/src/fs" + "git.urbach.dev/cli/q/src/exe" ) const ( @@ -24,31 +24,30 @@ type EXE struct { } // Write writes the EXE file to the given writer. -func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) { +func Write(writer io.Writer, codeBytes []byte, dataBytes []byte, dlls dll.List) { var ( - codeStart, codePadding = fs.Align(HeaderEnd, config.Align) - dataStart, dataPadding = fs.Align(codeStart+len(code), config.Align) - importsStart, importsPadding = fs.Align(dataStart+len(data), config.Align) - subSystem = IMAGE_SUBSYSTEM_WINDOWS_CUI - imports, dllData, dllImports, dllDataStart = importLibraries(dlls, importsStart) - importDirectoryStart = dllDataStart + len(dllData) - importDirectorySize = DLLImportSize * len(dllImports) - importSectionSize = len(imports)*8 + len(dllData) + importDirectorySize - imageSize, _ = fs.Align(importsStart+importSectionSize, config.Align) - arch uint16 + sections = exe.MakeSections(HeaderEnd, codeBytes, dataBytes, nil) + code = sections[0] + data = sections[1] + imports = sections[2] + subSystem = IMAGE_SUBSYSTEM_WINDOWS_CUI + arch = cpu() ) + importsData, dllData, dllImports, dllDataStart := importLibraries(dlls, imports.FileOffset) + buffer := bytes.Buffer{} + binary.Write(&buffer, binary.LittleEndian, &importsData) + binary.Write(&buffer, binary.LittleEndian, &dllData) + binary.Write(&buffer, binary.LittleEndian, &dllImports) + imports.Bytes = buffer.Bytes() + importDirectoryStart := dllDataStart + len(dllData) + importDirectorySize := DLLImportSize * len(dllImports) + imageSize := exe.Align(imports.MemoryOffset+len(imports.Bytes), config.MemoryAlign) + if dlls.Contains("user32") { subSystem = IMAGE_SUBSYSTEM_WINDOWS_GUI } - switch config.TargetArch { - case config.ARM: - arch = IMAGE_FILE_MACHINE_ARM64 - case config.X86: - arch = IMAGE_FILE_MACHINE_AMD64 - } - pe := &EXE{ DOSHeader: DOSHeader{ Magic: [4]byte{'M', 'Z', 0, 0}, @@ -68,14 +67,14 @@ func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) { Magic: 0x020B, // PE32+ / 64-bit executable MajorLinkerVersion: 0x0E, MinorLinkerVersion: 0x16, - SizeOfCode: uint32(len(code)), + SizeOfCode: uint32(len(code.Bytes)), SizeOfInitializedData: 0, SizeOfUninitializedData: 0, - AddressOfEntryPoint: uint32(codeStart), - BaseOfCode: uint32(codeStart), + AddressOfEntryPoint: uint32(code.MemoryOffset), + BaseOfCode: uint32(code.MemoryOffset), ImageBase: config.BaseAddress, - SectionAlignment: config.Align, // power of 2, must be greater than or equal to FileAlignment - FileAlignment: config.Align, // power of 2 + SectionAlignment: config.MemoryAlign, // power of 2, must be greater than or equal to FileAlignment + FileAlignment: config.FileAlign, // power of 2 MajorOperatingSystemVersion: 0x06, MinorOperatingSystemVersion: 0, MajorImageVersion: 0, @@ -83,8 +82,8 @@ func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) { MajorSubsystemVersion: 0x06, MinorSubsystemVersion: 0, Win32VersionValue: 0, - SizeOfImage: uint32(imageSize), - SizeOfHeaders: uint32(codeStart), // section bodies begin here + SizeOfImage: uint32(imageSize), // a multiple of SectionAlignment + SizeOfHeaders: uint32(code.FileOffset), // section bodies begin here CheckSum: 0, Subsystem: uint16(subSystem), DllCharacteristics: IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE, // IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE @@ -107,7 +106,7 @@ func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) { {VirtualAddress: 0, Size: 0}, {VirtualAddress: 0, Size: 0}, {VirtualAddress: 0, Size: 0}, - {VirtualAddress: uint32(importsStart), Size: uint32(len(imports) * 8)}, // RVA of the import address table + {VirtualAddress: uint32(imports.MemoryOffset), Size: uint32(len(importsData) * 8)}, // RVA of the import address table {VirtualAddress: 0, Size: 0}, {VirtualAddress: 0, Size: 0}, {VirtualAddress: 0, Size: 0}, @@ -116,26 +115,26 @@ func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) { Sections: []SectionHeader{ { Name: [8]byte{'.', 't', 'e', 'x', 't'}, - VirtualSize: uint32(len(code)), - VirtualAddress: uint32(codeStart), - RawSize: uint32(len(code)), // must be a multiple of FileAlignment - RawAddress: uint32(codeStart), // must be a multiple of FileAlignment + VirtualSize: uint32(len(code.Bytes)), + VirtualAddress: uint32(code.MemoryOffset), + RawSize: uint32(len(code.Bytes)), // must be a multiple of FileAlignment + RawAddress: uint32(code.FileOffset), // 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)), - RawAddress: uint32(dataStart), + VirtualSize: uint32(len(data.Bytes)), + VirtualAddress: uint32(data.MemoryOffset), + RawSize: uint32(len(data.Bytes)), + RawAddress: uint32(data.FileOffset), Characteristics: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, }, { Name: [8]byte{'.', 'i', 'd', 'a', 't', 'a'}, - VirtualSize: uint32(importSectionSize), - VirtualAddress: uint32(importsStart), - RawSize: uint32(importSectionSize), - RawAddress: uint32(importsStart), + VirtualSize: uint32(len(imports.Bytes)), + VirtualAddress: uint32(imports.MemoryOffset), + RawSize: uint32(len(imports.Bytes)), + RawAddress: uint32(imports.FileOffset), Characteristics: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, }, }, @@ -145,12 +144,10 @@ func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) { 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{0x00}, codePadding)) - writer.Write(code) - writer.Write(bytes.Repeat([]byte{0x00}, dataPadding)) - writer.Write(data) - writer.Write(bytes.Repeat([]byte{0x00}, importsPadding)) - binary.Write(writer, binary.LittleEndian, &imports) - binary.Write(writer, binary.LittleEndian, &dllData) - binary.Write(writer, binary.LittleEndian, &dllImports) + writer.Write(bytes.Repeat([]byte{0x00}, code.Padding)) + writer.Write(code.Bytes) + writer.Write(bytes.Repeat([]byte{0x00}, data.Padding)) + writer.Write(data.Bytes) + writer.Write(bytes.Repeat([]byte{0x00}, imports.Padding)) + writer.Write(imports.Bytes) } diff --git a/src/pe/cpu.go b/src/pe/cpu.go new file mode 100644 index 0000000..9f52560 --- /dev/null +++ b/src/pe/cpu.go @@ -0,0 +1,15 @@ +package pe + +import "git.urbach.dev/cli/q/src/config" + +// cpu returns the CPU architecture used in the PE header. +func cpu() uint16 { + switch config.TargetArch { + case config.ARM: + return IMAGE_FILE_MACHINE_ARM64 + case config.X86: + return IMAGE_FILE_MACHINE_AMD64 + default: + panic("unknown architecture") + } +} diff --git a/src/readme.md b/src/readme.md index 99ce70e..63ab66d 100644 --- a/src/readme.md +++ b/src/readme.md @@ -13,6 +13,7 @@ - [data](data) - Data container that can re-use existing data (e.g. the `Hello` in `Hello World`) - [dll](dll) - DLL support for Windows systems (w.i.p.) - [elf](elf) - ELF format for Linux executables +- [exe](exe) - Generic executable format to calculate section offsets - [errors](errors) - Error types - [eval](eval) - Evaluates expressions - [expression](expression) - Expression parser generating trees with the `Parse` function