### Install go-macho Package Source: https://github.com/blacktop/go-macho/blob/master/README.md Use this command to add the go-macho package to your project dependencies. ```bash go get github.com/blacktop/go-macho ``` -------------------------------- ### Enumerate Functions in Mach-O Source: https://context7.com/blacktop/go-macho/llms.txt Demonstrates how to enumerate functions within a Mach-O binary using the `LC_FUNCTION_STARTS` load command or by auto-detecting prologues on arm64e. It shows how to get all functions, find the function containing a specific virtual address, and read a function's raw bytes. ```go package main import ( "fmt" "log" "github.com/blacktop/go-macho" ) func main() { m, err := macho.Open("/usr/lib/libSystem.B.dylib") if err != nil { log.Fatal(err) } defer m.Close() funcs := m.GetFunctions() fmt.Printf("Total functions: %d\n", len(funcs)) for _, fn := range funcs[:5] { fmt.Printf(" start=%#016x end=%#016x size=%d\n", fn.StartAddr, fn.EndAddr, fn.EndAddr-fn.StartAddr) } // Look up the function that contains a specific address fn, err := m.GetFunctionForVMAddr(0x100003e20) if err != nil { log.Printf("not in any function: %v", err) } else { fmt.Printf("Address 0x100003e20 is in function %#x-%#x\n", fn.StartAddr, fn.EndAddr) } // Read the raw bytes of a function data, _ := m.GetFunctionData(fn) fmt.Printf("First 4 bytes: %x\n", data[:4]) } ``` -------------------------------- ### Open and Read Mach-O File Source: https://github.com/blacktop/go-macho/blob/master/README.md Demonstrates how to open a Mach-O file and print its FileTOC. Ensure the file path is correct and handle potential errors during file opening. ```go package main import "github.com/blacktop/go-macho" func main() { m, err := macho.Open("/path/to/macho") if err != nil { panic(err) } defer m.Close() fmt.Println(m.FileTOC.String()) } ``` -------------------------------- ### Open and Parse a Thin Mach-O File Source: https://context7.com/blacktop/go-macho/llms.txt Opens a Mach-O binary from disk and prints its table of contents and header information. Ensure the file path is correct. ```go package main import ( "fmt" "log" "github.com/blacktop/go-macho" ) func main() { // Open a thin Mach-O binary from disk m, err := macho.Open("/usr/lib/libSystem.B.dylib") if err != nil { log.Fatal(err) } defer m.Close() // Print the full table of contents (header + all load commands) fmt.Println(m.FileTOC.String()) // Access header fields directly fmt.Printf("Magic: %s\n", m.Magic) fmt.Printf("CPU: %s\n", m.CPU) fmt.Printf("Type: %s\n", m.Type) fmt.Printf("NCmd: %d\n", m.NCommands) fmt.Printf("UUID: %s\n", m.UUID()) fmt.Printf("BaseAddr:%#x\n", m.GetBaseAddress()) } // Output (example): // Magic: MH_MAGIC_64 // CPU: X86_64 // Type: MH_DYLIB // NCmd: 38 // UUID: {E1B9F4E2-...} // BaseAddr:0x0 ``` -------------------------------- ### Create a Universal (Fat) Mach-O Binary Source: https://context7.com/blacktop/go-macho/llms.txt Combines multiple thin Mach-O files into a single universal binary. Specify the output path and the paths to the thin binaries to be included. ```go package main import ( "log" "github.com/blacktop/go-macho" ) func main() { fat, err := macho.CreateFat("/tmp/MyApp.universal", "/tmp/MyApp.arm64", "/tmp/MyApp.x86_64", ) if err != nil { log.Fatal(err) } defer fat.Close() // /tmp/MyApp.universal now contains both architectures } ``` -------------------------------- ### List Mach-O Segments and Sections Source: https://context7.com/blacktop/go-macho/llms.txt Opens a Mach-O binary and iterates through its segments, printing their names, memory addresses, and sizes. It also shows how to access specific sections by name and find segments/sections by virtual address. Demonstrates virtual address to file offset conversion. ```go package main import ( "fmt" "log" "github.com/blacktop/go-macho" ) func main() { m, err := macho.Open("/usr/lib/libSystem.B.dylib") if err != nil { log.Fatal(err) } defer m.Close() // List all segments for _, seg := range m.Segments() { fmt.Printf("seg %-16s addr=%#016x memsz=%#x filesz=%#x\n", seg.Name, seg.Addr, seg.Memsz, seg.Filesz) } // Access a named section text := m.Section("__TEXT", "__text") if text != nil { data, err := text.Data() if err != nil { log.Fatal(err) } fmt.Printf("__TEXT.__text size=%d, first 4 bytes: %x\n", len(data), data[:4]) } // Find segment/section by virtual address seg := m.FindSegmentForVMAddr(0x100003e20) if seg != nil { fmt.Printf("vmaddr 0x100003e20 is in segment: %s\n", seg.Name) } sec := m.FindSectionForVMAddr(0x100003e20) if sec != nil { fmt.Printf("vmaddr 0x100003e20 is in section: %s.%s\n", sec.Seg, sec.Name) } // Virtual address <-> file offset conversion offset, _ := m.GetOffset(0x100003e20) fmt.Printf("VM addr 0x100003e20 -> file offset %#x\n", offset) vmaddr, _ := m.GetVMAddress(offset) fmt.Printf("File offset %#x -> VM addr %#x\n", offset, vmaddr) } ``` -------------------------------- ### Configure go-macho Logging Source: https://github.com/blacktop/go-macho/blob/master/README.md Set up a structured logging handler for the 'log/slog' package to enable diagnostic messages from go-macho. Adjust the log level as needed for debugging. ```go import ( "log/slog" "os" ) // Enable debug logging slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{ Level: slog.LevelWarn, // Or slog.LevelDebug for more verbose output }))) ``` -------------------------------- ### Open and Parse a Universal (Fat) Mach-O Binary Source: https://context7.com/blacktop/go-macho/llms.txt Opens a universal Mach-O binary and iterates through its architectures, printing details for each. This is useful for inspecting binaries compiled for multiple architectures. ```go package main import ( "fmt" "log" "github.com/blacktop/go-macho" ) func main() { ff, err := macho.OpenFat("/usr/bin/lipo") if err != nil { log.Fatal(err) } defer ff.Close() fmt.Printf("Architectures: %d\n", ff.Count) for _, arch := range ff.Arches { fmt.Printf(" CPU: %-12s SubCPU: %s Offset: %#x Size: %#x\n", arch.CPU, arch.SubCPU, arch.Offset, arch.Size) // Each FatArch embeds a *macho.File fmt.Printf(" UUID: %s\n", arch.UUID()) } } // Output (example): // Architectures: 2 // CPU: X86_64 SubCPU: ... Offset: 0x4000 Size: 0x12345 // UUID: {A1B2...} // CPU: ARM64 SubCPU: ... Offset: 0x20000 Size: 0x23456 // UUID: {C3D4...} ``` -------------------------------- ### Lookup Mach-O Symbols Source: https://context7.com/blacktop/go-macho/llms.txt Demonstrates symbol resolution in Mach-O binaries. It shows how to find a symbol's address by name, list symbols at a given address, and iterate through the symbol table. Also includes fetching imported symbol names. ```go package main import ( "fmt" "log" "github.com/blacktop/go-macho" ) func main() { m, err := macho.Open("/usr/lib/libSystem.B.dylib") if err != nil { log.Fatal(err) } defer m.Close() // Look up a symbol address by name addr, err := m.FindSymbolAddress("_malloc") if err != nil { log.Printf("symbol not found: %v", err) } else { fmt.Printf("_malloc @ %#016x\n", addr) } // Reverse: symbols at a given address syms, err := m.FindAddressSymbols(addr) if err == nil { for _, s := range syms { fmt.Printf(" name=%s value=%#x type=%s\n", s.Name, s.Value, s.Type) } } // Walk all symbols from the symbol table if m.Symtab != nil { for _, sym := range m.Symtab.Syms[:10] { fmt.Printf(" %s %#x %s\n", sym.Name, sym.Value, sym.Type) } } // Names of all imported symbol (undefined externs) names, _ := m.ImportedSymbolNames() fmt.Printf("Imported %d symbols, first: %s\n", len(names), names[0]) } ``` -------------------------------- ### Inspect Swift Metadata in Mach-O Files Source: https://context7.com/blacktop/go-macho/llms.txt Opens a Mach-O file and extracts various Swift runtime metadata, including the table of contents, type descriptors, protocol descriptors, field descriptors, reflection strings, builtin types, and the Swift entry point. Ensure the target binary contains Swift metadata. ```go package main import ( "fmt" "log" "github.com/blacktop/go-macho" ) func main() { m, err := macho.Open("/System/Library/Frameworks/SwiftUI.framework/SwiftUI") if err != nil { log.Fatal(err) } defer m.Close() if !m.HasSwift() { log.Fatal("no Swift metadata") } // Table of contents toc := m.GetSwiftTOC() fmt.Printf("Swift TOC: types=%d protocols=%d conformances=%d builtins=%d\n", toc.Types, toc.Protocols, toc.ProtocolConformances, toc.Builtins) // Toggle automatic Swift symbol demangling m.SetSwiftAutoDemangle(true) // All Swift type descriptors (structs, classes, enums, actors) types, err := m.GetSwiftTypes() if err != nil { log.Fatal(err) } for _, t := range types[:3] { fmt.Printf("Type: %s kind=%s\n", t.Name, t.Kind) } // Swift protocol descriptors protos, err := m.GetSwiftProtocols() if err == nil { for _, p := range protos[:3] { fmt.Printf("Protocol: %s\n", p.Name) } } // Swift field descriptors (type layout) fields, err := m.GetSwiftFields() if err == nil { for _, f := range fields[:2] { fmt.Printf("Field descriptor for %s (%d fields)\n", f.TypeName, len(f.Fields)) } } // Reflection strings (__swift5_reflstr section) reflStr, _ := m.GetSwiftReflectionStrings() fmt.Printf("Reflection strings: %d\n", len(reflStr)) // Builtin type descriptors (__swift5_builtin section) builtins, _ := m.GetSwiftBuiltinTypes() for _, bt := range builtins { fmt.Printf("Builtin: %s size=%d\n", bt.Name, bt.Size) break } // Swift entry point (top-level code) entry, err := m.GetSwiftEntry() if err == nil { fmt.Printf("Swift entry point: %#x\n", entry) } } ``` -------------------------------- ### Programmatic Mach-O Construction with FileTOC Source: https://context7.com/blacktop/go-macho/llms.txt Use FileTOC to build new Mach-O files by adding segments and sections. The DerivedCopy method allows creating variants with different types and flags. Load commands can be serialized using the Write interface. ```go package main import ( "bytes" "encoding/binary" "log" "github.com/blacktop/go-macho" "github.com/blacktop/go-macho/types" ) func main() { toc := &macho.FileTOC{ FileHeader: types.FileHeader{ Magic: types.Magic64, CPU: types.CPUArm64, SubCPU: types.CPUSubtypeArm64All, Type: types.MH_EXECUTE, Flags: types.MhPie, }, ByteOrder: binary.LittleEndian, } // Add a __TEXT segment textSeg := &macho.Segment{} textSeg.LoadCmd = types.LC_SEGMENT_64 textSeg.Name = "__TEXT" textSeg.Addr = 0x100000000 textSeg.Memsz = 0x4000 textSeg.Filesz = 0x4000 textSeg.Maxprot = types.PROT_READ | types.PROT_EXEC textSeg.Prot = types.PROT_READ | types.PROT_EXEC toc.AddSegment(textSeg) // Add a __text section inside it textSec := &types.Section{} textSec.Name = "__text" textSec.Seg = "__TEXT" textSec.Addr = 0x100000000 textSec.Size = 0x100 toc.AddSection(textSec) // Inspect sizes _ = toc.TOCSize() _ = toc.FileSize() // Derived copy with different type/flags execTOC := toc.DerivedCopy(types.MH_DYLIB, 0) _ = execTOC // Serialize using Write interface (each Load implements Write) var buf bytes.Buffer for _, l := range toc.Loads { if err := l.Write(&buf, binary.LittleEndian); err != nil { log.Fatal(err) } } } ``` -------------------------------- ### Read Mach-O Load Commands Source: https://context7.com/blacktop/go-macho/llms.txt Iterates through all load commands in a Mach-O file and accesses specific typed load commands like DylibID, SourceVersion, and BuildVersions. Also demonstrates retrieving imported libraries and symbols. ```go package main import ( "fmt" "log" "github.com/blacktop/go-macho" "github.com/blacktop/go-macho/types" ) func main() { m, err := macho.Open("/usr/lib/libSystem.B.dylib") if err != nil { log.Fatal(err) } defer m.Close() // Iterate all loads for i, l := range m.Loads { fmt.Printf("%03d: %-32s %s\n", i, l.Command(), l.String()) } // Access specific typed load commands if id := m.DylibID(); id != nil { fmt.Printf("DylibID: %s current=%s compat=%s\n", id.Name, id.CurrentVersion, id.CompatVersion) } if sv := m.SourceVersion(); sv != nil { fmt.Printf("SourceVersion: %s\n", sv) } for _, bv := range m.BuildVersions() { fmt.Printf("BuildVersion platform=%s minos=%s sdk=%s\n", bv.Platform, bv.Minos, bv.Sdk) } // Imported libraries for _, lib := range m.ImportedLibraries() { fmt.Println(" depends on:", lib) } // Linked-against symbols syms, _ := m.ImportedSymbols() for _, s := range syms[:5] { fmt.Printf(" import: %s type=%s sect=%d\n", s.Name, s.Type, s.Sect) } } ``` -------------------------------- ### Access Objective-C Runtime Metadata in Mach-O Binaries Source: https://context7.com/blacktop/go-macho/llms.txt Use HasObjC, GetObjCClasses, GetObjCProtocols, and related methods to expose Objective-C runtime layout. Ensure the binary has Objective-C metadata before proceeding. ```go package main import ( "fmt" "log" "github.com/blacktop/go-macho" ) func main() { m, err := macho.Open("/System/Library/Frameworks/Foundation.framework/Foundation") if err != nil { log.Fatal(err) } defer m.Close() if !m.HasObjC() { log.Fatal("no Objective-C metadata") } // Table of contents toc := m.GetObjCToc() fmt.Printf("ObjC TOC: classes=%d protocols=%d categories=%d\n", toc.ClassList, toc.ProtoList, toc.CatList) // Image info (Swift version flag, GC policy, etc.) info, err := m.GetObjCImageInfo() if err == nil { fmt.Printf("ObjC version flags: %s\n", info) } // All classes with their methods, properties, and ivars classes, err := m.GetObjCClasses() if err != nil { log.Fatal(err) } for _, cls := range classes[:2] { fmt.Printf("Class: %s superclass=%s\n", cls.Name, cls.SuperClass) for _, m := range cls.Methods { fmt.Printf(" - %s\n", m.Name) } } // Class names by virtual address names, _ := m.GetObjCClassNames() for addr, name := range names { fmt.Printf(" vmaddr=%#x name=%s\n", addr, name) break } // All protocols protos, err := m.GetObjCProtocols() if err == nil { for _, p := range protos[:2] { fmt.Printf("Protocol: %s methods=%d\n", p.Name, len(p.InstanceMethods)) } } // Method names methNames, _ := m.GetObjCMethodNames() fmt.Printf("Total method names: %d\n", len(methNames)) } ``` -------------------------------- ### Read C-strings from Mach-O Source: https://context7.com/blacktop/go-macho/llms.txt Provides methods to read C-strings from Mach-O binaries. It demonstrates reading a single null-terminated string at a specific virtual address and scanning all `__cstring` sections to extract all string literals. ```go package main import ( "fmt" "log" "github.com/blacktop/go-macho" ) func main() { m, err := macho.Open("/usr/bin/file") if err != nil { log.Fatal(err) } defer m.Close() // Read a single C-string at a known virtual address s, err := m.GetCString(0x100004500) if err != nil { log.Printf("GetCString: %v", err) } else { fmt.Printf("string @ 0x100004500: %q\n", s) } // Scan all C-string literals in all __cstring sections all, err := m.GetCStrings() if err != nil { log.Fatal(err) } for section, strings := range all { fmt.Printf("Section %s: %d strings\n", section, len(strings)) for str, addr := range strings { fmt.Printf(" %#x %q\n", addr, str) break // print just one per section } } } ``` -------------------------------- ### Configure go-macho Logging Source: https://context7.com/blacktop/go-macho/llms.txt Configure the default logger for go-macho using Go's `log/slog`. By default, no diagnostics are emitted; set a handler with a desired level to view warnings about malformed structures. ```go package main import ( "log/slog" "os" "github.com/blacktop/go-macho" ) func main() { // Emit warnings from go-macho to stderr slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{ Level: slog.LevelWarn, }))) m, err := macho.Open("/path/to/binary") if err != nil { panic(err) } defer m.Close() _ = m } ``` -------------------------------- ### Decode Dyld Linking Metadata in Mach-O Binaries Source: https://context7.com/blacktop/go-macho/llms.txt Use DyldExports, GetBindInfo, and GetRebaseInfo to decode dyld linking metadata for modern binaries. Requires opening a Mach-O file. ```go package main import ( "fmt" "log" "github.com/blacktop/go-macho" ) func main() { m, err := macho.Open("/usr/lib/libSystem.B.dylib") if err != nil { log.Fatal(err) } defer m.Close() // Dyld export trie exports, err := m.DyldExports() if err != nil { log.Printf("exports: %v", err) } else { fmt.Printf("Exports: %d\n", len(exports)) for _, exp := range exports[:3] { fmt.Printf(" %s @ %#x flags=%x\n", exp.Name, exp.Address, exp.Flags) } } // Bind info (external symbol fixups) binds, err := m.GetBindInfo() if err != nil { log.Printf("binds: %v", err) } else { for _, b := range binds[:3] { fmt.Printf(" bind: %s dylib=%s seg=%s offset=%#x\n", b.Name, b.Dylib, b.Segment, b.SegOffset) } } // Rebase info (ASLR fixups) rebases, err := m.GetRebaseInfo() if err != nil { log.Printf("rebases: %v", err) } else { fmt.Printf("Rebases: %d\n", len(rebases)) } // Dyld chained fixups (modern binaries) if m.HasDyldChainedFixups() { dcf, err := m.DyldChainedFixups() if err != nil { log.Fatal(err) } fmt.Printf("Chained fixup format: %s\n", dcf.PointerFormat) fmt.Printf("Import count: %d\n", len(dcf.Imports)) } // Pointer resolution (handles both legacy and chained fixups) ptr, _ := m.GetSlidPointerAtAddress(0x100010000) fmt.Printf("Slid pointer: %#x\n", ptr) } ``` -------------------------------- ### Extract DWARF Debug Information from Mach-O Files Source: https://context7.com/blacktop/go-macho/llms.txt Retrieves and parses the DWARF debug information from a Mach-O file using the go-dwarf library. This snippet demonstrates how to walk through compilation units and access their fields. Ensure the target binary contains DWARF debug information. ```go package main import ( "fmt" "log" "github.com/blacktop/go-macho" ) func main() { m, err := macho.Open("/usr/bin/clang") if err != nil { log.Fatal(err) } defer m.Close() d, err := m.DWARF() if err != nil { log.Fatalf("DWARF: %v", err) } // Walk compilation units reader := d.Reader() for { entry, err := reader.Next() if err != nil || entry == nil { break } if entry.Tag.String() == "TagCompileUnit" { for _, field := range entry.Field { fmt.Printf(" %s: %v\n", field.Attr, field.Val) } break } } } ``` -------------------------------- ### Parse Code Signature from Mach-O Files Source: https://context7.com/blacktop/go-macho/llms.txt Extracts the code signature from a Mach-O file, including code directories, entitlements, requirements, and the CMS signature blob. This is useful for verifying the integrity and permissions of an executable. Requires the binary to have a code signature. ```go package main import ( "fmt" "log" "github.com/blacktop/go-macho" ) func main() { m, err := macho.Open("/usr/bin/codesign") if err != nil { log.Fatal(err) } defer m.Close() cs := m.CodeSignature() if cs == nil { log.Fatal("no code signature") } // Code directories (hash type, hashes of pages) for _, cd := range cs.CodeDirectories { fmt.Printf("CodeDirectory: identifier=%s hashType=%s nCodeSlots=%d\n", cd.ID, cd.HashType, cd.NCodeSlots) } // Entitlements (XML plist string) if cs.Entitlements != "" { fmt.Printf("Entitlements:\n%s\n", cs.Entitlements) } // Requirements for _, req := range cs.Requirements { fmt.Printf("Requirement: %s\n", req) } // CMS/PKCS7 signature blob (DER bytes) if len(cs.CMSSignature) > 0 { fmt.Printf("CMS signature length: %d bytes\n", len(cs.CMSSignature)) } // Launch constraints (macOS 13+) if len(cs.LaunchConstraintsSelf) > 0 { fmt.Printf("LaunchConstraints (self): %d bytes\n", len(cs.LaunchConstraintsSelf)) } } ``` -------------------------------- ### Extract Embedded Plist and LLVM Bitcode Source: https://context7.com/blacktop/go-macho/llms.txt Retrieve the embedded Info.plist and LLVM bitcode from a Mach-O binary. The GetEmbeddedLLVMBitcode function returns an XAR archive containing the bitcode files. ```go package main import ( "fmt" "log" "github.com/blacktop/go-macho" ) func main() { m, err := macho.Open("/System/Library/Frameworks/Foundation.framework/Foundation") if err != nil { log.Fatal(err) } defer m.Close() // Embedded Info.plist plist, err := m.GetEmbeddedInfoPlist() if err != nil { log.Printf("no embedded plist: %v", err) } else { fmt.Printf("Info.plist (%d bytes):\n%.200s...\n", len(plist), plist) } // Embedded LLVM bitcode XAR archive xr, err := m.GetEmbeddedLLVMBitcode() if err != nil { log.Printf("no LLVM bitcode: %v", err) } else { for _, xf := range xr.File { fmt.Printf("bitcode file: %s type=%v\n", xf.Name, xf.Type) } } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.