Simplified executable file formats
This commit is contained in:
parent
fe1b353fe6
commit
7092cb6626
@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
"git.akyoto.dev/cli/q/src/arch/x64"
|
"git.akyoto.dev/cli/q/src/arch/x64"
|
||||||
"git.akyoto.dev/cli/q/src/config"
|
"git.akyoto.dev/cli/q/src/config"
|
||||||
"git.akyoto.dev/cli/q/src/os/common"
|
"git.akyoto.dev/cli/q/src/exe"
|
||||||
"git.akyoto.dev/cli/q/src/sizeof"
|
"git.akyoto.dev/cli/q/src/sizeof"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -339,7 +339,7 @@ restart:
|
|||||||
data, dataLabels = a.Data.Finalize()
|
data, dataLabels = a.Data.Finalize()
|
||||||
|
|
||||||
dataStart := Address(config.BaseAddress) + config.CodeOffset + Address(len(code))
|
dataStart := Address(config.BaseAddress) + config.CodeOffset + Address(len(code))
|
||||||
dataStart += int32(common.Padding(dataStart, config.Align))
|
dataStart += exe.Padding(dataStart, config.Align)
|
||||||
|
|
||||||
for _, pointer := range dataPointers {
|
for _, pointer := range dataPointers {
|
||||||
address := dataStart + pointer.Resolve()
|
address := dataStart + pointer.Resolve()
|
||||||
|
@ -10,11 +10,11 @@ import (
|
|||||||
"git.akyoto.dev/cli/q/src/asm"
|
"git.akyoto.dev/cli/q/src/asm"
|
||||||
"git.akyoto.dev/cli/q/src/config"
|
"git.akyoto.dev/cli/q/src/config"
|
||||||
"git.akyoto.dev/cli/q/src/core"
|
"git.akyoto.dev/cli/q/src/core"
|
||||||
|
"git.akyoto.dev/cli/q/src/exe/elf"
|
||||||
|
"git.akyoto.dev/cli/q/src/exe/macho"
|
||||||
|
"git.akyoto.dev/cli/q/src/exe/pe"
|
||||||
"git.akyoto.dev/cli/q/src/os/linux"
|
"git.akyoto.dev/cli/q/src/os/linux"
|
||||||
"git.akyoto.dev/cli/q/src/os/linux/elf"
|
|
||||||
"git.akyoto.dev/cli/q/src/os/mac"
|
"git.akyoto.dev/cli/q/src/os/mac"
|
||||||
"git.akyoto.dev/cli/q/src/os/mac/macho"
|
|
||||||
"git.akyoto.dev/cli/q/src/os/windows/pe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Result contains all the compiled functions in a build.
|
// Result contains all the compiled functions in a build.
|
||||||
@ -147,14 +147,11 @@ func write(writer io.Writer, code []byte, data []byte) error {
|
|||||||
|
|
||||||
switch config.TargetOS {
|
switch config.TargetOS {
|
||||||
case "linux":
|
case "linux":
|
||||||
exe := elf.New(code, data)
|
elf.Write(buffer, code, data)
|
||||||
exe.Write(buffer)
|
|
||||||
case "mac":
|
case "mac":
|
||||||
exe := macho.New(code, data)
|
macho.Write(buffer, code, data)
|
||||||
exe.Write(buffer)
|
|
||||||
case "windows":
|
case "windows":
|
||||||
exe := pe.New(code, data)
|
pe.Write(buffer, code, data)
|
||||||
exe.Write(buffer)
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported platform '%s'", config.TargetOS)
|
return fmt.Errorf("unsupported platform '%s'", config.TargetOS)
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package common
|
package exe
|
||||||
|
|
||||||
// Padding calculates the padding needed to align `n` bytes with the specified alignment.
|
// Padding calculates the padding needed to align `n` bytes with the specified alignment.
|
||||||
func Padding[T int | uint | int64 | uint64 | int32 | uint32](n T, align T) T {
|
func Padding[T int | uint | int64 | uint64 | int32 | uint32](n T, align T) T {
|
@ -6,7 +6,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
"git.akyoto.dev/cli/q/src/config"
|
"git.akyoto.dev/cli/q/src/config"
|
||||||
"git.akyoto.dev/cli/q/src/os/common"
|
"git.akyoto.dev/cli/q/src/exe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ELF represents an ELF file.
|
// ELF represents an ELF file.
|
||||||
@ -14,20 +14,20 @@ type ELF struct {
|
|||||||
Header
|
Header
|
||||||
CodeHeader ProgramHeader
|
CodeHeader ProgramHeader
|
||||||
DataHeader ProgramHeader
|
DataHeader ProgramHeader
|
||||||
CodePadding []byte
|
|
||||||
Code []byte
|
|
||||||
DataPadding []byte
|
|
||||||
Data []byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new ELF binary.
|
// Write writes the ELF64 format to the given writer.
|
||||||
func New(code []byte, data []byte) *ELF {
|
func Write(writer io.Writer, code []byte, data []byte) {
|
||||||
codePadding := common.Padding(HeaderSize+ProgramHeaderSize*2, config.Align)
|
const HeaderEnd = HeaderSize + ProgramHeaderSize*2
|
||||||
dataOffset := config.CodeOffset + int64(len(code))
|
|
||||||
dataPadding := common.Padding(dataOffset, config.Align)
|
|
||||||
dataOffset += dataPadding
|
|
||||||
|
|
||||||
return &ELF{
|
var (
|
||||||
|
codePadding = exe.Padding(HeaderEnd, config.Align)
|
||||||
|
codeEnd = config.CodeOffset + len(code)
|
||||||
|
dataPadding = exe.Padding(codeEnd, config.Align)
|
||||||
|
dataStart = codeEnd + dataPadding
|
||||||
|
)
|
||||||
|
|
||||||
|
elf := &ELF{
|
||||||
Header: Header{
|
Header: Header{
|
||||||
Magic: [4]byte{0x7F, 'E', 'L', 'F'},
|
Magic: [4]byte{0x7F, 'E', 'L', 'F'},
|
||||||
Class: 2,
|
Class: 2,
|
||||||
@ -62,30 +62,23 @@ func New(code []byte, data []byte) *ELF {
|
|||||||
DataHeader: ProgramHeader{
|
DataHeader: ProgramHeader{
|
||||||
Type: ProgramTypeLOAD,
|
Type: ProgramTypeLOAD,
|
||||||
Flags: ProgramFlagsReadable,
|
Flags: ProgramFlagsReadable,
|
||||||
Offset: dataOffset,
|
Offset: int64(dataStart),
|
||||||
VirtualAddress: config.BaseAddress + dataOffset,
|
VirtualAddress: int64(config.BaseAddress + dataStart),
|
||||||
PhysicalAddress: config.BaseAddress + dataOffset,
|
PhysicalAddress: int64(config.BaseAddress + dataStart),
|
||||||
SizeInFile: int64(len(data)),
|
SizeInFile: int64(len(data)),
|
||||||
SizeInMemory: int64(len(data)),
|
SizeInMemory: int64(len(data)),
|
||||||
Align: config.Align,
|
Align: config.Align,
|
||||||
},
|
},
|
||||||
CodePadding: bytes.Repeat([]byte{0}, int(codePadding)),
|
|
||||||
Code: code,
|
|
||||||
DataPadding: bytes.Repeat([]byte{0}, int(dataPadding)),
|
|
||||||
Data: data,
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Write writes the ELF64 format to the given writer.
|
|
||||||
func (elf *ELF) Write(writer io.Writer) {
|
|
||||||
binary.Write(writer, binary.LittleEndian, &elf.Header)
|
binary.Write(writer, binary.LittleEndian, &elf.Header)
|
||||||
binary.Write(writer, binary.LittleEndian, &elf.CodeHeader)
|
binary.Write(writer, binary.LittleEndian, &elf.CodeHeader)
|
||||||
binary.Write(writer, binary.LittleEndian, &elf.DataHeader)
|
binary.Write(writer, binary.LittleEndian, &elf.DataHeader)
|
||||||
writer.Write(elf.CodePadding)
|
writer.Write(bytes.Repeat([]byte{0}, codePadding))
|
||||||
writer.Write(elf.Code)
|
writer.Write(code)
|
||||||
|
|
||||||
if len(elf.Data) > 0 {
|
if len(data) > 0 {
|
||||||
writer.Write(elf.DataPadding)
|
writer.Write(bytes.Repeat([]byte{0}, dataPadding))
|
||||||
writer.Write(elf.Data)
|
writer.Write(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
12
src/exe/elf/ELF_test.go
Normal file
12
src/exe/elf/ELF_test.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package elf_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.akyoto.dev/cli/q/src/exe/elf"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWrite(t *testing.T) {
|
||||||
|
elf.Write(io.Discard, nil, nil)
|
||||||
|
}
|
@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
1. ELF header (0x00 - 0x40)
|
1. ELF header (0x00 - 0x40)
|
||||||
2. Program header (0x40 - 0x78)
|
2. Program header (0x40 - 0x78)
|
||||||
3. Padding (0x78 - 0x80)
|
3. Padding
|
||||||
4. Machine code (0x80)
|
4. Machine code
|
||||||
|
|
||||||
## Entry point
|
## Entry point
|
||||||
|
|
||||||
@ -28,3 +28,11 @@ https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/binfm
|
|||||||
|
|
||||||
ELF register definitions:
|
ELF register definitions:
|
||||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/include/asm/elf.h
|
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/include/asm/elf.h
|
||||||
|
|
||||||
|
## Links
|
||||||
|
|
||||||
|
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/elf.h
|
||||||
|
- https://lwn.net/Articles/631631/
|
||||||
|
- https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
|
||||||
|
- https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
|
||||||
|
- https://nathanotterness.com/2021/10/tiny_elf_modernized.html
|
126
src/exe/macho/MachO.go
Normal file
126
src/exe/macho/MachO.go
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
package macho
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"git.akyoto.dev/cli/q/src/config"
|
||||||
|
"git.akyoto.dev/cli/q/src/exe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MachO is the executable format used on MacOS.
|
||||||
|
type MachO struct {
|
||||||
|
Header
|
||||||
|
PageZero Segment64
|
||||||
|
CodeHeader Segment64
|
||||||
|
DataHeader Segment64
|
||||||
|
UnixThread Thread
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write writes the Mach-O format to the given writer.
|
||||||
|
func Write(writer io.Writer, code []byte, data []byte) {
|
||||||
|
const (
|
||||||
|
SizeCommands = Segment64Size*3 + ThreadSize
|
||||||
|
HeaderEnd = HeaderSize + SizeCommands
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
codePadding = exe.Padding(HeaderEnd, config.Align)
|
||||||
|
codeEnd = config.CodeOffset + len(code)
|
||||||
|
dataPadding = exe.Padding(codeEnd, config.Align)
|
||||||
|
dataStart = codeEnd + dataPadding
|
||||||
|
)
|
||||||
|
|
||||||
|
m := &MachO{
|
||||||
|
Header: Header{
|
||||||
|
Magic: 0xFEEDFACF,
|
||||||
|
Architecture: CPU_X86_64,
|
||||||
|
MicroArchitecture: 3 | 0x80000000,
|
||||||
|
Type: TypeExecute,
|
||||||
|
NumCommands: 4,
|
||||||
|
SizeCommands: SizeCommands,
|
||||||
|
Flags: FlagNoUndefs | FlagNoHeapExecution,
|
||||||
|
Reserved: 0,
|
||||||
|
},
|
||||||
|
PageZero: Segment64{
|
||||||
|
LoadCommand: LcSegment64,
|
||||||
|
Length: 72,
|
||||||
|
Name: [16]byte{'_', '_', 'P', 'A', 'G', 'E', 'Z', 'E', 'R', 'O'},
|
||||||
|
Address: 0,
|
||||||
|
SizeInMemory: config.BaseAddress,
|
||||||
|
Offset: 0,
|
||||||
|
SizeInFile: 0,
|
||||||
|
NumSections: 0,
|
||||||
|
Flag: 0,
|
||||||
|
MaxProt: 0,
|
||||||
|
InitProt: 0,
|
||||||
|
},
|
||||||
|
CodeHeader: Segment64{
|
||||||
|
LoadCommand: LcSegment64,
|
||||||
|
Length: Segment64Size,
|
||||||
|
Name: [16]byte{'_', '_', 'T', 'E', 'X', 'T'},
|
||||||
|
Address: config.BaseAddress,
|
||||||
|
SizeInMemory: uint64(codeEnd),
|
||||||
|
Offset: 0,
|
||||||
|
SizeInFile: uint64(codeEnd),
|
||||||
|
NumSections: 0,
|
||||||
|
Flag: 0,
|
||||||
|
MaxProt: ProtReadable | ProtExecutable,
|
||||||
|
InitProt: ProtReadable | ProtExecutable,
|
||||||
|
},
|
||||||
|
DataHeader: Segment64{
|
||||||
|
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)),
|
||||||
|
NumSections: 0,
|
||||||
|
Flag: 0,
|
||||||
|
MaxProt: ProtReadable,
|
||||||
|
InitProt: ProtReadable,
|
||||||
|
},
|
||||||
|
UnixThread: Thread{
|
||||||
|
LoadCommand: LcUnixthread,
|
||||||
|
Len: ThreadSize,
|
||||||
|
Type: 0x4,
|
||||||
|
Data: [43]uint32{
|
||||||
|
42,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
config.BaseAddress + config.CodeOffset, 0,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
binary.Write(writer, binary.LittleEndian, &m.Header)
|
||||||
|
binary.Write(writer, binary.LittleEndian, &m.PageZero)
|
||||||
|
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{0}, int(codePadding)))
|
||||||
|
writer.Write(code)
|
||||||
|
writer.Write(bytes.Repeat([]byte{0}, int(dataPadding)))
|
||||||
|
writer.Write(data)
|
||||||
|
}
|
16
src/exe/macho/macho.md
Normal file
16
src/exe/macho/macho.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# Mach-O
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
MacOS is the only operating system that requires loading the headers
|
||||||
|
explicitly with both readable and executable permissions.
|
||||||
|
|
||||||
|
## Loader
|
||||||
|
|
||||||
|
https://github.com/apple-oss-distributions/xnu/blob/main/EXTERNAL_HEADERS/mach-o/loader.h
|
||||||
|
|
||||||
|
## Links
|
||||||
|
|
||||||
|
- https://en.wikipedia.org/wiki/Mach-O
|
||||||
|
- https://github.com/aidansteele/osx-abi-macho-file-format-reference
|
||||||
|
- https://stackoverflow.com/questions/39863112/what-is-required-for-a-mach-o-executable-to-load
|
@ -6,7 +6,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
"git.akyoto.dev/cli/q/src/config"
|
"git.akyoto.dev/cli/q/src/config"
|
||||||
"git.akyoto.dev/cli/q/src/os/common"
|
"git.akyoto.dev/cli/q/src/exe"
|
||||||
)
|
)
|
||||||
|
|
||||||
const NumSections = 2
|
const NumSections = 2
|
||||||
@ -17,29 +17,28 @@ type EXE struct {
|
|||||||
NTHeader
|
NTHeader
|
||||||
OptionalHeader64
|
OptionalHeader64
|
||||||
Sections [NumSections]SectionHeader
|
Sections [NumSections]SectionHeader
|
||||||
CodePadding []byte
|
|
||||||
Code []byte
|
|
||||||
DataPadding []byte
|
|
||||||
Data []byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new EXE file.
|
// Write writes the EXE file to the given writer.
|
||||||
func New(code []byte, data []byte) *EXE {
|
func Write(writer io.Writer, code []byte, data []byte) {
|
||||||
codeStart := uint32(DOSHeaderSize + NTHeaderSize + OptionalHeader64Size + SectionHeaderSize*NumSections)
|
const (
|
||||||
codePadding := common.Padding(codeStart, config.Align)
|
HeaderEnd = DOSHeaderSize + NTHeaderSize + OptionalHeader64Size + SectionHeaderSize*NumSections
|
||||||
codeStart += codePadding
|
)
|
||||||
|
|
||||||
dataStart := codeStart + uint32(len(code))
|
var (
|
||||||
dataPadding := common.Padding(dataStart, config.Align)
|
codePadding = exe.Padding(HeaderEnd, config.Align)
|
||||||
dataStart += dataPadding
|
codeEnd = config.CodeOffset + len(code)
|
||||||
|
dataPadding = exe.Padding(codeEnd, config.Align)
|
||||||
|
dataStart = codeEnd + dataPadding
|
||||||
|
)
|
||||||
|
|
||||||
imageSize := uint32(dataStart + uint32(len(data)))
|
imageSize := dataStart + len(data)
|
||||||
imageSize += common.Padding(imageSize, config.Align)
|
imageSize += exe.Padding(imageSize, config.Align)
|
||||||
|
|
||||||
return &EXE{
|
pe := &EXE{
|
||||||
DOSHeader: DOSHeader{
|
DOSHeader: DOSHeader{
|
||||||
Magic: [4]byte{'M', 'Z', 0, 0},
|
Magic: [4]byte{'M', 'Z', 0, 0},
|
||||||
NTHeaderOffset: 0x40,
|
NTHeaderOffset: DOSHeaderSize,
|
||||||
},
|
},
|
||||||
NTHeader: NTHeader{
|
NTHeader: NTHeader{
|
||||||
Signature: [4]byte{'P', 'E', 0, 0},
|
Signature: [4]byte{'P', 'E', 0, 0},
|
||||||
@ -53,15 +52,15 @@ func New(code []byte, data []byte) *EXE {
|
|||||||
MajorLinkerVersion: 0x0E,
|
MajorLinkerVersion: 0x0E,
|
||||||
MinorLinkerVersion: 0x16,
|
MinorLinkerVersion: 0x16,
|
||||||
SizeOfCode: uint32(len(code)),
|
SizeOfCode: uint32(len(code)),
|
||||||
AddressOfEntryPoint: codeStart,
|
AddressOfEntryPoint: config.CodeOffset,
|
||||||
BaseOfCode: codeStart,
|
BaseOfCode: config.CodeOffset,
|
||||||
ImageBase: config.BaseAddress,
|
ImageBase: config.BaseAddress,
|
||||||
SectionAlignment: config.Align, // power of 2, must be greater than or equal to FileAlignment
|
SectionAlignment: config.Align, // power of 2, must be greater than or equal to FileAlignment
|
||||||
FileAlignment: config.Align, // power of 2
|
FileAlignment: config.Align, // power of 2
|
||||||
MajorOperatingSystemVersion: 0x06,
|
MajorOperatingSystemVersion: 0x06,
|
||||||
MajorSubsystemVersion: 0x06,
|
MajorSubsystemVersion: 0x06,
|
||||||
SizeOfImage: imageSize,
|
SizeOfImage: uint32(imageSize),
|
||||||
SizeOfHeaders: codeStart, // section bodies begin here
|
SizeOfHeaders: config.CodeOffset, // section bodies begin here
|
||||||
Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI,
|
Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI,
|
||||||
DllCharacteristics: IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE,
|
DllCharacteristics: IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE,
|
||||||
SizeOfStackReserve: 0x100000,
|
SizeOfStackReserve: 0x100000,
|
||||||
@ -92,35 +91,29 @@ func New(code []byte, data []byte) *EXE {
|
|||||||
{
|
{
|
||||||
Name: [8]byte{'.', 't', 'e', 'x', 't'},
|
Name: [8]byte{'.', 't', 'e', 'x', 't'},
|
||||||
VirtualSize: uint32(len(code)),
|
VirtualSize: uint32(len(code)),
|
||||||
VirtualAddress: codeStart,
|
VirtualAddress: config.CodeOffset,
|
||||||
RawSize: uint32(len(code)), // must be a multiple of FileAlignment
|
RawSize: uint32(len(code)), // must be a multiple of FileAlignment
|
||||||
RawAddress: codeStart, // 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,
|
Characteristics: IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: [8]byte{'.', 'r', 'd', 'a', 't', 'a'},
|
Name: [8]byte{'.', 'r', 'd', 'a', 't', 'a'},
|
||||||
VirtualSize: uint32(len(data)),
|
VirtualSize: uint32(len(data)),
|
||||||
VirtualAddress: dataStart,
|
VirtualAddress: uint32(dataStart),
|
||||||
RawSize: uint32(len(data)), // must be a multiple of FileAlignment
|
RawSize: uint32(len(data)), // must be a multiple of FileAlignment
|
||||||
RawAddress: dataStart, // 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,
|
Characteristics: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CodePadding: bytes.Repeat([]byte{0}, int(codePadding)),
|
|
||||||
Code: code,
|
|
||||||
DataPadding: bytes.Repeat([]byte{0}, int(dataPadding)),
|
|
||||||
Data: data,
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Write writes the EXE file to the given writer.
|
|
||||||
func (pe *EXE) Write(writer io.Writer) {
|
|
||||||
binary.Write(writer, binary.LittleEndian, &pe.DOSHeader)
|
binary.Write(writer, binary.LittleEndian, &pe.DOSHeader)
|
||||||
binary.Write(writer, binary.LittleEndian, &pe.NTHeader)
|
binary.Write(writer, binary.LittleEndian, &pe.NTHeader)
|
||||||
binary.Write(writer, binary.LittleEndian, &pe.OptionalHeader64)
|
binary.Write(writer, binary.LittleEndian, &pe.OptionalHeader64)
|
||||||
binary.Write(writer, binary.LittleEndian, &pe.Sections)
|
binary.Write(writer, binary.LittleEndian, &pe.Sections)
|
||||||
binary.Write(writer, binary.LittleEndian, &pe.CodePadding)
|
|
||||||
binary.Write(writer, binary.LittleEndian, &pe.Code)
|
writer.Write(bytes.Repeat([]byte{0}, int(codePadding)))
|
||||||
binary.Write(writer, binary.LittleEndian, &pe.DataPadding)
|
writer.Write(code)
|
||||||
binary.Write(writer, binary.LittleEndian, &pe.Data)
|
writer.Write(bytes.Repeat([]byte{0}, int(dataPadding)))
|
||||||
|
writer.Write(data)
|
||||||
}
|
}
|
11
src/exe/pe/pe.md
Normal file
11
src/exe/pe/pe.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
## Portable Executable
|
||||||
|
|
||||||
|
## Links
|
||||||
|
|
||||||
|
- https://learn.microsoft.com/en-us/previous-versions/ms809762(v=msdn.10)
|
||||||
|
- https://learn.microsoft.com/en-us/archive/msdn-magazine/2002/february/inside-windows-win32-portable-executable-file-format-in-detail
|
||||||
|
- https://learn.microsoft.com/en-us/archive/msdn-magazine/2002/march/inside-windows-an-in-depth-look-into-the-win32-portable-executable-file-format-part-2
|
||||||
|
- https://blog.kowalczyk.info/articles/pefileformat.html
|
||||||
|
- https://keyj.emphy.de/win32-pe/
|
||||||
|
- https://corkamiwiki.github.io/PE
|
||||||
|
- https://github.com/ayaka14732/TinyPE-on-Win10
|
@ -2,9 +2,6 @@ package linux
|
|||||||
|
|
||||||
// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/entry/syscalls/syscall_64.tbl
|
// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/entry/syscalls/syscall_64.tbl
|
||||||
const (
|
const (
|
||||||
Read = 0
|
|
||||||
Write = 1
|
Write = 1
|
||||||
Open = 2
|
|
||||||
Close = 3
|
|
||||||
Exit = 60
|
Exit = 60
|
||||||
)
|
)
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
package elf_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"git.akyoto.dev/cli/q/src/os/linux/elf"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestELF(t *testing.T) {
|
|
||||||
exe := elf.New(nil, nil)
|
|
||||||
exe.Write(io.Discard)
|
|
||||||
}
|
|
@ -1,122 +0,0 @@
|
|||||||
package macho
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"git.akyoto.dev/cli/q/src/config"
|
|
||||||
"git.akyoto.dev/cli/q/src/os/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MachO is the executable format used on MacOS.
|
|
||||||
type MachO struct {
|
|
||||||
Header
|
|
||||||
Code []byte
|
|
||||||
Data []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new Mach-O binary.
|
|
||||||
func New(code []byte, data []byte) *MachO {
|
|
||||||
return &MachO{
|
|
||||||
Header: Header{
|
|
||||||
Magic: 0xFEEDFACF,
|
|
||||||
Architecture: CPU_X86_64,
|
|
||||||
MicroArchitecture: 3 | 0x80000000,
|
|
||||||
Type: TypeExecute,
|
|
||||||
NumCommands: 4,
|
|
||||||
SizeCommands: Segment64Size*3 + ThreadSize,
|
|
||||||
Flags: FlagNoUndefs | FlagNoHeapExecution,
|
|
||||||
Reserved: 0,
|
|
||||||
},
|
|
||||||
Code: code,
|
|
||||||
Data: data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write writes the Mach-O format to the given writer.
|
|
||||||
func (m *MachO) Write(writer io.Writer) {
|
|
||||||
binary.Write(writer, binary.LittleEndian, &m.Header)
|
|
||||||
|
|
||||||
binary.Write(writer, binary.LittleEndian, &Segment64{
|
|
||||||
LoadCommand: LcSegment64,
|
|
||||||
Length: 72,
|
|
||||||
Name: [16]byte{'_', '_', 'P', 'A', 'G', 'E', 'Z', 'E', 'R', 'O'},
|
|
||||||
Address: 0,
|
|
||||||
SizeInMemory: config.BaseAddress,
|
|
||||||
Offset: 0,
|
|
||||||
SizeInFile: 0,
|
|
||||||
NumSections: 0,
|
|
||||||
Flag: 0,
|
|
||||||
MaxProt: 0,
|
|
||||||
InitProt: 0,
|
|
||||||
})
|
|
||||||
|
|
||||||
codePadding := common.Padding(HeaderSize+m.Header.SizeCommands, config.Align)
|
|
||||||
codeEnd := uint64(config.CodeOffset + len(m.Code))
|
|
||||||
dataPadding := common.Padding(codeEnd, config.Align)
|
|
||||||
dataStart := codeEnd + dataPadding
|
|
||||||
|
|
||||||
binary.Write(writer, binary.LittleEndian, &Segment64{
|
|
||||||
LoadCommand: LcSegment64,
|
|
||||||
Length: 72,
|
|
||||||
Name: [16]byte{'_', '_', 'T', 'E', 'X', 'T'},
|
|
||||||
Address: config.BaseAddress,
|
|
||||||
SizeInMemory: config.CodeOffset + uint64(len(m.Code)),
|
|
||||||
Offset: 0,
|
|
||||||
SizeInFile: config.CodeOffset + uint64(len(m.Code)),
|
|
||||||
NumSections: 0,
|
|
||||||
Flag: 0,
|
|
||||||
MaxProt: ProtReadable | ProtExecutable,
|
|
||||||
InitProt: ProtReadable | ProtExecutable,
|
|
||||||
})
|
|
||||||
|
|
||||||
binary.Write(writer, binary.LittleEndian, &Segment64{
|
|
||||||
LoadCommand: LcSegment64,
|
|
||||||
Length: 72,
|
|
||||||
Name: [16]byte{'_', '_', 'D', 'A', 'T', 'A'},
|
|
||||||
Address: config.BaseAddress + dataStart,
|
|
||||||
SizeInMemory: uint64(len(m.Data)),
|
|
||||||
Offset: dataStart,
|
|
||||||
SizeInFile: uint64(len(m.Data)),
|
|
||||||
NumSections: 0,
|
|
||||||
Flag: 0,
|
|
||||||
MaxProt: ProtReadable,
|
|
||||||
InitProt: ProtReadable,
|
|
||||||
})
|
|
||||||
|
|
||||||
binary.Write(writer, binary.LittleEndian, &Thread{
|
|
||||||
LoadCommand: LcUnixthread,
|
|
||||||
Len: 184,
|
|
||||||
Type: 0x4,
|
|
||||||
Data: [43]uint32{
|
|
||||||
42,
|
|
||||||
0, 0,
|
|
||||||
0, 0,
|
|
||||||
0, 0,
|
|
||||||
0, 0,
|
|
||||||
0, 0,
|
|
||||||
0, 0,
|
|
||||||
0, 0,
|
|
||||||
0, 0,
|
|
||||||
0, 0,
|
|
||||||
0, 0,
|
|
||||||
0, 0,
|
|
||||||
0, 0,
|
|
||||||
0, 0,
|
|
||||||
0, 0,
|
|
||||||
0, 0,
|
|
||||||
0, 0,
|
|
||||||
config.BaseAddress + config.CodeOffset, 0,
|
|
||||||
0, 0,
|
|
||||||
0, 0,
|
|
||||||
0, 0,
|
|
||||||
0, 0,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
writer.Write(bytes.Repeat([]byte{0}, int(codePadding)))
|
|
||||||
writer.Write(m.Code)
|
|
||||||
writer.Write(bytes.Repeat([]byte{0}, int(dataPadding)))
|
|
||||||
writer.Write(m.Data)
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user