ruby-macho 1.3.1 → 2.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/README.md +8 -1
- data/lib/macho.rb +23 -2
- data/lib/macho/exceptions.rb +9 -7
- data/lib/macho/fat_file.rb +24 -18
- data/lib/macho/headers.rb +12 -5
- data/lib/macho/load_commands.rb +47 -40
- data/lib/macho/macho_file.rb +34 -21
- data/lib/macho/sections.rb +4 -2
- data/lib/macho/structure.rb +3 -1
- data/lib/macho/tools.rb +14 -0
- data/lib/macho/utils.rb +5 -3
- data/lib/macho/view.rb +2 -0
- metadata +4 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 73c21b87da2cf6cdac1c2123d846fa6fd8eb2863c4fe87d0170fa6162d110329
|
4
|
+
data.tar.gz: 0a59a2d38d59665eee474aad3f394aa54f1f2da5926c01b65824a75992da3e61
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac41936e243431a8346059b40e32fa6ed33c7f9f1f9dbbb9efcd7d1391d40931a6bdc33bf8fb5f676fb87af305cb92d18df9fe47151724cfb141996db47a2bd5
|
7
|
+
data.tar.gz: 4feeb4b940e38cb0fe641b28ae08dff26a17d213e6c8602442912ce59d7de756618adbd36feac62846ee1b8f0aa0bb2f0a765f5b74fe462b371954184eaa65bc
|
data/README.md
CHANGED
@@ -13,6 +13,14 @@ The [Mach-O file format](https://en.wikipedia.org/wiki/Mach-O) is used by macOS
|
|
13
13
|
and iOS (among others) as a general purpose binary format for object files,
|
14
14
|
executables, dynamic libraries, and so forth.
|
15
15
|
|
16
|
+
### Installation
|
17
|
+
|
18
|
+
ruby-macho can be installed via RubyGems:
|
19
|
+
|
20
|
+
```bash
|
21
|
+
$ gem install ruby-macho
|
22
|
+
```
|
23
|
+
|
16
24
|
### Documentation
|
17
25
|
|
18
26
|
Full documentation is available on [RubyDoc](http://www.rubydoc.info/gems/ruby-macho/).
|
@@ -46,7 +54,6 @@ puts lc_vers.version_string # => "10.10.0"
|
|
46
54
|
|
47
55
|
### What needs to be done?
|
48
56
|
|
49
|
-
* Documentation.
|
50
57
|
* Unit and performance testing.
|
51
58
|
|
52
59
|
Attribution:
|
data/lib/macho.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "English"
|
1
4
|
require_relative "macho/structure"
|
2
5
|
require_relative "macho/view"
|
3
6
|
require_relative "macho/headers"
|
@@ -12,7 +15,7 @@ require_relative "macho/tools"
|
|
12
15
|
# The primary namespace for ruby-macho.
|
13
16
|
module MachO
|
14
17
|
# release version
|
15
|
-
VERSION = "
|
18
|
+
VERSION = "2.3.0"
|
16
19
|
|
17
20
|
# Opens the given filename as a MachOFile or FatFile, depending on its magic.
|
18
21
|
# @param filename [String] the file being opened
|
@@ -25,7 +28,7 @@ module MachO
|
|
25
28
|
raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
|
26
29
|
raise TruncatedFileError unless File.stat(filename).size >= 4
|
27
30
|
|
28
|
-
magic = File.open(filename, "rb") { |f| f.read(4) }.
|
31
|
+
magic = File.open(filename, "rb") { |f| f.read(4) }.unpack1("N")
|
29
32
|
|
30
33
|
if Utils.fat_magic?(magic)
|
31
34
|
file = FatFile.new(filename)
|
@@ -37,4 +40,22 @@ module MachO
|
|
37
40
|
|
38
41
|
file
|
39
42
|
end
|
43
|
+
|
44
|
+
# Signs the dylib using an ad-hoc identity.
|
45
|
+
# Necessary after making any changes to a dylib, since otherwise
|
46
|
+
# changing a signed file invalidates its signature.
|
47
|
+
# @param filename [String] the file being opened
|
48
|
+
# @return [void]
|
49
|
+
# @raise [ModificationError] if the operation fails
|
50
|
+
def self.codesign!(filename)
|
51
|
+
# codesign binary is not available on Linux
|
52
|
+
return if RUBY_PLATFORM !~ /darwin/
|
53
|
+
raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
|
54
|
+
|
55
|
+
system("codesign", "--sign", "-", "--force",
|
56
|
+
"--preserve-metadata=entitlements,requirements,flags,runtime",
|
57
|
+
filename)
|
58
|
+
|
59
|
+
raise ModificationError, "#{filename}: signing failed!" unless $CHILD_STATUS.success?
|
60
|
+
end
|
40
61
|
end
|
data/lib/macho/exceptions.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module MachO
|
2
4
|
# A generic Mach-O error in execution.
|
3
5
|
class MachOError < RuntimeError
|
@@ -41,8 +43,8 @@ module MachO
|
|
41
43
|
# Raised when a file's magic bytes are not valid Mach-O magic.
|
42
44
|
class MagicError < NotAMachOError
|
43
45
|
# @param num [Integer] the unknown number
|
44
|
-
def initialize(
|
45
|
-
super "Unrecognized Mach-O magic: 0x
|
46
|
+
def initialize(magic)
|
47
|
+
super "Unrecognized Mach-O magic: 0x%02<magic>x" % { :magic => magic }
|
46
48
|
end
|
47
49
|
end
|
48
50
|
|
@@ -71,7 +73,7 @@ module MachO
|
|
71
73
|
class CPUTypeError < MachOError
|
72
74
|
# @param cputype [Integer] the unknown CPU type
|
73
75
|
def initialize(cputype)
|
74
|
-
super "Unrecognized CPU type: 0x
|
76
|
+
super "Unrecognized CPU type: 0x%08<cputype>x" % { :cputype => cputype }
|
75
77
|
end
|
76
78
|
end
|
77
79
|
|
@@ -80,8 +82,8 @@ module MachO
|
|
80
82
|
# @param cputype [Integer] the CPU type of the unknown pair
|
81
83
|
# @param cpusubtype [Integer] the CPU sub-type of the unknown pair
|
82
84
|
def initialize(cputype, cpusubtype)
|
83
|
-
super "Unrecognized CPU sub-type: 0x
|
84
|
-
" (for CPU type: 0x
|
85
|
+
super "Unrecognized CPU sub-type: 0x%08<cpusubtype>x" \
|
86
|
+
" (for CPU type: 0x%08<cputype>x" % { :cputype => cputype, :cpusubtype => cpusubtype }
|
85
87
|
end
|
86
88
|
end
|
87
89
|
|
@@ -89,7 +91,7 @@ module MachO
|
|
89
91
|
class FiletypeError < MachOError
|
90
92
|
# @param num [Integer] the unknown number
|
91
93
|
def initialize(num)
|
92
|
-
super "Unrecognized Mach-O filetype code: 0x
|
94
|
+
super "Unrecognized Mach-O filetype code: 0x%02<num>x" % { :num => num }
|
93
95
|
end
|
94
96
|
end
|
95
97
|
|
@@ -97,7 +99,7 @@ module MachO
|
|
97
99
|
class LoadCommandError < MachOError
|
98
100
|
# @param num [Integer] the unknown number
|
99
101
|
def initialize(num)
|
100
|
-
super "Unrecognized Mach-O load command: 0x
|
102
|
+
super "Unrecognized Mach-O load command: 0x%02<num>x" % { :num => num }
|
101
103
|
end
|
102
104
|
end
|
103
105
|
|
data/lib/macho/fat_file.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "forwardable"
|
2
4
|
|
3
5
|
module MachO
|
@@ -11,6 +13,10 @@ module MachO
|
|
11
13
|
# @return [String] the filename loaded from, or nil if loaded from a binary string
|
12
14
|
attr_accessor :filename
|
13
15
|
|
16
|
+
# @return [Hash] any parser options that the instance was created with
|
17
|
+
# @note Options specified in a {FatFile} trickle down into the internal {MachOFile}s.
|
18
|
+
attr_reader :options
|
19
|
+
|
14
20
|
# @return [Headers::FatHeader] the file's header
|
15
21
|
attr_reader :header
|
16
22
|
|
@@ -39,11 +45,7 @@ module MachO
|
|
39
45
|
# put the smaller alignments further forwards in fat macho, so that we do less padding
|
40
46
|
machos = machos.sort_by(&:segment_alignment)
|
41
47
|
|
42
|
-
bin =
|
43
|
-
+""
|
44
|
-
else
|
45
|
-
""
|
46
|
-
end
|
48
|
+
bin = +""
|
47
49
|
|
48
50
|
bin << Headers::FatHeader.new(magic, machos.size).serialize
|
49
51
|
offset = Headers::FatHeader.bytesize + (machos.size * fa_klass.bytesize)
|
@@ -53,9 +55,7 @@ module MachO
|
|
53
55
|
machos.each do |macho|
|
54
56
|
macho_offset = Utils.round(offset, 2**macho.segment_alignment)
|
55
57
|
|
56
|
-
if !fat64 && macho_offset > (2**32 - 1)
|
57
|
-
raise FatArchOffsetOverflowError, macho_offset
|
58
|
-
end
|
58
|
+
raise FatArchOffsetOverflowError, macho_offset if !fat64 && macho_offset > (2**32 - 1)
|
59
59
|
|
60
60
|
macho_pads[macho] = Utils.padding_for(offset, 2**macho.segment_alignment)
|
61
61
|
|
@@ -76,30 +76,36 @@ module MachO
|
|
76
76
|
|
77
77
|
# Creates a new FatFile instance from a binary string.
|
78
78
|
# @param bin [String] a binary string containing raw Mach-O data
|
79
|
+
# @param opts [Hash] options to control the parser with
|
80
|
+
# @note see {MachOFile#initialize} for currently valid options
|
79
81
|
# @return [FatFile] a new FatFile
|
80
|
-
def self.new_from_bin(bin)
|
82
|
+
def self.new_from_bin(bin, **opts)
|
81
83
|
instance = allocate
|
82
|
-
instance.initialize_from_bin(bin)
|
84
|
+
instance.initialize_from_bin(bin, opts)
|
83
85
|
|
84
86
|
instance
|
85
87
|
end
|
86
88
|
|
87
89
|
# Creates a new FatFile from the given filename.
|
88
90
|
# @param filename [String] the fat file to load from
|
91
|
+
# @param opts [Hash] options to control the parser with
|
92
|
+
# @note see {MachOFile#initialize} for currently valid options
|
89
93
|
# @raise [ArgumentError] if the given file does not exist
|
90
|
-
def initialize(filename)
|
94
|
+
def initialize(filename, **opts)
|
91
95
|
raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
|
92
96
|
|
93
97
|
@filename = filename
|
98
|
+
@options = opts
|
94
99
|
@raw_data = File.open(@filename, "rb", &:read)
|
95
100
|
populate_fields
|
96
101
|
end
|
97
102
|
|
98
|
-
# Initializes a new FatFile instance from a binary string.
|
103
|
+
# Initializes a new FatFile instance from a binary string with the given options.
|
99
104
|
# @see new_from_bin
|
100
105
|
# @api private
|
101
|
-
def initialize_from_bin(bin)
|
106
|
+
def initialize_from_bin(bin, opts)
|
102
107
|
@filename = nil
|
108
|
+
@options = opts
|
103
109
|
@raw_data = bin
|
104
110
|
populate_fields
|
105
111
|
end
|
@@ -362,7 +368,7 @@ module MachO
|
|
362
368
|
machos = []
|
363
369
|
|
364
370
|
fat_archs.each do |arch|
|
365
|
-
machos << MachOFile.new_from_bin(@raw_data[arch.offset, arch.size])
|
371
|
+
machos << MachOFile.new_from_bin(@raw_data[arch.offset, arch.size], **options)
|
366
372
|
end
|
367
373
|
|
368
374
|
machos
|
@@ -394,13 +400,13 @@ module MachO
|
|
394
400
|
machos.each_with_index do |macho, index|
|
395
401
|
begin
|
396
402
|
yield macho
|
397
|
-
rescue RecoverableModificationError =>
|
398
|
-
|
403
|
+
rescue RecoverableModificationError => e
|
404
|
+
e.macho_slice = index
|
399
405
|
|
400
406
|
# Strict mode: Immediately re-raise. Otherwise: Retain, check later.
|
401
|
-
raise
|
407
|
+
raise e if strict
|
402
408
|
|
403
|
-
errors <<
|
409
|
+
errors << e
|
404
410
|
end
|
405
411
|
end
|
406
412
|
|
data/lib/macho/headers.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module MachO
|
2
4
|
# Classes and constants for parsing the headers of Mach-O binaries.
|
3
5
|
module Headers
|
@@ -241,6 +243,10 @@ module MachO
|
|
241
243
|
# @api private
|
242
244
|
CPU_SUBTYPE_ARM64_32_V8 = 1
|
243
245
|
|
246
|
+
# the e (A12) sub-type for `CPU_TYPE_ARM64`
|
247
|
+
# @api private
|
248
|
+
CPU_SUBTYPE_ARM64E = 2
|
249
|
+
|
244
250
|
# the lowest common sub-type for `CPU_TYPE_MC88000`
|
245
251
|
# @api private
|
246
252
|
CPU_SUBTYPE_MC88000_ALL = 0
|
@@ -350,6 +356,7 @@ module MachO
|
|
350
356
|
CPU_TYPE_ARM64 => {
|
351
357
|
CPU_SUBTYPE_ARM64_ALL => :arm64,
|
352
358
|
CPU_SUBTYPE_ARM64_V8 => :arm64v8,
|
359
|
+
CPU_SUBTYPE_ARM64E => :arm64e,
|
353
360
|
}.freeze,
|
354
361
|
CPU_TYPE_ARM64_32 => {
|
355
362
|
CPU_SUBTYPE_ARM64_32_V8 => :arm64_32v8,
|
@@ -485,7 +492,7 @@ module MachO
|
|
485
492
|
# always big-endian
|
486
493
|
# @see MachOStructure::FORMAT
|
487
494
|
# @api private
|
488
|
-
FORMAT = "N2"
|
495
|
+
FORMAT = "N2"
|
489
496
|
|
490
497
|
# @see MachOStructure::SIZEOF
|
491
498
|
# @api private
|
@@ -536,7 +543,7 @@ module MachO
|
|
536
543
|
# @note Always big endian.
|
537
544
|
# @see MachOStructure::FORMAT
|
538
545
|
# @api private
|
539
|
-
FORMAT = "L>5"
|
546
|
+
FORMAT = "L>5"
|
540
547
|
|
541
548
|
# @see MachOStructure::SIZEOF
|
542
549
|
# @api private
|
@@ -582,7 +589,7 @@ module MachO
|
|
582
589
|
# @note Always big endian.
|
583
590
|
# @see MachOStructure::FORMAT
|
584
591
|
# @api private
|
585
|
-
FORMAT = "L>2Q>2L>2"
|
592
|
+
FORMAT = "L>2Q>2L>2"
|
586
593
|
|
587
594
|
# @see MachOStructure::SIZEOF
|
588
595
|
# @api private
|
@@ -632,7 +639,7 @@ module MachO
|
|
632
639
|
|
633
640
|
# @see MachOStructure::FORMAT
|
634
641
|
# @api private
|
635
|
-
FORMAT = "L=7"
|
642
|
+
FORMAT = "L=7"
|
636
643
|
|
637
644
|
# @see MachOStructure::SIZEOF
|
638
645
|
# @api private
|
@@ -755,7 +762,7 @@ module MachO
|
|
755
762
|
|
756
763
|
# @see MachOStructure::FORMAT
|
757
764
|
# @api private
|
758
|
-
FORMAT = "L=8"
|
765
|
+
FORMAT = "L=8"
|
759
766
|
|
760
767
|
# @see MachOStructure::SIZEOF
|
761
768
|
# @api private
|
data/lib/macho/load_commands.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module MachO
|
2
4
|
# Classes and constants for parsing load commands in Mach-O binaries.
|
3
5
|
module LoadCommands
|
@@ -60,6 +62,8 @@ module MachO
|
|
60
62
|
0x30 => :LC_VERSION_MIN_WATCHOS,
|
61
63
|
0x31 => :LC_NOTE,
|
62
64
|
0x32 => :LC_BUILD_VERSION,
|
65
|
+
(0x33 | LC_REQ_DYLD) => :LC_DYLD_EXPORTS_TRIE,
|
66
|
+
(0x34 | LC_REQ_DYLD) => :LD_DYLD_CHAINED_FIXUPS,
|
63
67
|
}.freeze
|
64
68
|
|
65
69
|
# association of symbol representations to load command constants
|
@@ -145,6 +149,8 @@ module MachO
|
|
145
149
|
:LC_VERSION_MIN_WATCHOS => "VersionMinCommand",
|
146
150
|
:LC_NOTE => "NoteCommand",
|
147
151
|
:LC_BUILD_VERSION => "BuildVersionCommand",
|
152
|
+
:LC_DYLD_EXPORTS_TRIE => "LinkeditDataCommand",
|
153
|
+
:LD_DYLD_CHAINED_FIXUPS => "LinkeditDataCommand",
|
148
154
|
}.freeze
|
149
155
|
|
150
156
|
# association of segment name symbols to names
|
@@ -186,7 +192,7 @@ module MachO
|
|
186
192
|
|
187
193
|
# @see MachOStructure::FORMAT
|
188
194
|
# @api private
|
189
|
-
FORMAT = "L=2"
|
195
|
+
FORMAT = "L=2"
|
190
196
|
|
191
197
|
# @see MachOStructure::SIZEOF
|
192
198
|
# @api private
|
@@ -365,7 +371,7 @@ module MachO
|
|
365
371
|
|
366
372
|
# @see MachOStructure::FORMAT
|
367
373
|
# @api private
|
368
|
-
FORMAT = "L=2a16"
|
374
|
+
FORMAT = "L=2a16"
|
369
375
|
|
370
376
|
# @see MachOStructure::SIZEOF
|
371
377
|
# @api private
|
@@ -379,7 +385,7 @@ module MachO
|
|
379
385
|
|
380
386
|
# @return [String] a string representation of the UUID
|
381
387
|
def uuid_string
|
382
|
-
hexes = uuid.map { |
|
388
|
+
hexes = uuid.map { |elem| "%02<elem>x" % { :elem => elem } }
|
383
389
|
segs = [
|
384
390
|
hexes[0..3].join, hexes[4..5].join, hexes[6..7].join,
|
385
391
|
hexes[8..9].join, hexes[10..15].join
|
@@ -429,7 +435,7 @@ module MachO
|
|
429
435
|
|
430
436
|
# @see MachOStructure::FORMAT
|
431
437
|
# @api private
|
432
|
-
FORMAT = "L=2Z16L=4l=2L=2"
|
438
|
+
FORMAT = "L=2Z16L=4l=2L=2"
|
433
439
|
|
434
440
|
# @see MachOStructure::SIZEOF
|
435
441
|
# @api private
|
@@ -524,7 +530,7 @@ module MachO
|
|
524
530
|
class SegmentCommand64 < SegmentCommand
|
525
531
|
# @see MachOStructure::FORMAT
|
526
532
|
# @api private
|
527
|
-
FORMAT = "L=2Z16Q=4l=2L=2"
|
533
|
+
FORMAT = "L=2Z16Q=4l=2L=2"
|
528
534
|
|
529
535
|
# @see MachOStructure::SIZEOF
|
530
536
|
# @api private
|
@@ -550,7 +556,7 @@ module MachO
|
|
550
556
|
|
551
557
|
# @see MachOStructure::FORMAT
|
552
558
|
# @api private
|
553
|
-
FORMAT = "L=6"
|
559
|
+
FORMAT = "L=6"
|
554
560
|
|
555
561
|
# @see MachOStructure::SIZEOF
|
556
562
|
# @api private
|
@@ -601,7 +607,7 @@ module MachO
|
|
601
607
|
|
602
608
|
# @see MachOStructure::FORMAT
|
603
609
|
# @api private
|
604
|
-
FORMAT = "L=3"
|
610
|
+
FORMAT = "L=3"
|
605
611
|
|
606
612
|
# @see MachOStructure::SIZEOF
|
607
613
|
# @api private
|
@@ -649,7 +655,7 @@ module MachO
|
|
649
655
|
|
650
656
|
# @see MachOStructure::FORMAT
|
651
657
|
# @api private
|
652
|
-
FORMAT = "L=5"
|
658
|
+
FORMAT = "L=5"
|
653
659
|
|
654
660
|
# @see MachOStructure::SIZEOF
|
655
661
|
# @api private
|
@@ -679,7 +685,7 @@ module MachO
|
|
679
685
|
class ThreadCommand < LoadCommand
|
680
686
|
# @see MachOStructure::FORMAT
|
681
687
|
# @api private
|
682
|
-
FORMAT = "L=2"
|
688
|
+
FORMAT = "L=2"
|
683
689
|
|
684
690
|
# @see MachOStructure::SIZEOF
|
685
691
|
# @api private
|
@@ -717,7 +723,7 @@ module MachO
|
|
717
723
|
|
718
724
|
# @see MachOStructure::FORMAT
|
719
725
|
# @api private
|
720
|
-
FORMAT = "L=10"
|
726
|
+
FORMAT = "L=10"
|
721
727
|
|
722
728
|
# @see MachOStructure::SIZEOF
|
723
729
|
# @api private
|
@@ -758,7 +764,7 @@ module MachO
|
|
758
764
|
class RoutinesCommand64 < RoutinesCommand
|
759
765
|
# @see MachOStructure::FORMAT
|
760
766
|
# @api private
|
761
|
-
FORMAT = "L=2Q=8"
|
767
|
+
FORMAT = "L=2Q=8"
|
762
768
|
|
763
769
|
# @see MachOStructure::SIZEOF
|
764
770
|
# @api private
|
@@ -773,7 +779,7 @@ module MachO
|
|
773
779
|
|
774
780
|
# @see MachOStructure::FORMAT
|
775
781
|
# @api private
|
776
|
-
FORMAT = "L=3"
|
782
|
+
FORMAT = "L=3"
|
777
783
|
|
778
784
|
# @see MachOStructure::SIZEOF
|
779
785
|
# @api private
|
@@ -801,7 +807,7 @@ module MachO
|
|
801
807
|
|
802
808
|
# @see MachOStructure::FORMAT
|
803
809
|
# @api private
|
804
|
-
FORMAT = "L=3"
|
810
|
+
FORMAT = "L=3"
|
805
811
|
|
806
812
|
# @see MachOStructure::SIZEOF
|
807
813
|
# @api private
|
@@ -829,7 +835,7 @@ module MachO
|
|
829
835
|
|
830
836
|
# @see MachOStructure::FORMAT
|
831
837
|
# @api private
|
832
|
-
FORMAT = "L=3"
|
838
|
+
FORMAT = "L=3"
|
833
839
|
|
834
840
|
# @see MachOStructure::SIZEOF
|
835
841
|
# @api private
|
@@ -857,7 +863,7 @@ module MachO
|
|
857
863
|
|
858
864
|
# @see MachOStructure::FORMAT
|
859
865
|
# @api private
|
860
|
-
FORMAT = "L=3"
|
866
|
+
FORMAT = "L=3"
|
861
867
|
|
862
868
|
# @see MachOStructure::SIZEOF
|
863
869
|
# @api private
|
@@ -894,7 +900,7 @@ module MachO
|
|
894
900
|
|
895
901
|
# @see MachOStructure::FORMAT
|
896
902
|
# @api private
|
897
|
-
FORMAT = "L=6"
|
903
|
+
FORMAT = "L=6"
|
898
904
|
|
899
905
|
# @see MachOStructure::SIZEOF
|
900
906
|
# @api private
|
@@ -979,7 +985,7 @@ module MachO
|
|
979
985
|
|
980
986
|
# @see MachOStructure::FORMAT
|
981
987
|
# @api private
|
982
|
-
FORMAT = "L=20"
|
988
|
+
FORMAT = "L=20"
|
983
989
|
|
984
990
|
# @see MachOStructure::SIZEOF
|
985
991
|
# @api private
|
@@ -1052,7 +1058,7 @@ module MachO
|
|
1052
1058
|
|
1053
1059
|
# @see MachOStructure::FORMAT
|
1054
1060
|
# @api private
|
1055
|
-
FORMAT = "L=4"
|
1061
|
+
FORMAT = "L=4"
|
1056
1062
|
|
1057
1063
|
# @see MachOStructure::SIZEOF
|
1058
1064
|
# @api private
|
@@ -1127,7 +1133,7 @@ module MachO
|
|
1127
1133
|
|
1128
1134
|
# @see MachOStructure::FORMAT
|
1129
1135
|
# @api private
|
1130
|
-
FORMAT = "L=3"
|
1136
|
+
FORMAT = "L=3"
|
1131
1137
|
|
1132
1138
|
# @see MachOStructure::SIZEOF
|
1133
1139
|
# @api private
|
@@ -1156,7 +1162,7 @@ module MachO
|
|
1156
1162
|
|
1157
1163
|
# @see MachOStructure::FORMAT
|
1158
1164
|
# @api private
|
1159
|
-
FORMAT = "L=3"
|
1165
|
+
FORMAT = "L=3"
|
1160
1166
|
|
1161
1167
|
# @see MachOStructure::SIZEOF
|
1162
1168
|
# @api private
|
@@ -1191,7 +1197,8 @@ module MachO
|
|
1191
1197
|
# A load command representing the offsets and sizes of a blob of data in
|
1192
1198
|
# the __LINKEDIT segment. Corresponds to LC_CODE_SIGNATURE,
|
1193
1199
|
# LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE,
|
1194
|
-
# LC_DYLIB_CODE_SIGN_DRS,
|
1200
|
+
# LC_DYLIB_CODE_SIGN_DRS, LC_LINKER_OPTIMIZATION_HINT, LC_DYLD_EXPORTS_TRIE,
|
1201
|
+
# or LC_DYLD_CHAINED_FIXUPS.
|
1195
1202
|
class LinkeditDataCommand < LoadCommand
|
1196
1203
|
# @return [Integer] offset to the data in the __LINKEDIT segment
|
1197
1204
|
attr_reader :dataoff
|
@@ -1201,7 +1208,7 @@ module MachO
|
|
1201
1208
|
|
1202
1209
|
# @see MachOStructure::FORMAT
|
1203
1210
|
# @api private
|
1204
|
-
FORMAT = "L=4"
|
1211
|
+
FORMAT = "L=4"
|
1205
1212
|
|
1206
1213
|
# @see MachOStructure::SIZEOF
|
1207
1214
|
# @api private
|
@@ -1237,7 +1244,7 @@ module MachO
|
|
1237
1244
|
|
1238
1245
|
# @see MachOStructure::FORMAT
|
1239
1246
|
# @api private
|
1240
|
-
FORMAT = "L=5"
|
1247
|
+
FORMAT = "L=5"
|
1241
1248
|
|
1242
1249
|
# @see MachOStructure::SIZEOF
|
1243
1250
|
# @api private
|
@@ -1269,7 +1276,7 @@ module MachO
|
|
1269
1276
|
|
1270
1277
|
# @see MachOStructure::FORMAT
|
1271
1278
|
# @api private
|
1272
|
-
FORMAT = "L=6"
|
1279
|
+
FORMAT = "L=6"
|
1273
1280
|
|
1274
1281
|
# @see MachOStructure::SIZEOF
|
1275
1282
|
# @api private
|
@@ -1301,7 +1308,7 @@ module MachO
|
|
1301
1308
|
|
1302
1309
|
# @see MachOStructure::FORMAT
|
1303
1310
|
# @api private
|
1304
|
-
FORMAT = "L=4"
|
1311
|
+
FORMAT = "L=4"
|
1305
1312
|
|
1306
1313
|
# @see MachOStructure::SIZEOF
|
1307
1314
|
# @api private
|
@@ -1317,7 +1324,7 @@ module MachO
|
|
1317
1324
|
# A string representation of the binary's minimum OS version.
|
1318
1325
|
# @return [String] a string representing the minimum OS version.
|
1319
1326
|
def version_string
|
1320
|
-
binary = "%
|
1327
|
+
binary = "%032<version>b" % { :version => version }
|
1321
1328
|
segs = [
|
1322
1329
|
binary[0..15], binary[16..23], binary[24..31]
|
1323
1330
|
].map { |s| s.to_i(2) }
|
@@ -1328,7 +1335,7 @@ module MachO
|
|
1328
1335
|
# A string representation of the binary's SDK version.
|
1329
1336
|
# @return [String] a string representing the SDK version.
|
1330
1337
|
def sdk_string
|
1331
|
-
binary = "%
|
1338
|
+
binary = "%032<sdk>b" % { :sdk => sdk }
|
1332
1339
|
segs = [
|
1333
1340
|
binary[0..15], binary[16..23], binary[24..31]
|
1334
1341
|
].map { |s| s.to_i(2) }
|
@@ -1365,7 +1372,7 @@ module MachO
|
|
1365
1372
|
|
1366
1373
|
# @see MachOStructure::FORMAT
|
1367
1374
|
# @api private
|
1368
|
-
FORMAT = "L=6"
|
1375
|
+
FORMAT = "L=6"
|
1369
1376
|
|
1370
1377
|
# @see MachOStructure::SIZEOF
|
1371
1378
|
# @api private
|
@@ -1383,7 +1390,7 @@ module MachO
|
|
1383
1390
|
# A string representation of the binary's minimum OS version.
|
1384
1391
|
# @return [String] a string representing the minimum OS version.
|
1385
1392
|
def minos_string
|
1386
|
-
binary = "%
|
1393
|
+
binary = "%032<minos>b" % { :minos => minos }
|
1387
1394
|
segs = [
|
1388
1395
|
binary[0..15], binary[16..23], binary[24..31]
|
1389
1396
|
].map { |s| s.to_i(2) }
|
@@ -1394,7 +1401,7 @@ module MachO
|
|
1394
1401
|
# A string representation of the binary's SDK version.
|
1395
1402
|
# @return [String] a string representing the SDK version.
|
1396
1403
|
def sdk_string
|
1397
|
-
binary = "%
|
1404
|
+
binary = "%032<sdk>b" % { :sdk => sdk }
|
1398
1405
|
segs = [
|
1399
1406
|
binary[0..15], binary[16..23], binary[24..31]
|
1400
1407
|
].map { |s| s.to_i(2) }
|
@@ -1494,7 +1501,7 @@ module MachO
|
|
1494
1501
|
|
1495
1502
|
# @see MachOStructure::FORMAT
|
1496
1503
|
# @api private
|
1497
|
-
FORMAT = "L=12"
|
1504
|
+
FORMAT = "L=12"
|
1498
1505
|
|
1499
1506
|
# @see MachOStructure::SIZEOF
|
1500
1507
|
# @api private
|
@@ -1542,7 +1549,7 @@ module MachO
|
|
1542
1549
|
|
1543
1550
|
# @see MachOStructure::FORMAT
|
1544
1551
|
# @api private
|
1545
|
-
FORMAT = "L=3"
|
1552
|
+
FORMAT = "L=3"
|
1546
1553
|
|
1547
1554
|
# @see MachOStructure::SIZEOF
|
1548
1555
|
# @api private
|
@@ -1572,7 +1579,7 @@ module MachO
|
|
1572
1579
|
|
1573
1580
|
# @see MachOStructure::FORMAT
|
1574
1581
|
# @api private
|
1575
|
-
FORMAT = "L=2Q=2"
|
1582
|
+
FORMAT = "L=2Q=2"
|
1576
1583
|
|
1577
1584
|
# @see MachOStructure::SIZEOF
|
1578
1585
|
# @api private
|
@@ -1602,7 +1609,7 @@ module MachO
|
|
1602
1609
|
|
1603
1610
|
# @see MachOStructure::FORMAT
|
1604
1611
|
# @api private
|
1605
|
-
FORMAT = "L=2Q=1"
|
1612
|
+
FORMAT = "L=2Q=1"
|
1606
1613
|
|
1607
1614
|
# @see MachOStructure::SIZEOF
|
1608
1615
|
# @api private
|
@@ -1617,7 +1624,7 @@ module MachO
|
|
1617
1624
|
# A string representation of the sources used to build the binary.
|
1618
1625
|
# @return [String] a string representation of the version
|
1619
1626
|
def version_string
|
1620
|
-
binary = "%
|
1627
|
+
binary = "%064<version>b" % { :version => version }
|
1621
1628
|
segs = [
|
1622
1629
|
binary[0..23], binary[24..33], binary[34..43], binary[44..53],
|
1623
1630
|
binary[54..63]
|
@@ -1646,7 +1653,7 @@ module MachO
|
|
1646
1653
|
|
1647
1654
|
# @see MachOStructure::FORMAT
|
1648
1655
|
# @api private
|
1649
|
-
FORMAT = "L=4"
|
1656
|
+
FORMAT = "L=4"
|
1650
1657
|
|
1651
1658
|
# @see MachOStructure::SIZEOF
|
1652
1659
|
# @api private
|
@@ -1674,7 +1681,7 @@ module MachO
|
|
1674
1681
|
class IdentCommand < LoadCommand
|
1675
1682
|
# @see MachOStructure::FORMAT
|
1676
1683
|
# @api private
|
1677
|
-
FORMAT = "L=2"
|
1684
|
+
FORMAT = "L=2"
|
1678
1685
|
|
1679
1686
|
# @see MachOStructure::SIZEOF
|
1680
1687
|
# @api private
|
@@ -1692,7 +1699,7 @@ module MachO
|
|
1692
1699
|
|
1693
1700
|
# @see MachOStructure::FORMAT
|
1694
1701
|
# @api private
|
1695
|
-
FORMAT = "L=4"
|
1702
|
+
FORMAT = "L=4"
|
1696
1703
|
|
1697
1704
|
# @see MachOStructure::SIZEOF
|
1698
1705
|
# @api private
|
@@ -1727,7 +1734,7 @@ module MachO
|
|
1727
1734
|
|
1728
1735
|
# @see MachOStructure::FORMAT
|
1729
1736
|
# @api private
|
1730
|
-
FORMAT = "L=5"
|
1737
|
+
FORMAT = "L=5"
|
1731
1738
|
|
1732
1739
|
# @see MachOStructure::SIZEOF
|
1733
1740
|
# @api private
|
@@ -1764,7 +1771,7 @@ module MachO
|
|
1764
1771
|
|
1765
1772
|
# @see MachOStructure::FORMAT
|
1766
1773
|
# @api private
|
1767
|
-
FORMAT = "L=2Z16Q=2"
|
1774
|
+
FORMAT = "L=2Z16Q=2"
|
1768
1775
|
|
1769
1776
|
# @see MachOStructure::SIZEOF
|
1770
1777
|
# @api private
|
data/lib/macho/macho_file.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "forwardable"
|
2
4
|
|
3
5
|
module MachO
|
@@ -9,10 +11,13 @@ module MachO
|
|
9
11
|
class MachOFile
|
10
12
|
extend Forwardable
|
11
13
|
|
12
|
-
# @return [String] the filename loaded from, or nil if loaded from a binary
|
14
|
+
# @return [String, nil] the filename loaded from, or nil if loaded from a binary
|
13
15
|
# string
|
14
16
|
attr_accessor :filename
|
15
17
|
|
18
|
+
# @return [Hash] any parser options that the instance was created with
|
19
|
+
attr_reader :options
|
20
|
+
|
16
21
|
# @return [Symbol] the endianness of the file, :big or :little
|
17
22
|
attr_reader :endianness
|
18
23
|
|
@@ -27,30 +32,36 @@ module MachO
|
|
27
32
|
|
28
33
|
# Creates a new instance from a binary string.
|
29
34
|
# @param bin [String] a binary string containing raw Mach-O data
|
35
|
+
# @param opts [Hash] options to control the parser with
|
36
|
+
# @option opts [Boolean] :permissive whether to ignore unknown load commands
|
30
37
|
# @return [MachOFile] a new MachOFile
|
31
|
-
def self.new_from_bin(bin)
|
38
|
+
def self.new_from_bin(bin, **opts)
|
32
39
|
instance = allocate
|
33
|
-
instance.initialize_from_bin(bin)
|
40
|
+
instance.initialize_from_bin(bin, opts)
|
34
41
|
|
35
42
|
instance
|
36
43
|
end
|
37
44
|
|
38
45
|
# Creates a new instance from data read from the given filename.
|
39
46
|
# @param filename [String] the Mach-O file to load from
|
47
|
+
# @param opts [Hash] options to control the parser with
|
48
|
+
# @option opts [Boolean] :permissive whether to ignore unknown load commands
|
40
49
|
# @raise [ArgumentError] if the given file does not exist
|
41
|
-
def initialize(filename)
|
50
|
+
def initialize(filename, **opts)
|
42
51
|
raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
|
43
52
|
|
44
53
|
@filename = filename
|
54
|
+
@options = opts
|
45
55
|
@raw_data = File.open(@filename, "rb", &:read)
|
46
56
|
populate_fields
|
47
57
|
end
|
48
58
|
|
49
|
-
# Initializes a new MachOFile instance from a binary string.
|
59
|
+
# Initializes a new MachOFile instance from a binary string with the given options.
|
50
60
|
# @see MachO::MachOFile.new_from_bin
|
51
61
|
# @api private
|
52
|
-
def initialize_from_bin(bin)
|
62
|
+
def initialize_from_bin(bin, opts)
|
53
63
|
@filename = nil
|
64
|
+
@options = opts
|
54
65
|
@raw_data = bin
|
55
66
|
populate_fields
|
56
67
|
end
|
@@ -146,16 +157,13 @@ module MachO
|
|
146
157
|
def insert_command(offset, lc, options = {})
|
147
158
|
context = LoadCommands::LoadCommand::SerializationContext.context_for(self)
|
148
159
|
cmd_raw = lc.serialize(context)
|
160
|
+
fileoff = offset + cmd_raw.bytesize
|
149
161
|
|
150
|
-
if offset < header.class.bytesize ||
|
151
|
-
raise OffsetInsertionError, offset
|
152
|
-
end
|
162
|
+
raise OffsetInsertionError, offset if offset < header.class.bytesize || fileoff > low_fileoff
|
153
163
|
|
154
164
|
new_sizeofcmds = sizeofcmds + cmd_raw.bytesize
|
155
165
|
|
156
|
-
if header.class.bytesize + new_sizeofcmds > low_fileoff
|
157
|
-
raise HeaderPadError, @filename
|
158
|
-
end
|
166
|
+
raise HeaderPadError, @filename if header.class.bytesize + new_sizeofcmds > low_fileoff
|
159
167
|
|
160
168
|
# update Mach-O header fields to account for inserted load command
|
161
169
|
update_ncmds(ncmds + 1)
|
@@ -178,9 +186,8 @@ module MachO
|
|
178
186
|
context = LoadCommands::LoadCommand::SerializationContext.context_for(self)
|
179
187
|
cmd_raw = new_lc.serialize(context)
|
180
188
|
new_sizeofcmds = sizeofcmds + cmd_raw.bytesize - old_lc.cmdsize
|
181
|
-
|
182
|
-
|
183
|
-
end
|
189
|
+
|
190
|
+
raise HeaderPadError, @filename if header.class.bytesize + new_sizeofcmds > low_fileoff
|
184
191
|
|
185
192
|
delete_command(old_lc)
|
186
193
|
insert_command(old_lc.view.offset, new_lc)
|
@@ -471,7 +478,7 @@ module MachO
|
|
471
478
|
# @raise [FatBinaryError] if the magic is for a Fat file
|
472
479
|
# @api private
|
473
480
|
def populate_and_check_magic
|
474
|
-
magic = @raw_data[0..3].
|
481
|
+
magic = @raw_data[0..3].unpack1("N")
|
475
482
|
|
476
483
|
raise MagicError, magic unless Utils.magic?(magic)
|
477
484
|
raise FatBinaryError if Utils.fat_magic?(magic)
|
@@ -511,19 +518,25 @@ module MachO
|
|
511
518
|
# @raise [LoadCommandError] if an unknown load command is encountered
|
512
519
|
# @api private
|
513
520
|
def populate_load_commands
|
521
|
+
permissive = options.fetch(:permissive, false)
|
514
522
|
offset = header.class.bytesize
|
515
523
|
load_commands = []
|
516
524
|
|
517
525
|
header.ncmds.times do
|
518
526
|
fmt = Utils.specialize_format("L=", endianness)
|
519
|
-
cmd = @raw_data.slice(offset, 4).
|
527
|
+
cmd = @raw_data.slice(offset, 4).unpack1(fmt)
|
520
528
|
cmd_sym = LoadCommands::LOAD_COMMANDS[cmd]
|
521
529
|
|
522
|
-
raise LoadCommandError, cmd
|
530
|
+
raise LoadCommandError, cmd unless cmd_sym || permissive
|
531
|
+
|
532
|
+
# If we're here, then either cmd_sym represents a valid load
|
533
|
+
# command *or* we're in permissive mode.
|
534
|
+
klass = if (klass_str = LoadCommands::LC_STRUCTURES[cmd_sym])
|
535
|
+
LoadCommands.const_get klass_str
|
536
|
+
else
|
537
|
+
LoadCommands::LoadCommand
|
538
|
+
end
|
523
539
|
|
524
|
-
# why do I do this? i don't like declaring constants below
|
525
|
-
# classes, and i need them to resolve...
|
526
|
-
klass = LoadCommands.const_get LoadCommands::LC_STRUCTURES[cmd_sym]
|
527
540
|
view = MachOView.new(@raw_data, endianness, offset)
|
528
541
|
command = klass.new_from_bin(view)
|
529
542
|
|
data/lib/macho/sections.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module MachO
|
2
4
|
# Classes and constants for parsing sections in Mach-O binaries.
|
3
5
|
module Sections
|
@@ -108,7 +110,7 @@ module MachO
|
|
108
110
|
attr_reader :reserved2
|
109
111
|
|
110
112
|
# @see MachOStructure::FORMAT
|
111
|
-
FORMAT = "Z16Z16L=9"
|
113
|
+
FORMAT = "Z16Z16L=9"
|
112
114
|
|
113
115
|
# @see MachOStructure::SIZEOF
|
114
116
|
SIZEOF = 68
|
@@ -180,7 +182,7 @@ module MachO
|
|
180
182
|
attr_reader :reserved3
|
181
183
|
|
182
184
|
# @see MachOStructure::FORMAT
|
183
|
-
FORMAT = "Z16Z16Q=2L=8"
|
185
|
+
FORMAT = "Z16Z16Q=2L=8"
|
184
186
|
|
185
187
|
# @see MachOStructure::SIZEOF
|
186
188
|
SIZEOF = 80
|
data/lib/macho/structure.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module MachO
|
2
4
|
# A general purpose pseudo-structure.
|
3
5
|
# @abstract
|
@@ -5,7 +7,7 @@ module MachO
|
|
5
7
|
# The String#unpack format of the data structure.
|
6
8
|
# @return [String] the unpacking format
|
7
9
|
# @api private
|
8
|
-
FORMAT = ""
|
10
|
+
FORMAT = ""
|
9
11
|
|
10
12
|
# The size of the data structure, in bytes.
|
11
13
|
# @return [Integer] the size, in bytes
|
data/lib/macho/tools.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module MachO
|
2
4
|
# A collection of convenient methods for common operations on Mach-O and Fat
|
3
5
|
# binaries.
|
@@ -23,6 +25,8 @@ module MachO
|
|
23
25
|
|
24
26
|
file.change_dylib_id(new_id, options)
|
25
27
|
file.write!
|
28
|
+
|
29
|
+
MachO.codesign!(filename)
|
26
30
|
end
|
27
31
|
|
28
32
|
# Changes a shared library install name in a Mach-O or Fat binary,
|
@@ -39,6 +43,8 @@ module MachO
|
|
39
43
|
|
40
44
|
file.change_install_name(old_name, new_name, options)
|
41
45
|
file.write!
|
46
|
+
|
47
|
+
MachO.codesign!(filename)
|
42
48
|
end
|
43
49
|
|
44
50
|
# Changes a runtime path in a Mach-O or Fat binary, overwriting the source
|
@@ -55,6 +61,8 @@ module MachO
|
|
55
61
|
|
56
62
|
file.change_rpath(old_path, new_path, options)
|
57
63
|
file.write!
|
64
|
+
|
65
|
+
MachO.codesign!(filename)
|
58
66
|
end
|
59
67
|
|
60
68
|
# Add a runtime path to a Mach-O or Fat binary, overwriting the source file.
|
@@ -69,6 +77,8 @@ module MachO
|
|
69
77
|
|
70
78
|
file.add_rpath(new_path, options)
|
71
79
|
file.write!
|
80
|
+
|
81
|
+
MachO.codesign!(filename)
|
72
82
|
end
|
73
83
|
|
74
84
|
# Delete a runtime path from a Mach-O or Fat binary, overwriting the source
|
@@ -84,6 +94,8 @@ module MachO
|
|
84
94
|
|
85
95
|
file.delete_rpath(old_path, options)
|
86
96
|
file.write!
|
97
|
+
|
98
|
+
MachO.codesign!(filename)
|
87
99
|
end
|
88
100
|
|
89
101
|
# Merge multiple Mach-Os into one universal (Fat) binary.
|
@@ -104,6 +116,8 @@ module MachO
|
|
104
116
|
|
105
117
|
fat_macho = MachO::FatFile.new_from_machos(*machos, :fat64 => fat64)
|
106
118
|
fat_macho.write(filename)
|
119
|
+
|
120
|
+
MachO.codesign!(filename)
|
107
121
|
end
|
108
122
|
end
|
109
123
|
end
|
data/lib/macho/utils.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module MachO
|
2
4
|
# A collection of utility functions used throughout ruby-macho.
|
3
5
|
module Utils
|
@@ -27,7 +29,7 @@ module MachO
|
|
27
29
|
# @return [String] the null string (or empty string, for `size = 0`)
|
28
30
|
# @raise [ArgumentError] if a non-positive nullpad is requested
|
29
31
|
def self.nullpad(size)
|
30
|
-
raise ArgumentError, "size < 0: #{size}" if size
|
32
|
+
raise ArgumentError, "size < 0: #{size}" if size.negative?
|
31
33
|
|
32
34
|
"\x00" * size
|
33
35
|
end
|
@@ -51,7 +53,7 @@ module MachO
|
|
51
53
|
def self.pack_strings(fixed_offset, alignment, strings = {})
|
52
54
|
offsets = {}
|
53
55
|
next_offset = fixed_offset
|
54
|
-
payload = ""
|
56
|
+
payload = +""
|
55
57
|
|
56
58
|
strings.each do |key, string|
|
57
59
|
offsets[key] = next_offset
|
@@ -61,7 +63,7 @@ module MachO
|
|
61
63
|
end
|
62
64
|
|
63
65
|
payload << Utils.nullpad(padding_for(fixed_offset + payload.bytesize, alignment))
|
64
|
-
[payload, offsets]
|
66
|
+
[payload.freeze, offsets]
|
65
67
|
end
|
66
68
|
|
67
69
|
# Compares the given number to valid Mach-O magic numbers.
|
data/lib/macho/view.rb
CHANGED
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:
|
4
|
+
version: 2.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:
|
11
|
+
date: 2020-10-12 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,15 +42,14 @@ 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
50
|
version: '0'
|
51
51
|
requirements: []
|
52
|
-
|
53
|
-
rubygems_version: 2.7.6
|
52
|
+
rubygems_version: 3.1.2
|
54
53
|
signing_key:
|
55
54
|
specification_version: 4
|
56
55
|
summary: ruby-macho - Mach-O file analyzer.
|