This commit is contained in:
parent
8b5cca921b
commit
e3444b3626
8 changed files with 119 additions and 41 deletions
|
@ -2,7 +2,8 @@
|
|||
|
||||
## 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
|
||||
|
||||
|
|
|
@ -2,6 +2,6 @@ package macho
|
|||
|
||||
const (
|
||||
BaseAddress = 0x1000000
|
||||
SizeCommands = Segment64Size*3 + ThreadSize
|
||||
SizeCommands = Segment64Size*4 + DyldInfoCommandSize + MainSize + DylinkerCommandSize + len(LinkerString) + DylibCommandSize + len(LibSystemString)
|
||||
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
|
||||
LcUnixthread LoadCommand = 0x5
|
||||
LcDysymtab LoadCommand = 0xB
|
||||
LcDylib LoadCommand = 0xC
|
||||
LcLoadDylib LoadCommand = 0xC
|
||||
LcIdDylib LoadCommand = 0xD
|
||||
LcLoadDylinker LoadCommand = 0xE
|
||||
LcIdDylinker LoadCommand = 0xF
|
||||
|
|
|
@ -11,19 +11,23 @@ import (
|
|||
// MachO is the executable format used on MacOS.
|
||||
type MachO struct {
|
||||
Header
|
||||
PageZero Segment64
|
||||
CodeHeader Segment64
|
||||
DataHeader Segment64
|
||||
UnixThread Thread
|
||||
PageZero Segment64
|
||||
CodeHeader Segment64
|
||||
DataHeader Segment64
|
||||
ImportsHeader Segment64
|
||||
MainHeader Main
|
||||
InfoHeader DyldInfoCommand
|
||||
LinkerHeader DylinkerCommand
|
||||
LibSystemHeader DylibCommand
|
||||
}
|
||||
|
||||
// Write writes the Mach-O format to the given writer.
|
||||
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]
|
||||
data := x.Sections[1]
|
||||
imports := x.Sections[2]
|
||||
arch, microArch := Arch(b.Arch)
|
||||
entryPoint := BaseAddress + code.MemoryOffset
|
||||
|
||||
m := &MachO{
|
||||
Header: Header{
|
||||
|
@ -31,8 +35,8 @@ func Write(writer io.WriteSeeker, b *build.Build, codeBytes []byte, dataBytes []
|
|||
Architecture: arch,
|
||||
MicroArchitecture: microArch,
|
||||
Type: TypeExecute,
|
||||
NumCommands: 4,
|
||||
SizeCommands: SizeCommands,
|
||||
NumCommands: 8,
|
||||
SizeCommands: uint32(SizeCommands),
|
||||
Flags: FlagNoUndefs | FlagPIE | FlagNoHeapExecution,
|
||||
Reserved: 0,
|
||||
},
|
||||
|
@ -65,7 +69,7 @@ func Write(writer io.WriteSeeker, b *build.Build, codeBytes []byte, dataBytes []
|
|||
DataHeader: Segment64{
|
||||
LoadCommand: LcSegment64,
|
||||
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),
|
||||
SizeInMemory: uint64(len(data.Bytes)),
|
||||
Offset: uint64(data.FileOffset),
|
||||
|
@ -75,34 +79,40 @@ func Write(writer io.WriteSeeker, b *build.Build, codeBytes []byte, dataBytes []
|
|||
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(entryPoint), 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
},
|
||||
ImportsHeader: Segment64{
|
||||
LoadCommand: LcSegment64,
|
||||
Length: Segment64Size,
|
||||
Name: [16]byte{'_', '_', 'L', 'I', 'N', 'K', 'E', 'D', 'I', 'T'},
|
||||
Address: uint64(BaseAddress + imports.MemoryOffset),
|
||||
SizeInMemory: uint64(len(imports.Bytes)),
|
||||
Offset: uint64(imports.FileOffset),
|
||||
SizeInFile: uint64(len(imports.Bytes)),
|
||||
NumSections: 0,
|
||||
Flag: 0,
|
||||
MaxProt: ProtReadable,
|
||||
InitProt: ProtReadable,
|
||||
},
|
||||
MainHeader: Main{
|
||||
LoadCommand: LcMain,
|
||||
Length: MainSize,
|
||||
EntryFileOffset: uint64(code.MemoryOffset),
|
||||
StackSize: 0,
|
||||
},
|
||||
InfoHeader: DyldInfoCommand{
|
||||
LoadCommand: LcDyldInfoOnly,
|
||||
Length: DyldInfoCommandSize,
|
||||
RebaseOffset: uint32(imports.FileOffset),
|
||||
RebaseSize: uint32(len(imports.Bytes)),
|
||||
},
|
||||
LinkerHeader: DylinkerCommand{
|
||||
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.CodeHeader)
|
||||
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.Write(code.Bytes)
|
||||
writer.Seek(int64(data.Padding), io.SeekCurrent)
|
||||
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