ruby-macho 1.3.1 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|