ruby-macho 4.1.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +17 -2
- data/lib/macho/code_signing.rb +583 -0
- data/lib/macho/exceptions.rb +39 -31
- data/lib/macho/fat_file.rb +50 -4
- data/lib/macho/headers.rb +21 -9
- data/lib/macho/load_commands.rb +48 -3
- data/lib/macho/macho_file.rb +76 -25
- data/lib/macho/structure.rb +1 -1
- data/lib/macho.rb +12 -13
- metadata +6 -7
data/lib/macho/exceptions.rb
CHANGED
|
@@ -37,7 +37,7 @@ module MachO
|
|
|
37
37
|
# Raised when a file is too short to be a valid Mach-O file.
|
|
38
38
|
class TruncatedFileError < NotAMachOError
|
|
39
39
|
def initialize
|
|
40
|
-
super
|
|
40
|
+
super("File is too short to be a valid Mach-O")
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
|
|
@@ -45,21 +45,21 @@ module MachO
|
|
|
45
45
|
class MagicError < NotAMachOError
|
|
46
46
|
# @param num [Integer] the unknown number
|
|
47
47
|
def initialize(magic)
|
|
48
|
-
super
|
|
48
|
+
super("Unrecognized Mach-O magic: 0x%02<magic>x" % { :magic => magic })
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
# Raised when a file is a Java classfile instead of a fat Mach-O.
|
|
53
53
|
class JavaClassFileError < NotAMachOError
|
|
54
54
|
def initialize
|
|
55
|
-
super
|
|
55
|
+
super("File is a Java class file")
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
# Raised when a a fat Mach-O file has zero architectures
|
|
60
60
|
class ZeroArchitectureError < NotAMachOError
|
|
61
61
|
def initialize
|
|
62
|
-
super
|
|
62
|
+
super("Fat file has zero internal architectures")
|
|
63
63
|
end
|
|
64
64
|
end
|
|
65
65
|
|
|
@@ -71,24 +71,24 @@ module MachO
|
|
|
71
71
|
# @param cpusubtype_fat [Integer] the CPU subtype in the fat header
|
|
72
72
|
# @param cputype_macho [Integer] the CPU type in the macho header
|
|
73
73
|
# @param cpusubtype_macho [Integer] the CPU subtype in the macho header
|
|
74
|
-
super
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
super("Mismatch between cputypes >> 0x%08<fat_cputype>x and 0x%08<macho_cputype>x\n" \
|
|
75
|
+
"and/or cpusubtypes >> 0x%08<fat_cpusubtype>x and 0x%08<macho_cpusubtype>x" %
|
|
76
|
+
{ :fat_cputype => fat_cputype, :macho_cputype => macho_cputype,
|
|
77
|
+
:fat_cpusubtype => fat_cpusubtype, :macho_cpusubtype => macho_cpusubtype })
|
|
78
78
|
end
|
|
79
79
|
end
|
|
80
80
|
|
|
81
81
|
# Raised when a fat binary is loaded with MachOFile.
|
|
82
82
|
class FatBinaryError < MachOError
|
|
83
83
|
def initialize
|
|
84
|
-
super
|
|
84
|
+
super("Fat binaries must be loaded with MachO::FatFile")
|
|
85
85
|
end
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
# Raised when a Mach-O is loaded with FatFile.
|
|
89
89
|
class MachOBinaryError < MachOError
|
|
90
90
|
def initialize
|
|
91
|
-
super
|
|
91
|
+
super("Normal binaries must be loaded with MachO::MachOFile")
|
|
92
92
|
end
|
|
93
93
|
end
|
|
94
94
|
|
|
@@ -96,7 +96,7 @@ module MachO
|
|
|
96
96
|
class CPUTypeError < MachOError
|
|
97
97
|
# @param cputype [Integer] the unknown CPU type
|
|
98
98
|
def initialize(cputype)
|
|
99
|
-
super
|
|
99
|
+
super("Unrecognized CPU type: 0x%08<cputype>x" % { :cputype => cputype })
|
|
100
100
|
end
|
|
101
101
|
end
|
|
102
102
|
|
|
@@ -105,8 +105,8 @@ module MachO
|
|
|
105
105
|
# @param cputype [Integer] the CPU type of the unknown pair
|
|
106
106
|
# @param cpusubtype [Integer] the CPU sub-type of the unknown pair
|
|
107
107
|
def initialize(cputype, cpusubtype)
|
|
108
|
-
super
|
|
109
|
-
"(for CPU type: 0x%08<cputype>x" % { :cputype => cputype, :cpusubtype => cpusubtype }
|
|
108
|
+
super("Unrecognized CPU sub-type: 0x%08<cpusubtype>x " \
|
|
109
|
+
"(for CPU type: 0x%08<cputype>x" % { :cputype => cputype, :cpusubtype => cpusubtype })
|
|
110
110
|
end
|
|
111
111
|
end
|
|
112
112
|
|
|
@@ -114,7 +114,7 @@ module MachO
|
|
|
114
114
|
class FiletypeError < MachOError
|
|
115
115
|
# @param num [Integer] the unknown number
|
|
116
116
|
def initialize(num)
|
|
117
|
-
super
|
|
117
|
+
super("Unrecognized Mach-O filetype code: 0x%02<num>x" % { :num => num })
|
|
118
118
|
end
|
|
119
119
|
end
|
|
120
120
|
|
|
@@ -122,7 +122,15 @@ module MachO
|
|
|
122
122
|
class LoadCommandError < MachOError
|
|
123
123
|
# @param num [Integer] the unknown number
|
|
124
124
|
def initialize(num)
|
|
125
|
-
super
|
|
125
|
+
super("Unrecognized Mach-O load command: 0x%02<num>x" % { :num => num })
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Raised when a load command has an invalid size.
|
|
130
|
+
class LoadCommandSizeError < NotAMachOError
|
|
131
|
+
# @param size [Integer] the invalid size
|
|
132
|
+
def initialize(size)
|
|
133
|
+
super("Invalid Mach-O load command size: #{size}")
|
|
126
134
|
end
|
|
127
135
|
end
|
|
128
136
|
|
|
@@ -130,7 +138,7 @@ module MachO
|
|
|
130
138
|
class LoadCommandNotCreatableError < MachOError
|
|
131
139
|
# @param cmd_sym [Symbol] the uncreatable load command's symbol
|
|
132
140
|
def initialize(cmd_sym)
|
|
133
|
-
super
|
|
141
|
+
super("Load commands of type #{cmd_sym} cannot be created manually")
|
|
134
142
|
end
|
|
135
143
|
end
|
|
136
144
|
|
|
@@ -141,8 +149,8 @@ module MachO
|
|
|
141
149
|
# @param expected_arity [Integer] the number of arguments expected
|
|
142
150
|
# @param actual_arity [Integer] the number of arguments received
|
|
143
151
|
def initialize(cmd_sym, expected_arity, actual_arity)
|
|
144
|
-
super
|
|
145
|
-
"got #{actual_arity}"
|
|
152
|
+
super("Expected #{expected_arity} arguments for #{cmd_sym} creation, " \
|
|
153
|
+
"got #{actual_arity}")
|
|
146
154
|
end
|
|
147
155
|
end
|
|
148
156
|
|
|
@@ -150,7 +158,7 @@ module MachO
|
|
|
150
158
|
class LoadCommandNotSerializableError < MachOError
|
|
151
159
|
# @param cmd_sym [Symbol] the load command's symbol
|
|
152
160
|
def initialize(cmd_sym)
|
|
153
|
-
super
|
|
161
|
+
super("Load commands of type #{cmd_sym} cannot be serialized")
|
|
154
162
|
end
|
|
155
163
|
end
|
|
156
164
|
|
|
@@ -158,8 +166,8 @@ module MachO
|
|
|
158
166
|
class LCStrMalformedError < MachOError
|
|
159
167
|
# @param lc [MachO::LoadCommand] the load command containing the string
|
|
160
168
|
def initialize(lc)
|
|
161
|
-
super
|
|
162
|
-
"malformed string"
|
|
169
|
+
super("Load command #{lc.type} at offset #{lc.view.offset} contains a " \
|
|
170
|
+
"malformed string")
|
|
163
171
|
end
|
|
164
172
|
end
|
|
165
173
|
|
|
@@ -167,7 +175,7 @@ module MachO
|
|
|
167
175
|
class OffsetInsertionError < ModificationError
|
|
168
176
|
# @param offset [Integer] the invalid offset
|
|
169
177
|
def initialize(offset)
|
|
170
|
-
super
|
|
178
|
+
super("Insertion at offset #{offset} is not valid")
|
|
171
179
|
end
|
|
172
180
|
end
|
|
173
181
|
|
|
@@ -175,9 +183,9 @@ module MachO
|
|
|
175
183
|
class HeaderPadError < ModificationError
|
|
176
184
|
# @param filename [String] the filename
|
|
177
185
|
def initialize(filename)
|
|
178
|
-
super
|
|
186
|
+
super("Updated load commands do not fit in the header of " \
|
|
179
187
|
"#{filename}. #{filename} needs to be relinked, possibly with " \
|
|
180
|
-
"-headerpad or -headerpad_max_install_names"
|
|
188
|
+
"-headerpad or -headerpad_max_install_names")
|
|
181
189
|
end
|
|
182
190
|
end
|
|
183
191
|
|
|
@@ -185,14 +193,14 @@ module MachO
|
|
|
185
193
|
class DylibUnknownError < RecoverableModificationError
|
|
186
194
|
# @param dylib [String] the unknown shared library name
|
|
187
195
|
def initialize(dylib)
|
|
188
|
-
super
|
|
196
|
+
super("No such dylib name: #{dylib}")
|
|
189
197
|
end
|
|
190
198
|
end
|
|
191
199
|
|
|
192
200
|
# Raised when a dylib is missing an ID
|
|
193
201
|
class DylibIdMissingError < RecoverableModificationError
|
|
194
202
|
def initialize
|
|
195
|
-
super
|
|
203
|
+
super("Dylib is missing a dylib ID")
|
|
196
204
|
end
|
|
197
205
|
end
|
|
198
206
|
|
|
@@ -200,7 +208,7 @@ module MachO
|
|
|
200
208
|
class RpathUnknownError < RecoverableModificationError
|
|
201
209
|
# @param path [String] the unknown runtime path
|
|
202
210
|
def initialize(path)
|
|
203
|
-
super
|
|
211
|
+
super("No such runtime path: #{path}")
|
|
204
212
|
end
|
|
205
213
|
end
|
|
206
214
|
|
|
@@ -208,7 +216,7 @@ module MachO
|
|
|
208
216
|
class RpathExistsError < RecoverableModificationError
|
|
209
217
|
# @param path [String] the extant path
|
|
210
218
|
def initialize(path)
|
|
211
|
-
super
|
|
219
|
+
super("#{path} already exists")
|
|
212
220
|
end
|
|
213
221
|
end
|
|
214
222
|
|
|
@@ -216,7 +224,7 @@ module MachO
|
|
|
216
224
|
class UnimplementedError < MachOError
|
|
217
225
|
# @param thing [String] the thing that is unimplemented
|
|
218
226
|
def initialize(thing)
|
|
219
|
-
super
|
|
227
|
+
super("Unimplemented: #{thing}")
|
|
220
228
|
end
|
|
221
229
|
end
|
|
222
230
|
|
|
@@ -225,8 +233,8 @@ module MachO
|
|
|
225
233
|
class FatArchOffsetOverflowError < MachOError
|
|
226
234
|
# @param offset [Integer] the offending offset
|
|
227
235
|
def initialize(offset)
|
|
228
|
-
super
|
|
229
|
-
"Consider merging with `fat64: true`"
|
|
236
|
+
super("Offset #{offset} exceeds the 32-bit width of a fat_arch offset. " \
|
|
237
|
+
"Consider merging with `fat64: true`")
|
|
230
238
|
end
|
|
231
239
|
end
|
|
232
240
|
|
data/lib/macho/fat_file.rb
CHANGED
|
@@ -96,7 +96,12 @@ module MachO
|
|
|
96
96
|
|
|
97
97
|
@filename = filename
|
|
98
98
|
@options = opts
|
|
99
|
-
|
|
99
|
+
File.open(@filename, "rb") do |file|
|
|
100
|
+
@raw_data = file.read(Headers::FatHeader.bytesize)
|
|
101
|
+
@raw_data ||= ""
|
|
102
|
+
populate_fat_header
|
|
103
|
+
@raw_data << file.read.to_s
|
|
104
|
+
end
|
|
100
105
|
populate_fields
|
|
101
106
|
end
|
|
102
107
|
|
|
@@ -165,7 +170,7 @@ module MachO
|
|
|
165
170
|
# All load commands responsible for loading dylibs in the file's Mach-O's.
|
|
166
171
|
# @return [Array<LoadCommands::DylibCommand>] an array of DylibCommands
|
|
167
172
|
def dylib_load_commands
|
|
168
|
-
machos.
|
|
173
|
+
machos.flat_map(&:dylib_load_commands)
|
|
169
174
|
end
|
|
170
175
|
|
|
171
176
|
# Changes the file's dylib ID to `new_id`. If the file is not a dylib,
|
|
@@ -199,7 +204,7 @@ module MachO
|
|
|
199
204
|
# Individual architectures in a fat binary can link to different subsets
|
|
200
205
|
# of libraries, but at this point we want to have the full picture, i.e.
|
|
201
206
|
# the union of all libraries used by all architectures.
|
|
202
|
-
machos.
|
|
207
|
+
machos.flat_map(&:linked_dylibs).uniq
|
|
203
208
|
end
|
|
204
209
|
|
|
205
210
|
# Changes all dependent shared library install names from `old_name` to
|
|
@@ -229,7 +234,7 @@ module MachO
|
|
|
229
234
|
# @see MachOFile#rpaths
|
|
230
235
|
def rpaths
|
|
231
236
|
# Can individual architectures have different runtime paths?
|
|
232
|
-
machos.
|
|
237
|
+
machos.flat_map(&:rpaths).uniq
|
|
233
238
|
end
|
|
234
239
|
|
|
235
240
|
# Change the runtime path `old_path` to `new_path` in the file's Mach-Os.
|
|
@@ -283,6 +288,16 @@ module MachO
|
|
|
283
288
|
repopulate_raw_machos
|
|
284
289
|
end
|
|
285
290
|
|
|
291
|
+
# Replaces every embedded signature with a pure-Ruby ad-hoc signature.
|
|
292
|
+
# @param identifier [String, nil] the signing identifier
|
|
293
|
+
# @return [void]
|
|
294
|
+
def codesign!(identifier: nil)
|
|
295
|
+
identifier ||= CodeSigning.identifier(canonical_macho, filename)
|
|
296
|
+
machos.each { |macho| macho.codesign!(:identifier => identifier) }
|
|
297
|
+
repopulate_resized_raw_machos
|
|
298
|
+
nil
|
|
299
|
+
end
|
|
300
|
+
|
|
286
301
|
# Extract a Mach-O with the given CPU type from the file.
|
|
287
302
|
# @example
|
|
288
303
|
# file.extract(:i386) # => MachO::MachOFile
|
|
@@ -402,6 +417,37 @@ module MachO
|
|
|
402
417
|
end
|
|
403
418
|
end
|
|
404
419
|
|
|
420
|
+
# Rebuild the fat header and slice layout after internal Mach-Os change size.
|
|
421
|
+
# {#repopulate_raw_machos} assumes slice lengths are unchanged and writes at
|
|
422
|
+
# their recorded ranges. Signing appends data, so every architecture's size
|
|
423
|
+
# and each following aligned offset must be recalculated.
|
|
424
|
+
# @return [void]
|
|
425
|
+
# @api private
|
|
426
|
+
def repopulate_resized_raw_machos
|
|
427
|
+
fat_arch_class = Utils.fat_magic32?(header.magic) ? Headers::FatArch : Headers::FatArch64
|
|
428
|
+
header_size = Headers::FatHeader.bytesize + (fat_archs.size * fat_arch_class.bytesize)
|
|
429
|
+
header_data = @raw_data.byteslice(0, header_size)
|
|
430
|
+
slices = +"".b
|
|
431
|
+
offset = header_size
|
|
432
|
+
|
|
433
|
+
fat_archs.zip(machos).each_with_index do |(arch, macho), index|
|
|
434
|
+
macho_offset = Utils.round(offset, 2**arch.align)
|
|
435
|
+
slices << Utils.nullpad(macho_offset - offset) << macho.serialize
|
|
436
|
+
arch_offset = Headers::FatHeader.bytesize + (index * fat_arch_class.bytesize)
|
|
437
|
+
if fat_arch_class == Headers::FatArch
|
|
438
|
+
raise FatArchOffsetOverflowError, macho_offset if macho_offset > 0xffffffff
|
|
439
|
+
|
|
440
|
+
header_data[arch_offset + 8, 8] = [macho_offset, macho.serialize.bytesize].pack("N2")
|
|
441
|
+
else
|
|
442
|
+
header_data[arch_offset + 8, 16] = [macho_offset, macho.serialize.bytesize].pack("Q>2")
|
|
443
|
+
end
|
|
444
|
+
offset = macho_offset + macho.serialize.bytesize
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
@raw_data = header_data + slices
|
|
448
|
+
populate_fields
|
|
449
|
+
end
|
|
450
|
+
|
|
405
451
|
# Yield each Mach-O object in the file, rescuing and accumulating errors.
|
|
406
452
|
# @param options [Hash]
|
|
407
453
|
# @option options [Boolean] :strict (true) whether or not to fail loudly
|
data/lib/macho/headers.rb
CHANGED
|
@@ -60,14 +60,14 @@ module MachO
|
|
|
60
60
|
MH_CIGAM_64 => "MH_CIGAM_64",
|
|
61
61
|
}.freeze
|
|
62
62
|
|
|
63
|
-
# mask for
|
|
63
|
+
# mask for 64-bit CPU architectures with 64-bit types
|
|
64
64
|
# @api private
|
|
65
65
|
CPU_ARCH_ABI64 = 0x01000000
|
|
66
66
|
|
|
67
|
-
# mask for
|
|
67
|
+
# mask for 64-bit CPU architectures with 32-bit types (ILP32)
|
|
68
68
|
# @see https://github.com/Homebrew/ruby-macho/issues/113
|
|
69
69
|
# @api private
|
|
70
|
-
|
|
70
|
+
CPU_ARCH_ABI64_32 = 0x02000000
|
|
71
71
|
|
|
72
72
|
# any CPU (unused?)
|
|
73
73
|
# @api private
|
|
@@ -97,9 +97,10 @@ module MachO
|
|
|
97
97
|
# @api private
|
|
98
98
|
CPU_TYPE_ARM64 = (CPU_TYPE_ARM | CPU_ARCH_ABI64)
|
|
99
99
|
|
|
100
|
-
# 64-bit ARM compatible CPUs (
|
|
100
|
+
# 64-bit ARM compatible CPUs (with 32-bit types)
|
|
101
101
|
# @see https://github.com/Homebrew/ruby-macho/issues/113
|
|
102
|
-
|
|
102
|
+
# @api private
|
|
103
|
+
CPU_TYPE_ARM64_32 = (CPU_TYPE_ARM | CPU_ARCH_ABI64_32)
|
|
103
104
|
|
|
104
105
|
# PowerPC compatible CPUs
|
|
105
106
|
# @api private
|
|
@@ -450,6 +451,14 @@ module MachO
|
|
|
450
451
|
# @api private
|
|
451
452
|
MH_FILESET = 0xc
|
|
452
453
|
|
|
454
|
+
# gpu program
|
|
455
|
+
# @api private
|
|
456
|
+
MH_GPU_EXECUTE = 0xd
|
|
457
|
+
|
|
458
|
+
# gpu support functions
|
|
459
|
+
# @api private
|
|
460
|
+
MH_GPU_DYLIB = 0xe
|
|
461
|
+
|
|
453
462
|
# association of filetypes to Symbol representations
|
|
454
463
|
# @api private
|
|
455
464
|
MH_FILETYPES = {
|
|
@@ -465,6 +474,8 @@ module MachO
|
|
|
465
474
|
MH_DSYM => :dsym,
|
|
466
475
|
MH_KEXT_BUNDLE => :kext_bundle,
|
|
467
476
|
MH_FILESET => :fileset,
|
|
477
|
+
MH_GPU_EXECUTE => :gpu_execute,
|
|
478
|
+
MH_GPU_DYLIB => :gpu_dylib,
|
|
468
479
|
}.freeze
|
|
469
480
|
|
|
470
481
|
# association of mach header flag symbols to values
|
|
@@ -480,7 +491,7 @@ module MachO
|
|
|
480
491
|
:MH_TWOLEVEL => 0x80,
|
|
481
492
|
:MH_FORCE_FLAT => 0x100,
|
|
482
493
|
:MH_NOMULTIDEFS => 0x200,
|
|
483
|
-
:
|
|
494
|
+
:MH_NOFIXPREBINDING => 0x400,
|
|
484
495
|
:MH_PREBINDABLE => 0x800,
|
|
485
496
|
:MH_ALLMODSBOUND => 0x1000,
|
|
486
497
|
:MH_SUBSECTIONS_VIA_SYMBOLS => 0x2000,
|
|
@@ -495,9 +506,10 @@ module MachO
|
|
|
495
506
|
:MH_DEAD_STRIPPABLE_DYLIB => 0x400000,
|
|
496
507
|
:MH_HAS_TLV_DESCRIPTORS => 0x800000,
|
|
497
508
|
:MH_NO_HEAP_EXECUTION => 0x1000000,
|
|
498
|
-
:MH_APP_EXTENSION_SAFE =>
|
|
499
|
-
:MH_NLIST_OUTOFSYNC_WITH_DYLDINFO =>
|
|
500
|
-
:MH_SIM_SUPPORT =>
|
|
509
|
+
:MH_APP_EXTENSION_SAFE => 0x2000000,
|
|
510
|
+
:MH_NLIST_OUTOFSYNC_WITH_DYLDINFO => 0x4000000,
|
|
511
|
+
:MH_SIM_SUPPORT => 0x8000000,
|
|
512
|
+
:MH_IMPLICIT_PAGEZERO => 0x10000000,
|
|
501
513
|
:MH_DYLIB_IN_CACHE => 0x80000000,
|
|
502
514
|
}.freeze
|
|
503
515
|
|
data/lib/macho/load_commands.rb
CHANGED
|
@@ -66,6 +66,10 @@ module MachO
|
|
|
66
66
|
(LC_REQ_DYLD | 0x34) => :LC_DYLD_CHAINED_FIXUPS,
|
|
67
67
|
(LC_REQ_DYLD | 0x35) => :LC_FILESET_ENTRY,
|
|
68
68
|
0x36 => :LC_ATOM_INFO,
|
|
69
|
+
0x37 => :LC_FUNCTION_VARIANTS,
|
|
70
|
+
0x38 => :LC_FUNCTION_VARIANT_FIXUPS,
|
|
71
|
+
0x39 => :LC_TARGET_TRIPLE,
|
|
72
|
+
0x3a => :LC_LAZY_LOAD_DYLIB_INFO,
|
|
69
73
|
}.freeze
|
|
70
74
|
|
|
71
75
|
# association of symbol representations to load command constants
|
|
@@ -88,6 +92,7 @@ module MachO
|
|
|
88
92
|
LC_ID_DYLIB
|
|
89
93
|
LC_RPATH
|
|
90
94
|
LC_LOAD_DYLINKER
|
|
95
|
+
LC_CODE_SIGNATURE
|
|
91
96
|
].freeze
|
|
92
97
|
|
|
93
98
|
# association of load command symbols to string representations of classes
|
|
@@ -155,6 +160,10 @@ module MachO
|
|
|
155
160
|
:LC_DYLD_CHAINED_FIXUPS => "LinkeditDataCommand",
|
|
156
161
|
:LC_FILESET_ENTRY => "FilesetEntryCommand",
|
|
157
162
|
:LC_ATOM_INFO => "LinkeditDataCommand",
|
|
163
|
+
:LC_FUNCTION_VARIANTS => "LinkeditDataCommand",
|
|
164
|
+
:LC_FUNCTION_VARIANT_FIXUPS => "LinkeditDataCommand",
|
|
165
|
+
:LC_TARGET_TRIPLE => "TargetTripleCommand",
|
|
166
|
+
:LC_LAZY_LOAD_DYLIB_INFO => "LinkeditDataCommand",
|
|
158
167
|
}.freeze
|
|
159
168
|
|
|
160
169
|
# association of segment name symbols to names
|
|
@@ -324,6 +333,8 @@ module MachO
|
|
|
324
333
|
view = lc.view
|
|
325
334
|
|
|
326
335
|
if view
|
|
336
|
+
raise LCStrMalformedError, lc if lc_str < lc.class.bytesize || lc_str >= lc.cmdsize
|
|
337
|
+
|
|
327
338
|
lc_str_abs = view.offset + lc_str
|
|
328
339
|
lc_end = view.offset + lc.cmdsize - 1
|
|
329
340
|
raw_string = view.raw_data.slice(lc_str_abs..lc_end)
|
|
@@ -488,7 +499,7 @@ module MachO
|
|
|
488
499
|
align = 0
|
|
489
500
|
segalign = 1
|
|
490
501
|
|
|
491
|
-
while (
|
|
502
|
+
while segalign.nobits?(vmaddr)
|
|
492
503
|
segalign <<= 1
|
|
493
504
|
align += 1
|
|
494
505
|
end
|
|
@@ -610,7 +621,7 @@ module MachO
|
|
|
610
621
|
|
|
611
622
|
if dylib_command.timestamp == DYLIB_USE_MARKER &&
|
|
612
623
|
dylib_command.name.to_i == DylibUseCommand.bytesize
|
|
613
|
-
super
|
|
624
|
+
super
|
|
614
625
|
else
|
|
615
626
|
dylib_command
|
|
616
627
|
end
|
|
@@ -1053,11 +1064,26 @@ module MachO
|
|
|
1053
1064
|
end
|
|
1054
1065
|
end
|
|
1055
1066
|
|
|
1067
|
+
# A load command containing the target triple used when compiling the binary.
|
|
1068
|
+
# Corresponds to LC_TARGET_TRIPLE.
|
|
1069
|
+
class TargetTripleCommand < LoadCommand
|
|
1070
|
+
# @return [LCStr] the target triple used when compiling the binary
|
|
1071
|
+
field :triple, :lcstr, :to_s => true
|
|
1072
|
+
|
|
1073
|
+
# @return [Hash] a hash representation of this {TargetTripleCommand}
|
|
1074
|
+
def to_h
|
|
1075
|
+
{
|
|
1076
|
+
"triple" => triple.to_h,
|
|
1077
|
+
}.merge super
|
|
1078
|
+
end
|
|
1079
|
+
end
|
|
1080
|
+
|
|
1056
1081
|
# A load command representing the offsets and sizes of a blob of data in
|
|
1057
1082
|
# the __LINKEDIT segment. Corresponds to LC_CODE_SIGNATURE,
|
|
1058
1083
|
# LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE,
|
|
1059
1084
|
# LC_DYLIB_CODE_SIGN_DRS, LC_LINKER_OPTIMIZATION_HINT, LC_DYLD_EXPORTS_TRIE,
|
|
1060
|
-
# LC_DYLD_CHAINED_FIXUPS,
|
|
1085
|
+
# LC_DYLD_CHAINED_FIXUPS, LC_ATOM_INFO, LC_FUNCTION_VARIANTS,
|
|
1086
|
+
# LC_FUNCTION_VARIANT_FIXUPS, or LC_LAZY_LOAD_DYLIB_INFO.
|
|
1061
1087
|
class LinkeditDataCommand < LoadCommand
|
|
1062
1088
|
# @return [Integer] offset to the data in the __LINKEDIT segment
|
|
1063
1089
|
field :dataoff, :uint32
|
|
@@ -1065,6 +1091,25 @@ module MachO
|
|
|
1065
1091
|
# @return [Integer] size of the data in the __LINKEDIT segment
|
|
1066
1092
|
field :datasize, :uint32
|
|
1067
1093
|
|
|
1094
|
+
# @param context [SerializationContext] the context
|
|
1095
|
+
# @return [String] the serialized fields of the load command
|
|
1096
|
+
# @api private
|
|
1097
|
+
def serialize(context)
|
|
1098
|
+
raise LoadCommandNotSerializableError, type unless serializable?
|
|
1099
|
+
|
|
1100
|
+
format = Utils.specialize_format(self.class.format, context.endianness)
|
|
1101
|
+
[cmd, self.class.bytesize, dataoff, datasize].pack(format)
|
|
1102
|
+
end
|
|
1103
|
+
|
|
1104
|
+
# The embedded signature referenced by this command.
|
|
1105
|
+
# @return [CodeSigning::SuperBlob]
|
|
1106
|
+
# @raise [CodeSigningError] if this is not an LC_CODE_SIGNATURE command
|
|
1107
|
+
def superblob
|
|
1108
|
+
raise CodeSigningError, "#{type} does not contain a code signature" unless type == :LC_CODE_SIGNATURE
|
|
1109
|
+
|
|
1110
|
+
CodeSigning::SuperBlob.new(view.raw_data.byteslice(dataoff, datasize))
|
|
1111
|
+
end
|
|
1112
|
+
|
|
1068
1113
|
# @return [Hash] a hash representation of this {LinkeditDataCommand}
|
|
1069
1114
|
def to_h
|
|
1070
1115
|
{
|