123 lines
2.9 KiB
Go
123 lines
2.9 KiB
Go
package macho
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"io"
|
|
|
|
"git.urbach.dev/cli/q/src/config"
|
|
"git.urbach.dev/cli/q/src/fs"
|
|
)
|
|
|
|
const (
|
|
SizeCommands = Segment64Size*3 + ThreadSize
|
|
HeaderEnd = HeaderSize + SizeCommands
|
|
)
|
|
|
|
// 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) {
|
|
var (
|
|
codeStart, codePadding = fs.Align(HeaderEnd, config.Align)
|
|
dataStart, dataPadding = fs.Align(codeStart+len(code), config.Align)
|
|
)
|
|
|
|
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(codeStart + len(code)),
|
|
Offset: 0,
|
|
SizeInFile: uint64(codeStart + len(code)),
|
|
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,
|
|
uint32(config.BaseAddress + codeStart), 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{0x00}, codePadding))
|
|
writer.Write(code)
|
|
writer.Write(bytes.Repeat([]byte{0x00}, dataPadding))
|
|
writer.Write(data)
|
|
}
|