1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package obj
18
19 import (
20 `encoding/binary`
21 `io`
22 `unsafe`
23 )
24
25 type MachOHeader struct {
26 Magic uint32
27 CPUType uint32
28 CPUSubType uint32
29 FileType uint32
30 CmdCount uint32
31 CmdSize uint32
32 Flags uint32
33 _ uint32
34 }
35
36 type SegmentCommand struct {
37 Cmd uint32
38 Size uint32
39 Name [16]byte
40 VMAddr uint64
41 VMSize uint64
42 FileOffset uint64
43 FileSize uint64
44 MaxProtect uint32
45 InitProtect uint32
46 SectionCount uint32
47 Flags uint32
48 }
49
50 type SegmentSection struct {
51 Name [16]byte
52 SegName [16]byte
53 Addr uint64
54 Size uint64
55 Offset uint32
56 Align uint32
57 RelOffset uint32
58 RelCount uint32
59 Flags uint32
60 _ [3]uint32
61 }
62
63 type Registers struct {
64 RAX uint64
65 RBX uint64
66 RCX uint64
67 RDX uint64
68 RDI uint64
69 RSI uint64
70 RBP uint64
71 RSP uint64
72 R8 uint64
73 R9 uint64
74 R10 uint64
75 R11 uint64
76 R12 uint64
77 R13 uint64
78 R14 uint64
79 R15 uint64
80 RIP uint64
81 RFLAGS uint64
82 CS uint64
83 FS uint64
84 GS uint64
85 }
86
87 type UnixThreadCommand struct {
88 Cmd uint32
89 Size uint32
90 Flavor uint32
91 Count uint32
92 Regs Registers
93 }
94
95 const (
96 _MH_MAGIC_64 = 0xfeedfacf
97 _MH_EXECUTE = 0x02
98 _MH_NOUNDEFS = 0x01
99 )
100
101 const (
102 _CPU_TYPE_I386 = 0x00000007
103 _CPU_ARCH_ABI64 = 0x01000000
104 )
105
106 const (
107 _CPU_SUBTYPE_LIB64 = 0x80000000
108 _CPU_SUBTYPE_I386_ALL = 0x00000003
109 )
110
111 const (
112 _LC_SEGMENT_64 = 0x19
113 _LC_UNIXTHREAD = 0x05
114 )
115
116 const (
117 _VM_PROT_READ = 0x01
118 _VM_PROT_WRITE = 0x02
119 _VM_PROT_EXECUTE = 0x04
120 )
121
122 const (
123 _S_ATTR_SOME_INSTRUCTIONS = 0x00000400
124 _S_ATTR_PURE_INSTRUCTIONS = 0x80000000
125 )
126
127 const (
128 _x86_THREAD_STATE64 = 0x04
129 _x86_EXCEPTION_STATE64_COUNT = 42
130 )
131
132 const (
133 _MACHO_SIZE = uint32(unsafe.Sizeof(MachOHeader{}))
134 _SEGMENT_SIZE = uint32(unsafe.Sizeof(SegmentCommand{}))
135 _SECTION_SIZE = uint32(unsafe.Sizeof(SegmentSection{}))
136 _UNIXTHREAD_SIZE = uint32(unsafe.Sizeof(UnixThreadCommand{}))
137 )
138
139 const (
140 _IMAGE_SIZE = 4096
141 _IMAGE_BASE = 0x04000000
142 )
143
144 const (
145 _HDR_SIZE = _MACHO_SIZE + _SEGMENT_SIZE * 2 + _SECTION_SIZE + _UNIXTHREAD_SIZE
146 _ZERO_SIZE = (_IMAGE_SIZE - _HDR_SIZE %_IMAGE_SIZE) % _IMAGE_SIZE
147 )
148
149 var (
150 zeroBytes = [_ZERO_SIZE]byte{}
151 )
152
153 func assembleMachO(w io.Writer, code []byte, base uint64, entry uint64) error {
154 var p0name [16]byte
155 var txname [16]byte
156 var tsname [16]byte
157
158
159 copy(tsname[:], "__text")
160 copy(txname[:], "__TEXT")
161 copy(p0name[:], "__PAGEZERO")
162
163
164 clen := uint64(len(code))
165 hlen := uint64(_HDR_SIZE + _ZERO_SIZE)
166
167
168 if base == 0 {
169 base = _IMAGE_BASE
170 entry += _IMAGE_BASE
171 }
172
173
174 p0 := SegmentCommand {
175 Cmd : _LC_SEGMENT_64,
176 Size : _SEGMENT_SIZE,
177 Name : p0name,
178 VMSize : base,
179 }
180
181
182 text := SegmentCommand {
183 Cmd : _LC_SEGMENT_64,
184 Size : _SEGMENT_SIZE + _SECTION_SIZE,
185 Name : txname,
186 VMAddr : base,
187 VMSize : hlen + clen,
188 FileSize : hlen + clen,
189 MaxProtect : _VM_PROT_READ | _VM_PROT_WRITE | _VM_PROT_EXECUTE,
190 InitProtect : _VM_PROT_READ | _VM_PROT_EXECUTE,
191 SectionCount : 1,
192 }
193
194
195 tsec := SegmentSection {
196 Name : tsname,
197 SegName : txname,
198 Addr : base + hlen,
199 Size : clen,
200 Offset : uint32(hlen),
201 Flags : _S_ATTR_SOME_INSTRUCTIONS | _S_ATTR_PURE_INSTRUCTIONS,
202 }
203
204
205 unix := UnixThreadCommand {
206 Cmd : _LC_UNIXTHREAD,
207 Size : _UNIXTHREAD_SIZE,
208 Flavor : _x86_THREAD_STATE64,
209 Count : _x86_EXCEPTION_STATE64_COUNT,
210 Regs : Registers { RIP: hlen + entry },
211 }
212
213
214 macho := MachOHeader {
215 Magic : _MH_MAGIC_64,
216 CPUType : _CPU_ARCH_ABI64 | _CPU_TYPE_I386,
217 CPUSubType : _CPU_SUBTYPE_LIB64 | _CPU_SUBTYPE_I386_ALL,
218 FileType : _MH_EXECUTE,
219 CmdCount : 3,
220 CmdSize : _SEGMENT_SIZE * 2 + _SECTION_SIZE + _UNIXTHREAD_SIZE,
221 Flags : _MH_NOUNDEFS,
222 }
223
224
225 if err := binary.Write(w, binary.LittleEndian, &macho) ; err != nil { return err }
226 if err := binary.Write(w, binary.LittleEndian, &p0) ; err != nil { return err }
227 if err := binary.Write(w, binary.LittleEndian, &text) ; err != nil { return err }
228 if err := binary.Write(w, binary.LittleEndian, &tsec) ; err != nil { return err }
229 if err := binary.Write(w, binary.LittleEndian, &unix) ; err != nil { return err }
230 if err := binary.Write(w, binary.LittleEndian, &zeroBytes) ; err != nil { return err }
231
232
233 if n, err := w.Write(code); err != nil {
234 return err
235 } else if n != len(code) {
236 return io.ErrShortWrite
237 } else {
238 return nil
239 }
240 }
241
View as plain text