ruby-macho 1.3.0.pre.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/macho.rb +11 -11
- data/lib/macho/exceptions.rb +10 -0
- data/lib/macho/fat_file.rb +52 -16
- data/lib/macho/headers.rb +73 -6
- data/lib/macho/load_commands.rb +25 -0
- data/lib/macho/macho_file.rb +29 -2
- data/lib/macho/sections.rb +6 -0
- data/lib/macho/tools.rb +3 -2
- data/lib/macho/utils.rb +30 -6
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 644d3e65c34cd64ddcba05a186fa28caa4032adb7ca7c4022e485f5d2a5bb399
|
4
|
+
data.tar.gz: 6835b176571ab230e171080c418a4f2873be9af58b47ebd1a316e8e219119222
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d4e29aaa92deb1128369c0f5368b6832d9c1068a89c5d1e35951ca17dc068806fc7674064dcf603ba3b6ba66a1e7b57189cb9589bbd53f74b7df4602d7726926
|
7
|
+
data.tar.gz: '0838f24f7b496660ce71eb06b1167c65f8c8b551ae6b6f223ec1518664d43bb8c1bdc0803e605ff93319c07ca2c8088a80aad1d2f397c9019c7fc067bae6c3d6'
|
data/lib/macho.rb
CHANGED
@@ -1,18 +1,18 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
1
|
+
require_relative "macho/structure"
|
2
|
+
require_relative "macho/view"
|
3
|
+
require_relative "macho/headers"
|
4
|
+
require_relative "macho/load_commands"
|
5
|
+
require_relative "macho/sections"
|
6
|
+
require_relative "macho/macho_file"
|
7
|
+
require_relative "macho/fat_file"
|
8
|
+
require_relative "macho/exceptions"
|
9
|
+
require_relative "macho/utils"
|
10
|
+
require_relative "macho/tools"
|
11
11
|
|
12
12
|
# The primary namespace for ruby-macho.
|
13
13
|
module MachO
|
14
14
|
# release version
|
15
|
-
VERSION = "1.3.0
|
15
|
+
VERSION = "1.3.0".freeze
|
16
16
|
|
17
17
|
# Opens the given filename as a MachOFile or FatFile, depending on its magic.
|
18
18
|
# @param filename [String] the file being opened
|
data/lib/macho/exceptions.rb
CHANGED
@@ -194,4 +194,14 @@ module MachO
|
|
194
194
|
super "Unimplemented: #{thing}"
|
195
195
|
end
|
196
196
|
end
|
197
|
+
|
198
|
+
# Raised when attempting to create a {FatFile} from one or more {MachOFile}s
|
199
|
+
# whose offsets will not fit within the resulting 32-bit {Headers::FatArch#offset} fields.
|
200
|
+
class FatArchOffsetOverflowError < MachOError
|
201
|
+
# @param offset [Integer] the offending offset
|
202
|
+
def initialize(offset)
|
203
|
+
super "Offset #{offset} exceeds the 32-bit width of a fat_arch offset." \
|
204
|
+
" Consider merging with `fat64: true`"
|
205
|
+
end
|
206
|
+
end
|
197
207
|
end
|
data/lib/macho/fat_file.rb
CHANGED
@@ -14,7 +14,7 @@ module MachO
|
|
14
14
|
# @return [Headers::FatHeader] the file's header
|
15
15
|
attr_reader :header
|
16
16
|
|
17
|
-
# @return [Array<Headers::FatArch
|
17
|
+
# @return [Array<Headers::FatArch>, Array<Headers::FatArch64] an array of fat architectures
|
18
18
|
attr_reader :fat_archs
|
19
19
|
|
20
20
|
# @return [Array<MachOFile>] an array of Mach-O binaries
|
@@ -22,22 +22,54 @@ module MachO
|
|
22
22
|
|
23
23
|
# Creates a new FatFile from the given (single-arch) Mach-Os
|
24
24
|
# @param machos [Array<MachOFile>] the machos to combine
|
25
|
+
# @param fat64 [Boolean] whether to use {Headers::FatArch64}s to represent each slice
|
25
26
|
# @return [FatFile] a new FatFile containing the give machos
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
# @raise [ArgumentError] if less than one Mach-O is given
|
28
|
+
# @raise [FatArchOffsetOverflowError] if the Mach-Os are too big to be represented
|
29
|
+
# in a 32-bit {Headers::FatArch} and `fat64` is `false`.
|
30
|
+
def self.new_from_machos(*machos, fat64: false)
|
31
|
+
raise ArgumentError, "expected at least one Mach-O" if machos.empty?
|
32
|
+
|
33
|
+
fa_klass, magic = if fat64
|
34
|
+
[Headers::FatArch64, Headers::FAT_MAGIC_64]
|
35
|
+
else
|
36
|
+
[Headers::FatArch, Headers::FAT_MAGIC]
|
37
|
+
end
|
38
|
+
|
39
|
+
# put the smaller alignments further forwards in fat macho, so that we do less padding
|
40
|
+
machos = machos.sort_by(&:segment_alignment)
|
41
|
+
|
42
|
+
bin = if String.instance_methods.include? :+@
|
43
|
+
+""
|
44
|
+
else
|
45
|
+
""
|
46
|
+
end
|
47
|
+
|
48
|
+
bin << Headers::FatHeader.new(magic, machos.size).serialize
|
49
|
+
offset = Headers::FatHeader.bytesize + (machos.size * fa_klass.bytesize)
|
50
|
+
|
51
|
+
macho_pads = {}
|
52
|
+
|
30
53
|
machos.each do |macho|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
54
|
+
macho_offset = Utils.round(offset, 2**macho.segment_alignment)
|
55
|
+
|
56
|
+
if !fat64 && macho_offset > (2**32 - 1)
|
57
|
+
raise FatArchOffsetOverflowError, macho_offset
|
58
|
+
end
|
59
|
+
|
60
|
+
macho_pads[macho] = Utils.padding_for(offset, 2**macho.segment_alignment)
|
61
|
+
|
62
|
+
bin << fa_klass.new(macho.header.cputype, macho.header.cpusubtype,
|
63
|
+
macho_offset, macho.serialize.bytesize,
|
64
|
+
macho.segment_alignment).serialize
|
65
|
+
|
66
|
+
offset += (macho.serialize.bytesize + macho_pads[macho])
|
36
67
|
end
|
37
68
|
|
38
|
-
|
39
|
-
|
40
|
-
|
69
|
+
machos.each do |macho|
|
70
|
+
bin << Utils.nullpad(macho_pads[macho])
|
71
|
+
bin << macho.serialize
|
72
|
+
end
|
41
73
|
|
42
74
|
new_from_bin(bin)
|
43
75
|
end
|
@@ -262,6 +294,7 @@ module MachO
|
|
262
294
|
# @note Overwrites all data in the file!
|
263
295
|
def write!
|
264
296
|
raise MachOError, "no initial file to write to" if filename.nil?
|
297
|
+
|
265
298
|
File.open(@filename, "wb") { |f| f.write(@raw_data) }
|
266
299
|
end
|
267
300
|
|
@@ -311,10 +344,12 @@ module MachO
|
|
311
344
|
def populate_fat_archs
|
312
345
|
archs = []
|
313
346
|
|
314
|
-
|
315
|
-
|
347
|
+
fa_klass = Utils.fat_magic32?(header.magic) ? Headers::FatArch : Headers::FatArch64
|
348
|
+
fa_off = Headers::FatHeader.bytesize
|
349
|
+
fa_len = fa_klass.bytesize
|
350
|
+
|
316
351
|
header.nfat_arch.times do |i|
|
317
|
-
archs <<
|
352
|
+
archs << fa_klass.new_from_bin(:big, @raw_data[fa_off + (fa_len * i), fa_len])
|
318
353
|
end
|
319
354
|
|
320
355
|
archs
|
@@ -364,6 +399,7 @@ module MachO
|
|
364
399
|
|
365
400
|
# Strict mode: Immediately re-raise. Otherwise: Retain, check later.
|
366
401
|
raise error if strict
|
402
|
+
|
367
403
|
errors << error
|
368
404
|
end
|
369
405
|
end
|
data/lib/macho/headers.rb
CHANGED
@@ -6,11 +6,19 @@ module MachO
|
|
6
6
|
FAT_MAGIC = 0xcafebabe
|
7
7
|
|
8
8
|
# little-endian fat magic
|
9
|
-
#
|
10
|
-
# fat headers are always big-endian
|
9
|
+
# @note This is defined for completeness, but should never appear in ruby-macho code,
|
10
|
+
# since fat headers are always big-endian.
|
11
11
|
# @api private
|
12
12
|
FAT_CIGAM = 0xbebafeca
|
13
13
|
|
14
|
+
# 64-bit big-endian fat magic
|
15
|
+
FAT_MAGIC_64 = 0xcafebabf
|
16
|
+
|
17
|
+
# 64-bit little-endian fat magic
|
18
|
+
# @note This is defined for completeness, but should never appear in ruby-macho code,
|
19
|
+
# since fat headers are always big-endian.
|
20
|
+
FAT_CIGAM_64 = 0xbfbafeca
|
21
|
+
|
14
22
|
# 32-bit big-endian magic
|
15
23
|
# @api private
|
16
24
|
MH_MAGIC = 0xfeedface
|
@@ -31,6 +39,7 @@ module MachO
|
|
31
39
|
# @api private
|
32
40
|
MH_MAGICS = {
|
33
41
|
FAT_MAGIC => "FAT_MAGIC",
|
42
|
+
FAT_MAGIC_64 => "FAT_MAGIC_64",
|
34
43
|
MH_MAGIC => "MH_MAGIC",
|
35
44
|
MH_CIGAM => "MH_CIGAM",
|
36
45
|
MH_MAGIC_64 => "MH_MAGIC_64",
|
@@ -41,6 +50,11 @@ module MachO
|
|
41
50
|
# @api private
|
42
51
|
CPU_ARCH_ABI64 = 0x01000000
|
43
52
|
|
53
|
+
# mask for CPUs with 64-bit architectures (when running a 32-bit ABI?)
|
54
|
+
# @see https://github.com/Homebrew/ruby-macho/issues/113
|
55
|
+
# @api private
|
56
|
+
CPU_ARCH_ABI32 = 0x02000000
|
57
|
+
|
44
58
|
# any CPU (unused?)
|
45
59
|
# @api private
|
46
60
|
CPU_TYPE_ANY = -1
|
@@ -69,6 +83,10 @@ module MachO
|
|
69
83
|
# @api private
|
70
84
|
CPU_TYPE_ARM64 = (CPU_TYPE_ARM | CPU_ARCH_ABI64)
|
71
85
|
|
86
|
+
# 64-bit ARM compatible CPUs (running in 32-bit mode?)
|
87
|
+
# @see https://github.com/Homebrew/ruby-macho/issues/113
|
88
|
+
CPU_TYPE_ARM64_32 = (CPU_TYPE_ARM | CPU_ARCH_ABI32)
|
89
|
+
|
72
90
|
# PowerPC compatible CPUs
|
73
91
|
# @api private
|
74
92
|
CPU_TYPE_POWERPC = 0x12
|
@@ -85,6 +103,7 @@ module MachO
|
|
85
103
|
CPU_TYPE_X86_64 => :x86_64,
|
86
104
|
CPU_TYPE_ARM => :arm,
|
87
105
|
CPU_TYPE_ARM64 => :arm64,
|
106
|
+
CPU_TYPE_ARM64_32 => :arm64_32,
|
88
107
|
CPU_TYPE_POWERPC => :ppc,
|
89
108
|
CPU_TYPE_POWERPC64 => :ppc64,
|
90
109
|
}.freeze
|
@@ -218,6 +237,10 @@ module MachO
|
|
218
237
|
# @api private
|
219
238
|
CPU_SUBTYPE_ARM64_V8 = 1
|
220
239
|
|
240
|
+
# the v8 sub-type for `CPU_TYPE_ARM64_32`
|
241
|
+
# @api private
|
242
|
+
CPU_SUBTYPE_ARM64_32_V8 = 1
|
243
|
+
|
221
244
|
# the lowest common sub-type for `CPU_TYPE_MC88000`
|
222
245
|
# @api private
|
223
246
|
CPU_SUBTYPE_MC88000_ALL = 0
|
@@ -328,6 +351,9 @@ module MachO
|
|
328
351
|
CPU_SUBTYPE_ARM64_ALL => :arm64,
|
329
352
|
CPU_SUBTYPE_ARM64_V8 => :arm64v8,
|
330
353
|
}.freeze,
|
354
|
+
CPU_TYPE_ARM64_32 => {
|
355
|
+
CPU_SUBTYPE_ARM64_32_V8 => :arm64_32v8,
|
356
|
+
}.freeze,
|
331
357
|
CPU_TYPE_POWERPC => {
|
332
358
|
CPU_SUBTYPE_POWERPC_ALL => :ppc,
|
333
359
|
CPU_SUBTYPE_POWERPC_601 => :ppc601,
|
@@ -486,8 +512,10 @@ module MachO
|
|
486
512
|
end
|
487
513
|
end
|
488
514
|
|
489
|
-
#
|
490
|
-
#
|
515
|
+
# 32-bit fat binary header architecture structure. A 32-bit fat Mach-O has one or more of
|
516
|
+
# these, indicating one or more internal Mach-O blobs.
|
517
|
+
# @note "32-bit" indicates the fact that this structure stores 32-bit offsets, not that the
|
518
|
+
# Mach-Os that it points to necessarily *are* 32-bit.
|
491
519
|
# @see MachO::Headers::FatHeader
|
492
520
|
class FatArch < MachOStructure
|
493
521
|
# @return [Integer] the CPU type of the Mach-O
|
@@ -505,10 +533,10 @@ module MachO
|
|
505
533
|
# @return [Integer] the alignment, as a power of 2
|
506
534
|
attr_reader :align
|
507
535
|
|
508
|
-
#
|
536
|
+
# @note Always big endian.
|
509
537
|
# @see MachOStructure::FORMAT
|
510
538
|
# @api private
|
511
|
-
FORMAT = "
|
539
|
+
FORMAT = "L>5".freeze
|
512
540
|
|
513
541
|
# @see MachOStructure::SIZEOF
|
514
542
|
# @api private
|
@@ -542,6 +570,43 @@ module MachO
|
|
542
570
|
end
|
543
571
|
end
|
544
572
|
|
573
|
+
# 64-bit fat binary header architecture structure. A 64-bit fat Mach-O has one or more of
|
574
|
+
# these, indicating one or more internal Mach-O blobs.
|
575
|
+
# @note "64-bit" indicates the fact that this structure stores 64-bit offsets, not that the
|
576
|
+
# Mach-Os that it points to necessarily *are* 64-bit.
|
577
|
+
# @see MachO::Headers::FatHeader
|
578
|
+
class FatArch64 < FatArch
|
579
|
+
# @return [void]
|
580
|
+
attr_reader :reserved
|
581
|
+
|
582
|
+
# @note Always big endian.
|
583
|
+
# @see MachOStructure::FORMAT
|
584
|
+
# @api private
|
585
|
+
FORMAT = "L>2Q>2L>2".freeze
|
586
|
+
|
587
|
+
# @see MachOStructure::SIZEOF
|
588
|
+
# @api private
|
589
|
+
SIZEOF = 32
|
590
|
+
|
591
|
+
# @api private
|
592
|
+
def initialize(cputype, cpusubtype, offset, size, align, reserved = 0)
|
593
|
+
super(cputype, cpusubtype, offset, size, align)
|
594
|
+
@reserved = reserved
|
595
|
+
end
|
596
|
+
|
597
|
+
# @return [String] the serialized fields of the fat arch
|
598
|
+
def serialize
|
599
|
+
[cputype, cpusubtype, offset, size, align, reserved].pack(FORMAT)
|
600
|
+
end
|
601
|
+
|
602
|
+
# @return [Hash] a hash representation of this {FatArch64}
|
603
|
+
def to_h
|
604
|
+
{
|
605
|
+
"reserved" => reserved,
|
606
|
+
}.merge super
|
607
|
+
end
|
608
|
+
end
|
609
|
+
|
545
610
|
# 32-bit Mach-O file header structure
|
546
611
|
class MachHeader < MachOStructure
|
547
612
|
# @return [Integer] the magic number
|
@@ -593,7 +658,9 @@ module MachO
|
|
593
658
|
# @return [Boolean] true if `flag` is present in the header's flag section
|
594
659
|
def flag?(flag)
|
595
660
|
flag = MH_FLAGS[flag]
|
661
|
+
|
596
662
|
return false if flag.nil?
|
663
|
+
|
597
664
|
flags & flag == flag
|
598
665
|
end
|
599
666
|
|
data/lib/macho/load_commands.rb
CHANGED
@@ -242,6 +242,7 @@ module MachO
|
|
242
242
|
# @api private
|
243
243
|
def serialize(context)
|
244
244
|
raise LoadCommandNotSerializableError, LOAD_COMMANDS[cmd] unless serializable?
|
245
|
+
|
245
246
|
format = Utils.specialize_format(FORMAT, context.endianness)
|
246
247
|
[cmd, SIZEOF].pack(format)
|
247
248
|
end
|
@@ -298,7 +299,9 @@ module MachO
|
|
298
299
|
lc_end = view.offset + lc.cmdsize - 1
|
299
300
|
raw_string = view.raw_data.slice(lc_str_abs..lc_end)
|
300
301
|
@string, null_byte, _padding = raw_string.partition("\x00")
|
302
|
+
|
301
303
|
raise LCStrMalformedError, lc if null_byte.empty?
|
304
|
+
|
302
305
|
@string_offset = lc_str
|
303
306
|
else
|
304
307
|
@string = lc_str
|
@@ -473,10 +476,32 @@ module MachO
|
|
473
476
|
# @return [Boolean] true if `flag` is present in the segment's flag field
|
474
477
|
def flag?(flag)
|
475
478
|
flag = SEGMENT_FLAGS[flag]
|
479
|
+
|
476
480
|
return false if flag.nil?
|
481
|
+
|
477
482
|
flags & flag == flag
|
478
483
|
end
|
479
484
|
|
485
|
+
# Guesses the alignment of the segment.
|
486
|
+
# @return [Integer] the guessed alignment, as a power of 2
|
487
|
+
# @note See `guess_align` in `cctools/misc/lipo.c`
|
488
|
+
def guess_align
|
489
|
+
return Sections::MAX_SECT_ALIGN if vmaddr.zero?
|
490
|
+
|
491
|
+
align = 0
|
492
|
+
segalign = 1
|
493
|
+
|
494
|
+
while (segalign & vmaddr).zero?
|
495
|
+
segalign <<= 1
|
496
|
+
align += 1
|
497
|
+
end
|
498
|
+
|
499
|
+
return 2 if align < 2
|
500
|
+
return Sections::MAX_SECT_ALIGN if align > Sections::MAX_SECT_ALIGN
|
501
|
+
|
502
|
+
align
|
503
|
+
end
|
504
|
+
|
480
505
|
# @return [Hash] a hash representation of this {SegmentCommand}
|
481
506
|
def to_h
|
482
507
|
{
|
data/lib/macho/macho_file.rb
CHANGED
@@ -219,8 +219,7 @@ module MachO
|
|
219
219
|
update_sizeofcmds(sizeofcmds - lc.cmdsize)
|
220
220
|
|
221
221
|
# pad the space after the load commands to preserve offsets
|
222
|
-
|
223
|
-
@raw_data.insert(header.class.bytesize + sizeofcmds - lc.cmdsize, null_pad)
|
222
|
+
@raw_data.insert(header.class.bytesize + sizeofcmds - lc.cmdsize, Utils.nullpad(lc.cmdsize))
|
224
223
|
|
225
224
|
populate_fields if options.fetch(:repopulate, true)
|
226
225
|
end
|
@@ -252,6 +251,33 @@ module MachO
|
|
252
251
|
end
|
253
252
|
end
|
254
253
|
|
254
|
+
# The segment alignment for the Mach-O. Guesses conservatively.
|
255
|
+
# @return [Integer] the alignment, as a power of 2
|
256
|
+
# @note This is **not** the same as {#alignment}!
|
257
|
+
# @note See `get_align` and `get_align_64` in `cctools/misc/lipo.c`
|
258
|
+
def segment_alignment
|
259
|
+
# special cases: 12 for x86/64/PPC/PP64, 14 for ARM/ARM64
|
260
|
+
return 12 if %i[i386 x86_64 ppc ppc64].include?(cputype)
|
261
|
+
return 14 if %i[arm arm64].include?(cputype)
|
262
|
+
|
263
|
+
cur_align = Sections::MAX_SECT_ALIGN
|
264
|
+
|
265
|
+
segments.each do |segment|
|
266
|
+
if filetype == :object
|
267
|
+
# start with the smallest alignment, and work our way up
|
268
|
+
align = magic32? ? 2 : 3
|
269
|
+
segment.sections.each do |section|
|
270
|
+
align = section.align unless section.align <= align
|
271
|
+
end
|
272
|
+
else
|
273
|
+
align = segment.guess_align
|
274
|
+
end
|
275
|
+
cur_align = align if align < cur_align
|
276
|
+
end
|
277
|
+
|
278
|
+
cur_align
|
279
|
+
end
|
280
|
+
|
255
281
|
# The Mach-O's dylib ID, or `nil` if not a dylib.
|
256
282
|
# @example
|
257
283
|
# file.dylib_id # => 'libBar.dylib'
|
@@ -405,6 +431,7 @@ module MachO
|
|
405
431
|
# @note Overwrites all data in the file!
|
406
432
|
def write!
|
407
433
|
raise MachOError, "no initial file to write to" if @filename.nil?
|
434
|
+
|
408
435
|
File.open(@filename, "wb") { |f| f.write(@raw_data) }
|
409
436
|
end
|
410
437
|
|
data/lib/macho/sections.rb
CHANGED
@@ -13,6 +13,10 @@ module MachO
|
|
13
13
|
# system settable attributes mask
|
14
14
|
SECTION_ATTRIBUTES_SYS = 0x00ffff00
|
15
15
|
|
16
|
+
# maximum specifiable section alignment, as a power of 2
|
17
|
+
# @note see `MAXSECTALIGN` macro in `cctools/misc/lipo.c`
|
18
|
+
MAX_SECT_ALIGN = 15
|
19
|
+
|
16
20
|
# association of section flag symbols to values
|
17
21
|
# @api private
|
18
22
|
SECTION_FLAGS = {
|
@@ -146,7 +150,9 @@ module MachO
|
|
146
150
|
# @return [Boolean] whether the flag is present in the section's {flags}
|
147
151
|
def flag?(flag)
|
148
152
|
flag = SECTION_FLAGS[flag]
|
153
|
+
|
149
154
|
return false if flag.nil?
|
155
|
+
|
150
156
|
flags & flag == flag
|
151
157
|
end
|
152
158
|
|
data/lib/macho/tools.rb
CHANGED
@@ -89,8 +89,9 @@ module MachO
|
|
89
89
|
# Merge multiple Mach-Os into one universal (Fat) binary.
|
90
90
|
# @param filename [String] the fat binary to create
|
91
91
|
# @param files [Array<String>] the files to merge
|
92
|
+
# @param fat64 [Boolean] whether to use {Headers::FatArch64}s to represent each slice
|
92
93
|
# @return [void]
|
93
|
-
def self.merge_machos(filename, *files)
|
94
|
+
def self.merge_machos(filename, *files, fat64: false)
|
94
95
|
machos = files.map do |file|
|
95
96
|
macho = MachO.open(file)
|
96
97
|
case macho
|
@@ -101,7 +102,7 @@ module MachO
|
|
101
102
|
end
|
102
103
|
end.flatten
|
103
104
|
|
104
|
-
fat_macho = MachO::FatFile.new_from_machos(*machos)
|
105
|
+
fat_macho = MachO::FatFile.new_from_machos(*machos, :fat64 => fat64)
|
105
106
|
fat_macho.write(filename)
|
106
107
|
end
|
107
108
|
end
|
data/lib/macho/utils.rb
CHANGED
@@ -22,6 +22,16 @@ module MachO
|
|
22
22
|
round(size, alignment) - size
|
23
23
|
end
|
24
24
|
|
25
|
+
# Returns a string of null bytes of the requested (non-negative) size
|
26
|
+
# @param size [Integer] the size of the nullpad
|
27
|
+
# @return [String] the null string (or empty string, for `size = 0`)
|
28
|
+
# @raise [ArgumentError] if a non-positive nullpad is requested
|
29
|
+
def self.nullpad(size)
|
30
|
+
raise ArgumentError, "size < 0: #{size}" if size < 0
|
31
|
+
|
32
|
+
"\x00" * size
|
33
|
+
end
|
34
|
+
|
25
35
|
# Converts an abstract (native-endian) String#unpack format to big or
|
26
36
|
# little.
|
27
37
|
# @param format [String] the format string being converted
|
@@ -46,11 +56,11 @@ module MachO
|
|
46
56
|
strings.each do |key, string|
|
47
57
|
offsets[key] = next_offset
|
48
58
|
payload << string
|
49
|
-
payload <<
|
59
|
+
payload << Utils.nullpad(1)
|
50
60
|
next_offset += string.bytesize + 1
|
51
61
|
end
|
52
62
|
|
53
|
-
payload <<
|
63
|
+
payload << Utils.nullpad(padding_for(fixed_offset + payload.bytesize, alignment))
|
54
64
|
[payload, offsets]
|
55
65
|
end
|
56
66
|
|
@@ -65,35 +75,49 @@ module MachO
|
|
65
75
|
# @param num [Integer] the number being checked
|
66
76
|
# @return [Boolean] whether `num` is a valid Fat magic number
|
67
77
|
def self.fat_magic?(num)
|
78
|
+
[Headers::FAT_MAGIC, Headers::FAT_MAGIC_64].include? num
|
79
|
+
end
|
80
|
+
|
81
|
+
# Compares the given number to valid 32-bit Fat magic numbers.
|
82
|
+
# @param num [Integer] the number being checked
|
83
|
+
# @return [Boolean] whether `num` is a valid 32-bit fat magic number
|
84
|
+
def self.fat_magic32?(num)
|
68
85
|
num == Headers::FAT_MAGIC
|
69
86
|
end
|
70
87
|
|
88
|
+
# Compares the given number to valid 64-bit Fat magic numbers.
|
89
|
+
# @param num [Integer] the number being checked
|
90
|
+
# @return [Boolean] whether `num` is a valid 64-bit fat magic number
|
91
|
+
def self.fat_magic64?(num)
|
92
|
+
num == Headers::FAT_MAGIC_64
|
93
|
+
end
|
94
|
+
|
71
95
|
# Compares the given number to valid 32-bit Mach-O magic numbers.
|
72
96
|
# @param num [Integer] the number being checked
|
73
97
|
# @return [Boolean] whether `num` is a valid 32-bit magic number
|
74
98
|
def self.magic32?(num)
|
75
|
-
|
99
|
+
[Headers::MH_MAGIC, Headers::MH_CIGAM].include? num
|
76
100
|
end
|
77
101
|
|
78
102
|
# Compares the given number to valid 64-bit Mach-O magic numbers.
|
79
103
|
# @param num [Integer] the number being checked
|
80
104
|
# @return [Boolean] whether `num` is a valid 64-bit magic number
|
81
105
|
def self.magic64?(num)
|
82
|
-
|
106
|
+
[Headers::MH_MAGIC_64, Headers::MH_CIGAM_64].include? num
|
83
107
|
end
|
84
108
|
|
85
109
|
# Compares the given number to valid little-endian magic numbers.
|
86
110
|
# @param num [Integer] the number being checked
|
87
111
|
# @return [Boolean] whether `num` is a valid little-endian magic number
|
88
112
|
def self.little_magic?(num)
|
89
|
-
|
113
|
+
[Headers::MH_CIGAM, Headers::MH_CIGAM_64].include? num
|
90
114
|
end
|
91
115
|
|
92
116
|
# Compares the given number to valid big-endian magic numbers.
|
93
117
|
# @param num [Integer] the number being checked
|
94
118
|
# @return [Boolean] whether `num` is a valid big-endian magic number
|
95
119
|
def self.big_magic?(num)
|
96
|
-
|
120
|
+
[Headers::MH_MAGIC, Headers::MH_MAGIC_64].include? num
|
97
121
|
end
|
98
122
|
end
|
99
123
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-macho
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.0
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- William Woodruff
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-09-30 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A library for viewing and manipulating Mach-O files in Ruby.
|
14
14
|
email: william@yossarian.net
|
@@ -42,12 +42,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
42
42
|
requirements:
|
43
43
|
- - ">="
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
version: '2.
|
45
|
+
version: '2.3'
|
46
46
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
47
|
requirements:
|
48
|
-
- - "
|
48
|
+
- - ">="
|
49
49
|
- !ruby/object:Gem::Version
|
50
|
-
version:
|
50
|
+
version: '0'
|
51
51
|
requirements: []
|
52
52
|
rubyforge_project:
|
53
53
|
rubygems_version: 2.7.6
|