ruby-macho 2.1.0 → 2.5.1
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 +14 -11
- data/lib/macho/fat_file.rb +26 -18
- data/lib/macho/headers.rb +15 -5
- data/lib/macho/load_commands.rb +48 -40
- data/lib/macho/macho_file.rb +36 -26
- data/lib/macho/sections.rb +5 -2
- data/lib/macho/structure.rb +3 -1
- data/lib/macho/tools.rb +2 -0
- data/lib/macho/utils.rb +4 -2
- 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: cfe1d04c6c841958f4ac428e7207d89e02371fa9ca9ac3cb48e3e2a34a65dc24
|
4
|
+
data.tar.gz: 21dc14db70485e37ff5e430d5f8a99af6cb1c0ac14f02ae1943121fa2c482629
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d668c48f840f4423ae4bbc89d30c53e26a709491d2f8ca66bc98c637563e596d107638779bd517bf1fe89458d5f05beadf76ea60d80a44578aa0b409be61fc43
|
7
|
+
data.tar.gz: 84009cdfbe5c61bc84ffd8838c7fe033171ebc05af18b7748c53ced99a0e92fd7f45f1a7c0f50001c05eb253e00564b3f8dbe7735fe04df087b3fef72d2be7e6
|
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,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "open3"
|
4
|
+
|
1
5
|
require_relative "macho/structure"
|
2
6
|
require_relative "macho/view"
|
3
7
|
require_relative "macho/headers"
|
@@ -12,7 +16,7 @@ require_relative "macho/tools"
|
|
12
16
|
# The primary namespace for ruby-macho.
|
13
17
|
module MachO
|
14
18
|
# release version
|
15
|
-
VERSION = "2.1
|
19
|
+
VERSION = "2.5.1"
|
16
20
|
|
17
21
|
# Opens the given filename as a MachOFile or FatFile, depending on its magic.
|
18
22
|
# @param filename [String] the file being opened
|
@@ -25,7 +29,7 @@ module MachO
|
|
25
29
|
raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
|
26
30
|
raise TruncatedFileError unless File.stat(filename).size >= 4
|
27
31
|
|
28
|
-
magic = File.open(filename, "rb") { |f| f.read(4) }.
|
32
|
+
magic = File.open(filename, "rb") { |f| f.read(4) }.unpack1("N")
|
29
33
|
|
30
34
|
if Utils.fat_magic?(magic)
|
31
35
|
file = FatFile.new(filename)
|
@@ -37,4 +41,21 @@ module MachO
|
|
37
41
|
|
38
42
|
file
|
39
43
|
end
|
44
|
+
|
45
|
+
# Signs the dylib using an ad-hoc identity.
|
46
|
+
# Necessary after making any changes to a dylib, since otherwise
|
47
|
+
# changing a signed file invalidates its signature.
|
48
|
+
# @param filename [String] the file being opened
|
49
|
+
# @return [void]
|
50
|
+
# @raise [ModificationError] if the operation fails
|
51
|
+
def self.codesign!(filename)
|
52
|
+
raise ArgumentError, "codesign binary is not available on Linux" if RUBY_PLATFORM !~ /darwin/
|
53
|
+
raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
|
54
|
+
|
55
|
+
_, _, status = Open3.capture3("codesign", "--sign", "-", "--force",
|
56
|
+
"--preserve-metadata=entitlements,requirements,flags,runtime",
|
57
|
+
filename)
|
58
|
+
|
59
|
+
raise CodeSigningError, "#{filename}: signing failed!" unless 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
|
@@ -7,6 +9,11 @@ module MachO
|
|
7
9
|
class ModificationError < MachOError
|
8
10
|
end
|
9
11
|
|
12
|
+
# Raised when codesigning fails. Certain environments
|
13
|
+
# may want to rescue this to treat it as non-fatal.
|
14
|
+
class CodeSigningError < MachOError
|
15
|
+
end
|
16
|
+
|
10
17
|
# Raised when a Mach-O file modification fails but can be recovered when
|
11
18
|
# operating on multiple Mach-O slices of a fat binary in non-strict mode.
|
12
19
|
class RecoverableModificationError < ModificationError
|
@@ -25,10 +32,6 @@ module MachO
|
|
25
32
|
|
26
33
|
# Raised when a file is not a Mach-O.
|
27
34
|
class NotAMachOError < MachOError
|
28
|
-
# @param error [String] the error in question
|
29
|
-
def initialize(error)
|
30
|
-
super error
|
31
|
-
end
|
32
35
|
end
|
33
36
|
|
34
37
|
# Raised when a file is too short to be a valid Mach-O file.
|
@@ -41,8 +44,8 @@ module MachO
|
|
41
44
|
# Raised when a file's magic bytes are not valid Mach-O magic.
|
42
45
|
class MagicError < NotAMachOError
|
43
46
|
# @param num [Integer] the unknown number
|
44
|
-
def initialize(
|
45
|
-
super "Unrecognized Mach-O magic: 0x
|
47
|
+
def initialize(magic)
|
48
|
+
super "Unrecognized Mach-O magic: 0x%02<magic>x" % { :magic => magic }
|
46
49
|
end
|
47
50
|
end
|
48
51
|
|
@@ -71,7 +74,7 @@ module MachO
|
|
71
74
|
class CPUTypeError < MachOError
|
72
75
|
# @param cputype [Integer] the unknown CPU type
|
73
76
|
def initialize(cputype)
|
74
|
-
super "Unrecognized CPU type: 0x
|
77
|
+
super "Unrecognized CPU type: 0x%08<cputype>x" % { :cputype => cputype }
|
75
78
|
end
|
76
79
|
end
|
77
80
|
|
@@ -80,8 +83,8 @@ module MachO
|
|
80
83
|
# @param cputype [Integer] the CPU type of the unknown pair
|
81
84
|
# @param cpusubtype [Integer] the CPU sub-type of the unknown pair
|
82
85
|
def initialize(cputype, cpusubtype)
|
83
|
-
super "Unrecognized CPU sub-type: 0x
|
84
|
-
" (for CPU type: 0x
|
86
|
+
super "Unrecognized CPU sub-type: 0x%08<cpusubtype>x" \
|
87
|
+
" (for CPU type: 0x%08<cputype>x" % { :cputype => cputype, :cpusubtype => cpusubtype }
|
85
88
|
end
|
86
89
|
end
|
87
90
|
|
@@ -89,7 +92,7 @@ module MachO
|
|
89
92
|
class FiletypeError < MachOError
|
90
93
|
# @param num [Integer] the unknown number
|
91
94
|
def initialize(num)
|
92
|
-
super "Unrecognized Mach-O filetype code: 0x
|
95
|
+
super "Unrecognized Mach-O filetype code: 0x%02<num>x" % { :num => num }
|
93
96
|
end
|
94
97
|
end
|
95
98
|
|
@@ -97,7 +100,7 @@ module MachO
|
|
97
100
|
class LoadCommandError < MachOError
|
98
101
|
# @param num [Integer] the unknown number
|
99
102
|
def initialize(num)
|
100
|
-
super "Unrecognized Mach-O load command: 0x
|
103
|
+
super "Unrecognized Mach-O load command: 0x%02<num>x" % { :num => num }
|
101
104
|
end
|
102
105
|
end
|
103
106
|
|
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
|
|
@@ -49,9 +55,7 @@ module MachO
|
|
49
55
|
machos.each do |macho|
|
50
56
|
macho_offset = Utils.round(offset, 2**macho.segment_alignment)
|
51
57
|
|
52
|
-
if !fat64 && macho_offset > (2**32 - 1)
|
53
|
-
raise FatArchOffsetOverflowError, macho_offset
|
54
|
-
end
|
58
|
+
raise FatArchOffsetOverflowError, macho_offset if !fat64 && macho_offset > (2**32 - 1)
|
55
59
|
|
56
60
|
macho_pads[macho] = Utils.padding_for(offset, 2**macho.segment_alignment)
|
57
61
|
|
@@ -62,7 +66,7 @@ module MachO
|
|
62
66
|
offset += (macho.serialize.bytesize + macho_pads[macho])
|
63
67
|
end
|
64
68
|
|
65
|
-
machos.each do |macho|
|
69
|
+
machos.each do |macho| # rubocop:disable Style/CombinableLoops
|
66
70
|
bin << Utils.nullpad(macho_pads[macho])
|
67
71
|
bin << macho.serialize
|
68
72
|
end
|
@@ -72,30 +76,36 @@ module MachO
|
|
72
76
|
|
73
77
|
# Creates a new FatFile instance from a binary string.
|
74
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
|
75
81
|
# @return [FatFile] a new FatFile
|
76
|
-
def self.new_from_bin(bin)
|
82
|
+
def self.new_from_bin(bin, **opts)
|
77
83
|
instance = allocate
|
78
|
-
instance.initialize_from_bin(bin)
|
84
|
+
instance.initialize_from_bin(bin, opts)
|
79
85
|
|
80
86
|
instance
|
81
87
|
end
|
82
88
|
|
83
89
|
# Creates a new FatFile from the given filename.
|
84
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
|
85
93
|
# @raise [ArgumentError] if the given file does not exist
|
86
|
-
def initialize(filename)
|
94
|
+
def initialize(filename, **opts)
|
87
95
|
raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
|
88
96
|
|
89
97
|
@filename = filename
|
98
|
+
@options = opts
|
90
99
|
@raw_data = File.open(@filename, "rb", &:read)
|
91
100
|
populate_fields
|
92
101
|
end
|
93
102
|
|
94
|
-
# Initializes a new FatFile instance from a binary string.
|
103
|
+
# Initializes a new FatFile instance from a binary string with the given options.
|
95
104
|
# @see new_from_bin
|
96
105
|
# @api private
|
97
|
-
def initialize_from_bin(bin)
|
106
|
+
def initialize_from_bin(bin, opts)
|
98
107
|
@filename = nil
|
108
|
+
@options = opts
|
99
109
|
@raw_data = bin
|
100
110
|
populate_fields
|
101
111
|
end
|
@@ -358,7 +368,7 @@ module MachO
|
|
358
368
|
machos = []
|
359
369
|
|
360
370
|
fat_archs.each do |arch|
|
361
|
-
machos << MachOFile.new_from_bin(@raw_data[arch.offset, arch.size])
|
371
|
+
machos << MachOFile.new_from_bin(@raw_data[arch.offset, arch.size], **options)
|
362
372
|
end
|
363
373
|
|
364
374
|
machos
|
@@ -388,16 +398,14 @@ module MachO
|
|
388
398
|
errors = []
|
389
399
|
|
390
400
|
machos.each_with_index do |macho, index|
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
error.macho_slice = index
|
401
|
+
yield macho
|
402
|
+
rescue RecoverableModificationError => e
|
403
|
+
e.macho_slice = index
|
395
404
|
|
396
|
-
|
397
|
-
|
405
|
+
# Strict mode: Immediately re-raise. Otherwise: Retain, check later.
|
406
|
+
raise e if strict
|
398
407
|
|
399
|
-
|
400
|
-
end
|
408
|
+
errors << e
|
401
409
|
end
|
402
410
|
|
403
411
|
# Non-strict mode: Raise first error if *all* Mach-O slices failed.
|
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
|
@@ -493,6 +500,7 @@ module MachO
|
|
493
500
|
|
494
501
|
# @api private
|
495
502
|
def initialize(magic, nfat_arch)
|
503
|
+
super()
|
496
504
|
@magic = magic
|
497
505
|
@nfat_arch = nfat_arch
|
498
506
|
end
|
@@ -536,7 +544,7 @@ module MachO
|
|
536
544
|
# @note Always big endian.
|
537
545
|
# @see MachOStructure::FORMAT
|
538
546
|
# @api private
|
539
|
-
FORMAT = "L>5"
|
547
|
+
FORMAT = "L>5"
|
540
548
|
|
541
549
|
# @see MachOStructure::SIZEOF
|
542
550
|
# @api private
|
@@ -544,6 +552,7 @@ module MachO
|
|
544
552
|
|
545
553
|
# @api private
|
546
554
|
def initialize(cputype, cpusubtype, offset, size, align)
|
555
|
+
super()
|
547
556
|
@cputype = cputype
|
548
557
|
@cpusubtype = cpusubtype & ~CPU_SUBTYPE_MASK
|
549
558
|
@offset = offset
|
@@ -582,7 +591,7 @@ module MachO
|
|
582
591
|
# @note Always big endian.
|
583
592
|
# @see MachOStructure::FORMAT
|
584
593
|
# @api private
|
585
|
-
FORMAT = "L>2Q>2L>2"
|
594
|
+
FORMAT = "L>2Q>2L>2"
|
586
595
|
|
587
596
|
# @see MachOStructure::SIZEOF
|
588
597
|
# @api private
|
@@ -632,7 +641,7 @@ module MachO
|
|
632
641
|
|
633
642
|
# @see MachOStructure::FORMAT
|
634
643
|
# @api private
|
635
|
-
FORMAT = "L=7"
|
644
|
+
FORMAT = "L=7"
|
636
645
|
|
637
646
|
# @see MachOStructure::SIZEOF
|
638
647
|
# @api private
|
@@ -641,6 +650,7 @@ module MachO
|
|
641
650
|
# @api private
|
642
651
|
def initialize(magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds,
|
643
652
|
flags)
|
653
|
+
super()
|
644
654
|
@magic = magic
|
645
655
|
@cputype = cputype
|
646
656
|
# For now we're not interested in additional capability bits also to be
|
@@ -755,7 +765,7 @@ module MachO
|
|
755
765
|
|
756
766
|
# @see MachOStructure::FORMAT
|
757
767
|
# @api private
|
758
|
-
FORMAT = "L=8"
|
768
|
+
FORMAT = "L=8"
|
759
769
|
|
760
770
|
# @see MachOStructure::SIZEOF
|
761
771
|
# @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
|
@@ -225,6 +231,7 @@ module MachO
|
|
225
231
|
# @param cmdsize [Integer] the size of the load command in bytes
|
226
232
|
# @api private
|
227
233
|
def initialize(view, cmd, cmdsize)
|
234
|
+
super()
|
228
235
|
@view = view
|
229
236
|
@cmd = cmd
|
230
237
|
@cmdsize = cmdsize
|
@@ -365,7 +372,7 @@ module MachO
|
|
365
372
|
|
366
373
|
# @see MachOStructure::FORMAT
|
367
374
|
# @api private
|
368
|
-
FORMAT = "L=2a16"
|
375
|
+
FORMAT = "L=2a16"
|
369
376
|
|
370
377
|
# @see MachOStructure::SIZEOF
|
371
378
|
# @api private
|
@@ -379,7 +386,7 @@ module MachO
|
|
379
386
|
|
380
387
|
# @return [String] a string representation of the UUID
|
381
388
|
def uuid_string
|
382
|
-
hexes = uuid.map { |
|
389
|
+
hexes = uuid.map { |elem| "%02<elem>x" % { :elem => elem } }
|
383
390
|
segs = [
|
384
391
|
hexes[0..3].join, hexes[4..5].join, hexes[6..7].join,
|
385
392
|
hexes[8..9].join, hexes[10..15].join
|
@@ -429,7 +436,7 @@ module MachO
|
|
429
436
|
|
430
437
|
# @see MachOStructure::FORMAT
|
431
438
|
# @api private
|
432
|
-
FORMAT = "L=2Z16L=4l=2L=2"
|
439
|
+
FORMAT = "L=2Z16L=4l=2L=2"
|
433
440
|
|
434
441
|
# @see MachOStructure::SIZEOF
|
435
442
|
# @api private
|
@@ -524,7 +531,7 @@ module MachO
|
|
524
531
|
class SegmentCommand64 < SegmentCommand
|
525
532
|
# @see MachOStructure::FORMAT
|
526
533
|
# @api private
|
527
|
-
FORMAT = "L=2Z16Q=4l=2L=2"
|
534
|
+
FORMAT = "L=2Z16Q=4l=2L=2"
|
528
535
|
|
529
536
|
# @see MachOStructure::SIZEOF
|
530
537
|
# @api private
|
@@ -550,7 +557,7 @@ module MachO
|
|
550
557
|
|
551
558
|
# @see MachOStructure::FORMAT
|
552
559
|
# @api private
|
553
|
-
FORMAT = "L=6"
|
560
|
+
FORMAT = "L=6"
|
554
561
|
|
555
562
|
# @see MachOStructure::SIZEOF
|
556
563
|
# @api private
|
@@ -601,7 +608,7 @@ module MachO
|
|
601
608
|
|
602
609
|
# @see MachOStructure::FORMAT
|
603
610
|
# @api private
|
604
|
-
FORMAT = "L=3"
|
611
|
+
FORMAT = "L=3"
|
605
612
|
|
606
613
|
# @see MachOStructure::SIZEOF
|
607
614
|
# @api private
|
@@ -649,7 +656,7 @@ module MachO
|
|
649
656
|
|
650
657
|
# @see MachOStructure::FORMAT
|
651
658
|
# @api private
|
652
|
-
FORMAT = "L=5"
|
659
|
+
FORMAT = "L=5"
|
653
660
|
|
654
661
|
# @see MachOStructure::SIZEOF
|
655
662
|
# @api private
|
@@ -679,7 +686,7 @@ module MachO
|
|
679
686
|
class ThreadCommand < LoadCommand
|
680
687
|
# @see MachOStructure::FORMAT
|
681
688
|
# @api private
|
682
|
-
FORMAT = "L=2"
|
689
|
+
FORMAT = "L=2"
|
683
690
|
|
684
691
|
# @see MachOStructure::SIZEOF
|
685
692
|
# @api private
|
@@ -717,7 +724,7 @@ module MachO
|
|
717
724
|
|
718
725
|
# @see MachOStructure::FORMAT
|
719
726
|
# @api private
|
720
|
-
FORMAT = "L=10"
|
727
|
+
FORMAT = "L=10"
|
721
728
|
|
722
729
|
# @see MachOStructure::SIZEOF
|
723
730
|
# @api private
|
@@ -758,7 +765,7 @@ module MachO
|
|
758
765
|
class RoutinesCommand64 < RoutinesCommand
|
759
766
|
# @see MachOStructure::FORMAT
|
760
767
|
# @api private
|
761
|
-
FORMAT = "L=2Q=8"
|
768
|
+
FORMAT = "L=2Q=8"
|
762
769
|
|
763
770
|
# @see MachOStructure::SIZEOF
|
764
771
|
# @api private
|
@@ -773,7 +780,7 @@ module MachO
|
|
773
780
|
|
774
781
|
# @see MachOStructure::FORMAT
|
775
782
|
# @api private
|
776
|
-
FORMAT = "L=3"
|
783
|
+
FORMAT = "L=3"
|
777
784
|
|
778
785
|
# @see MachOStructure::SIZEOF
|
779
786
|
# @api private
|
@@ -801,7 +808,7 @@ module MachO
|
|
801
808
|
|
802
809
|
# @see MachOStructure::FORMAT
|
803
810
|
# @api private
|
804
|
-
FORMAT = "L=3"
|
811
|
+
FORMAT = "L=3"
|
805
812
|
|
806
813
|
# @see MachOStructure::SIZEOF
|
807
814
|
# @api private
|
@@ -829,7 +836,7 @@ module MachO
|
|
829
836
|
|
830
837
|
# @see MachOStructure::FORMAT
|
831
838
|
# @api private
|
832
|
-
FORMAT = "L=3"
|
839
|
+
FORMAT = "L=3"
|
833
840
|
|
834
841
|
# @see MachOStructure::SIZEOF
|
835
842
|
# @api private
|
@@ -857,7 +864,7 @@ module MachO
|
|
857
864
|
|
858
865
|
# @see MachOStructure::FORMAT
|
859
866
|
# @api private
|
860
|
-
FORMAT = "L=3"
|
867
|
+
FORMAT = "L=3"
|
861
868
|
|
862
869
|
# @see MachOStructure::SIZEOF
|
863
870
|
# @api private
|
@@ -894,7 +901,7 @@ module MachO
|
|
894
901
|
|
895
902
|
# @see MachOStructure::FORMAT
|
896
903
|
# @api private
|
897
|
-
FORMAT = "L=6"
|
904
|
+
FORMAT = "L=6"
|
898
905
|
|
899
906
|
# @see MachOStructure::SIZEOF
|
900
907
|
# @api private
|
@@ -979,7 +986,7 @@ module MachO
|
|
979
986
|
|
980
987
|
# @see MachOStructure::FORMAT
|
981
988
|
# @api private
|
982
|
-
FORMAT = "L=20"
|
989
|
+
FORMAT = "L=20"
|
983
990
|
|
984
991
|
# @see MachOStructure::SIZEOF
|
985
992
|
# @api private
|
@@ -1052,7 +1059,7 @@ module MachO
|
|
1052
1059
|
|
1053
1060
|
# @see MachOStructure::FORMAT
|
1054
1061
|
# @api private
|
1055
|
-
FORMAT = "L=4"
|
1062
|
+
FORMAT = "L=4"
|
1056
1063
|
|
1057
1064
|
# @see MachOStructure::SIZEOF
|
1058
1065
|
# @api private
|
@@ -1127,7 +1134,7 @@ module MachO
|
|
1127
1134
|
|
1128
1135
|
# @see MachOStructure::FORMAT
|
1129
1136
|
# @api private
|
1130
|
-
FORMAT = "L=3"
|
1137
|
+
FORMAT = "L=3"
|
1131
1138
|
|
1132
1139
|
# @see MachOStructure::SIZEOF
|
1133
1140
|
# @api private
|
@@ -1156,7 +1163,7 @@ module MachO
|
|
1156
1163
|
|
1157
1164
|
# @see MachOStructure::FORMAT
|
1158
1165
|
# @api private
|
1159
|
-
FORMAT = "L=3"
|
1166
|
+
FORMAT = "L=3"
|
1160
1167
|
|
1161
1168
|
# @see MachOStructure::SIZEOF
|
1162
1169
|
# @api private
|
@@ -1191,7 +1198,8 @@ module MachO
|
|
1191
1198
|
# A load command representing the offsets and sizes of a blob of data in
|
1192
1199
|
# the __LINKEDIT segment. Corresponds to LC_CODE_SIGNATURE,
|
1193
1200
|
# LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE,
|
1194
|
-
# LC_DYLIB_CODE_SIGN_DRS,
|
1201
|
+
# LC_DYLIB_CODE_SIGN_DRS, LC_LINKER_OPTIMIZATION_HINT, LC_DYLD_EXPORTS_TRIE,
|
1202
|
+
# or LC_DYLD_CHAINED_FIXUPS.
|
1195
1203
|
class LinkeditDataCommand < LoadCommand
|
1196
1204
|
# @return [Integer] offset to the data in the __LINKEDIT segment
|
1197
1205
|
attr_reader :dataoff
|
@@ -1201,7 +1209,7 @@ module MachO
|
|
1201
1209
|
|
1202
1210
|
# @see MachOStructure::FORMAT
|
1203
1211
|
# @api private
|
1204
|
-
FORMAT = "L=4"
|
1212
|
+
FORMAT = "L=4"
|
1205
1213
|
|
1206
1214
|
# @see MachOStructure::SIZEOF
|
1207
1215
|
# @api private
|
@@ -1237,7 +1245,7 @@ module MachO
|
|
1237
1245
|
|
1238
1246
|
# @see MachOStructure::FORMAT
|
1239
1247
|
# @api private
|
1240
|
-
FORMAT = "L=5"
|
1248
|
+
FORMAT = "L=5"
|
1241
1249
|
|
1242
1250
|
# @see MachOStructure::SIZEOF
|
1243
1251
|
# @api private
|
@@ -1269,7 +1277,7 @@ module MachO
|
|
1269
1277
|
|
1270
1278
|
# @see MachOStructure::FORMAT
|
1271
1279
|
# @api private
|
1272
|
-
FORMAT = "L=6"
|
1280
|
+
FORMAT = "L=6"
|
1273
1281
|
|
1274
1282
|
# @see MachOStructure::SIZEOF
|
1275
1283
|
# @api private
|
@@ -1301,7 +1309,7 @@ module MachO
|
|
1301
1309
|
|
1302
1310
|
# @see MachOStructure::FORMAT
|
1303
1311
|
# @api private
|
1304
|
-
FORMAT = "L=4"
|
1312
|
+
FORMAT = "L=4"
|
1305
1313
|
|
1306
1314
|
# @see MachOStructure::SIZEOF
|
1307
1315
|
# @api private
|
@@ -1317,7 +1325,7 @@ module MachO
|
|
1317
1325
|
# A string representation of the binary's minimum OS version.
|
1318
1326
|
# @return [String] a string representing the minimum OS version.
|
1319
1327
|
def version_string
|
1320
|
-
binary = "%
|
1328
|
+
binary = "%032<version>b" % { :version => version }
|
1321
1329
|
segs = [
|
1322
1330
|
binary[0..15], binary[16..23], binary[24..31]
|
1323
1331
|
].map { |s| s.to_i(2) }
|
@@ -1328,7 +1336,7 @@ module MachO
|
|
1328
1336
|
# A string representation of the binary's SDK version.
|
1329
1337
|
# @return [String] a string representing the SDK version.
|
1330
1338
|
def sdk_string
|
1331
|
-
binary = "%
|
1339
|
+
binary = "%032<sdk>b" % { :sdk => sdk }
|
1332
1340
|
segs = [
|
1333
1341
|
binary[0..15], binary[16..23], binary[24..31]
|
1334
1342
|
].map { |s| s.to_i(2) }
|
@@ -1365,7 +1373,7 @@ module MachO
|
|
1365
1373
|
|
1366
1374
|
# @see MachOStructure::FORMAT
|
1367
1375
|
# @api private
|
1368
|
-
FORMAT = "L=6"
|
1376
|
+
FORMAT = "L=6"
|
1369
1377
|
|
1370
1378
|
# @see MachOStructure::SIZEOF
|
1371
1379
|
# @api private
|
@@ -1383,7 +1391,7 @@ module MachO
|
|
1383
1391
|
# A string representation of the binary's minimum OS version.
|
1384
1392
|
# @return [String] a string representing the minimum OS version.
|
1385
1393
|
def minos_string
|
1386
|
-
binary = "%
|
1394
|
+
binary = "%032<minos>b" % { :minos => minos }
|
1387
1395
|
segs = [
|
1388
1396
|
binary[0..15], binary[16..23], binary[24..31]
|
1389
1397
|
].map { |s| s.to_i(2) }
|
@@ -1394,7 +1402,7 @@ module MachO
|
|
1394
1402
|
# A string representation of the binary's SDK version.
|
1395
1403
|
# @return [String] a string representing the SDK version.
|
1396
1404
|
def sdk_string
|
1397
|
-
binary = "%
|
1405
|
+
binary = "%032<sdk>b" % { :sdk => sdk }
|
1398
1406
|
segs = [
|
1399
1407
|
binary[0..15], binary[16..23], binary[24..31]
|
1400
1408
|
].map { |s| s.to_i(2) }
|
@@ -1494,7 +1502,7 @@ module MachO
|
|
1494
1502
|
|
1495
1503
|
# @see MachOStructure::FORMAT
|
1496
1504
|
# @api private
|
1497
|
-
FORMAT = "L=12"
|
1505
|
+
FORMAT = "L=12"
|
1498
1506
|
|
1499
1507
|
# @see MachOStructure::SIZEOF
|
1500
1508
|
# @api private
|
@@ -1542,7 +1550,7 @@ module MachO
|
|
1542
1550
|
|
1543
1551
|
# @see MachOStructure::FORMAT
|
1544
1552
|
# @api private
|
1545
|
-
FORMAT = "L=3"
|
1553
|
+
FORMAT = "L=3"
|
1546
1554
|
|
1547
1555
|
# @see MachOStructure::SIZEOF
|
1548
1556
|
# @api private
|
@@ -1572,7 +1580,7 @@ module MachO
|
|
1572
1580
|
|
1573
1581
|
# @see MachOStructure::FORMAT
|
1574
1582
|
# @api private
|
1575
|
-
FORMAT = "L=2Q=2"
|
1583
|
+
FORMAT = "L=2Q=2"
|
1576
1584
|
|
1577
1585
|
# @see MachOStructure::SIZEOF
|
1578
1586
|
# @api private
|
@@ -1602,7 +1610,7 @@ module MachO
|
|
1602
1610
|
|
1603
1611
|
# @see MachOStructure::FORMAT
|
1604
1612
|
# @api private
|
1605
|
-
FORMAT = "L=2Q=1"
|
1613
|
+
FORMAT = "L=2Q=1"
|
1606
1614
|
|
1607
1615
|
# @see MachOStructure::SIZEOF
|
1608
1616
|
# @api private
|
@@ -1617,7 +1625,7 @@ module MachO
|
|
1617
1625
|
# A string representation of the sources used to build the binary.
|
1618
1626
|
# @return [String] a string representation of the version
|
1619
1627
|
def version_string
|
1620
|
-
binary = "%
|
1628
|
+
binary = "%064<version>b" % { :version => version }
|
1621
1629
|
segs = [
|
1622
1630
|
binary[0..23], binary[24..33], binary[34..43], binary[44..53],
|
1623
1631
|
binary[54..63]
|
@@ -1646,7 +1654,7 @@ module MachO
|
|
1646
1654
|
|
1647
1655
|
# @see MachOStructure::FORMAT
|
1648
1656
|
# @api private
|
1649
|
-
FORMAT = "L=4"
|
1657
|
+
FORMAT = "L=4"
|
1650
1658
|
|
1651
1659
|
# @see MachOStructure::SIZEOF
|
1652
1660
|
# @api private
|
@@ -1674,7 +1682,7 @@ module MachO
|
|
1674
1682
|
class IdentCommand < LoadCommand
|
1675
1683
|
# @see MachOStructure::FORMAT
|
1676
1684
|
# @api private
|
1677
|
-
FORMAT = "L=2"
|
1685
|
+
FORMAT = "L=2"
|
1678
1686
|
|
1679
1687
|
# @see MachOStructure::SIZEOF
|
1680
1688
|
# @api private
|
@@ -1692,7 +1700,7 @@ module MachO
|
|
1692
1700
|
|
1693
1701
|
# @see MachOStructure::FORMAT
|
1694
1702
|
# @api private
|
1695
|
-
FORMAT = "L=4"
|
1703
|
+
FORMAT = "L=4"
|
1696
1704
|
|
1697
1705
|
# @see MachOStructure::SIZEOF
|
1698
1706
|
# @api private
|
@@ -1727,7 +1735,7 @@ module MachO
|
|
1727
1735
|
|
1728
1736
|
# @see MachOStructure::FORMAT
|
1729
1737
|
# @api private
|
1730
|
-
FORMAT = "L=5"
|
1738
|
+
FORMAT = "L=5"
|
1731
1739
|
|
1732
1740
|
# @see MachOStructure::SIZEOF
|
1733
1741
|
# @api private
|
@@ -1764,7 +1772,7 @@ module MachO
|
|
1764
1772
|
|
1765
1773
|
# @see MachOStructure::FORMAT
|
1766
1774
|
# @api private
|
1767
|
-
FORMAT = "L=2Z16Q=2"
|
1775
|
+
FORMAT = "L=2Z16Q=2"
|
1768
1776
|
|
1769
1777
|
# @see MachOStructure::SIZEOF
|
1770
1778
|
# @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)
|
@@ -411,11 +418,8 @@ module MachO
|
|
411
418
|
rpath_cmds = command(:LC_RPATH).select { |r| r.path.to_s == path }
|
412
419
|
raise RpathUnknownError, path if rpath_cmds.empty?
|
413
420
|
|
414
|
-
# delete the commands in reverse order, offset descending.
|
415
|
-
|
416
|
-
rpath_cmds.reverse_each { |cmd| delete_command(cmd, :repopulate => false) }
|
417
|
-
|
418
|
-
populate_fields
|
421
|
+
# delete the commands in reverse order, offset descending.
|
422
|
+
rpath_cmds.reverse_each { |cmd| delete_command(cmd) }
|
419
423
|
end
|
420
424
|
|
421
425
|
# Write all Mach-O data to the given filename.
|
@@ -471,7 +475,7 @@ module MachO
|
|
471
475
|
# @raise [FatBinaryError] if the magic is for a Fat file
|
472
476
|
# @api private
|
473
477
|
def populate_and_check_magic
|
474
|
-
magic = @raw_data[0..3].
|
478
|
+
magic = @raw_data[0..3].unpack1("N")
|
475
479
|
|
476
480
|
raise MagicError, magic unless Utils.magic?(magic)
|
477
481
|
raise FatBinaryError if Utils.fat_magic?(magic)
|
@@ -511,19 +515,25 @@ module MachO
|
|
511
515
|
# @raise [LoadCommandError] if an unknown load command is encountered
|
512
516
|
# @api private
|
513
517
|
def populate_load_commands
|
518
|
+
permissive = options.fetch(:permissive, false)
|
514
519
|
offset = header.class.bytesize
|
515
520
|
load_commands = []
|
516
521
|
|
517
522
|
header.ncmds.times do
|
518
523
|
fmt = Utils.specialize_format("L=", endianness)
|
519
|
-
cmd = @raw_data.slice(offset, 4).
|
524
|
+
cmd = @raw_data.slice(offset, 4).unpack1(fmt)
|
520
525
|
cmd_sym = LoadCommands::LOAD_COMMANDS[cmd]
|
521
526
|
|
522
|
-
raise LoadCommandError, cmd
|
527
|
+
raise LoadCommandError, cmd unless cmd_sym || permissive
|
528
|
+
|
529
|
+
# If we're here, then either cmd_sym represents a valid load
|
530
|
+
# command *or* we're in permissive mode.
|
531
|
+
klass = if (klass_str = LoadCommands::LC_STRUCTURES[cmd_sym])
|
532
|
+
LoadCommands.const_get klass_str
|
533
|
+
else
|
534
|
+
LoadCommands::LoadCommand
|
535
|
+
end
|
523
536
|
|
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
537
|
view = MachOView.new(@raw_data, endianness, offset)
|
528
538
|
command = klass.new_from_bin(view)
|
529
539
|
|
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
|
@@ -116,6 +118,7 @@ module MachO
|
|
116
118
|
# @api private
|
117
119
|
def initialize(sectname, segname, addr, size, offset, align, reloff,
|
118
120
|
nreloc, flags, reserved1, reserved2)
|
121
|
+
super()
|
119
122
|
@sectname = sectname
|
120
123
|
@segname = segname
|
121
124
|
@addr = addr
|
@@ -180,7 +183,7 @@ module MachO
|
|
180
183
|
attr_reader :reserved3
|
181
184
|
|
182
185
|
# @see MachOStructure::FORMAT
|
183
|
-
FORMAT = "Z16Z16Q=2L=8"
|
186
|
+
FORMAT = "Z16Z16Q=2L=8"
|
184
187
|
|
185
188
|
# @see MachOStructure::SIZEOF
|
186
189
|
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
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
|
@@ -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: 2.1
|
4
|
+
version: 2.5.1
|
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: 2021-05-15 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.5'
|
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.0.3
|
54
53
|
signing_key:
|
55
54
|
specification_version: 4
|
56
55
|
summary: ruby-macho - Mach-O file analyzer.
|