This commit is contained in:
parent
8b5cca921b
commit
e3444b3626
8 changed files with 119 additions and 41 deletions
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
MacOS requires including the headers in the __TEXT segment.
|
- Headers must be included in the __TEXT segment.
|
||||||
|
- Load command size must be divisible by 8.
|
||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,6 @@ package macho
|
||||||
|
|
||||||
const (
|
const (
|
||||||
BaseAddress = 0x1000000
|
BaseAddress = 0x1000000
|
||||||
SizeCommands = Segment64Size*3 + ThreadSize
|
SizeCommands = Segment64Size*4 + DyldInfoCommandSize + MainSize + DylinkerCommandSize + len(LinkerString) + DylibCommandSize + len(LibSystemString)
|
||||||
HeaderEnd = HeaderSize + SizeCommands
|
HeaderEnd = HeaderSize + SizeCommands
|
||||||
)
|
)
|
19
src/macho/DyldInfoCommand.go
Normal file
19
src/macho/DyldInfoCommand.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
package macho
|
||||||
|
|
||||||
|
const DyldInfoCommandSize = 48
|
||||||
|
|
||||||
|
// DyldInfoCommand contains the file offsets and sizes that dyld needs to load the image.
|
||||||
|
type DyldInfoCommand struct {
|
||||||
|
LoadCommand
|
||||||
|
Length uint32
|
||||||
|
RebaseOffset uint32
|
||||||
|
RebaseSize uint32
|
||||||
|
BindOffset uint32
|
||||||
|
BindSize uint32
|
||||||
|
WeakBindOffset uint32
|
||||||
|
WeakBindSize uint32
|
||||||
|
LazyBindOffset uint32
|
||||||
|
LazyBindSize uint32
|
||||||
|
ExportOffset uint32
|
||||||
|
ExportSize uint32
|
||||||
|
}
|
16
src/macho/DylibCommand.go
Normal file
16
src/macho/DylibCommand.go
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package macho
|
||||||
|
|
||||||
|
const (
|
||||||
|
DylibCommandSize = 24
|
||||||
|
LibSystemString = "/usr/lib/libSystem.B.dylib\000\000\000\000\000\000"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DylibCommand is added for each shared library.
|
||||||
|
type DylibCommand struct {
|
||||||
|
LoadCommand
|
||||||
|
Length uint32
|
||||||
|
Name uint32
|
||||||
|
TimeStamp uint32
|
||||||
|
CurrentVersion uint32
|
||||||
|
CompatibilityVersion uint32
|
||||||
|
}
|
13
src/macho/DylinkerCommand.go
Normal file
13
src/macho/DylinkerCommand.go
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package macho
|
||||||
|
|
||||||
|
const (
|
||||||
|
DylinkerCommandSize = 12
|
||||||
|
LinkerString = "/usr/lib/dyld\000\000\000\000\000\000\000"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DylinkerCommand is needed if the program uses a dynamic linker.
|
||||||
|
type DylinkerCommand struct {
|
||||||
|
LoadCommand
|
||||||
|
Length uint32
|
||||||
|
Name uint32
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ const (
|
||||||
LcThread LoadCommand = 0x4
|
LcThread LoadCommand = 0x4
|
||||||
LcUnixthread LoadCommand = 0x5
|
LcUnixthread LoadCommand = 0x5
|
||||||
LcDysymtab LoadCommand = 0xB
|
LcDysymtab LoadCommand = 0xB
|
||||||
LcDylib LoadCommand = 0xC
|
LcLoadDylib LoadCommand = 0xC
|
||||||
LcIdDylib LoadCommand = 0xD
|
LcIdDylib LoadCommand = 0xD
|
||||||
LcLoadDylinker LoadCommand = 0xE
|
LcLoadDylinker LoadCommand = 0xE
|
||||||
LcIdDylinker LoadCommand = 0xF
|
LcIdDylinker LoadCommand = 0xF
|
||||||
|
|
|
@ -11,19 +11,23 @@ import (
|
||||||
// MachO is the executable format used on MacOS.
|
// MachO is the executable format used on MacOS.
|
||||||
type MachO struct {
|
type MachO struct {
|
||||||
Header
|
Header
|
||||||
PageZero Segment64
|
PageZero Segment64
|
||||||
CodeHeader Segment64
|
CodeHeader Segment64
|
||||||
DataHeader Segment64
|
DataHeader Segment64
|
||||||
UnixThread Thread
|
ImportsHeader Segment64
|
||||||
|
MainHeader Main
|
||||||
|
InfoHeader DyldInfoCommand
|
||||||
|
LinkerHeader DylinkerCommand
|
||||||
|
LibSystemHeader DylibCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write writes the Mach-O format to the given writer.
|
// Write writes the Mach-O format to the given writer.
|
||||||
func Write(writer io.WriteSeeker, b *build.Build, codeBytes []byte, dataBytes []byte) {
|
func Write(writer io.WriteSeeker, b *build.Build, codeBytes []byte, dataBytes []byte) {
|
||||||
x := exe.New(HeaderEnd, b.FileAlign(), b.MemoryAlign(), b.Congruent(), codeBytes, dataBytes)
|
x := exe.New(HeaderEnd, b.FileAlign(), b.MemoryAlign(), b.Congruent(), codeBytes, dataBytes, nil)
|
||||||
code := x.Sections[0]
|
code := x.Sections[0]
|
||||||
data := x.Sections[1]
|
data := x.Sections[1]
|
||||||
|
imports := x.Sections[2]
|
||||||
arch, microArch := Arch(b.Arch)
|
arch, microArch := Arch(b.Arch)
|
||||||
entryPoint := BaseAddress + code.MemoryOffset
|
|
||||||
|
|
||||||
m := &MachO{
|
m := &MachO{
|
||||||
Header: Header{
|
Header: Header{
|
||||||
|
@ -31,8 +35,8 @@ func Write(writer io.WriteSeeker, b *build.Build, codeBytes []byte, dataBytes []
|
||||||
Architecture: arch,
|
Architecture: arch,
|
||||||
MicroArchitecture: microArch,
|
MicroArchitecture: microArch,
|
||||||
Type: TypeExecute,
|
Type: TypeExecute,
|
||||||
NumCommands: 4,
|
NumCommands: 8,
|
||||||
SizeCommands: SizeCommands,
|
SizeCommands: uint32(SizeCommands),
|
||||||
Flags: FlagNoUndefs | FlagPIE | FlagNoHeapExecution,
|
Flags: FlagNoUndefs | FlagPIE | FlagNoHeapExecution,
|
||||||
Reserved: 0,
|
Reserved: 0,
|
||||||
},
|
},
|
||||||
|
@ -65,7 +69,7 @@ func Write(writer io.WriteSeeker, b *build.Build, codeBytes []byte, dataBytes []
|
||||||
DataHeader: Segment64{
|
DataHeader: Segment64{
|
||||||
LoadCommand: LcSegment64,
|
LoadCommand: LcSegment64,
|
||||||
Length: Segment64Size,
|
Length: Segment64Size,
|
||||||
Name: [16]byte{'_', '_', 'D', 'A', 'T', 'A'},
|
Name: [16]byte{'_', '_', 'D', 'A', 'T', 'A', '_', 'C', 'O', 'N', 'S', 'T'},
|
||||||
Address: uint64(BaseAddress + data.MemoryOffset),
|
Address: uint64(BaseAddress + data.MemoryOffset),
|
||||||
SizeInMemory: uint64(len(data.Bytes)),
|
SizeInMemory: uint64(len(data.Bytes)),
|
||||||
Offset: uint64(data.FileOffset),
|
Offset: uint64(data.FileOffset),
|
||||||
|
@ -75,34 +79,40 @@ func Write(writer io.WriteSeeker, b *build.Build, codeBytes []byte, dataBytes []
|
||||||
MaxProt: ProtReadable,
|
MaxProt: ProtReadable,
|
||||||
InitProt: ProtReadable,
|
InitProt: ProtReadable,
|
||||||
},
|
},
|
||||||
UnixThread: Thread{
|
ImportsHeader: Segment64{
|
||||||
LoadCommand: LcUnixthread,
|
LoadCommand: LcSegment64,
|
||||||
Len: ThreadSize,
|
Length: Segment64Size,
|
||||||
Type: 0x4,
|
Name: [16]byte{'_', '_', 'L', 'I', 'N', 'K', 'E', 'D', 'I', 'T'},
|
||||||
Data: [43]uint32{
|
Address: uint64(BaseAddress + imports.MemoryOffset),
|
||||||
42,
|
SizeInMemory: uint64(len(imports.Bytes)),
|
||||||
0, 0,
|
Offset: uint64(imports.FileOffset),
|
||||||
0, 0,
|
SizeInFile: uint64(len(imports.Bytes)),
|
||||||
0, 0,
|
NumSections: 0,
|
||||||
0, 0,
|
Flag: 0,
|
||||||
0, 0,
|
MaxProt: ProtReadable,
|
||||||
0, 0,
|
InitProt: ProtReadable,
|
||||||
0, 0,
|
},
|
||||||
0, 0,
|
MainHeader: Main{
|
||||||
0, 0,
|
LoadCommand: LcMain,
|
||||||
0, 0,
|
Length: MainSize,
|
||||||
0, 0,
|
EntryFileOffset: uint64(code.MemoryOffset),
|
||||||
0, 0,
|
StackSize: 0,
|
||||||
0, 0,
|
},
|
||||||
0, 0,
|
InfoHeader: DyldInfoCommand{
|
||||||
0, 0,
|
LoadCommand: LcDyldInfoOnly,
|
||||||
0, 0,
|
Length: DyldInfoCommandSize,
|
||||||
uint32(entryPoint), 0,
|
RebaseOffset: uint32(imports.FileOffset),
|
||||||
0, 0,
|
RebaseSize: uint32(len(imports.Bytes)),
|
||||||
0, 0,
|
},
|
||||||
0, 0,
|
LinkerHeader: DylinkerCommand{
|
||||||
0, 0,
|
LoadCommand: LcLoadDylinker,
|
||||||
},
|
Length: uint32(DylinkerCommandSize + len(LinkerString)),
|
||||||
|
Name: DylinkerCommandSize,
|
||||||
|
},
|
||||||
|
LibSystemHeader: DylibCommand{
|
||||||
|
LoadCommand: LcLoadDylib,
|
||||||
|
Length: uint32(DylibCommandSize + len(LibSystemString)),
|
||||||
|
Name: DylibCommandSize,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,9 +120,17 @@ func Write(writer io.WriteSeeker, b *build.Build, codeBytes []byte, dataBytes []
|
||||||
binary.Write(writer, binary.LittleEndian, &m.PageZero)
|
binary.Write(writer, binary.LittleEndian, &m.PageZero)
|
||||||
binary.Write(writer, binary.LittleEndian, &m.CodeHeader)
|
binary.Write(writer, binary.LittleEndian, &m.CodeHeader)
|
||||||
binary.Write(writer, binary.LittleEndian, &m.DataHeader)
|
binary.Write(writer, binary.LittleEndian, &m.DataHeader)
|
||||||
binary.Write(writer, binary.LittleEndian, &m.UnixThread)
|
binary.Write(writer, binary.LittleEndian, &m.ImportsHeader)
|
||||||
|
binary.Write(writer, binary.LittleEndian, &m.MainHeader)
|
||||||
|
binary.Write(writer, binary.LittleEndian, &m.InfoHeader)
|
||||||
|
binary.Write(writer, binary.LittleEndian, &m.LinkerHeader)
|
||||||
|
writer.Write([]byte(LinkerString))
|
||||||
|
binary.Write(writer, binary.LittleEndian, &m.LibSystemHeader)
|
||||||
|
writer.Write([]byte(LibSystemString))
|
||||||
writer.Seek(int64(code.Padding), io.SeekCurrent)
|
writer.Seek(int64(code.Padding), io.SeekCurrent)
|
||||||
writer.Write(code.Bytes)
|
writer.Write(code.Bytes)
|
||||||
writer.Seek(int64(data.Padding), io.SeekCurrent)
|
writer.Seek(int64(data.Padding), io.SeekCurrent)
|
||||||
writer.Write(data.Bytes)
|
writer.Write(data.Bytes)
|
||||||
|
writer.Seek(int64(imports.Padding), io.SeekCurrent)
|
||||||
|
writer.Write(imports.Bytes)
|
||||||
}
|
}
|
11
src/macho/Main.go
Normal file
11
src/macho/Main.go
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package macho
|
||||||
|
|
||||||
|
const MainSize = 24
|
||||||
|
|
||||||
|
// Main is the structure of the LC_MAIN load command.
|
||||||
|
type Main struct {
|
||||||
|
LoadCommand
|
||||||
|
Length uint32
|
||||||
|
EntryFileOffset uint64
|
||||||
|
StackSize uint64
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue