ruby-macho 1.3.0.pre.1 → 1.3.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/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
|