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 file is of type
MH_BUNDLE, false otherwise. -
#change_install_name(old_name, new_name) ⇒ void
(also: #change_dylib)
Changes the shared library
old_nametonew_name. -
#change_rpath(old_path, new_path) ⇒ void
private
Changes the runtime path
old_pathtonew_path. -
#command(name) ⇒ Array<MachO::LoadCommand>
(also: #[])
All load commands of a given name.
-
#core? ⇒ Boolean
True if the file is of type
MH_CORE, false otherwise. -
#cpusubtype ⇒ String
A string representation of the Mach-O's CPU subtype.
-
#cputype ⇒ String
A string representation of the Mach-O's CPU type.
-
#dsym? ⇒ Boolean
True if the file is of type
MH_DSYM, false otherwise. -
#dylib? ⇒ Boolean
True if the file is of type
MH_DYLIB, false otherwise. -
#dylib_id ⇒ String?
The Mach-O's dylib ID, or
nilif not a dylib. -
#dylib_id=(new_id) ⇒ void
Changes the Mach-O's dylib ID to
new_id. -
#dylib_load_commands ⇒ Array<MachO::DylibCommand>
All load commands responsible for loading dylibs.
-
#dylinker? ⇒ Boolean
True if the file is of type
MH_DYLINKER, false otherwise. -
#executable? ⇒ Boolean
True if the file 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.
-
#fvmlib? ⇒ Boolean
True if the file is of type
MH_FVMLIB, false otherwise. -
#initialize(filename) ⇒ MachOFile
constructor
Creates a new FatFile from the given filename.
- #initialize_from_bin(bin) ⇒ Object private
-
#kext? ⇒ Boolean
True if the file is of type
MH_KEXT_BUNDLE, false otherwise. -
#linked_dylibs ⇒ Array<String>
All shared libraries linked to the Mach-O.
-
#magic ⇒ Fixnum
The file'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 file's magic number.
-
#ncmds ⇒ Fixnum
The number of load commands in the Mach-O's header.
-
#object? ⇒ Boolean
True if the file is of type
MH_OBJECT, false otherwise. -
#preload? ⇒ Boolean
True if the file is of type
MH_PRELOAD, false otherwise. -
#rpaths ⇒ Array<String>
All runtime paths searched by the dynamic linker for the Mach-O.
-
#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 file is of type MH_BUNDLE, false otherwise.
97 98 99 |
# File 'lib/macho/macho_file.rb', line 97 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
228 229 230 231 232 233 |
# File 'lib/macho/macho_file.rb', line 228 def change_install_name(old_name, new_name) dylib_cmd = dylib_load_commands.find { |d| d.name.to_s == old_name } raise DylibUnknownError.new(old_name) if dylib_cmd.nil? set_name_in_dylib(dylib_cmd, old_name, new_name) end |
#change_rpath(old_path, new_path) ⇒ void
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.
This method returns an undefined value.
Changes the runtime path old_path to new_path
251 252 253 254 255 256 |
# File 'lib/macho/macho_file.rb', line 251 def change_rpath(old_path, new_path) rpath_cmd = command(:LC_RPATH).find { |r| r.path.to_s == old_path } raise RpathUnknownError.new(old_path) if rpath_cmd.nil? set_path_in_rpath(rpath_cmd, old_path, new_path) end |
#command(name) ⇒ Array<MachO::LoadCommand> Also known as: []
All load commands of a given name.
157 158 159 |
# File 'lib/macho/macho_file.rb', line 157 def command(name) load_commands.select { |lc| lc.type == name.to_sym } end |
#core? ⇒ Boolean
Returns true if the file is of type MH_CORE, false otherwise.
77 78 79 |
# File 'lib/macho/macho_file.rb', line 77 def core? header.filetype == MH_CORE end |
#cpusubtype ⇒ String
Returns a string representation of the Mach-O's CPU subtype.
132 133 134 |
# File 'lib/macho/macho_file.rb', line 132 def cpusubtype CPU_SUBTYPES[header.cpusubtype] end |
#cputype ⇒ String
Returns a string representation of the Mach-O's CPU type.
127 128 129 |
# File 'lib/macho/macho_file.rb', line 127 def cputype CPU_TYPES[header.cputype] end |
#dsym? ⇒ Boolean
Returns true if the file is of type MH_DSYM, false otherwise.
102 103 104 |
# File 'lib/macho/macho_file.rb', line 102 def dsym? header.filetype == MH_DSYM end |
#dylib? ⇒ Boolean
Returns true if the file is of type MH_DYLIB, false otherwise.
87 88 89 |
# File 'lib/macho/macho_file.rb', line 87 def dylib? header.filetype == MH_DYLIB end |
#dylib_id ⇒ String?
The Mach-O's dylib ID, or nil if not a dylib.
184 185 186 187 188 189 190 191 192 |
# File 'lib/macho/macho_file.rb', line 184 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.
200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/macho/macho_file.rb', line 200 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 |
#dylib_load_commands ⇒ Array<MachO::DylibCommand>
All load commands responsible for loading dylibs.
165 166 167 |
# File 'lib/macho/macho_file.rb', line 165 def dylib_load_commands load_commands.select { |lc| DYLIB_LOAD_COMMANDS.include?(lc.type) } end |
#dylinker? ⇒ Boolean
Returns true if the file is of type MH_DYLINKER, false otherwise.
92 93 94 |
# File 'lib/macho/macho_file.rb', line 92 def dylinker? header.filetype == MH_DYLINKER end |
#executable? ⇒ Boolean
Returns true if the file is of type MH_EXECUTE, false otherwise.
67 68 69 |
# File 'lib/macho/macho_file.rb', line 67 def executable? header.filetype == MH_EXECUTE end |
#filetype ⇒ String
Returns a string representation of the Mach-O's filetype.
122 123 124 |
# File 'lib/macho/macho_file.rb', line 122 def filetype MH_FILETYPES[header.filetype] end |
#flags ⇒ Fixnum
Returns execution flags set by the linker.
147 148 149 |
# File 'lib/macho/macho_file.rb', line 147 def flags header.flags end |
#fvmlib? ⇒ Boolean
Returns true if the file is of type MH_FVMLIB, false otherwise.
72 73 74 |
# File 'lib/macho/macho_file.rb', line 72 def fvmlib? header.filetype == MH_FVMLIB 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 |
#kext? ⇒ Boolean
Returns true if the file is of type MH_KEXT_BUNDLE, false otherwise.
107 108 109 |
# File 'lib/macho/macho_file.rb', line 107 def kext? header.filetype == MH_KEXT_BUNDLE end |
#linked_dylibs ⇒ Array<String>
All shared libraries linked to the Mach-O.
217 218 219 |
# File 'lib/macho/macho_file.rb', line 217 def linked_dylibs dylib_load_commands.map(&:name).map(&:to_s) end |
#magic ⇒ Fixnum
Returns the file's magic number.
112 113 114 |
# File 'lib/macho/macho_file.rb', line 112 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 file's magic number.
117 118 119 |
# File 'lib/macho/macho_file.rb', line 117 def magic_string MH_MAGICS[magic] end |
#ncmds ⇒ Fixnum
Returns the number of load commands in the Mach-O's header.
137 138 139 |
# File 'lib/macho/macho_file.rb', line 137 def ncmds header.ncmds end |
#object? ⇒ Boolean
Returns true if the file is of type MH_OBJECT, false otherwise.
62 63 64 |
# File 'lib/macho/macho_file.rb', line 62 def object? header.filetype == MH_OBJECT end |
#preload? ⇒ Boolean
Returns true if the file is of type MH_PRELOAD, false otherwise.
82 83 84 |
# File 'lib/macho/macho_file.rb', line 82 def preload? header.filetype == MH_PRELOAD end |
#rpaths ⇒ Array<String>
All runtime paths searched by the dynamic linker for the Mach-O.
239 240 241 |
# File 'lib/macho/macho_file.rb', line 239 def rpaths command(:LC_RPATH).map(&:path).map(&:to_s) end |
#sections(segment) ⇒ Array<MachO::Section>, Array<MachO::Section64>
All sections of the segment segment.
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
# File 'lib/macho/macho_file.rb', line 262 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.
172 173 174 175 176 177 178 |
# File 'lib/macho/macho_file.rb', line 172 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.
142 143 144 |
# File 'lib/macho/macho_file.rb', line 142 def sizeofcmds header.sizeofcmds end |
#write(filename) ⇒ void
This method returns an undefined value.
Write all Mach-O data to the given filename.
291 292 293 |
# File 'lib/macho/macho_file.rb', line 291 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.
300 301 302 303 304 305 306 |
# File 'lib/macho/macho_file.rb', line 300 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 |