macho

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 15, 2025 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package macho provides a parser for untrusted Mach object (Mach-O) files.

See https://en.wikipedia.org/wiki/Mach-O and https://github.com/apple/darwin-xnu/blob/main/EXTERNAL_HEADERS/mach-o/loader.h for documentation on the format.

Index

Constants

View Source
const CodeSignatureBlobMinSize = 8

CodeSignatureBlobMinSize is the minimum size in bytes of a serialized CodeSignatureBlob.

View Source
const LoadCommandMinSize = 8

LoadCommandMinSize is the minimum size (in bytes) of a Mach-O load command.

View Source
const MagicNumberSize = 4

MagicNumberSize is the size (in bytes) of the magic number at the start of the Mach-O file.

Variables

This section is empty.

Functions

func IsSingleArchitecture

func IsSingleArchitecture(head []byte) bool

IsSingleArchitecture reports whether head starts with the Mach-O magic number for a single-architecture Mach-O file. IsSingleArchitecture will always report false if len(head) < MagicNumberSize.

func IsUniversal

func IsUniversal(head []byte) bool

IsUniversal reports whether head starts with the Mach-O magic number for a multi-architecture Mach-O file. IsUniversal will always report false if len(head) < MagicNumberSize.

Types

type Alignment

type Alignment uint32

Alignment is an alignment value. Its raw value is the exponent of two.

func (Alignment) Bytes

func (align Alignment) Bytes() (_ uint64, ok bool)

Bytes returns the number of bytes that align represents.

func (Alignment) String

func (align Alignment) String() string

String returns a string in the format "2^X", where X is the decimal representation of align.

type CPUType

type CPUType uint32

CPUType is an enumeration of instruction set architectures.

const (
	CPUTypeVAX       CPUType = 0x00000001 // CPU_TYPE_VAX
	CPUTypeMC680x0   CPUType = 0x00000006 // CPU_TYPE_MC680x0
	CPUTypeI386      CPUType = 0x00000007 // CPU_TYPE_X86
	CPUTypeX86_64    CPUType = 0x01000007 // CPU_TYPE_X86_64
	CPUTypeMC98000   CPUType = 0x0000000a // CPU_TYPE_MC98000
	CPUTypeHPPA      CPUType = 0x0000000b // CPU_TYPE_HPPA
	CPUTypeARM       CPUType = 0x0000000c // CPU_TYPE_ARM
	CPUTypeARM64     CPUType = 0x0100000c // CPU_TYPE_ARM64
	CPUTypeARM64_32  CPUType = 0x0200000c // CPU_TYPE_ARM64_32
	CPUTypeMC88000   CPUType = 0x0000000d // CPU_TYPE_MC88000
	CPUTypeSPARC     CPUType = 0x0000000e // CPU_TYPE_SPARC
	CPUTypeI860      CPUType = 0x0000000f // CPU_TYPE_I860
	CPUTypePowerPC   CPUType = 0x00000012 // CPU_TYPE_POWERPC
	CPUTypePowerPC64 CPUType = 0x01000012 // CPU_TYPE_POWERPC64
)

CPUType values defined by Mach-O file format.

func (CPUType) Is64Bit

func (ct CPUType) Is64Bit() bool

Is64Bit reports whether the CPU type has a 64-bit address width.

func (CPUType) String

func (i CPUType) String() string

type CodeDirectory

type CodeDirectory struct {
	Flags            CodeSignatureFlags
	HashData         []byte
	Identifier       string
	SpecialSlotCount uint32
	CodeLimit        uint64
	HashType         HashType
	Platform         uint8
	PageSize         Alignment
	TeamIdentifier   string

	ExecutableSegmentBase  uint64
	ExecutableSegmentLimit uint64
	ExecutableSegmentFlags uint64
}

CodeDirectory represents a parsed CodeSignatureBlob for the CodeSignatureMagicCodeDirectory magic number.

func (*CodeDirectory) HashSlotCount

func (cd *CodeDirectory) HashSlotCount() int

HashSlotCount returns the number of hash slots present in cd.HashData based on cd.HashType.

func (*CodeDirectory) HashSlots

func (cd *CodeDirectory) HashSlots() iter.Seq2[int, []byte]

HashSlots returns an iterator over the hash slots (including the special ones).

func (*CodeDirectory) UnmarshalBinary

func (cd *CodeDirectory) UnmarshalBinary(data []byte) error

UnmarshalBinary parses a Mach-O code signature blob as a CodeDirectory.

type CodeSignatureBlob

type CodeSignatureBlob struct {
	Magic CodeSignatureMagic
	Data  []byte
}

A CodeSignatureBlob represents a single record in a Mach-O code signature.

func (CodeSignatureBlob) AppendBinary

func (blob CodeSignatureBlob) AppendBinary(dst []byte) ([]byte, error)

AppendBinary marshals blob as a Mach-O code signature blob and appends the result to dst.

func (CodeSignatureBlob) MarshalBinary

func (blob CodeSignatureBlob) MarshalBinary() ([]byte, error)

MarshalBinary marshals blob as a Mach-O code signature blob.

func (*CodeSignatureBlob) UnmarshalBinary

func (blob *CodeSignatureBlob) UnmarshalBinary(data []byte) error

UnmarshalBinary unmarshals the Mach-O code signature blob into blob.

type CodeSignatureFlags

type CodeSignatureFlags uint32

CodeSignatureFlags is a bitset of flags used in CodeDirectory.

const (
	// CodeSignatureAdHoc indicates that the bundle is ad hoc signed.
	CodeSignatureAdHoc CodeSignatureFlags = 0x00000002 // CS_ADHOC
	// CodeSignatureHard requests to not load invalid pages.
	CodeSignatureHard CodeSignatureFlags = 0x00000100 // CS_HARD
	// CodeSignatureKill requests to kill the process if it becomes invalid.
	CodeSignatureKill CodeSignatureFlags = 0x00000200 // CS_KILL
	// CodeSignatureCheckExpiration forces expiration checking.
	CodeSignatureCheckExpiration CodeSignatureFlags = 0x00000400 // CS_CHECK_EXPIRATION
	// CodeSignatureRestrict tells dyld to treat the bundle as restricted.
	CodeSignatureRestrict CodeSignatureFlags = 0x00000800 // CS_RESTRICT
	// CodeSignatureEnforcement indicates that the bundle requires enforcement.
	CodeSignatureEnforcement CodeSignatureFlags = 0x00001000 // CS_ENFORCEMENT
	// CodeSignatureRequireLV indicates that the bundle requires library validation
	CodeSignatureRequireLV CodeSignatureFlags = 0x00002000 // CS_REQUIRE_LV
	// CodeSignatureRuntime requests to apply hardened runtime policies.
	CodeSignatureRuntime CodeSignatureFlags = 0x00010000 // CS_RUNTIME
	// CodeSignatureLinkerSigned indicates the bundle was automatically signed by the linker.
	CodeSignatureLinkerSigned CodeSignatureFlags = 0x00020000 // CS_LINKER_SIGNED
)

CodeSignatureFlags permitted to be used in the Mach-O format.

type CodeSignatureMagic

type CodeSignatureMagic uint32

CodeSignatureMagic is an enumeration of types of CodeSignatureBlob.

const (
	CodeSignatureMagicRequirement          CodeSignatureMagic = 0xfade0c00
	CodeSignatureMagicRequirements         CodeSignatureMagic = 0xfade0c01
	CodeSignatureMagicCodeDirectory        CodeSignatureMagic = 0xfade0c02
	CodeSignatureMagicEmbeddedSignature    CodeSignatureMagic = 0xfade0cc0
	CodeSignatureMagicEmbeddedEntitlements CodeSignatureMagic = 0xfade7171
	CodeSignatureMagicDetachedSignature    CodeSignatureMagic = 0xfade0cc1
	CodeSignatureMagicBlobWrapper          CodeSignatureMagic = 0xfade0b01
)

Known CodeSignatureMagic values.

func (CodeSignatureMagic) String

func (i CodeSignatureMagic) String() string

type CommandReader

type CommandReader struct {
	// contains filtered or unexported fields
}

A CommandReader reads Mach-O load commands from a stream. CommandReaders do not buffer their reads and will not read past the load command region defined by the FileHeader.

func (*CommandReader) Command

func (r *CommandReader) Command() (_ LoadCmd, ok bool)

Command returns the type of the current command if it has been read. ok will be true if and only if at least 4 bytes of the current command have been read.

func (*CommandReader) Err

func (r *CommandReader) Err() error

Err returns the first non-io.EOF error encountered by r.

func (*CommandReader) Next

func (r *CommandReader) Next() bool

Next advances r to the next load command, which will then be available through *CommandReader.Read. It returns false when there are no more load commands, either by reaching the end of the input or an error. If the previous load command was not fully read, Next will discard the unread bytes. After Next returns false, the *CommandReader.Err method will return any error that occurred during scanning, except that if it was io.EOF, *CommandReader.Err will return nil.

func (*CommandReader) Read

func (r *CommandReader) Read(p []byte) (n int, err error)

Read reads up to the next len(p) bytes of the current load command into p. It returns the number of bytes read (0 <= n <= len(p)) and any error encountered. The first LoadCommandMinSize bytes of a load command are always the its type and size. After reading the first LoadCommandMinSize bytes, use *CommandReader.Command and *CommandReader.Size to parse these values.

Read does not introduce any buffering: each call to Read corresponds to at most one call to r's underlying io.Reader.

func (*CommandReader) Size

func (r *CommandReader) Size() (_ uint32, ok bool)

Size returns the total size of the current command in bytes. ok is false if the first LoadCommandMinSize bytes of the command haven't been read yet or the size is invalid. Size will never return a value less than LoadCommandMinSize.

type FileHeader

type FileHeader struct {
	ByteOrder    binary.ByteOrder
	AddressWidth int
	CPUType      CPUType
	CPUSubtype   uint32
	Type         Type

	LoadCommandCount      uint32
	LoadCommandRegionSize uint32
}

FileHeader represents a Mach-O single-architecture file header.

func ReadFileHeader

func ReadFileHeader(r io.Reader) (*FileHeader, error)

ReadFileHeader reads the header of a Mach-O single architecture file. After a successful call to ReadFileHeader, calling *FileHeader.NewCommandReader on the reader allows iteration over the load commands in the file.

func (*FileHeader) DataOffset

func (hdr *FileHeader) DataOffset() int64

DataOffset returns the offset in bytes from the beginning of the Mach-O file where the data region begins.

func (*FileHeader) LoadCommandsOffset

func (hdr *FileHeader) LoadCommandsOffset() int64

LoadCommandsOffset returns the offset in bytes from the beginning of the Mach-O file where the load commands region begins.

func (*FileHeader) NewCommandReader

func (hdr *FileHeader) NewCommandReader(r io.Reader) *CommandReader

NewCommandReader returns a CommandReader that reads from r. r should read from the part of the Mach-O file directly after the header, as in the state of a reader after calling ReadFileHeader.

type HashType

type HashType uint8

HashType is an enumeration of cryptographic hash algorithms used in CodeDirectory.

const (
	HashTypeSHA1            HashType = 1 // CS_HASHTYPE_SHA1
	HashTypeSHA256          HashType = 2 // CS_HASHTYPE_SHA256
	HashTypeSHA256Truncated HashType = 3 // CS_HASHTYPE_SHA256_TRUNCATED
	HashTypeSHA384          HashType = 4 // CS_HASHTYPE_SHA384
)

Known HashType values.

func (HashType) Size

func (ht HashType) Size() (_ int, ok bool)

Size returns the number of bytes the hash type is expected to produce.

func (HashType) String

func (i HashType) String() string

type LinkeditDataCommand

type LinkeditDataCommand struct {
	Command LoadCmd
	// DataOffset is the offset in bytes of the data's start
	// relative to the start of the __LINKEDIT segment.
	DataOffset uint32
	// DataSize is the size in bytes of data in the __LINKEDIT segment.
	DataSize uint32
}

LinkeditDataCommand is the structure for LoadCmdCodeSignature, LoadCmdFunctionStarts, and LoadCmdDataInCode.

func (*LinkeditDataCommand) UnmarshalMachO

func (cmd *LinkeditDataCommand) UnmarshalMachO(byteOrder binary.ByteOrder, data []byte) error

UnmarshalMachO unmarshals the load command in data into cmd.

type LoadCmd

type LoadCmd uint32

LoadCmd is an enumeration of load command types.

const (
	LoadCmdSegment        LoadCmd = 0x1        // LC_SEGMENT
	LoadCmdSymtab         LoadCmd = 0x2        // LC_SYMTAB
	LoadCmdThread         LoadCmd = 0x4        // LC_THREAD
	LoadCmdUnixThread     LoadCmd = 0x5        // LC_UNIXTHREAD
	LoadCmdDysymtab       LoadCmd = 0xb        // LC_DYSYMTAB
	LoadCmdLoadDylib      LoadCmd = 0xc        // LC_LOAD_DYLIB
	LoadCmdLoadDylinker   LoadCmd = 0xe        // LC_LOAD_DYLINKER
	LoadCmdIDDylinker     LoadCmd = 0xf        // LC_ID_DYLINKER
	LoadCmdSegment64      LoadCmd = 0x19       // LC_SEGMENT_64
	LoadCmdUUID           LoadCmd = 0x1b       // LC_UUID
	LoadCmdRPath          LoadCmd = 0x8000001c // LC_RPATH
	LoadCmdCodeSignature  LoadCmd = 0x1d       // LC_CODE_SIGNATURE
	LoadCmdSourceVersion  LoadCmd = 0x2a       // LC_SOURCE_VERSION
	LoadCmdDyldInfo       LoadCmd = 0x22       // LC_DYLD_INFO
	LoadCmdDyldInfoOnly   LoadCmd = 0x80000022 // LC_DYLD_INFO_ONLY
	LoadCmdFunctionStarts LoadCmd = 0x26       // LC_FUNCTION_STARTS
	LoadCmdDataInCode     LoadCmd = 0x29       // LC_DATA_IN_CODE
	LoadCmdMain           LoadCmd = 0x80000028 // LC_MAIN
	LoadCmdBuildVersion   LoadCmd = 0x32       // LC_BUILD_VERSION
)

func (LoadCmd) String

func (i LoadCmd) String() string

type Section

type Section struct {
	RawName        [16]byte
	RawSegmentName [16]byte
	// Address is the memory address of this section.
	Address uint64
	// Size is the size in bytes of this section.
	Size uint64
	// Offset is the file offset of this section.
	Offset uint32
	// Alignment is the section's alignment.
	Alignment Alignment
	// RelocationOffset is the file offset of relocation entries.
	RelocationOffset uint32
	// RelocationCount is the number of relocation entries.
	RelocationCount uint32
	// Flags holds the section type and attributes.
	Flags uint32
}

Section represents an instruction within a SegmentCommand to load a contiguous chunk of the file into virtual memory.

func (*Section) Name

func (s *Section) Name() string

Name returns the section's name as a string.

func (*Section) SegmentName

func (s *Section) SegmentName() string

SegmentName returns the name of the segment that contains the section as a string.

type SegmentCommand

type SegmentCommand struct {
	Command              LoadCmd
	RawName              [16]byte
	VirtualMemoryAddress uint64
	VirtualMemorySize    uint64
	FileOffset           uint64
	FileSize             uint64
	MaxProtection        VirtualMemoryProtection
	InitProtection       VirtualMemoryProtection
	Flags                uint32

	Sections []Section
}

SegmentCommand is the structure for LoadCmdSegment and LoadCmdSegment64.

func (*SegmentCommand) Name

func (cmd *SegmentCommand) Name() string

Name returns the segment's name as a string.

func (*SegmentCommand) UnmarshalMachO

func (cmd *SegmentCommand) UnmarshalMachO(byteOrder binary.ByteOrder, data []byte) error

UnmarshalMachO unmarshals the load command in data into cmd.

type SuperBlob

type SuperBlob struct {
	Magic CodeSignatureMagic
	Blobs []SuperBlobEntry
}

SuperBlob is a container of CodeSignatureBlob.

func (*SuperBlob) UnmarshalBinary

func (blob *SuperBlob) UnmarshalBinary(data []byte) error

UnmarshalBinary unmarshals a Mach-O code signature blob as a SuperBlob.

type SuperBlobEntry

type SuperBlobEntry struct {
	Type SuperBlobSlot
	Blob CodeSignatureBlob
}

SuperBlobEntry is a CodeSignatureBlob with a "slot" (its intended usage).

type SuperBlobSlot

type SuperBlobSlot uint32

SuperBlobSlot is an enumeration of types used in SuperBlobEntry.

const (
	SuperBlobCodeDirectorySlot SuperBlobSlot = 0 // CSSLOT_CODEDIRECTORY
	SuperBlobInfoSlot          SuperBlobSlot = 1 // CSSLOT_INFOSLOT
	SuperBlobRequirementsSlot  SuperBlobSlot = 2 // CSSLOT_REQUIREMENTS
	SuperBlobResourceDirSlot   SuperBlobSlot = 3 // CSSLOT_RESOURCEDIR
	SuperBlobApplicationSlot   SuperBlobSlot = 4 // CSSLOT_APPLICATION
	SuperBlobEntitlementsSlot  SuperBlobSlot = 5 // CSSLOT_ENTITLEMENTS
)

Known SuperBlobSlot values.

func (SuperBlobSlot) String

func (i SuperBlobSlot) String() string

type Type

type Type uint32

Type is an enumeration of Mach-O file types.

const (
	TypeObj    Type = 1
	TypeExec   Type = 2
	TypeDylib  Type = 6
	TypeBundle Type = 8
)

Known Mach-O file types.

type UUIDCommand

type UUIDCommand struct {
	UUID uuid.UUID
}

UUIDCommand is the structure for LoadCmdUUID.

func (*UUIDCommand) UnmarshalMachO

func (cmd *UUIDCommand) UnmarshalMachO(byteOrder binary.ByteOrder, data []byte) error

UnmarshalMachO unmarshals the UUID command in data into cmd.

type UniversalFileEntry

type UniversalFileEntry struct {
	CPU        CPUType
	CPUSubtype uint32
	// Offset is the offset in bytes from the beginning of the Mach-O file
	// that this image starts at.
	Offset uint32
	// Size is the size of the image in bytes.
	Size      uint32
	Alignment Alignment
}

UniversalFileEntry is a single record from a Mach-O multi-architecture file.

func ReadUniversalHeader

func ReadUniversalHeader(r io.Reader) ([]UniversalFileEntry, error)

ReadUniversalHeader reads a Mach-O multi-architecture header and all of its entries.

func (*UniversalFileEntry) UnmarshalBinary

func (ent *UniversalFileEntry) UnmarshalBinary(data []byte) error

UnmarshalBinary unmarshals a universal file entry in Mach-O format.

type VirtualMemoryProtection

type VirtualMemoryProtection uint32

VirtualMemoryProtection is a set of bitflags used to indicate permissions on a SegmentCommand.

const (
	VirtualMemoryReadPermission    VirtualMemoryProtection = 0x1
	VirtualMemoryWritePermission   VirtualMemoryProtection = 0x2
	VirtualMemoryExecutePermission VirtualMemoryProtection = 0x4
)

Virtual memory permissions.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL