ruby-macho 1.4.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 50aeda7d9f7ac3c91c6e34a9d150ffbf79d89389cb591d06494fb0eb4e48023b
4
- data.tar.gz: e7f56ff39f7159c20572e66bd07b506e826152e8b1da3d78afe22f4e8516b4a9
3
+ metadata.gz: 6341c1a29aeae7169fea7f1e7fc11339331f21c2b07a3a19e7f68b5dd76af03d
4
+ data.tar.gz: 9b5dd29c4a03c18bf6261e20641c95c584958ee142d4d64a37f9db8352065727
5
5
  SHA512:
6
- metadata.gz: 2bb5bd7d605eb023b8cdf95446776507ddcfb08a7d30bc45acf3fff24d3b4edc5666b8c5f4801e226524ba60dad043a3c251819ff8b0cdd77e0e5b491a4a2e81
7
- data.tar.gz: a2d553f64c0e73882dcbce972bf8cdab7554c98f1c6daf2d504588e11d05d194ac417127d61a32f93263fa3487ab1655cf16867994018464c8d5a9f4df9b6073
6
+ metadata.gz: c3964af02f0b1abf51de625e1d69a8fd966c30d5bf93cfde410ac127fab57864ae6331441d2afa1acdd100c7187f5d05883ecd8736d88076507823b16627ab10
7
+ data.tar.gz: c5a8ec50db69dccef0161dd96d6b7f23a47713a0fb8551d1bae10afa2690ed6837b52f9f3f49bd0826610b7c7a1841fadda2d1c53f6ab91f118732e36a3a4bd7
@@ -12,7 +12,7 @@ require_relative "macho/tools"
12
12
  # The primary namespace for ruby-macho.
13
13
  module MachO
14
14
  # release version
15
- VERSION = "1.4.0".freeze
15
+ VERSION = "2.0.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
@@ -194,14 +194,4 @@ 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
207
197
  end
@@ -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>, Array<Headers::FatArch64] an array of fat architectures
17
+ # @return [Array<Headers::FatArch>] 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,53 +22,37 @@ 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
26
25
  # @return [FatFile] a new FatFile containing the give machos
27
26
  # @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)
27
+ def self.new_from_machos(*machos)
31
28
  raise ArgumentError, "expected at least one Mach-O" if machos.empty?
32
29
 
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
30
  # put the smaller alignments further forwards in fat macho, so that we do less padding
40
31
  machos = machos.sort_by(&:segment_alignment)
41
32
 
42
- bin = if String.instance_methods.include? :+@
43
- +""
44
- else
45
- ""
46
- end
33
+ bin = +""
47
34
 
48
- bin << Headers::FatHeader.new(magic, machos.size).serialize
49
- offset = Headers::FatHeader.bytesize + (machos.size * fa_klass.bytesize)
35
+ bin << Headers::FatHeader.new(Headers::FAT_MAGIC, machos.size).serialize
36
+ offset = Headers::FatHeader.bytesize + (machos.size * Headers::FatArch.bytesize)
50
37
 
51
38
  macho_pads = {}
39
+ macho_bins = {}
52
40
 
53
41
  machos.each do |macho|
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
-
42
+ macho_offset = Utils.round(offset, 2**macho.segment_alignment)
60
43
  macho_pads[macho] = Utils.padding_for(offset, 2**macho.segment_alignment)
44
+ macho_bins[macho] = macho.serialize
61
45
 
62
- bin << fa_klass.new(macho.header.cputype, macho.header.cpusubtype,
63
- macho_offset, macho.serialize.bytesize,
64
- macho.segment_alignment).serialize
46
+ bin << Headers::FatArch.new(macho.header.cputype, macho.header.cpusubtype,
47
+ macho_offset, macho_bins[macho].bytesize,
48
+ macho.segment_alignment).serialize
65
49
 
66
- offset += (macho.serialize.bytesize + macho_pads[macho])
50
+ offset += (macho_bins[macho].bytesize + macho_pads[macho])
67
51
  end
68
52
 
69
53
  machos.each do |macho|
70
54
  bin << Utils.nullpad(macho_pads[macho])
71
- bin << macho.serialize
55
+ bin << macho_bins[macho]
72
56
  end
73
57
 
74
58
  new_from_bin(bin)
@@ -294,7 +278,6 @@ module MachO
294
278
  # @note Overwrites all data in the file!
295
279
  def write!
296
280
  raise MachOError, "no initial file to write to" if filename.nil?
297
-
298
281
  File.open(@filename, "wb") { |f| f.write(@raw_data) }
299
282
  end
300
283
 
@@ -344,12 +327,10 @@ module MachO
344
327
  def populate_fat_archs
345
328
  archs = []
346
329
 
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
-
330
+ fa_off = Headers::FatHeader.bytesize
331
+ fa_len = Headers::FatArch.bytesize
351
332
  header.nfat_arch.times do |i|
352
- archs << fa_klass.new_from_bin(:big, @raw_data[fa_off + (fa_len * i), fa_len])
333
+ archs << Headers::FatArch.new_from_bin(:big, @raw_data[fa_off + (fa_len * i), fa_len])
353
334
  end
354
335
 
355
336
  archs
@@ -399,7 +380,6 @@ module MachO
399
380
 
400
381
  # Strict mode: Immediately re-raise. Otherwise: Retain, check later.
401
382
  raise error if strict
402
-
403
383
  errors << error
404
384
  end
405
385
  end
@@ -6,19 +6,11 @@ module MachO
6
6
  FAT_MAGIC = 0xcafebabe
7
7
 
8
8
  # little-endian fat magic
9
- # @note This is defined for completeness, but should never appear in ruby-macho code,
10
- # since fat headers are always big-endian.
9
+ # this is defined, but should never appear in ruby-macho code because
10
+ # fat headers are always big-endian and therefore always unpacked as such.
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
-
22
14
  # 32-bit big-endian magic
23
15
  # @api private
24
16
  MH_MAGIC = 0xfeedface
@@ -39,7 +31,6 @@ module MachO
39
31
  # @api private
40
32
  MH_MAGICS = {
41
33
  FAT_MAGIC => "FAT_MAGIC",
42
- FAT_MAGIC_64 => "FAT_MAGIC_64",
43
34
  MH_MAGIC => "MH_MAGIC",
44
35
  MH_CIGAM => "MH_CIGAM",
45
36
  MH_MAGIC_64 => "MH_MAGIC_64",
@@ -50,11 +41,6 @@ module MachO
50
41
  # @api private
51
42
  CPU_ARCH_ABI64 = 0x01000000
52
43
 
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
-
58
44
  # any CPU (unused?)
59
45
  # @api private
60
46
  CPU_TYPE_ANY = -1
@@ -83,10 +69,6 @@ module MachO
83
69
  # @api private
84
70
  CPU_TYPE_ARM64 = (CPU_TYPE_ARM | CPU_ARCH_ABI64)
85
71
 
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
-
90
72
  # PowerPC compatible CPUs
91
73
  # @api private
92
74
  CPU_TYPE_POWERPC = 0x12
@@ -103,7 +85,6 @@ module MachO
103
85
  CPU_TYPE_X86_64 => :x86_64,
104
86
  CPU_TYPE_ARM => :arm,
105
87
  CPU_TYPE_ARM64 => :arm64,
106
- CPU_TYPE_ARM64_32 => :arm64_32,
107
88
  CPU_TYPE_POWERPC => :ppc,
108
89
  CPU_TYPE_POWERPC64 => :ppc64,
109
90
  }.freeze
@@ -237,14 +218,6 @@ module MachO
237
218
  # @api private
238
219
  CPU_SUBTYPE_ARM64_V8 = 1
239
220
 
240
- # the v8 sub-type for `CPU_TYPE_ARM64_32`
241
- # @api private
242
- CPU_SUBTYPE_ARM64_32_V8 = 1
243
-
244
- # the e (A12) sub-type for `CPU_TYPE_ARM64`
245
- # @api private
246
- CPU_SUBTYPE_ARM64E = 2
247
-
248
221
  # the lowest common sub-type for `CPU_TYPE_MC88000`
249
222
  # @api private
250
223
  CPU_SUBTYPE_MC88000_ALL = 0
@@ -354,10 +327,6 @@ module MachO
354
327
  CPU_TYPE_ARM64 => {
355
328
  CPU_SUBTYPE_ARM64_ALL => :arm64,
356
329
  CPU_SUBTYPE_ARM64_V8 => :arm64v8,
357
- CPU_SUBTYPE_ARM64E => :arm64e,
358
- }.freeze,
359
- CPU_TYPE_ARM64_32 => {
360
- CPU_SUBTYPE_ARM64_32_V8 => :arm64_32v8,
361
330
  }.freeze,
362
331
  CPU_TYPE_POWERPC => {
363
332
  CPU_SUBTYPE_POWERPC_ALL => :ppc,
@@ -517,10 +486,8 @@ module MachO
517
486
  end
518
487
  end
519
488
 
520
- # 32-bit fat binary header architecture structure. A 32-bit fat Mach-O has one or more of
521
- # these, indicating one or more internal Mach-O blobs.
522
- # @note "32-bit" indicates the fact that this structure stores 32-bit offsets, not that the
523
- # Mach-Os that it points to necessarily *are* 32-bit.
489
+ # Fat binary header architecture structure. A Fat binary has one or more of
490
+ # these, representing one or more internal Mach-O blobs.
524
491
  # @see MachO::Headers::FatHeader
525
492
  class FatArch < MachOStructure
526
493
  # @return [Integer] the CPU type of the Mach-O
@@ -538,10 +505,10 @@ module MachO
538
505
  # @return [Integer] the alignment, as a power of 2
539
506
  attr_reader :align
540
507
 
541
- # @note Always big endian.
508
+ # always big-endian
542
509
  # @see MachOStructure::FORMAT
543
510
  # @api private
544
- FORMAT = "L>5".freeze
511
+ FORMAT = "N5".freeze
545
512
 
546
513
  # @see MachOStructure::SIZEOF
547
514
  # @api private
@@ -575,43 +542,6 @@ module MachO
575
542
  end
576
543
  end
577
544
 
578
- # 64-bit fat binary header architecture structure. A 64-bit fat Mach-O has one or more of
579
- # these, indicating one or more internal Mach-O blobs.
580
- # @note "64-bit" indicates the fact that this structure stores 64-bit offsets, not that the
581
- # Mach-Os that it points to necessarily *are* 64-bit.
582
- # @see MachO::Headers::FatHeader
583
- class FatArch64 < FatArch
584
- # @return [void]
585
- attr_reader :reserved
586
-
587
- # @note Always big endian.
588
- # @see MachOStructure::FORMAT
589
- # @api private
590
- FORMAT = "L>2Q>2L>2".freeze
591
-
592
- # @see MachOStructure::SIZEOF
593
- # @api private
594
- SIZEOF = 32
595
-
596
- # @api private
597
- def initialize(cputype, cpusubtype, offset, size, align, reserved = 0)
598
- super(cputype, cpusubtype, offset, size, align)
599
- @reserved = reserved
600
- end
601
-
602
- # @return [String] the serialized fields of the fat arch
603
- def serialize
604
- [cputype, cpusubtype, offset, size, align, reserved].pack(FORMAT)
605
- end
606
-
607
- # @return [Hash] a hash representation of this {FatArch64}
608
- def to_h
609
- {
610
- "reserved" => reserved,
611
- }.merge super
612
- end
613
- end
614
-
615
545
  # 32-bit Mach-O file header structure
616
546
  class MachHeader < MachOStructure
617
547
  # @return [Integer] the magic number
@@ -663,9 +593,7 @@ module MachO
663
593
  # @return [Boolean] true if `flag` is present in the header's flag section
664
594
  def flag?(flag)
665
595
  flag = MH_FLAGS[flag]
666
-
667
596
  return false if flag.nil?
668
-
669
597
  flags & flag == flag
670
598
  end
671
599
 
@@ -242,7 +242,6 @@ module MachO
242
242
  # @api private
243
243
  def serialize(context)
244
244
  raise LoadCommandNotSerializableError, LOAD_COMMANDS[cmd] unless serializable?
245
-
246
245
  format = Utils.specialize_format(FORMAT, context.endianness)
247
246
  [cmd, SIZEOF].pack(format)
248
247
  end
@@ -299,9 +298,7 @@ module MachO
299
298
  lc_end = view.offset + lc.cmdsize - 1
300
299
  raw_string = view.raw_data.slice(lc_str_abs..lc_end)
301
300
  @string, null_byte, _padding = raw_string.partition("\x00")
302
-
303
301
  raise LCStrMalformedError, lc if null_byte.empty?
304
-
305
302
  @string_offset = lc_str
306
303
  else
307
304
  @string = lc_str
@@ -476,9 +473,7 @@ module MachO
476
473
  # @return [Boolean] true if `flag` is present in the segment's flag field
477
474
  def flag?(flag)
478
475
  flag = SEGMENT_FLAGS[flag]
479
-
480
476
  return false if flag.nil?
481
-
482
477
  flags & flag == flag
483
478
  end
484
479
 
@@ -431,7 +431,6 @@ module MachO
431
431
  # @note Overwrites all data in the file!
432
432
  def write!
433
433
  raise MachOError, "no initial file to write to" if @filename.nil?
434
-
435
434
  File.open(@filename, "wb") { |f| f.write(@raw_data) }
436
435
  end
437
436
 
@@ -150,9 +150,7 @@ module MachO
150
150
  # @return [Boolean] whether the flag is present in the section's {flags}
151
151
  def flag?(flag)
152
152
  flag = SECTION_FLAGS[flag]
153
-
154
153
  return false if flag.nil?
155
-
156
154
  flags & flag == flag
157
155
  end
158
156
 
@@ -89,9 +89,8 @@ 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
93
92
  # @return [void]
94
- def self.merge_machos(filename, *files, fat64: false)
93
+ def self.merge_machos(filename, *files)
95
94
  machos = files.map do |file|
96
95
  macho = MachO.open(file)
97
96
  case macho
@@ -102,7 +101,7 @@ module MachO
102
101
  end
103
102
  end.flatten
104
103
 
105
- fat_macho = MachO::FatFile.new_from_machos(*machos, :fat64 => fat64)
104
+ fat_macho = MachO::FatFile.new_from_machos(*machos)
106
105
  fat_macho.write(filename)
107
106
  end
108
107
  end
@@ -27,7 +27,7 @@ module MachO
27
27
  # @return [String] the null string (or empty string, for `size = 0`)
28
28
  # @raise [ArgumentError] if a non-positive nullpad is requested
29
29
  def self.nullpad(size)
30
- raise ArgumentError, "size < 0: #{size}" if size < 0
30
+ raise ArgumentError, "size < 0: #{size}" if size.negative?
31
31
 
32
32
  "\x00" * size
33
33
  end
@@ -75,49 +75,35 @@ module MachO
75
75
  # @param num [Integer] the number being checked
76
76
  # @return [Boolean] whether `num` is a valid Fat magic number
77
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)
85
78
  num == Headers::FAT_MAGIC
86
79
  end
87
80
 
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
-
95
81
  # Compares the given number to valid 32-bit Mach-O magic numbers.
96
82
  # @param num [Integer] the number being checked
97
83
  # @return [Boolean] whether `num` is a valid 32-bit magic number
98
84
  def self.magic32?(num)
99
- [Headers::MH_MAGIC, Headers::MH_CIGAM].include? num
85
+ num == Headers::MH_MAGIC || num == Headers::MH_CIGAM
100
86
  end
101
87
 
102
88
  # Compares the given number to valid 64-bit Mach-O magic numbers.
103
89
  # @param num [Integer] the number being checked
104
90
  # @return [Boolean] whether `num` is a valid 64-bit magic number
105
91
  def self.magic64?(num)
106
- [Headers::MH_MAGIC_64, Headers::MH_CIGAM_64].include? num
92
+ num == Headers::MH_MAGIC_64 || num == Headers::MH_CIGAM_64
107
93
  end
108
94
 
109
95
  # Compares the given number to valid little-endian magic numbers.
110
96
  # @param num [Integer] the number being checked
111
97
  # @return [Boolean] whether `num` is a valid little-endian magic number
112
98
  def self.little_magic?(num)
113
- [Headers::MH_CIGAM, Headers::MH_CIGAM_64].include? num
99
+ num == Headers::MH_CIGAM || num == Headers::MH_CIGAM_64
114
100
  end
115
101
 
116
102
  # Compares the given number to valid big-endian magic numbers.
117
103
  # @param num [Integer] the number being checked
118
104
  # @return [Boolean] whether `num` is a valid big-endian magic number
119
105
  def self.big_magic?(num)
120
- [Headers::MH_MAGIC, Headers::MH_MAGIC_64].include? num
106
+ num == Headers::MH_CIGAM || num == Headers::MH_CIGAM_64
121
107
  end
122
108
  end
123
109
  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.4.0
4
+ version: 2.0.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: 2019-02-21 00:00:00.000000000 Z
11
+ date: 2018-07-03 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,14 +42,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
42
42
  requirements:
43
43
  - - ">="
44
44
  - !ruby/object:Gem::Version
45
- version: '2.0'
45
+ version: '2.1'
46
46
  required_rubygems_version: !ruby/object:Gem::Requirement
47
47
  requirements:
48
48
  - - ">="
49
49
  - !ruby/object:Gem::Version
50
50
  version: '0'
51
51
  requirements: []
52
- rubygems_version: 3.0.1
52
+ rubyforge_project:
53
+ rubygems_version: 2.7.6
53
54
  signing_key:
54
55
  specification_version: 4
55
56
  summary: ruby-macho - Mach-O file analyzer.