1
2
3
4
5
6
7 package macho
8
9 import (
10 "debug/macho"
11 "encoding/binary"
12 "io"
13 "unsafe"
14 )
15
16 const (
17 LC_SEGMENT = 0x1
18 LC_SYMTAB = 0x2
19 LC_SYMSEG = 0x3
20 LC_THREAD = 0x4
21 LC_UNIXTHREAD = 0x5
22 LC_LOADFVMLIB = 0x6
23 LC_IDFVMLIB = 0x7
24 LC_IDENT = 0x8
25 LC_FVMFILE = 0x9
26 LC_PREPAGE = 0xa
27 LC_DYSYMTAB = 0xb
28 LC_LOAD_DYLIB = 0xc
29 LC_ID_DYLIB = 0xd
30 LC_LOAD_DYLINKER = 0xe
31 LC_ID_DYLINKER = 0xf
32 LC_PREBOUND_DYLIB = 0x10
33 LC_ROUTINES = 0x11
34 LC_SUB_FRAMEWORK = 0x12
35 LC_SUB_UMBRELLA = 0x13
36 LC_SUB_CLIENT = 0x14
37 LC_SUB_LIBRARY = 0x15
38 LC_TWOLEVEL_HINTS = 0x16
39 LC_PREBIND_CKSUM = 0x17
40 LC_LOAD_WEAK_DYLIB = 0x80000018
41 LC_SEGMENT_64 = 0x19
42 LC_ROUTINES_64 = 0x1a
43 LC_UUID = 0x1b
44 LC_RPATH = 0x8000001c
45 LC_CODE_SIGNATURE = 0x1d
46 LC_SEGMENT_SPLIT_INFO = 0x1e
47 LC_REEXPORT_DYLIB = 0x8000001f
48 LC_LAZY_LOAD_DYLIB = 0x20
49 LC_ENCRYPTION_INFO = 0x21
50 LC_DYLD_INFO = 0x22
51 LC_DYLD_INFO_ONLY = 0x80000022
52 LC_LOAD_UPWARD_DYLIB = 0x80000023
53 LC_VERSION_MIN_MACOSX = 0x24
54 LC_VERSION_MIN_IPHONEOS = 0x25
55 LC_FUNCTION_STARTS = 0x26
56 LC_DYLD_ENVIRONMENT = 0x27
57 LC_MAIN = 0x80000028
58 LC_DATA_IN_CODE = 0x29
59 LC_SOURCE_VERSION = 0x2A
60 LC_DYLIB_CODE_SIGN_DRS = 0x2B
61 LC_ENCRYPTION_INFO_64 = 0x2C
62 LC_LINKER_OPTION = 0x2D
63 LC_LINKER_OPTIMIZATION_HINT = 0x2E
64 LC_VERSION_MIN_TVOS = 0x2F
65 LC_VERSION_MIN_WATCHOS = 0x30
66 LC_VERSION_NOTE = 0x31
67 LC_BUILD_VERSION = 0x32
68 LC_DYLD_EXPORTS_TRIE = 0x80000033
69 LC_DYLD_CHAINED_FIXUPS = 0x80000034
70 )
71
72
73
74 type LoadCmd struct {
75 Cmd macho.LoadCmd
76 Len uint32
77 }
78
79 type LoadCmdReader struct {
80 offset, next int64
81 f io.ReadSeeker
82 order binary.ByteOrder
83 }
84
85 func NewLoadCmdReader(f io.ReadSeeker, order binary.ByteOrder, nextOffset int64) LoadCmdReader {
86 return LoadCmdReader{next: nextOffset, f: f, order: order}
87 }
88
89 func (r *LoadCmdReader) Next() (LoadCmd, error) {
90 var cmd LoadCmd
91
92 r.offset = r.next
93 if _, err := r.f.Seek(r.offset, 0); err != nil {
94 return cmd, err
95 }
96 if err := binary.Read(r.f, r.order, &cmd); err != nil {
97 return cmd, err
98 }
99 r.next = r.offset + int64(cmd.Len)
100 return cmd, nil
101 }
102
103 func (r LoadCmdReader) ReadAt(offset int64, data interface{}) error {
104 if _, err := r.f.Seek(r.offset+offset, 0); err != nil {
105 return err
106 }
107 return binary.Read(r.f, r.order, data)
108 }
109
110 func (r LoadCmdReader) Offset() int64 { return r.offset }
111
112 type LoadCmdUpdater struct {
113 LoadCmdReader
114 }
115
116 func NewLoadCmdUpdater(f io.ReadWriteSeeker, order binary.ByteOrder, nextOffset int64) LoadCmdUpdater {
117 return LoadCmdUpdater{NewLoadCmdReader(f, order, nextOffset)}
118 }
119
120 func (u LoadCmdUpdater) WriteAt(offset int64, data interface{}) error {
121 if _, err := u.f.Seek(u.offset+offset, 0); err != nil {
122 return err
123 }
124 return binary.Write(u.f.(io.Writer), u.order, data)
125 }
126
127 func FileHeaderSize(f *macho.File) int64 {
128 offset := int64(unsafe.Sizeof(f.FileHeader))
129 if is64bit := f.Magic == macho.Magic64; is64bit {
130
131 offset += 4
132 }
133 return offset
134 }
135
View as plain text