ruby-macho 0.2.4 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
data/lib/macho/open.rb CHANGED
@@ -7,17 +7,17 @@ module MachO
7
7
  # @raise [MachO::TruncatedFileError] if the file is too small to have a valid header
8
8
  # @raise [MachO::MagicError] if the file's magic is not valid Mach-O magic
9
9
  def self.open(filename)
10
- raise ArgumentError.new("#{filename}: no such file") unless File.file?(filename)
11
- raise TruncatedFileError.new unless File.stat(filename).size >= 4
10
+ raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
11
+ raise TruncatedFileError unless File.stat(filename).size >= 4
12
12
 
13
13
  magic = File.open(filename, "rb") { |f| f.read(4) }.unpack("N").first
14
14
 
15
- if MachO.fat_magic?(magic)
15
+ if Utils.fat_magic?(magic)
16
16
  file = FatFile.new(filename)
17
- elsif MachO.magic?(magic)
17
+ elsif Utils.magic?(magic)
18
18
  file = MachOFile.new(filename)
19
19
  else
20
- raise MagicError.new(magic)
20
+ raise MagicError, magic
21
21
  end
22
22
 
23
23
  file
@@ -45,7 +45,7 @@ module MachO
45
45
  :S_ATTR_DEBUG => 0x02000000,
46
46
  :S_ATTR_SOME_INSTRUCTIONS => 0x00000400,
47
47
  :S_ATTR_EXT_RELOC => 0x00000200,
48
- :S_ATTR_LOC_RELOC => 0x00000100
48
+ :S_ATTR_LOC_RELOC => 0x00000100,
49
49
  }.freeze
50
50
 
51
51
  # association of section name symbols to names
@@ -62,7 +62,7 @@ module MachO
62
62
  :SECT_OBJC_STRINGS => "__selector_strs",
63
63
  :SECT_OBJC_REFS => "__selector_refs",
64
64
  :SECT_ICON_HEADER => "__header",
65
- :SECT_ICON_TIFF => "__tiff"
65
+ :SECT_ICON_TIFF => "__tiff",
66
66
  }.freeze
67
67
 
68
68
  # Represents a section of a segment for 32-bit architectures.
@@ -91,7 +91,7 @@ module MachO
91
91
  # @return [Fixnum] the number of relocation entries
92
92
  attr_reader :nreloc
93
93
 
94
- # @return [Fixnum] flags for type and addrributes of the section
94
+ # @return [Fixnum] flags for type and attributes of the section
95
95
  attr_reader :flags
96
96
 
97
97
  # @return [void] reserved (for offset or index)
@@ -100,12 +100,15 @@ module MachO
100
100
  # @return [void] reserved (for count or sizeof)
101
101
  attr_reader :reserved2
102
102
 
103
- FORMAT = "a16a16L=9"
103
+ # @see MachOStructure::FORMAT
104
+ FORMAT = "a16a16L=9".freeze
105
+
106
+ # @see MachOStructure::SIZEOF
104
107
  SIZEOF = 68
105
108
 
106
109
  # @api private
107
110
  def initialize(sectname, segname, addr, size, offset, align, reloff,
108
- nreloc, flags, reserved1, reserved2)
111
+ nreloc, flags, reserved1, reserved2)
109
112
  @sectname = sectname
110
113
  @segname = segname
111
114
  @addr = addr
@@ -121,12 +124,17 @@ module MachO
121
124
 
122
125
  # @return [String] the section's name, with any trailing NULL characters removed
123
126
  def section_name
124
- @sectname.delete("\x00")
127
+ sectname.delete("\x00")
125
128
  end
126
129
 
127
130
  # @return [String] the parent segment's name, with any trailing NULL characters removed
128
131
  def segment_name
129
- @segname.delete("\x00")
132
+ segname.delete("\x00")
133
+ end
134
+
135
+ # @return [Boolean] true if the section has no contents (i.e, `size` is 0)
136
+ def empty?
137
+ size.zero?
130
138
  end
131
139
 
132
140
  # @example
@@ -145,12 +153,15 @@ module MachO
145
153
  # @return [void] reserved
146
154
  attr_reader :reserved3
147
155
 
148
- FORMAT = "a16a16Q=2L=8"
156
+ # @see MachOStructure::FORMAT
157
+ FORMAT = "a16a16Q=2L=8".freeze
158
+
159
+ # @see MachOStructure::SIZEOF
149
160
  SIZEOF = 80
150
161
 
151
162
  # @api private
152
163
  def initialize(sectname, segname, addr, size, offset, align, reloff,
153
- nreloc, flags, reserved1, reserved2, reserved3)
164
+ nreloc, flags, reserved1, reserved2, reserved3)
154
165
  super(sectname, segname, addr, size, offset, align, reloff,
155
166
  nreloc, flags, reserved1, reserved2)
156
167
  @reserved3 = reserved3
@@ -3,9 +3,13 @@ module MachO
3
3
  # @abstract
4
4
  class MachOStructure
5
5
  # The String#unpack format of the data structure.
6
- FORMAT = ""
6
+ # @return [String] the unpacking format
7
+ # @api private
8
+ FORMAT = "".freeze
7
9
 
8
10
  # The size of the data structure, in bytes.
11
+ # @return [Fixnum] the size, in bytes
12
+ # @api private
9
13
  SIZEOF = 0
10
14
 
11
15
  # @return [Fixnum] the size, in bytes, of the represented structure.
@@ -13,26 +17,14 @@ module MachO
13
17
  self::SIZEOF
14
18
  end
15
19
 
16
- # @param endianness [Symbol] either :big or :little
20
+ # @param endianness [Symbol] either `:big` or `:little`
17
21
  # @param bin [String] the string to be unpacked into the new structure
18
22
  # @return [MachO::MachOStructure] a new MachOStructure initialized with `bin`
19
23
  # @api private
20
24
  def self.new_from_bin(endianness, bin)
21
- format = specialize_format(self::FORMAT, endianness)
22
-
23
- self.new(*bin.unpack(format))
24
- end
25
-
26
- private
25
+ format = Utils.specialize_format(self::FORMAT, endianness)
27
26
 
28
- # Convert an abstract (native-endian) String#unpack format to big or little.
29
- # @param format [String] the format string being converted
30
- # @param endianness [Symbol] either :big or :little
31
- # @return [String] the converted string
32
- # @api private
33
- def self.specialize_format(format, endianness)
34
- modifier = (endianness == :big) ? ">" : "<"
35
- format.tr("=", modifier)
27
+ new(*bin.unpack(format))
36
28
  end
37
29
  end
38
30
  end
data/lib/macho/tools.rb CHANGED
@@ -12,12 +12,14 @@ module MachO
12
12
  # Changes the dylib ID of a Mach-O or Fat binary, overwriting the source file.
13
13
  # @param filename [String] the Mach-O or Fat binary being modified
14
14
  # @param new_id [String] the new dylib ID for the binary
15
+ # @param options [Hash]
16
+ # @option options [Boolean] :strict (true) whether or not to fail loudly
17
+ # with an exception if the change cannot be performed
15
18
  # @return [void]
16
- # @todo unstub for fat files
17
- def self.change_dylib_id(filename, new_id)
19
+ def self.change_dylib_id(filename, new_id, options = {})
18
20
  file = MachO.open(filename)
19
21
 
20
- file.dylib_id = new_id
22
+ file.change_dylib_id(new_id, options)
21
23
  file.write!
22
24
  end
23
25
 
@@ -25,12 +27,14 @@ module MachO
25
27
  # @param filename [String] the Mach-O or Fat binary being modified
26
28
  # @param old_name [String] the old shared library name
27
29
  # @param new_name [String] the new shared library name
30
+ # @param options [Hash]
31
+ # @option options [Boolean] :strict (true) whether or not to fail loudly
32
+ # with an exception if the change cannot be performed
28
33
  # @return [void]
29
- # @todo unstub for fat files
30
- def self.change_install_name(filename, old_name, new_name)
34
+ def self.change_install_name(filename, old_name, new_name, options = {})
31
35
  file = MachO.open(filename)
32
36
 
33
- file.change_install_name(old_name, new_name)
37
+ file.change_install_name(old_name, new_name, options)
34
38
  file.write!
35
39
  end
36
40
 
@@ -38,28 +42,43 @@ module MachO
38
42
  # @param filename [String] the Mach-O or Fat binary being modified
39
43
  # @param old_path [String] the old runtime path
40
44
  # @param new_path [String] the new runtime path
45
+ # @param options [Hash]
46
+ # @option options [Boolean] :strict (true) whether or not to fail loudly
47
+ # with an exception if the change cannot be performed
41
48
  # @return [void]
42
- # @todo unstub
43
- def self.change_rpath(filename, old_path, new_path)
44
- raise UnimplementedError.new("changing rpaths in a Mach-O")
49
+ def self.change_rpath(filename, old_path, new_path, options = {})
50
+ file = MachO.open(filename)
51
+
52
+ file.change_rpath(old_path, new_path, options)
53
+ file.write!
45
54
  end
46
55
 
47
56
  # Add a runtime path to a Mach-O or Fat binary, overwriting the source file.
48
57
  # @param filename [String] the Mach-O or Fat binary being modified
49
58
  # @param new_path [String] the new runtime path
59
+ # @param options [Hash]
60
+ # @option options [Boolean] :strict (true) whether or not to fail loudly
61
+ # with an exception if the change cannot be performed
50
62
  # @return [void]
51
- # @todo unstub
52
- def self.add_rpath(filename, new_path)
53
- raise UnimplementedError.new("adding rpaths to a Mach-O")
63
+ def self.add_rpath(filename, new_path, options = {})
64
+ file = MachO.open(filename)
65
+
66
+ file.add_rpath(new_path, options)
67
+ file.write!
54
68
  end
55
69
 
56
70
  # Delete a runtime path from a Mach-O or Fat binary, overwriting the source file.
57
71
  # @param filename [String] the Mach-O or Fat binary being modified
58
72
  # @param old_path [String] the old runtime path
73
+ # @param options [Hash]
74
+ # @option options [Boolean] :strict (true) whether or not to fail loudly
75
+ # with an exception if the change cannot be performed
59
76
  # @return [void]
60
- # @todo unstub
61
- def self.delete_rpath(filename, old_path)
62
- raise UnimplementedError.new("removing rpaths from a Mach-O")
77
+ def self.delete_rpath(filename, old_path, options = {})
78
+ file = MachO.open(filename)
79
+
80
+ file.delete_rpath(old_path, options)
81
+ file.write!
63
82
  end
64
83
  end
65
84
  end
data/lib/macho/utils.rb CHANGED
@@ -1,48 +1,96 @@
1
1
  module MachO
2
- # @param value [Fixnum] the number being rounded
3
- # @param round [Fixnum] the number being rounded with
4
- # @return [Fixnum] the next number >= `value` such that `round` is its divisor
5
- # @see http://www.opensource.apple.com/source/cctools/cctools-870/libstuff/rnd.c
6
- def self.round(value, round)
7
- round -= 1
8
- value += round
9
- value &= ~round
10
- value
11
- end
2
+ # A collection of utility functions used throughout ruby-macho.
3
+ module Utils
4
+ # Rounds a value to the next multiple of the given round.
5
+ # @param value [Fixnum] the number being rounded
6
+ # @param round [Fixnum] the number being rounded with
7
+ # @return [Fixnum] the rounded value
8
+ # @see http://www.opensource.apple.com/source/cctools/cctools-870/libstuff/rnd.c
9
+ def self.round(value, round)
10
+ round -= 1
11
+ value += round
12
+ value &= ~round
13
+ value
14
+ end
12
15
 
13
- # @param num [Fixnum] the number being checked
14
- # @return [Boolean] true if `num` is a valid Mach-O magic number, false otherwise
15
- def self.magic?(num)
16
- MH_MAGICS.has_key?(num)
17
- end
16
+ # Returns the number of bytes needed to pad the given size to the given alignment.
17
+ # @param size [Fixnum] the unpadded size
18
+ # @param alignment [Fixnum] the number to alignment the size with
19
+ # @return [Fixnum] the number of pad bytes required
20
+ def self.padding_for(size, alignment)
21
+ round(size, alignment) - size
22
+ end
18
23
 
19
- # @param num [Fixnum] the number being checked
20
- # @return [Boolean] true if `num` is a valid Fat magic number, false otherwise
21
- def self.fat_magic?(num)
22
- num == FAT_MAGIC
23
- end
24
+ # Converts an abstract (native-endian) String#unpack format to big or little.
25
+ # @param format [String] the format string being converted
26
+ # @param endianness [Symbol] either `:big` or `:little`
27
+ # @return [String] the converted string
28
+ def self.specialize_format(format, endianness)
29
+ modifier = endianness == :big ? ">" : "<"
30
+ format.tr("=", modifier)
31
+ end
24
32
 
25
- # @param num [Fixnum] the number being checked
26
- # @return [Boolean] true if `num` is a valid 32-bit magic number, false otherwise
27
- def self.magic32?(num)
28
- num == MH_MAGIC || num == MH_CIGAM
29
- end
33
+ # Packs tagged strings into an aligned payload.
34
+ # @param fixed_offset [Fixnum] the baseline offset for the first packed string
35
+ # @param alignment [Fixnum] the alignment value to use for packing
36
+ # @param strings [Hash] the labeled strings to pack
37
+ # @return [Array<String, Hash>] the packed string and labeled offsets
38
+ def self.pack_strings(fixed_offset, alignment, strings = {})
39
+ offsets = {}
40
+ next_offset = fixed_offset
41
+ payload = ""
30
42
 
31
- # @param num [Fixnum] the number being checked
32
- # @return [Boolean] true if `num` is a valid 64-bit magic number, false otherwise
33
- def self.magic64?(num)
34
- num == MH_MAGIC_64 || num == MH_CIGAM_64
35
- end
43
+ strings.each do |key, string|
44
+ offsets[key] = next_offset
45
+ payload << string
46
+ payload << "\x00"
47
+ next_offset += string.bytesize + 1
48
+ end
36
49
 
37
- # @param num [Fixnum] the number being checked
38
- # @return [Boolean] true if `num` is a valid little-endian magic number, false otherwise
39
- def self.little_magic?(num)
40
- num == MH_CIGAM || num == MH_CIGAM_64
41
- end
50
+ payload << "\x00" * padding_for(fixed_offset + payload.bytesize, alignment)
51
+ [payload, offsets]
52
+ end
53
+
54
+ # Compares the given number to valid Mach-O magic numbers.
55
+ # @param num [Fixnum] the number being checked
56
+ # @return [Boolean] true if `num` is a valid Mach-O magic number, false otherwise
57
+ def self.magic?(num)
58
+ MH_MAGICS.key?(num)
59
+ end
60
+
61
+ # Compares the given number to valid Fat magic numbers.
62
+ # @param num [Fixnum] the number being checked
63
+ # @return [Boolean] true if `num` is a valid Fat magic number, false otherwise
64
+ def self.fat_magic?(num)
65
+ num == FAT_MAGIC
66
+ end
67
+
68
+ # Compares the given number to valid 32-bit Mach-O magic numbers.
69
+ # @param num [Fixnum] the number being checked
70
+ # @return [Boolean] true if `num` is a valid 32-bit magic number, false otherwise
71
+ def self.magic32?(num)
72
+ num == MH_MAGIC || num == MH_CIGAM
73
+ end
74
+
75
+ # Compares the given number to valid 64-bit Mach-O magic numbers.
76
+ # @param num [Fixnum] the number being checked
77
+ # @return [Boolean] true if `num` is a valid 64-bit magic number, false otherwise
78
+ def self.magic64?(num)
79
+ num == MH_MAGIC_64 || num == MH_CIGAM_64
80
+ end
81
+
82
+ # Compares the given number to valid little-endian magic numbers.
83
+ # @param num [Fixnum] the number being checked
84
+ # @return [Boolean] true if `num` is a valid little-endian magic number, false otherwise
85
+ def self.little_magic?(num)
86
+ num == MH_CIGAM || num == MH_CIGAM_64
87
+ end
42
88
 
43
- # @param num [Fixnum] the number being checked
44
- # @return [Boolean] true if `num` is a valid big-endian magic number, false otherwise
45
- def self.big_magic?(num)
46
- num == MH_CIGAM || num == MH_CIGAM_64
89
+ # Compares the given number to valid big-endian magic numbers.
90
+ # @param num [Fixnum] the number being checked
91
+ # @return [Boolean] true if `num` is a valid big-endian magic number, false otherwise
92
+ def self.big_magic?(num)
93
+ num == MH_CIGAM || num == MH_CIGAM_64
94
+ end
47
95
  end
48
96
  end
data/lib/macho/view.rb ADDED
@@ -0,0 +1,23 @@
1
+ module MachO
2
+ # A representation of some unspecified Mach-O data.
3
+ class MachOView
4
+ # @return [String] the raw Mach-O data
5
+ attr_reader :raw_data
6
+
7
+ # @return [Symbol] the endianness of the data (`:big` or `:little`)
8
+ attr_reader :endianness
9
+
10
+ # @return [Fixnum] the offset of the relevant data (in {#raw_data})
11
+ attr_reader :offset
12
+
13
+ # Creates a new MachOView.
14
+ # @param raw_data [String] the raw Mach-O data
15
+ # @param endianness [Symbol] the endianness of the data
16
+ # @param offset [Fixnum] the offset of the relevant data
17
+ def initialize(raw_data, endianness, offset)
18
+ @raw_data = raw_data
19
+ @endianness = endianness
20
+ @offset = offset
21
+ end
22
+ end
23
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-macho
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Woodruff
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-18 00:00:00.000000000 Z
11
+ date: 2016-08-07 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@tuffbizz.com
@@ -30,6 +30,7 @@ files:
30
30
  - lib/macho/structure.rb
31
31
  - lib/macho/tools.rb
32
32
  - lib/macho/utils.rb
33
+ - lib/macho/view.rb
33
34
  homepage: https://github.com/Homebrew/ruby-macho
34
35
  licenses:
35
36
  - MIT
@@ -55,3 +56,4 @@ signing_key:
55
56
  specification_version: 4
56
57
  summary: ruby-macho - Mach-O file analyzer.
57
58
  test_files: []
59
+ has_rdoc: