Class: MachO::MachOFile
- Inherits:
-
Object
- Object
- MachO::MachOFile
- Defined in:
- lib/macho/macho_file.rb
Overview
Represents a Mach-O file, which contains a header and load commands as well as binary executable instructions. Mach-O binaries are architecture specific.
Instance Attribute Summary collapse
- #header ⇒ MachO::MachHeader, MachO::MachHeader64 readonly
-
#load_commands ⇒ Array<MachO::LoadCommand>
readonly
An array of the file’s load commands.
Class Method Summary collapse
-
.new_from_bin(bin) ⇒ MachO::MachOFile
Creates a new MachOFile instance from a binary string.
Instance Method Summary collapse
-
#bundle? ⇒ Boolean
True if the Mach-O is of type ‘MH_BUNDLE`, false otherwise.
-
#change_install_name(old_name, new_name) ⇒ void
(also: #change_dylib)
Changes the shared library ‘old_name` to `new_name`.
-
#command(name) ⇒ Array<MachO::LoadCommand>
(also: #[])
All load commands of a given name.
-
#cpusubtype ⇒ String
A string representation of the Mach-O’s CPU subtype.
-
#cputype ⇒ String
A string representation of the Mach-O’s CPU type.
-
#dylib? ⇒ Boolean
True if the Mach-O is of type ‘MH_DYLIB`, false otherwise.
-
#dylib_id ⇒ String?
The Mach-O’s dylib ID, or ‘nil` if not a dylib.
-
#dylib_id=(new_id) ⇒ void
Changes the Mach-O’s dylib ID to ‘new_id`.
-
#executable? ⇒ Boolean
True if the Mach-O is of type ‘MH_EXECUTE`, false otherwise.
-
#filetype ⇒ String
A string representation of the Mach-O’s filetype.
-
#flags ⇒ Fixnum
Execution flags set by the linker.
-
#initialize(filename) ⇒ MachOFile
constructor
Creates a new FatFile from the given filename.
- #initialize_from_bin(bin) ⇒ Object private
-
#linked_dylibs ⇒ Array<String>
All shared libraries linked to the Mach-O.
-
#magic ⇒ Fixnum
The Mach-O’s magic number.
-
#magic32? ⇒ Boolean
True if the Mach-O has 32-bit magic, false otherwise.
-
#magic64? ⇒ Boolean
True if the Mach-O has 64-bit magic, false otherwise.
-
#magic_string ⇒ String
A string representation of the Mach-O’s magic number.
-
#ncmds ⇒ Fixnum
The number of load commands in the Mach-O’s header.
-
#sections(segment) ⇒ Array<MachO::Section>, Array<MachO::Section64>
All sections of the segment ‘segment`.
-
#segments ⇒ Array<MachO::SegmentCommand>, Array<MachO::SegmentCommand64>
All segment load commands in the Mach-O.
-
#serialize ⇒ String
The file’s raw Mach-O data.
-
#sizeofcmds ⇒ Fixnum
The size of all load commands, in bytes.
-
#write(filename) ⇒ void
Write all Mach-O data to the given filename.
-
#write! ⇒ void
Write all Mach-O data to the file used to initialize the instance.
Constructor Details
#initialize(filename) ⇒ MachOFile
Creates a new FatFile from the given filename.
28 29 30 31 32 33 34 35 |
# File 'lib/macho/macho_file.rb', line 28 def initialize(filename) raise ArgumentError.new("#{filetype}: no such file") unless File.exist?(filename) @filename = filename @raw_data = open(@filename, "rb") { |f| f.read } @header = get_mach_header @load_commands = get_load_commands end |
Instance Attribute Details
#header ⇒ MachO::MachHeader, MachO::MachHeader64 (readonly)
10 11 12 |
# File 'lib/macho/macho_file.rb', line 10 def header @header end |
#load_commands ⇒ Array<MachO::LoadCommand> (readonly)
Returns an array of the file’s load commands.
13 14 15 |
# File 'lib/macho/macho_file.rb', line 13 def load_commands @load_commands end |
Class Method Details
.new_from_bin(bin) ⇒ MachO::MachOFile
Creates a new MachOFile instance from a binary string.
18 19 20 21 22 23 |
# File 'lib/macho/macho_file.rb', line 18 def self.new_from_bin(bin) instance = allocate instance.initialize_from_bin(bin) instance end |
Instance Method Details
#bundle? ⇒ Boolean
Returns true if the Mach-O is of type ‘MH_BUNDLE`, false otherwise.
72 73 74 |
# File 'lib/macho/macho_file.rb', line 72 def bundle? header[:filetype] == MH_BUNDLE end |
#change_install_name(old_name, new_name) ⇒ void Also known as: change_dylib
This method returns an undefined value.
Changes the shared library ‘old_name` to `new_name`
195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/macho/macho_file.rb', line 195 def change_install_name(old_name, new_name) idx = linked_dylibs.index(old_name) raise DylibUnknownError.new(old_name) if idx.nil? # this is a bit of a hack - since there is a 1-1 ordered association # between linked_dylibs and command('LC_LOAD_DYLIB'), we can use # their indices interchangeably to avoid having to loop. dylib_cmd = command("LC_LOAD_DYLIB")[idx] set_name_in_dylib(dylib_cmd, old_name, new_name) end |
#command(name) ⇒ Array<MachO::LoadCommand> Also known as: []
All load commands of a given name.
121 122 123 |
# File 'lib/macho/macho_file.rb', line 121 def command(name) load_commands.select { |lc| lc.to_s == name } end |
#cpusubtype ⇒ String
Returns a string representation of the Mach-O’s CPU subtype.
97 98 99 |
# File 'lib/macho/macho_file.rb', line 97 def cpusubtype CPU_SUBTYPES[header[:cpusubtype]] end |
#cputype ⇒ String
Returns a string representation of the Mach-O’s CPU type.
92 93 94 |
# File 'lib/macho/macho_file.rb', line 92 def cputype CPU_TYPES[header[:cputype]] end |
#dylib? ⇒ Boolean
Returns true if the Mach-O is of type ‘MH_DYLIB`, false otherwise.
67 68 69 |
# File 'lib/macho/macho_file.rb', line 67 def dylib? header[:filetype] == MH_DYLIB end |
#dylib_id ⇒ String?
The Mach-O’s dylib ID, or ‘nil` if not a dylib.
142 143 144 145 146 147 148 149 150 |
# File 'lib/macho/macho_file.rb', line 142 def dylib_id if !dylib? return nil end dylib_id_cmd = command("LC_ID_DYLIB").first dylib_id_cmd.name.to_s end |
#dylib_id=(new_id) ⇒ void
This method returns an undefined value.
Changes the Mach-O’s dylib ID to ‘new_id`. Does nothing if not a dylib.
158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/macho/macho_file.rb', line 158 def dylib_id=(new_id) if !new_id.is_a?(String) raise ArgumentError.new("argument must be a String") end if !dylib? return nil end dylib_cmd = command("LC_ID_DYLIB").first old_id = dylib_id set_name_in_dylib(dylib_cmd, old_id, new_id) end |
#executable? ⇒ Boolean
Returns true if the Mach-O is of type ‘MH_EXECUTE`, false otherwise.
62 63 64 |
# File 'lib/macho/macho_file.rb', line 62 def executable? header[:filetype] == MH_EXECUTE end |
#filetype ⇒ String
Returns a string representation of the Mach-O’s filetype.
87 88 89 |
# File 'lib/macho/macho_file.rb', line 87 def filetype MH_FILETYPES[header[:filetype]] end |
#flags ⇒ Fixnum
Returns execution flags set by the linker.
112 113 114 |
# File 'lib/macho/macho_file.rb', line 112 def flags header[:flags] end |
#initialize_from_bin(bin) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
38 39 40 41 42 43 |
# File 'lib/macho/macho_file.rb', line 38 def initialize_from_bin(bin) @filename = nil @raw_data = bin @header = get_mach_header @load_commands = get_load_commands end |
#linked_dylibs ⇒ Array<String>
All shared libraries linked to the Mach-O.
175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/macho/macho_file.rb', line 175 def linked_dylibs dylibs = [] dylib_cmds = command("LC_LOAD_DYLIB") dylib_cmds.each do |dylib_cmd| dylib = dylib_cmd.name.to_s dylibs << dylib end dylibs end |
#magic ⇒ Fixnum
Returns the Mach-O’s magic number.
77 78 79 |
# File 'lib/macho/macho_file.rb', line 77 def magic header[:magic] end |
#magic32? ⇒ Boolean
Returns true if the Mach-O has 32-bit magic, false otherwise.
52 53 54 |
# File 'lib/macho/macho_file.rb', line 52 def magic32? MachO.magic32?(header[:magic]) end |
#magic64? ⇒ Boolean
Returns true if the Mach-O has 64-bit magic, false otherwise.
57 58 59 |
# File 'lib/macho/macho_file.rb', line 57 def magic64? MachO.magic64?(header[:magic]) end |
#magic_string ⇒ String
Returns a string representation of the Mach-O’s magic number.
82 83 84 |
# File 'lib/macho/macho_file.rb', line 82 def magic_string MH_MAGICS[header[:magic]] end |
#ncmds ⇒ Fixnum
Returns the number of load commands in the Mach-O’s header.
102 103 104 |
# File 'lib/macho/macho_file.rb', line 102 def ncmds header[:ncmds] end |
#sections(segment) ⇒ Array<MachO::Section>, Array<MachO::Section64>
All sections of the segment ‘segment`.
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/macho/macho_file.rb', line 213 def sections(segment) sections = [] if !segment.is_a?(SegmentCommand) && !segment.is_a?(SegmentCommand64) raise ArgumentError.new("not a valid segment") end if segment.nsects.zero? return sections end offset = segment.offset + segment.class.bytesize segment.nsects.times do if segment.is_a? SegmentCommand sections << Section.new_from_bin(@raw_data.slice(offset, Section.bytesize)) offset += Section.bytesize else sections << Section64.new_from_bin(@raw_data.slice(offset, Section64.bytesize)) offset += Section64.bytesize end end sections end |
#segments ⇒ Array<MachO::SegmentCommand>, Array<MachO::SegmentCommand64>
All segment load commands in the Mach-O.
130 131 132 133 134 135 136 |
# File 'lib/macho/macho_file.rb', line 130 def segments if magic32? command("LC_SEGMENT") else command("LC_SEGMENT_64") end end |
#serialize ⇒ String
The file’s raw Mach-O data.
47 48 49 |
# File 'lib/macho/macho_file.rb', line 47 def serialize @raw_data end |
#sizeofcmds ⇒ Fixnum
Returns the size of all load commands, in bytes.
107 108 109 |
# File 'lib/macho/macho_file.rb', line 107 def sizeofcmds header[:sizeofcmds] end |
#write(filename) ⇒ void
This method returns an undefined value.
Write all Mach-O data to the given filename.
242 243 244 |
# File 'lib/macho/macho_file.rb', line 242 def write(filename) File.open(filename, "wb") { |f| f.write(@raw_data) } end |
#write! ⇒ void
Overwrites all data in the file!
This method returns an undefined value.
Write all Mach-O data to the file used to initialize the instance.
251 252 253 254 255 256 257 |
# File 'lib/macho/macho_file.rb', line 251 def write! if @filename.nil? raise MachOError.new("cannot write to a default file when initialized from a binary string") else File.open(@filename, "wb") { |f| f.write(@raw_data) } end end |