ruby-macho 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/macho.rb +1 -1
- data/lib/macho/fat_file.rb +17 -9
- data/lib/macho/headers.rb +5 -0
- data/lib/macho/macho_file.rb +30 -19
- 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: a6043ad4ddee8f973862b3f37626351bce8bcd9a190ec5e3f87dbbc169185661
|
4
|
+
data.tar.gz: 95afb17f5b95f4c06e1c67ac51a8ea38903fe629b7914d5a67701509c2cad040
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55be478649522a73fe487013c9ff32378f773b4d21b1657d584e4436cbf3d4a5462482c6a1d6b50ae34e2506051905dd1349b8ef436d80423658e70a0ccc0315
|
7
|
+
data.tar.gz: 0524245cee9c8a416734449e9f2c3ac3b7a34b2922ff1c1468edf38fe45255f912e9cd80b677cc67692b2c976af41ce4d75a88dcbef5ffd2ac0e5259dbde5afd
|
data/lib/macho.rb
CHANGED
@@ -12,7 +12,7 @@ require_relative "macho/tools"
|
|
12
12
|
# The primary namespace for ruby-macho.
|
13
13
|
module MachO
|
14
14
|
# release version
|
15
|
-
VERSION = "2.
|
15
|
+
VERSION = "2.2.0".freeze
|
16
16
|
|
17
17
|
# Opens the given filename as a MachOFile or FatFile, depending on its magic.
|
18
18
|
# @param filename [String] the file being opened
|
data/lib/macho/fat_file.rb
CHANGED
@@ -11,6 +11,10 @@ module MachO
|
|
11
11
|
# @return [String] the filename loaded from, or nil if loaded from a binary string
|
12
12
|
attr_accessor :filename
|
13
13
|
|
14
|
+
# @return [Hash] any parser options that the instance was created with
|
15
|
+
# @note Options specified in a {FatFile} trickle down into the internal {MachOFile}s.
|
16
|
+
attr_reader :options
|
17
|
+
|
14
18
|
# @return [Headers::FatHeader] the file's header
|
15
19
|
attr_reader :header
|
16
20
|
|
@@ -49,9 +53,7 @@ module MachO
|
|
49
53
|
machos.each do |macho|
|
50
54
|
macho_offset = Utils.round(offset, 2**macho.segment_alignment)
|
51
55
|
|
52
|
-
if !fat64 && macho_offset > (2**32 - 1)
|
53
|
-
raise FatArchOffsetOverflowError, macho_offset
|
54
|
-
end
|
56
|
+
raise FatArchOffsetOverflowError, macho_offset if !fat64 && macho_offset > (2**32 - 1)
|
55
57
|
|
56
58
|
macho_pads[macho] = Utils.padding_for(offset, 2**macho.segment_alignment)
|
57
59
|
|
@@ -72,30 +74,36 @@ module MachO
|
|
72
74
|
|
73
75
|
# Creates a new FatFile instance from a binary string.
|
74
76
|
# @param bin [String] a binary string containing raw Mach-O data
|
77
|
+
# @param opts [Hash] options to control the parser with
|
78
|
+
# @note see {MachOFile#initialize} for currently valid options
|
75
79
|
# @return [FatFile] a new FatFile
|
76
|
-
def self.new_from_bin(bin)
|
80
|
+
def self.new_from_bin(bin, **opts)
|
77
81
|
instance = allocate
|
78
|
-
instance.initialize_from_bin(bin)
|
82
|
+
instance.initialize_from_bin(bin, opts)
|
79
83
|
|
80
84
|
instance
|
81
85
|
end
|
82
86
|
|
83
87
|
# Creates a new FatFile from the given filename.
|
84
88
|
# @param filename [String] the fat file to load from
|
89
|
+
# @param opts [Hash] options to control the parser with
|
90
|
+
# @note see {MachOFile#initialize} for currently valid options
|
85
91
|
# @raise [ArgumentError] if the given file does not exist
|
86
|
-
def initialize(filename)
|
92
|
+
def initialize(filename, **opts)
|
87
93
|
raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
|
88
94
|
|
89
95
|
@filename = filename
|
96
|
+
@options = opts
|
90
97
|
@raw_data = File.open(@filename, "rb", &:read)
|
91
98
|
populate_fields
|
92
99
|
end
|
93
100
|
|
94
|
-
# Initializes a new FatFile instance from a binary string.
|
101
|
+
# Initializes a new FatFile instance from a binary string with the given options.
|
95
102
|
# @see new_from_bin
|
96
103
|
# @api private
|
97
|
-
def initialize_from_bin(bin)
|
104
|
+
def initialize_from_bin(bin, opts)
|
98
105
|
@filename = nil
|
106
|
+
@options = opts
|
99
107
|
@raw_data = bin
|
100
108
|
populate_fields
|
101
109
|
end
|
@@ -358,7 +366,7 @@ module MachO
|
|
358
366
|
machos = []
|
359
367
|
|
360
368
|
fat_archs.each do |arch|
|
361
|
-
machos << MachOFile.new_from_bin(@raw_data[arch.offset, arch.size])
|
369
|
+
machos << MachOFile.new_from_bin(@raw_data[arch.offset, arch.size], **options)
|
362
370
|
end
|
363
371
|
|
364
372
|
machos
|
data/lib/macho/headers.rb
CHANGED
@@ -241,6 +241,10 @@ module MachO
|
|
241
241
|
# @api private
|
242
242
|
CPU_SUBTYPE_ARM64_32_V8 = 1
|
243
243
|
|
244
|
+
# the e (A12) sub-type for `CPU_TYPE_ARM64`
|
245
|
+
# @api private
|
246
|
+
CPU_SUBTYPE_ARM64E = 2
|
247
|
+
|
244
248
|
# the lowest common sub-type for `CPU_TYPE_MC88000`
|
245
249
|
# @api private
|
246
250
|
CPU_SUBTYPE_MC88000_ALL = 0
|
@@ -350,6 +354,7 @@ module MachO
|
|
350
354
|
CPU_TYPE_ARM64 => {
|
351
355
|
CPU_SUBTYPE_ARM64_ALL => :arm64,
|
352
356
|
CPU_SUBTYPE_ARM64_V8 => :arm64v8,
|
357
|
+
CPU_SUBTYPE_ARM64E => :arm64e,
|
353
358
|
}.freeze,
|
354
359
|
CPU_TYPE_ARM64_32 => {
|
355
360
|
CPU_SUBTYPE_ARM64_32_V8 => :arm64_32v8,
|
data/lib/macho/macho_file.rb
CHANGED
@@ -9,10 +9,13 @@ module MachO
|
|
9
9
|
class MachOFile
|
10
10
|
extend Forwardable
|
11
11
|
|
12
|
-
# @return [String] the filename loaded from, or nil if loaded from a binary
|
12
|
+
# @return [String, nil] the filename loaded from, or nil if loaded from a binary
|
13
13
|
# string
|
14
14
|
attr_accessor :filename
|
15
15
|
|
16
|
+
# @return [Hash] any parser options that the instance was created with
|
17
|
+
attr_reader :options
|
18
|
+
|
16
19
|
# @return [Symbol] the endianness of the file, :big or :little
|
17
20
|
attr_reader :endianness
|
18
21
|
|
@@ -27,30 +30,36 @@ module MachO
|
|
27
30
|
|
28
31
|
# Creates a new instance from a binary string.
|
29
32
|
# @param bin [String] a binary string containing raw Mach-O data
|
33
|
+
# @param opts [Hash] options to control the parser with
|
34
|
+
# @option opts [Boolean] :permissive whether to ignore unknown load commands
|
30
35
|
# @return [MachOFile] a new MachOFile
|
31
|
-
def self.new_from_bin(bin)
|
36
|
+
def self.new_from_bin(bin, **opts)
|
32
37
|
instance = allocate
|
33
|
-
instance.initialize_from_bin(bin)
|
38
|
+
instance.initialize_from_bin(bin, opts)
|
34
39
|
|
35
40
|
instance
|
36
41
|
end
|
37
42
|
|
38
43
|
# Creates a new instance from data read from the given filename.
|
39
44
|
# @param filename [String] the Mach-O file to load from
|
45
|
+
# @param opts [Hash] options to control the parser with
|
46
|
+
# @option opts [Boolean] :permissive whether to ignore unknown load commands
|
40
47
|
# @raise [ArgumentError] if the given file does not exist
|
41
|
-
def initialize(filename)
|
48
|
+
def initialize(filename, **opts)
|
42
49
|
raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
|
43
50
|
|
44
51
|
@filename = filename
|
52
|
+
@options = opts
|
45
53
|
@raw_data = File.open(@filename, "rb", &:read)
|
46
54
|
populate_fields
|
47
55
|
end
|
48
56
|
|
49
|
-
# Initializes a new MachOFile instance from a binary string.
|
57
|
+
# Initializes a new MachOFile instance from a binary string with the given options.
|
50
58
|
# @see MachO::MachOFile.new_from_bin
|
51
59
|
# @api private
|
52
|
-
def initialize_from_bin(bin)
|
60
|
+
def initialize_from_bin(bin, opts)
|
53
61
|
@filename = nil
|
62
|
+
@options = opts
|
54
63
|
@raw_data = bin
|
55
64
|
populate_fields
|
56
65
|
end
|
@@ -146,16 +155,13 @@ module MachO
|
|
146
155
|
def insert_command(offset, lc, options = {})
|
147
156
|
context = LoadCommands::LoadCommand::SerializationContext.context_for(self)
|
148
157
|
cmd_raw = lc.serialize(context)
|
158
|
+
fileoff = offset + cmd_raw.bytesize
|
149
159
|
|
150
|
-
if offset < header.class.bytesize ||
|
151
|
-
raise OffsetInsertionError, offset
|
152
|
-
end
|
160
|
+
raise OffsetInsertionError, offset if offset < header.class.bytesize || fileoff > low_fileoff
|
153
161
|
|
154
162
|
new_sizeofcmds = sizeofcmds + cmd_raw.bytesize
|
155
163
|
|
156
|
-
if header.class.bytesize + new_sizeofcmds > low_fileoff
|
157
|
-
raise HeaderPadError, @filename
|
158
|
-
end
|
164
|
+
raise HeaderPadError, @filename if header.class.bytesize + new_sizeofcmds > low_fileoff
|
159
165
|
|
160
166
|
# update Mach-O header fields to account for inserted load command
|
161
167
|
update_ncmds(ncmds + 1)
|
@@ -178,9 +184,8 @@ module MachO
|
|
178
184
|
context = LoadCommands::LoadCommand::SerializationContext.context_for(self)
|
179
185
|
cmd_raw = new_lc.serialize(context)
|
180
186
|
new_sizeofcmds = sizeofcmds + cmd_raw.bytesize - old_lc.cmdsize
|
181
|
-
|
182
|
-
|
183
|
-
end
|
187
|
+
|
188
|
+
raise HeaderPadError, @filename if header.class.bytesize + new_sizeofcmds > low_fileoff
|
184
189
|
|
185
190
|
delete_command(old_lc)
|
186
191
|
insert_command(old_lc.view.offset, new_lc)
|
@@ -511,6 +516,7 @@ module MachO
|
|
511
516
|
# @raise [LoadCommandError] if an unknown load command is encountered
|
512
517
|
# @api private
|
513
518
|
def populate_load_commands
|
519
|
+
permissive = options.fetch(:permissive, false)
|
514
520
|
offset = header.class.bytesize
|
515
521
|
load_commands = []
|
516
522
|
|
@@ -519,11 +525,16 @@ module MachO
|
|
519
525
|
cmd = @raw_data.slice(offset, 4).unpack(fmt).first
|
520
526
|
cmd_sym = LoadCommands::LOAD_COMMANDS[cmd]
|
521
527
|
|
522
|
-
raise LoadCommandError, cmd
|
528
|
+
raise LoadCommandError, cmd unless cmd_sym || permissive
|
529
|
+
|
530
|
+
# If we're here, then either cmd_sym represents a valid load
|
531
|
+
# command *or* we're in permissive mode.
|
532
|
+
klass = if (klass_str = LoadCommands::LC_STRUCTURES[cmd_sym])
|
533
|
+
LoadCommands.const_get klass_str
|
534
|
+
else
|
535
|
+
LoadCommands::LoadCommand
|
536
|
+
end
|
523
537
|
|
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
538
|
view = MachOView.new(@raw_data, endianness, offset)
|
528
539
|
command = klass.new_from_bin(view)
|
529
540
|
|
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.
|
4
|
+
version: 2.2.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: 2019-02-21 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.0.1
|
54
53
|
signing_key:
|
55
54
|
specification_version: 4
|
56
55
|
summary: ruby-macho - Mach-O file analyzer.
|