1 | /**************************************************************************/ |
2 | /* macho.cpp */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
10 | /* */ |
11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
12 | /* a copy of this software and associated documentation files (the */ |
13 | /* "Software"), to deal in the Software without restriction, including */ |
14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
17 | /* the following conditions: */ |
18 | /* */ |
19 | /* The above copyright notice and this permission notice shall be */ |
20 | /* included in all copies or substantial portions of the Software. */ |
21 | /* */ |
22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
29 | /**************************************************************************/ |
30 | |
31 | #include "macho.h" |
32 | |
33 | uint32_t MachO::seg_align(uint64_t p_vmaddr, uint32_t p_min, uint32_t p_max) { |
34 | uint32_t salign = p_max; |
35 | if (p_vmaddr != 0) { |
36 | uint64_t seg_align = 1; |
37 | salign = 0; |
38 | while ((seg_align & p_vmaddr) == 0) { |
39 | seg_align = seg_align << 1; |
40 | salign++; |
41 | } |
42 | salign = CLAMP(salign, p_min, p_max); |
43 | } |
44 | return salign; |
45 | } |
46 | |
47 | bool MachO::alloc_signature(uint64_t p_size) { |
48 | ERR_FAIL_COND_V_MSG(fa.is_null(), false, "MachO: File not opened." ); |
49 | if (signature_offset != 0) { |
50 | // Nothing to do, already have signature load command. |
51 | return true; |
52 | } |
53 | if (lc_limit == 0 || lc_limit + 16 > exe_base) { |
54 | ERR_FAIL_V_MSG(false, "MachO: Can't allocate signature load command, please use \"codesign_allocate\" utility first." ); |
55 | } else { |
56 | // Add signature load command. |
57 | signature_offset = lc_limit; |
58 | |
59 | fa->seek(lc_limit); |
60 | LoadCommandHeader lc; |
61 | lc.cmd = LC_CODE_SIGNATURE; |
62 | lc.cmdsize = 16; |
63 | if (swap) { |
64 | lc.cmdsize = BSWAP32(lc.cmdsize); |
65 | } |
66 | fa->store_buffer((const uint8_t *)&lc, sizeof(LoadCommandHeader)); |
67 | |
68 | uint32_t lc_offset = fa->get_length() + PAD(fa->get_length(), 16); |
69 | uint32_t lc_size = 0; |
70 | if (swap) { |
71 | lc_offset = BSWAP32(lc_offset); |
72 | lc_size = BSWAP32(lc_size); |
73 | } |
74 | fa->store_32(lc_offset); |
75 | fa->store_32(lc_size); |
76 | |
77 | // Write new command number. |
78 | fa->seek(0x10); |
79 | uint32_t ncmds = fa->get_32(); |
80 | uint32_t cmdssize = fa->get_32(); |
81 | if (swap) { |
82 | ncmds = BSWAP32(ncmds); |
83 | cmdssize = BSWAP32(cmdssize); |
84 | } |
85 | ncmds += 1; |
86 | cmdssize += 16; |
87 | if (swap) { |
88 | ncmds = BSWAP32(ncmds); |
89 | cmdssize = BSWAP32(cmdssize); |
90 | } |
91 | fa->seek(0x10); |
92 | fa->store_32(ncmds); |
93 | fa->store_32(cmdssize); |
94 | |
95 | lc_limit = lc_limit + sizeof(LoadCommandHeader) + 8; |
96 | |
97 | return true; |
98 | } |
99 | } |
100 | |
101 | bool MachO::is_macho(const String &p_path) { |
102 | Ref<FileAccess> fb = FileAccess::open(p_path, FileAccess::READ); |
103 | ERR_FAIL_COND_V_MSG(fb.is_null(), false, vformat("MachO: Can't open file: \"%s\"." , p_path)); |
104 | uint32_t magic = fb->get_32(); |
105 | return (magic == 0xcefaedfe || magic == 0xfeedface || magic == 0xcffaedfe || magic == 0xfeedfacf); |
106 | } |
107 | |
108 | bool MachO::open_file(const String &p_path) { |
109 | fa = FileAccess::open(p_path, FileAccess::READ_WRITE); |
110 | ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("MachO: Can't open file: \"%s\"." , p_path)); |
111 | uint32_t magic = fa->get_32(); |
112 | MachHeader ; |
113 | |
114 | // Read MachO header. |
115 | swap = (magic == 0xcffaedfe || magic == 0xcefaedfe); |
116 | if (magic == 0xcefaedfe || magic == 0xfeedface) { |
117 | // Thin 32-bit binary. |
118 | fa->get_buffer((uint8_t *)&mach_header, sizeof(MachHeader)); |
119 | } else if (magic == 0xcffaedfe || magic == 0xfeedfacf) { |
120 | // Thin 64-bit binary. |
121 | fa->get_buffer((uint8_t *)&mach_header, sizeof(MachHeader)); |
122 | fa->get_32(); // Skip extra reserved field. |
123 | } else { |
124 | ERR_FAIL_V_MSG(false, vformat("MachO: File is not a valid MachO binary: \"%s\"." , p_path)); |
125 | } |
126 | |
127 | if (swap) { |
128 | mach_header.ncmds = BSWAP32(mach_header.ncmds); |
129 | mach_header.cpusubtype = BSWAP32(mach_header.cpusubtype); |
130 | mach_header.cputype = BSWAP32(mach_header.cputype); |
131 | } |
132 | cpusubtype = mach_header.cpusubtype; |
133 | cputype = mach_header.cputype; |
134 | align = 0; |
135 | exe_base = std::numeric_limits<uint64_t>::max(); |
136 | exe_limit = 0; |
137 | lc_limit = 0; |
138 | link_edit_offset = 0; |
139 | signature_offset = 0; |
140 | |
141 | // Read load commands. |
142 | for (uint32_t i = 0; i < mach_header.ncmds; i++) { |
143 | LoadCommandHeader lc; |
144 | fa->get_buffer((uint8_t *)&lc, sizeof(LoadCommandHeader)); |
145 | if (swap) { |
146 | lc.cmd = BSWAP32(lc.cmd); |
147 | lc.cmdsize = BSWAP32(lc.cmdsize); |
148 | } |
149 | uint64_t ps = fa->get_position(); |
150 | switch (lc.cmd) { |
151 | case LC_SEGMENT: { |
152 | LoadCommandSegment lc_seg; |
153 | fa->get_buffer((uint8_t *)&lc_seg, sizeof(LoadCommandSegment)); |
154 | if (swap) { |
155 | lc_seg.nsects = BSWAP32(lc_seg.nsects); |
156 | lc_seg.vmaddr = BSWAP32(lc_seg.vmaddr); |
157 | lc_seg.vmsize = BSWAP32(lc_seg.vmsize); |
158 | } |
159 | align = MAX(align, seg_align(lc_seg.vmaddr, 2, 15)); |
160 | if (String(lc_seg.segname) == "__TEXT" ) { |
161 | exe_limit = MAX(exe_limit, lc_seg.vmsize); |
162 | for (uint32_t j = 0; j < lc_seg.nsects; j++) { |
163 | Section lc_sect; |
164 | fa->get_buffer((uint8_t *)&lc_sect, sizeof(Section)); |
165 | if (String(lc_sect.sectname) == "__text" ) { |
166 | if (swap) { |
167 | exe_base = MIN(exe_base, BSWAP32(lc_sect.offset)); |
168 | } else { |
169 | exe_base = MIN(exe_base, lc_sect.offset); |
170 | } |
171 | } |
172 | if (swap) { |
173 | align = MAX(align, BSWAP32(lc_sect.align)); |
174 | } else { |
175 | align = MAX(align, lc_sect.align); |
176 | } |
177 | } |
178 | } else if (String(lc_seg.segname) == "__LINKEDIT" ) { |
179 | link_edit_offset = ps - 8; |
180 | } |
181 | } break; |
182 | case LC_SEGMENT_64: { |
183 | LoadCommandSegment64 lc_seg; |
184 | fa->get_buffer((uint8_t *)&lc_seg, sizeof(LoadCommandSegment64)); |
185 | if (swap) { |
186 | lc_seg.nsects = BSWAP32(lc_seg.nsects); |
187 | lc_seg.vmaddr = BSWAP64(lc_seg.vmaddr); |
188 | lc_seg.vmsize = BSWAP64(lc_seg.vmsize); |
189 | } |
190 | align = MAX(align, seg_align(lc_seg.vmaddr, 3, 15)); |
191 | if (String(lc_seg.segname) == "__TEXT" ) { |
192 | exe_limit = MAX(exe_limit, lc_seg.vmsize); |
193 | for (uint32_t j = 0; j < lc_seg.nsects; j++) { |
194 | Section64 lc_sect; |
195 | fa->get_buffer((uint8_t *)&lc_sect, sizeof(Section64)); |
196 | if (String(lc_sect.sectname) == "__text" ) { |
197 | if (swap) { |
198 | exe_base = MIN(exe_base, BSWAP32(lc_sect.offset)); |
199 | } else { |
200 | exe_base = MIN(exe_base, lc_sect.offset); |
201 | } |
202 | if (swap) { |
203 | align = MAX(align, BSWAP32(lc_sect.align)); |
204 | } else { |
205 | align = MAX(align, lc_sect.align); |
206 | } |
207 | } |
208 | } |
209 | } else if (String(lc_seg.segname) == "__LINKEDIT" ) { |
210 | link_edit_offset = ps - 8; |
211 | } |
212 | } break; |
213 | case LC_CODE_SIGNATURE: { |
214 | signature_offset = ps - 8; |
215 | } break; |
216 | default: { |
217 | } break; |
218 | } |
219 | fa->seek(ps + lc.cmdsize - 8); |
220 | lc_limit = ps + lc.cmdsize - 8; |
221 | } |
222 | |
223 | if (exe_limit == 0 || lc_limit == 0) { |
224 | ERR_FAIL_V_MSG(false, vformat("MachO: No load commands or executable code found: \"%s\"." , p_path)); |
225 | } |
226 | |
227 | return true; |
228 | } |
229 | |
230 | uint64_t MachO::get_exe_base() { |
231 | ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened." ); |
232 | return exe_base; |
233 | } |
234 | |
235 | uint64_t MachO::get_exe_limit() { |
236 | ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened." ); |
237 | return exe_limit; |
238 | } |
239 | |
240 | int32_t MachO::get_align() { |
241 | ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened." ); |
242 | return align; |
243 | } |
244 | |
245 | uint32_t MachO::get_cputype() { |
246 | ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened." ); |
247 | return cputype; |
248 | } |
249 | |
250 | uint32_t MachO::get_cpusubtype() { |
251 | ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened." ); |
252 | return cpusubtype; |
253 | } |
254 | |
255 | uint64_t MachO::get_size() { |
256 | ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened." ); |
257 | return fa->get_length(); |
258 | } |
259 | |
260 | uint64_t MachO::get_signature_offset() { |
261 | ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened." ); |
262 | ERR_FAIL_COND_V_MSG(signature_offset == 0, 0, "MachO: No signature load command." ); |
263 | |
264 | fa->seek(signature_offset + 8); |
265 | if (swap) { |
266 | return BSWAP32(fa->get_32()); |
267 | } else { |
268 | return fa->get_32(); |
269 | } |
270 | } |
271 | |
272 | uint64_t MachO::get_code_limit() { |
273 | ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened." ); |
274 | |
275 | if (signature_offset == 0) { |
276 | return fa->get_length() + PAD(fa->get_length(), 16); |
277 | } else { |
278 | return get_signature_offset(); |
279 | } |
280 | } |
281 | |
282 | uint64_t MachO::get_signature_size() { |
283 | ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened." ); |
284 | ERR_FAIL_COND_V_MSG(signature_offset == 0, 0, "MachO: No signature load command." ); |
285 | |
286 | fa->seek(signature_offset + 12); |
287 | if (swap) { |
288 | return BSWAP32(fa->get_32()); |
289 | } else { |
290 | return fa->get_32(); |
291 | } |
292 | } |
293 | |
294 | bool MachO::is_signed() { |
295 | ERR_FAIL_COND_V_MSG(fa.is_null(), false, "MachO: File not opened." ); |
296 | if (signature_offset == 0) { |
297 | return false; |
298 | } |
299 | |
300 | fa->seek(get_signature_offset()); |
301 | uint32_t magic = BSWAP32(fa->get_32()); |
302 | if (magic != 0xfade0cc0) { |
303 | return false; // No SuperBlob found. |
304 | } |
305 | fa->get_32(); // Skip size field, unused. |
306 | uint32_t count = BSWAP32(fa->get_32()); |
307 | for (uint32_t i = 0; i < count; i++) { |
308 | uint32_t index_type = BSWAP32(fa->get_32()); |
309 | uint32_t offset = BSWAP32(fa->get_32()); |
310 | if (index_type == 0x00000000) { // CodeDirectory index type. |
311 | fa->seek(get_signature_offset() + offset + 12); |
312 | uint32_t flags = BSWAP32(fa->get_32()); |
313 | if (flags & 0x20000) { |
314 | return false; // Found CD, linker-signed. |
315 | } else { |
316 | return true; // Found CD, not linker-signed. |
317 | } |
318 | } |
319 | } |
320 | return false; // No CD found. |
321 | } |
322 | |
323 | PackedByteArray MachO::get_cdhash_sha1() { |
324 | ERR_FAIL_COND_V_MSG(fa.is_null(), PackedByteArray(), "MachO: File not opened." ); |
325 | if (signature_offset == 0) { |
326 | return PackedByteArray(); |
327 | } |
328 | |
329 | fa->seek(get_signature_offset()); |
330 | uint32_t magic = BSWAP32(fa->get_32()); |
331 | if (magic != 0xfade0cc0) { |
332 | return PackedByteArray(); // No SuperBlob found. |
333 | } |
334 | fa->get_32(); // Skip size field, unused. |
335 | uint32_t count = BSWAP32(fa->get_32()); |
336 | for (uint32_t i = 0; i < count; i++) { |
337 | fa->get_32(); // Index type, skip. |
338 | uint32_t offset = BSWAP32(fa->get_32()); |
339 | uint64_t pos = fa->get_position(); |
340 | |
341 | fa->seek(get_signature_offset() + offset); |
342 | uint32_t cdmagic = BSWAP32(fa->get_32()); |
343 | uint32_t cdsize = BSWAP32(fa->get_32()); |
344 | if (cdmagic == 0xfade0c02) { // CodeDirectory. |
345 | fa->seek(get_signature_offset() + offset + 36); |
346 | uint8_t hash_size = fa->get_8(); |
347 | uint8_t hash_type = fa->get_8(); |
348 | if (hash_size == 0x14 && hash_type == 0x01) { /* SHA-1 */ |
349 | PackedByteArray hash; |
350 | hash.resize(0x14); |
351 | |
352 | fa->seek(get_signature_offset() + offset); |
353 | PackedByteArray blob; |
354 | blob.resize(cdsize); |
355 | fa->get_buffer(blob.ptrw(), cdsize); |
356 | |
357 | CryptoCore::SHA1Context ctx; |
358 | ctx.start(); |
359 | ctx.update(blob.ptr(), blob.size()); |
360 | ctx.finish(hash.ptrw()); |
361 | |
362 | return hash; |
363 | } |
364 | } |
365 | fa->seek(pos); |
366 | } |
367 | return PackedByteArray(); |
368 | } |
369 | |
370 | PackedByteArray MachO::get_cdhash_sha256() { |
371 | ERR_FAIL_COND_V_MSG(fa.is_null(), PackedByteArray(), "MachO: File not opened." ); |
372 | if (signature_offset == 0) { |
373 | return PackedByteArray(); |
374 | } |
375 | |
376 | fa->seek(get_signature_offset()); |
377 | uint32_t magic = BSWAP32(fa->get_32()); |
378 | if (magic != 0xfade0cc0) { |
379 | return PackedByteArray(); // No SuperBlob found. |
380 | } |
381 | fa->get_32(); // Skip size field, unused. |
382 | uint32_t count = BSWAP32(fa->get_32()); |
383 | for (uint32_t i = 0; i < count; i++) { |
384 | fa->get_32(); // Index type, skip. |
385 | uint32_t offset = BSWAP32(fa->get_32()); |
386 | uint64_t pos = fa->get_position(); |
387 | |
388 | fa->seek(get_signature_offset() + offset); |
389 | uint32_t cdmagic = BSWAP32(fa->get_32()); |
390 | uint32_t cdsize = BSWAP32(fa->get_32()); |
391 | if (cdmagic == 0xfade0c02) { // CodeDirectory. |
392 | fa->seek(get_signature_offset() + offset + 36); |
393 | uint8_t hash_size = fa->get_8(); |
394 | uint8_t hash_type = fa->get_8(); |
395 | if (hash_size == 0x20 && hash_type == 0x02) { /* SHA-256 */ |
396 | PackedByteArray hash; |
397 | hash.resize(0x20); |
398 | |
399 | fa->seek(get_signature_offset() + offset); |
400 | PackedByteArray blob; |
401 | blob.resize(cdsize); |
402 | fa->get_buffer(blob.ptrw(), cdsize); |
403 | |
404 | CryptoCore::SHA256Context ctx; |
405 | ctx.start(); |
406 | ctx.update(blob.ptr(), blob.size()); |
407 | ctx.finish(hash.ptrw()); |
408 | |
409 | return hash; |
410 | } |
411 | } |
412 | fa->seek(pos); |
413 | } |
414 | return PackedByteArray(); |
415 | } |
416 | |
417 | PackedByteArray MachO::get_requirements() { |
418 | ERR_FAIL_COND_V_MSG(fa.is_null(), PackedByteArray(), "MachO: File not opened." ); |
419 | if (signature_offset == 0) { |
420 | return PackedByteArray(); |
421 | } |
422 | |
423 | fa->seek(get_signature_offset()); |
424 | uint32_t magic = BSWAP32(fa->get_32()); |
425 | if (magic != 0xfade0cc0) { |
426 | return PackedByteArray(); // No SuperBlob found. |
427 | } |
428 | fa->get_32(); // Skip size field, unused. |
429 | uint32_t count = BSWAP32(fa->get_32()); |
430 | for (uint32_t i = 0; i < count; i++) { |
431 | fa->get_32(); // Index type, skip. |
432 | uint32_t offset = BSWAP32(fa->get_32()); |
433 | uint64_t pos = fa->get_position(); |
434 | |
435 | fa->seek(get_signature_offset() + offset); |
436 | uint32_t rqmagic = BSWAP32(fa->get_32()); |
437 | uint32_t rqsize = BSWAP32(fa->get_32()); |
438 | if (rqmagic == 0xfade0c01) { // Requirements. |
439 | PackedByteArray blob; |
440 | fa->seek(get_signature_offset() + offset); |
441 | blob.resize(rqsize); |
442 | fa->get_buffer(blob.ptrw(), rqsize); |
443 | return blob; |
444 | } |
445 | fa->seek(pos); |
446 | } |
447 | return PackedByteArray(); |
448 | } |
449 | |
450 | const Ref<FileAccess> MachO::get_file() const { |
451 | return fa; |
452 | } |
453 | |
454 | Ref<FileAccess> MachO::get_file() { |
455 | return fa; |
456 | } |
457 | |
458 | bool MachO::set_signature_size(uint64_t p_size) { |
459 | ERR_FAIL_COND_V_MSG(fa.is_null(), false, "MachO: File not opened." ); |
460 | |
461 | // Ensure signature load command exists. |
462 | ERR_FAIL_COND_V_MSG(link_edit_offset == 0, false, "MachO: No __LINKEDIT segment found." ); |
463 | ERR_FAIL_COND_V_MSG(!alloc_signature(p_size), false, "MachO: Can't allocate signature load command." ); |
464 | |
465 | // Update signature load command. |
466 | uint64_t old_size = get_signature_size(); |
467 | uint64_t new_size = p_size + PAD(p_size, 16384); |
468 | |
469 | if (new_size <= old_size) { |
470 | fa->seek(get_signature_offset()); |
471 | for (uint64_t i = 0; i < old_size; i++) { |
472 | fa->store_8(0x00); |
473 | } |
474 | return true; |
475 | } |
476 | |
477 | fa->seek(signature_offset + 12); |
478 | if (swap) { |
479 | fa->store_32(BSWAP32(new_size)); |
480 | } else { |
481 | fa->store_32(new_size); |
482 | } |
483 | |
484 | uint64_t end = get_signature_offset() + new_size; |
485 | |
486 | // Update "__LINKEDIT" segment. |
487 | LoadCommandHeader lc; |
488 | fa->seek(link_edit_offset); |
489 | fa->get_buffer((uint8_t *)&lc, sizeof(LoadCommandHeader)); |
490 | if (swap) { |
491 | lc.cmd = BSWAP32(lc.cmd); |
492 | lc.cmdsize = BSWAP32(lc.cmdsize); |
493 | } |
494 | switch (lc.cmd) { |
495 | case LC_SEGMENT: { |
496 | LoadCommandSegment lc_seg; |
497 | fa->get_buffer((uint8_t *)&lc_seg, sizeof(LoadCommandSegment)); |
498 | if (swap) { |
499 | lc_seg.vmsize = BSWAP32(lc_seg.vmsize); |
500 | lc_seg.filesize = BSWAP32(lc_seg.filesize); |
501 | lc_seg.fileoff = BSWAP32(lc_seg.fileoff); |
502 | } |
503 | |
504 | lc_seg.vmsize = end - lc_seg.fileoff; |
505 | lc_seg.vmsize += PAD(lc_seg.vmsize, 4096); |
506 | lc_seg.filesize = end - lc_seg.fileoff; |
507 | |
508 | if (swap) { |
509 | lc_seg.vmsize = BSWAP32(lc_seg.vmsize); |
510 | lc_seg.filesize = BSWAP32(lc_seg.filesize); |
511 | } |
512 | fa->seek(link_edit_offset + 8); |
513 | fa->store_buffer((const uint8_t *)&lc_seg, sizeof(LoadCommandSegment)); |
514 | } break; |
515 | case LC_SEGMENT_64: { |
516 | LoadCommandSegment64 lc_seg; |
517 | fa->get_buffer((uint8_t *)&lc_seg, sizeof(LoadCommandSegment64)); |
518 | if (swap) { |
519 | lc_seg.vmsize = BSWAP64(lc_seg.vmsize); |
520 | lc_seg.filesize = BSWAP64(lc_seg.filesize); |
521 | lc_seg.fileoff = BSWAP64(lc_seg.fileoff); |
522 | } |
523 | lc_seg.vmsize = end - lc_seg.fileoff; |
524 | lc_seg.vmsize += PAD(lc_seg.vmsize, 4096); |
525 | lc_seg.filesize = end - lc_seg.fileoff; |
526 | if (swap) { |
527 | lc_seg.vmsize = BSWAP64(lc_seg.vmsize); |
528 | lc_seg.filesize = BSWAP64(lc_seg.filesize); |
529 | } |
530 | fa->seek(link_edit_offset + 8); |
531 | fa->store_buffer((const uint8_t *)&lc_seg, sizeof(LoadCommandSegment64)); |
532 | } break; |
533 | default: { |
534 | ERR_FAIL_V_MSG(false, "MachO: Invalid __LINKEDIT segment type." ); |
535 | } break; |
536 | } |
537 | fa->seek(get_signature_offset()); |
538 | for (uint64_t i = 0; i < new_size; i++) { |
539 | fa->store_8(0x00); |
540 | } |
541 | return true; |
542 | } |
543 | |