Merge pull request #12711 from Homebrew/dependabot/bundler/Library/Homebrew/ruby-macho-3.0.0
build(deps): bump ruby-macho from 2.5.1 to 3.0.0 in /Library/Homebrew
This commit is contained in:
commit
4fc7e3d8a8
@ -146,7 +146,7 @@ GEM
|
|||||||
rubocop (~> 1.19)
|
rubocop (~> 1.19)
|
||||||
rubocop-sorbet (0.6.5)
|
rubocop-sorbet (0.6.5)
|
||||||
rubocop (>= 0.90.0)
|
rubocop (>= 0.90.0)
|
||||||
ruby-macho (2.5.1)
|
ruby-macho (3.0.0)
|
||||||
ruby-progressbar (1.11.0)
|
ruby-progressbar (1.11.0)
|
||||||
rubyntlm (0.6.3)
|
rubyntlm (0.6.3)
|
||||||
simplecov (0.21.2)
|
simplecov (0.21.2)
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
|
# typed: true
|
||||||
|
|
||||||
# DO NOT EDIT MANUALLY
|
# DO NOT EDIT MANUALLY
|
||||||
# This is an autogenerated file for types exported from the `ruby-macho` gem.
|
# This is an autogenerated file for types exported from the `ruby-macho` gem.
|
||||||
# Please instead update this file by running `bin/tapioca gem ruby-macho`.
|
# Please instead update this file by running `bin/tapioca gem ruby-macho`.
|
||||||
|
|
||||||
# typed: true
|
|
||||||
|
|
||||||
module MachO
|
module MachO
|
||||||
class << self
|
class << self
|
||||||
def codesign!(filename); end
|
def codesign!(filename); end
|
||||||
@ -20,6 +20,8 @@ class MachO::CPUTypeError < ::MachO::MachOError
|
|||||||
end
|
end
|
||||||
|
|
||||||
class MachO::CodeSigningError < ::MachO::MachOError; end
|
class MachO::CodeSigningError < ::MachO::MachOError; end
|
||||||
|
class MachO::CompressedMachOError < ::MachO::MachOError; end
|
||||||
|
class MachO::DecompressionError < ::MachO::MachOError; end
|
||||||
|
|
||||||
class MachO::DylibIdMissingError < ::MachO::RecoverableModificationError
|
class MachO::DylibIdMissingError < ::MachO::RecoverableModificationError
|
||||||
def initialize; end
|
def initialize; end
|
||||||
@ -104,6 +106,9 @@ class MachO::HeaderPadError < ::MachO::ModificationError
|
|||||||
end
|
end
|
||||||
|
|
||||||
module MachO::Headers; end
|
module MachO::Headers; end
|
||||||
|
MachO::Headers::COMPRESSED_MAGIC = T.let(T.unsafe(nil), Integer)
|
||||||
|
MachO::Headers::COMP_TYPE_FASTLIB = T.let(T.unsafe(nil), Integer)
|
||||||
|
MachO::Headers::COMP_TYPE_LZSS = T.let(T.unsafe(nil), Integer)
|
||||||
MachO::Headers::CPU_ARCH_ABI32 = T.let(T.unsafe(nil), Integer)
|
MachO::Headers::CPU_ARCH_ABI32 = T.let(T.unsafe(nil), Integer)
|
||||||
MachO::Headers::CPU_ARCH_ABI64 = T.let(T.unsafe(nil), Integer)
|
MachO::Headers::CPU_ARCH_ABI64 = T.let(T.unsafe(nil), Integer)
|
||||||
MachO::Headers::CPU_SUBTYPES = T.let(T.unsafe(nil), Hash)
|
MachO::Headers::CPU_SUBTYPES = T.let(T.unsafe(nil), Hash)
|
||||||
@ -220,6 +225,7 @@ MachO::Headers::MH_DYLIB = T.let(T.unsafe(nil), Integer)
|
|||||||
MachO::Headers::MH_DYLIB_STUB = T.let(T.unsafe(nil), Integer)
|
MachO::Headers::MH_DYLIB_STUB = T.let(T.unsafe(nil), Integer)
|
||||||
MachO::Headers::MH_DYLINKER = T.let(T.unsafe(nil), Integer)
|
MachO::Headers::MH_DYLINKER = T.let(T.unsafe(nil), Integer)
|
||||||
MachO::Headers::MH_EXECUTE = T.let(T.unsafe(nil), Integer)
|
MachO::Headers::MH_EXECUTE = T.let(T.unsafe(nil), Integer)
|
||||||
|
MachO::Headers::MH_FILESET = T.let(T.unsafe(nil), Integer)
|
||||||
MachO::Headers::MH_FILETYPES = T.let(T.unsafe(nil), Hash)
|
MachO::Headers::MH_FILETYPES = T.let(T.unsafe(nil), Hash)
|
||||||
MachO::Headers::MH_FLAGS = T.let(T.unsafe(nil), Hash)
|
MachO::Headers::MH_FLAGS = T.let(T.unsafe(nil), Hash)
|
||||||
MachO::Headers::MH_FVMLIB = T.let(T.unsafe(nil), Integer)
|
MachO::Headers::MH_FVMLIB = T.let(T.unsafe(nil), Integer)
|
||||||
@ -242,6 +248,7 @@ class MachO::Headers::MachHeader < ::MachO::MachOStructure
|
|||||||
def dylib?; end
|
def dylib?; end
|
||||||
def dylinker?; end
|
def dylinker?; end
|
||||||
def executable?; end
|
def executable?; end
|
||||||
|
def fileset?; end
|
||||||
def filetype; end
|
def filetype; end
|
||||||
def flag?(flag); end
|
def flag?(flag); end
|
||||||
def flags; end
|
def flags; end
|
||||||
@ -269,6 +276,27 @@ MachO::Headers::MachHeader64::SIZEOF = T.let(T.unsafe(nil), Integer)
|
|||||||
MachO::Headers::MachHeader::FORMAT = T.let(T.unsafe(nil), String)
|
MachO::Headers::MachHeader::FORMAT = T.let(T.unsafe(nil), String)
|
||||||
MachO::Headers::MachHeader::SIZEOF = T.let(T.unsafe(nil), Integer)
|
MachO::Headers::MachHeader::SIZEOF = T.let(T.unsafe(nil), Integer)
|
||||||
|
|
||||||
|
class MachO::Headers::PrelinkedKernelHeader < ::MachO::MachOStructure
|
||||||
|
def initialize(signature, compress_type, adler32, uncompressed_size, compressed_size, prelink_version, reserved, platform_name, root_path); end
|
||||||
|
|
||||||
|
def adler32; end
|
||||||
|
def compress_type; end
|
||||||
|
def compressed_size; end
|
||||||
|
def kaslr?; end
|
||||||
|
def lzss?; end
|
||||||
|
def lzvn?; end
|
||||||
|
def platform_name; end
|
||||||
|
def prelink_version; end
|
||||||
|
def reserved; end
|
||||||
|
def root_path; end
|
||||||
|
def signature; end
|
||||||
|
def to_h; end
|
||||||
|
def uncompressed_size; end
|
||||||
|
end
|
||||||
|
|
||||||
|
MachO::Headers::PrelinkedKernelHeader::FORMAT = T.let(T.unsafe(nil), String)
|
||||||
|
MachO::Headers::PrelinkedKernelHeader::SIZEOF = T.let(T.unsafe(nil), Integer)
|
||||||
|
|
||||||
class MachO::JavaClassFileError < ::MachO::NotAMachOError
|
class MachO::JavaClassFileError < ::MachO::NotAMachOError
|
||||||
def initialize; end
|
def initialize; end
|
||||||
end
|
end
|
||||||
@ -430,6 +458,19 @@ end
|
|||||||
MachO::LoadCommands::EntryPointCommand::FORMAT = T.let(T.unsafe(nil), String)
|
MachO::LoadCommands::EntryPointCommand::FORMAT = T.let(T.unsafe(nil), String)
|
||||||
MachO::LoadCommands::EntryPointCommand::SIZEOF = T.let(T.unsafe(nil), Integer)
|
MachO::LoadCommands::EntryPointCommand::SIZEOF = T.let(T.unsafe(nil), Integer)
|
||||||
|
|
||||||
|
class MachO::LoadCommands::FilesetEntryCommand < ::MachO::LoadCommands::LoadCommand
|
||||||
|
def initialize(view, cmd, cmdsize, vmaddr, fileoff, entry_id, reserved); end
|
||||||
|
|
||||||
|
def entry_id; end
|
||||||
|
def fileoff; end
|
||||||
|
def reserved; end
|
||||||
|
def to_h; end
|
||||||
|
def vmaddr; end
|
||||||
|
end
|
||||||
|
|
||||||
|
MachO::LoadCommands::FilesetEntryCommand::FORMAT = T.let(T.unsafe(nil), String)
|
||||||
|
MachO::LoadCommands::FilesetEntryCommand::SIZEOF = T.let(T.unsafe(nil), Integer)
|
||||||
|
|
||||||
class MachO::LoadCommands::FvmfileCommand < ::MachO::LoadCommands::LoadCommand
|
class MachO::LoadCommands::FvmfileCommand < ::MachO::LoadCommands::LoadCommand
|
||||||
def initialize(view, cmd, cmdsize, name, header_addr); end
|
def initialize(view, cmd, cmdsize, name, header_addr); end
|
||||||
|
|
||||||
@ -762,13 +803,13 @@ class MachO::MachOFile
|
|||||||
def change_dylib(old_name, new_name, _options = T.unsafe(nil)); end
|
def change_dylib(old_name, new_name, _options = T.unsafe(nil)); end
|
||||||
def change_dylib_id(new_id, _options = T.unsafe(nil)); end
|
def change_dylib_id(new_id, _options = T.unsafe(nil)); end
|
||||||
def change_install_name(old_name, new_name, _options = T.unsafe(nil)); end
|
def change_install_name(old_name, new_name, _options = T.unsafe(nil)); end
|
||||||
def change_rpath(old_path, new_path, _options = T.unsafe(nil)); end
|
def change_rpath(old_path, new_path, options = T.unsafe(nil)); end
|
||||||
def command(name); end
|
def command(name); end
|
||||||
def core?(*args, &block); end
|
def core?(*args, &block); end
|
||||||
def cpusubtype; end
|
def cpusubtype; end
|
||||||
def cputype; end
|
def cputype; end
|
||||||
def delete_command(lc, options = T.unsafe(nil)); end
|
def delete_command(lc, options = T.unsafe(nil)); end
|
||||||
def delete_rpath(path, _options = T.unsafe(nil)); end
|
def delete_rpath(path, options = T.unsafe(nil)); end
|
||||||
def dsym?(*args, &block); end
|
def dsym?(*args, &block); end
|
||||||
def dylib?(*args, &block); end
|
def dylib?(*args, &block); end
|
||||||
def dylib_id; end
|
def dylib_id; end
|
||||||
@ -812,10 +853,12 @@ class MachO::MachOFile
|
|||||||
def check_cpusubtype(cputype, cpusubtype); end
|
def check_cpusubtype(cputype, cpusubtype); end
|
||||||
def check_cputype(cputype); end
|
def check_cputype(cputype); end
|
||||||
def check_filetype(filetype); end
|
def check_filetype(filetype); end
|
||||||
|
def decompress_macho_lzvn; end
|
||||||
def low_fileoff; end
|
def low_fileoff; end
|
||||||
def populate_and_check_magic; end
|
def populate_and_check_magic; end
|
||||||
def populate_load_commands; end
|
def populate_load_commands; end
|
||||||
def populate_mach_header; end
|
def populate_mach_header; end
|
||||||
|
def populate_prelinked_kernel_header; end
|
||||||
def update_ncmds(ncmds); end
|
def update_ncmds(ncmds); end
|
||||||
def update_sizeofcmds(size); end
|
def update_sizeofcmds(size); end
|
||||||
|
|
||||||
@ -872,18 +915,22 @@ end
|
|||||||
|
|
||||||
module MachO::Sections; end
|
module MachO::Sections; end
|
||||||
MachO::Sections::MAX_SECT_ALIGN = T.let(T.unsafe(nil), Integer)
|
MachO::Sections::MAX_SECT_ALIGN = T.let(T.unsafe(nil), Integer)
|
||||||
MachO::Sections::SECTION_ATTRIBUTES = T.let(T.unsafe(nil), Integer)
|
MachO::Sections::SECTION_ATTRIBUTES = T.let(T.unsafe(nil), Hash)
|
||||||
MachO::Sections::SECTION_ATTRIBUTES_SYS = T.let(T.unsafe(nil), Integer)
|
MachO::Sections::SECTION_ATTRIBUTES_MASK = T.let(T.unsafe(nil), Integer)
|
||||||
MachO::Sections::SECTION_ATTRIBUTES_USR = T.let(T.unsafe(nil), Integer)
|
MachO::Sections::SECTION_ATTRIBUTES_SYS_MASK = T.let(T.unsafe(nil), Integer)
|
||||||
|
MachO::Sections::SECTION_ATTRIBUTES_USR_MASK = T.let(T.unsafe(nil), Integer)
|
||||||
MachO::Sections::SECTION_FLAGS = T.let(T.unsafe(nil), Hash)
|
MachO::Sections::SECTION_FLAGS = T.let(T.unsafe(nil), Hash)
|
||||||
MachO::Sections::SECTION_NAMES = T.let(T.unsafe(nil), Hash)
|
MachO::Sections::SECTION_NAMES = T.let(T.unsafe(nil), Hash)
|
||||||
MachO::Sections::SECTION_TYPE = T.let(T.unsafe(nil), Integer)
|
MachO::Sections::SECTION_TYPES = T.let(T.unsafe(nil), Hash)
|
||||||
|
MachO::Sections::SECTION_TYPE_MASK = T.let(T.unsafe(nil), Integer)
|
||||||
|
|
||||||
class MachO::Sections::Section < ::MachO::MachOStructure
|
class MachO::Sections::Section < ::MachO::MachOStructure
|
||||||
def initialize(sectname, segname, addr, size, offset, align, reloff, nreloc, flags, reserved1, reserved2); end
|
def initialize(sectname, segname, addr, size, offset, align, reloff, nreloc, flags, reserved1, reserved2); end
|
||||||
|
|
||||||
def addr; end
|
def addr; end
|
||||||
def align; end
|
def align; end
|
||||||
|
def attribute?(attr_sym); end
|
||||||
|
def attributes; end
|
||||||
def empty?; end
|
def empty?; end
|
||||||
def flag?(flag); end
|
def flag?(flag); end
|
||||||
def flags; end
|
def flags; end
|
||||||
@ -898,6 +945,8 @@ class MachO::Sections::Section < ::MachO::MachOStructure
|
|||||||
def segname; end
|
def segname; end
|
||||||
def size; end
|
def size; end
|
||||||
def to_h; end
|
def to_h; end
|
||||||
|
def type; end
|
||||||
|
def type?(type_sym); end
|
||||||
end
|
end
|
||||||
|
|
||||||
class MachO::Sections::Section64 < ::MachO::Sections::Section
|
class MachO::Sections::Section64 < ::MachO::Sections::Section
|
||||||
@ -935,6 +984,7 @@ end
|
|||||||
module MachO::Utils
|
module MachO::Utils
|
||||||
class << self
|
class << self
|
||||||
def big_magic?(num); end
|
def big_magic?(num); end
|
||||||
|
def compressed_magic?(num); end
|
||||||
def fat_magic32?(num); end
|
def fat_magic32?(num); end
|
||||||
def fat_magic64?(num); end
|
def fat_magic64?(num); end
|
||||||
def fat_magic?(num); end
|
def fat_magic?(num); end
|
@ -91,7 +91,7 @@ $:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-performance-1
|
|||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rails-2.13.1/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rails-2.13.1/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-2.7.0/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-rspec-2.7.0/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-sorbet-0.6.5/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/rubocop-sorbet-0.6.5/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-macho-2.5.1/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/ruby-macho-3.0.0/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-html-0.12.3/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-html-0.12.3/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov_json_formatter-0.1.3/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov_json_formatter-0.1.3/lib"
|
||||||
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-0.21.2/lib"
|
$:.unshift "#{path}/../#{ruby_engine}/#{ruby_version}/gems/simplecov-0.21.2/lib"
|
||||||
|
@ -16,7 +16,7 @@ require_relative "macho/tools"
|
|||||||
# The primary namespace for ruby-macho.
|
# The primary namespace for ruby-macho.
|
||||||
module MachO
|
module MachO
|
||||||
# release version
|
# release version
|
||||||
VERSION = "2.5.1"
|
VERSION = "3.0.0"
|
||||||
|
|
||||||
# Opens the given filename as a MachOFile or FatFile, depending on its magic.
|
# Opens the given filename as a MachOFile or FatFile, depending on its magic.
|
||||||
# @param filename [String] the file being opened
|
# @param filename [String] the file being opened
|
@ -84,7 +84,7 @@ module MachO
|
|||||||
# @param cpusubtype [Integer] the CPU sub-type of the unknown pair
|
# @param cpusubtype [Integer] the CPU sub-type of the unknown pair
|
||||||
def initialize(cputype, cpusubtype)
|
def initialize(cputype, cpusubtype)
|
||||||
super "Unrecognized CPU sub-type: 0x%08<cpusubtype>x" \
|
super "Unrecognized CPU sub-type: 0x%08<cpusubtype>x" \
|
||||||
" (for CPU type: 0x%08<cputype>x" % { :cputype => cputype, :cpusubtype => cpusubtype }
|
" (for CPU type: 0x%08<cputype>x" % { :cputype => cputype, :cpusubtype => cpusubtype }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ module MachO
|
|||||||
# @param actual_arity [Integer] the number of arguments received
|
# @param actual_arity [Integer] the number of arguments received
|
||||||
def initialize(cmd_sym, expected_arity, actual_arity)
|
def initialize(cmd_sym, expected_arity, actual_arity)
|
||||||
super "Expected #{expected_arity} arguments for #{cmd_sym} creation," \
|
super "Expected #{expected_arity} arguments for #{cmd_sym} creation," \
|
||||||
" got #{actual_arity}"
|
" got #{actual_arity}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ module MachO
|
|||||||
# @param lc [MachO::LoadCommand] the load command containing the string
|
# @param lc [MachO::LoadCommand] the load command containing the string
|
||||||
def initialize(lc)
|
def initialize(lc)
|
||||||
super "Load command #{lc.type} at offset #{lc.view.offset} contains a" \
|
super "Load command #{lc.type} at offset #{lc.view.offset} contains a" \
|
||||||
" malformed string"
|
" malformed string"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -154,8 +154,8 @@ module MachO
|
|||||||
# @param filename [String] the filename
|
# @param filename [String] the filename
|
||||||
def initialize(filename)
|
def initialize(filename)
|
||||||
super "Updated load commands do not fit in the header of " \
|
super "Updated load commands do not fit in the header of " \
|
||||||
"#{filename}. #{filename} needs to be relinked, possibly with " \
|
"#{filename}. #{filename} needs to be relinked, possibly with " \
|
||||||
"-headerpad or -headerpad_max_install_names"
|
"-headerpad or -headerpad_max_install_names"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -207,4 +207,14 @@ module MachO
|
|||||||
" Consider merging with `fat64: true`"
|
" Consider merging with `fat64: true`"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Raised when attempting to parse a compressed Mach-O without explicitly
|
||||||
|
# requesting decompression.
|
||||||
|
class CompressedMachOError < MachOError
|
||||||
|
end
|
||||||
|
|
||||||
|
# Raised when attempting to decompress a compressed Mach-O without adequate
|
||||||
|
# dependencies, or on other decompression errors.
|
||||||
|
class DecompressionError < MachOError
|
||||||
|
end
|
||||||
end
|
end
|
@ -55,7 +55,7 @@ module MachO
|
|||||||
machos.each do |macho|
|
machos.each do |macho|
|
||||||
macho_offset = Utils.round(offset, 2**macho.segment_alignment)
|
macho_offset = Utils.round(offset, 2**macho.segment_alignment)
|
||||||
|
|
||||||
raise FatArchOffsetOverflowError, macho_offset if !fat64 && macho_offset > (2**32 - 1)
|
raise FatArchOffsetOverflowError, macho_offset if !fat64 && macho_offset > ((2**32) - 1)
|
||||||
|
|
||||||
macho_pads[macho] = Utils.padding_for(offset, 2**macho.segment_alignment)
|
macho_pads[macho] = Utils.padding_for(offset, 2**macho.segment_alignment)
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ module MachO
|
|||||||
|
|
||||||
@filename = filename
|
@filename = filename
|
||||||
@options = opts
|
@options = opts
|
||||||
@raw_data = File.open(@filename, "rb", &:read)
|
@raw_data = File.binread(@filename)
|
||||||
populate_fields
|
populate_fields
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -238,6 +238,8 @@ module MachO
|
|||||||
# @param options [Hash]
|
# @param options [Hash]
|
||||||
# @option options [Boolean] :strict (true) if true, fail if one slice fails.
|
# @option options [Boolean] :strict (true) if true, fail if one slice fails.
|
||||||
# if false, fail only if all slices fail.
|
# if false, fail only if all slices fail.
|
||||||
|
# @option options [Boolean] :uniq (false) for each slice: if true, change
|
||||||
|
# each rpath simultaneously.
|
||||||
# @return [void]
|
# @return [void]
|
||||||
# @see MachOFile#change_rpath
|
# @see MachOFile#change_rpath
|
||||||
def change_rpath(old_path, new_path, options = {})
|
def change_rpath(old_path, new_path, options = {})
|
||||||
@ -268,6 +270,9 @@ module MachO
|
|||||||
# @param options [Hash]
|
# @param options [Hash]
|
||||||
# @option options [Boolean] :strict (true) if true, fail if one slice fails.
|
# @option options [Boolean] :strict (true) if true, fail if one slice fails.
|
||||||
# if false, fail only if all slices fail.
|
# if false, fail only if all slices fail.
|
||||||
|
# @option options [Boolean] :uniq (false) for each slice: if true, delete
|
||||||
|
# only the first runtime path that matches. if false, delete all duplicate
|
||||||
|
# paths that match.
|
||||||
# @return void
|
# @return void
|
||||||
# @see MachOFile#delete_rpath
|
# @see MachOFile#delete_rpath
|
||||||
def delete_rpath(path, options = {})
|
def delete_rpath(path, options = {})
|
||||||
@ -291,7 +296,7 @@ module MachO
|
|||||||
# @param filename [String] the file to write to
|
# @param filename [String] the file to write to
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def write(filename)
|
def write(filename)
|
||||||
File.open(filename, "wb") { |f| f.write(@raw_data) }
|
File.binwrite(filename, @raw_data)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Write all (fat) data to the file used to initialize the instance.
|
# Write all (fat) data to the file used to initialize the instance.
|
||||||
@ -301,7 +306,7 @@ module MachO
|
|||||||
def write!
|
def write!
|
||||||
raise MachOError, "no initial file to write to" if filename.nil?
|
raise MachOError, "no initial file to write to" if filename.nil?
|
||||||
|
|
||||||
File.open(@filename, "wb") { |f| f.write(@raw_data) }
|
File.binwrite(@filename, @raw_data)
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return [Hash] a hash representation of this {FatFile}
|
# @return [Hash] a hash representation of this {FatFile}
|
@ -37,6 +37,18 @@ module MachO
|
|||||||
# @api private
|
# @api private
|
||||||
MH_CIGAM_64 = 0xcffaedfe
|
MH_CIGAM_64 = 0xcffaedfe
|
||||||
|
|
||||||
|
# compressed mach-o magic
|
||||||
|
# @api private
|
||||||
|
COMPRESSED_MAGIC = 0x636f6d70 # "comp"
|
||||||
|
|
||||||
|
# a compressed mach-o slice, using LZSS for compression
|
||||||
|
# @api private
|
||||||
|
COMP_TYPE_LZSS = 0x6c7a7373 # "lzss"
|
||||||
|
|
||||||
|
# a compressed mach-o slice, using LZVN ("FastLib") for compression
|
||||||
|
# @api private
|
||||||
|
COMP_TYPE_FASTLIB = 0x6c7a766e # "lzvn"
|
||||||
|
|
||||||
# association of magic numbers to string representations
|
# association of magic numbers to string representations
|
||||||
# @api private
|
# @api private
|
||||||
MH_MAGICS = {
|
MH_MAGICS = {
|
||||||
@ -433,6 +445,11 @@ module MachO
|
|||||||
# @api private
|
# @api private
|
||||||
MH_KEXT_BUNDLE = 0xb
|
MH_KEXT_BUNDLE = 0xb
|
||||||
|
|
||||||
|
# a set of Mach-Os, running in the same userspace, sharing a linkedit. The kext collection files are an example
|
||||||
|
# of this object type
|
||||||
|
# @api private
|
||||||
|
MH_FILESET = 0xc
|
||||||
|
|
||||||
# association of filetypes to Symbol representations
|
# association of filetypes to Symbol representations
|
||||||
# @api private
|
# @api private
|
||||||
MH_FILETYPES = {
|
MH_FILETYPES = {
|
||||||
@ -447,6 +464,7 @@ module MachO
|
|||||||
MH_DYLIB_STUB => :dylib_stub,
|
MH_DYLIB_STUB => :dylib_stub,
|
||||||
MH_DSYM => :dsym,
|
MH_DSYM => :dsym,
|
||||||
MH_KEXT_BUNDLE => :kext_bundle,
|
MH_KEXT_BUNDLE => :kext_bundle,
|
||||||
|
MH_FILESET => :fileset,
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
# association of mach header flag symbols to values
|
# association of mach header flag symbols to values
|
||||||
@ -478,6 +496,9 @@ module MachO
|
|||||||
:MH_HAS_TLV_DESCRIPTORS => 0x800000,
|
:MH_HAS_TLV_DESCRIPTORS => 0x800000,
|
||||||
:MH_NO_HEAP_EXECUTION => 0x1000000,
|
:MH_NO_HEAP_EXECUTION => 0x1000000,
|
||||||
:MH_APP_EXTENSION_SAFE => 0x02000000,
|
:MH_APP_EXTENSION_SAFE => 0x02000000,
|
||||||
|
:MH_NLIST_OUTOFSYNC_WITH_DYLDINFO => 0x04000000,
|
||||||
|
:MH_SIM_SUPPORT => 0x08000000,
|
||||||
|
:MH_DYLIB_IN_CACHE => 0x80000000,
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
# Fat binary header structure
|
# Fat binary header structure
|
||||||
@ -724,6 +745,11 @@ module MachO
|
|||||||
filetype == Headers::MH_KEXT_BUNDLE
|
filetype == Headers::MH_KEXT_BUNDLE
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# @return [Boolean] whether or not the file is of type `MH_FILESET`
|
||||||
|
def fileset?
|
||||||
|
filetype == Headers::MH_FILESET
|
||||||
|
end
|
||||||
|
|
||||||
# @return [Boolean] true if the Mach-O has 32-bit magic, false otherwise
|
# @return [Boolean] true if the Mach-O has 32-bit magic, false otherwise
|
||||||
def magic32?
|
def magic32?
|
||||||
Utils.magic32?(magic)
|
Utils.magic32?(magic)
|
||||||
@ -785,5 +811,88 @@ module MachO
|
|||||||
}.merge super
|
}.merge super
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Prelinked kernel/"kernelcache" header structure
|
||||||
|
class PrelinkedKernelHeader < MachOStructure
|
||||||
|
# @return [Integer] the magic number for a compressed header ({COMPRESSED_MAGIC})
|
||||||
|
attr_reader :signature
|
||||||
|
|
||||||
|
# @return [Integer] the type of compression used
|
||||||
|
attr_reader :compress_type
|
||||||
|
|
||||||
|
# @return [Integer] a checksum for the uncompressed data
|
||||||
|
attr_reader :adler32
|
||||||
|
|
||||||
|
# @return [Integer] the size of the uncompressed data, in bytes
|
||||||
|
attr_reader :uncompressed_size
|
||||||
|
|
||||||
|
# @return [Integer] the size of the compressed data, in bytes
|
||||||
|
attr_reader :compressed_size
|
||||||
|
|
||||||
|
# @return [Integer] the version of the prelink format
|
||||||
|
attr_reader :prelink_version
|
||||||
|
|
||||||
|
# @return [void]
|
||||||
|
attr_reader :reserved
|
||||||
|
|
||||||
|
# @return [void]
|
||||||
|
attr_reader :platform_name
|
||||||
|
|
||||||
|
# @return [void]
|
||||||
|
attr_reader :root_path
|
||||||
|
|
||||||
|
# @see MachOStructure::FORMAT
|
||||||
|
# @api private
|
||||||
|
FORMAT = "L>6a40a64a256"
|
||||||
|
|
||||||
|
# @see MachOStructure::SIZEOF
|
||||||
|
# @api private
|
||||||
|
SIZEOF = 384
|
||||||
|
|
||||||
|
# @api private
|
||||||
|
def initialize(signature, compress_type, adler32, uncompressed_size, compressed_size, prelink_version, reserved, platform_name, root_path)
|
||||||
|
super()
|
||||||
|
|
||||||
|
@signature = signature
|
||||||
|
@compress_type = compress_type
|
||||||
|
@adler32 = adler32
|
||||||
|
@uncompressed_size = uncompressed_size
|
||||||
|
@compressed_size = compressed_size
|
||||||
|
@prelink_version = prelink_version
|
||||||
|
@reserved = reserved.unpack("L>10")
|
||||||
|
@platform_name = platform_name
|
||||||
|
@root_path = root_path
|
||||||
|
end
|
||||||
|
|
||||||
|
# @return [Boolean] whether this prelinked kernel supports KASLR
|
||||||
|
def kaslr?
|
||||||
|
prelink_version >= 1
|
||||||
|
end
|
||||||
|
|
||||||
|
# @return [Boolean] whether this prelinked kernel is compressed with LZSS
|
||||||
|
def lzss?
|
||||||
|
compress_type == COMP_TYPE_LZSS
|
||||||
|
end
|
||||||
|
|
||||||
|
# @return [Boolean] whether this prelinked kernel is compressed with LZVN
|
||||||
|
def lzvn?
|
||||||
|
compress_type == COMP_TYPE_FASTLIB
|
||||||
|
end
|
||||||
|
|
||||||
|
# @return [Hash] a hash representation of this {PrelinkedKernelHeader}
|
||||||
|
def to_h
|
||||||
|
{
|
||||||
|
"signature" => signature,
|
||||||
|
"compress_type" => compress_type,
|
||||||
|
"adler32" => adler32,
|
||||||
|
"uncompressed_size" => uncompressed_size,
|
||||||
|
"compressed_size" => compressed_size,
|
||||||
|
"prelink_version" => prelink_version,
|
||||||
|
"reserved" => reserved,
|
||||||
|
"platform_name" => platform_name,
|
||||||
|
"root_path" => root_path,
|
||||||
|
}.merge super
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -63,7 +63,8 @@ module MachO
|
|||||||
0x31 => :LC_NOTE,
|
0x31 => :LC_NOTE,
|
||||||
0x32 => :LC_BUILD_VERSION,
|
0x32 => :LC_BUILD_VERSION,
|
||||||
(0x33 | LC_REQ_DYLD) => :LC_DYLD_EXPORTS_TRIE,
|
(0x33 | LC_REQ_DYLD) => :LC_DYLD_EXPORTS_TRIE,
|
||||||
(0x34 | LC_REQ_DYLD) => :LD_DYLD_CHAINED_FIXUPS,
|
(0x34 | LC_REQ_DYLD) => :LC_DYLD_CHAINED_FIXUPS,
|
||||||
|
(0x35 | LC_REQ_DYLD) => :LC_FILESET_ENTRY,
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
# association of symbol representations to load command constants
|
# association of symbol representations to load command constants
|
||||||
@ -150,7 +151,8 @@ module MachO
|
|||||||
:LC_NOTE => "NoteCommand",
|
:LC_NOTE => "NoteCommand",
|
||||||
:LC_BUILD_VERSION => "BuildVersionCommand",
|
:LC_BUILD_VERSION => "BuildVersionCommand",
|
||||||
:LC_DYLD_EXPORTS_TRIE => "LinkeditDataCommand",
|
:LC_DYLD_EXPORTS_TRIE => "LinkeditDataCommand",
|
||||||
:LD_DYLD_CHAINED_FIXUPS => "LinkeditDataCommand",
|
:LC_DYLD_CHAINED_FIXUPS => "LinkeditDataCommand",
|
||||||
|
:LC_FILESET_ENTRY => "FilesetEntryCommand",
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
# association of segment name symbols to names
|
# association of segment name symbols to names
|
||||||
@ -173,6 +175,7 @@ module MachO
|
|||||||
:SG_FVMLIB => 0x2,
|
:SG_FVMLIB => 0x2,
|
||||||
:SG_NORELOC => 0x4,
|
:SG_NORELOC => 0x4,
|
||||||
:SG_PROTECTED_VERSION_1 => 0x8,
|
:SG_PROTECTED_VERSION_1 => 0x8,
|
||||||
|
:SG_READ_ONLY => 0x10,
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
# The top-level Mach-O load command structure.
|
# The top-level Mach-O load command structure.
|
||||||
@ -1794,5 +1797,48 @@ module MachO
|
|||||||
}.merge super
|
}.merge super
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# A load command containing a description of a Mach-O that is a constituent of a fileset.
|
||||||
|
# Each entry is further described by its own Mach header.
|
||||||
|
# Corresponds to LC_FILESET_ENTRY.
|
||||||
|
class FilesetEntryCommand < LoadCommand
|
||||||
|
# @return [Integer] the virtual memory address of the entry
|
||||||
|
attr_reader :vmaddr
|
||||||
|
|
||||||
|
# @return [Integer] the file offset of the entry
|
||||||
|
attr_reader :fileoff
|
||||||
|
|
||||||
|
# @return [LCStr] the entry's ID
|
||||||
|
attr_reader :entry_id
|
||||||
|
|
||||||
|
# @return [void]
|
||||||
|
attr_reader :reserved
|
||||||
|
|
||||||
|
# @see MachOStructure::FORMAT
|
||||||
|
# @api private
|
||||||
|
FORMAT = "L=2Q=2L=2"
|
||||||
|
|
||||||
|
# @see MachOStructure::SIZEOF
|
||||||
|
# @api private
|
||||||
|
SIZEOF = 28
|
||||||
|
|
||||||
|
def initialize(view, cmd, cmdsize, vmaddr, fileoff, entry_id, reserved)
|
||||||
|
super(view, cmd, cmdsize)
|
||||||
|
@vmaddr = vmaddr
|
||||||
|
@fileoff = fileoff
|
||||||
|
@entry_id = LCStr.new(self, entry_id)
|
||||||
|
@reserved = reserved
|
||||||
|
end
|
||||||
|
|
||||||
|
# @return [Hash] a hash representation of this {FilesetEntryCommand}
|
||||||
|
def to_h
|
||||||
|
{
|
||||||
|
"vmaddr" => vmaddr,
|
||||||
|
"fileoff" => fileoff,
|
||||||
|
"entry_id" => entry_id,
|
||||||
|
"reserved" => reserved,
|
||||||
|
}.merge super
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -34,7 +34,11 @@ module MachO
|
|||||||
# @param bin [String] a binary string containing raw Mach-O data
|
# @param bin [String] a binary string containing raw Mach-O data
|
||||||
# @param opts [Hash] options to control the parser with
|
# @param opts [Hash] options to control the parser with
|
||||||
# @option opts [Boolean] :permissive whether to ignore unknown load commands
|
# @option opts [Boolean] :permissive whether to ignore unknown load commands
|
||||||
|
# @option opts [Boolean] :decompress whether to decompress, if capable
|
||||||
# @return [MachOFile] a new MachOFile
|
# @return [MachOFile] a new MachOFile
|
||||||
|
# @note The `:decompress` option relies on non-default dependencies. Compression
|
||||||
|
# is only used in niche Mach-Os, so leaving this disabled is a reasonable default for
|
||||||
|
# virtually all normal uses.
|
||||||
def self.new_from_bin(bin, **opts)
|
def self.new_from_bin(bin, **opts)
|
||||||
instance = allocate
|
instance = allocate
|
||||||
instance.initialize_from_bin(bin, opts)
|
instance.initialize_from_bin(bin, opts)
|
||||||
@ -46,13 +50,17 @@ module MachO
|
|||||||
# @param filename [String] the Mach-O file to load from
|
# @param filename [String] the Mach-O file to load from
|
||||||
# @param opts [Hash] options to control the parser with
|
# @param opts [Hash] options to control the parser with
|
||||||
# @option opts [Boolean] :permissive whether to ignore unknown load commands
|
# @option opts [Boolean] :permissive whether to ignore unknown load commands
|
||||||
|
# @option opts [Boolean] :decompress whether to decompress, if capable
|
||||||
# @raise [ArgumentError] if the given file does not exist
|
# @raise [ArgumentError] if the given file does not exist
|
||||||
|
# @note The `:decompress` option relies on non-default dependencies. Compression
|
||||||
|
# is only used in niche Mach-Os, so leaving this disabled is a reasonable default for
|
||||||
|
# virtually all normal uses.
|
||||||
def initialize(filename, **opts)
|
def initialize(filename, **opts)
|
||||||
raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
|
raise ArgumentError, "#{filename}: no such file" unless File.file?(filename)
|
||||||
|
|
||||||
@filename = filename
|
@filename = filename
|
||||||
@options = opts
|
@options = opts
|
||||||
@raw_data = File.open(@filename, "rb", &:read)
|
@raw_data = File.binread(@filename)
|
||||||
populate_fields
|
populate_fields
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -152,8 +160,8 @@ module MachO
|
|||||||
# the instance fields
|
# the instance fields
|
||||||
# @raise [OffsetInsertionError] if the offset is not in the load command region
|
# @raise [OffsetInsertionError] if the offset is not in the load command region
|
||||||
# @raise [HeaderPadError] if the new command exceeds the header pad buffer
|
# @raise [HeaderPadError] if the new command exceeds the header pad buffer
|
||||||
# @note Calling this method with an arbitrary offset in the load command
|
# @note Calling this method with an arbitrary offset in the load command region
|
||||||
# region **will leave the object in an inconsistent state**.
|
# **will leave the object in an inconsistent state**.
|
||||||
def insert_command(offset, lc, options = {})
|
def insert_command(offset, lc, options = {})
|
||||||
context = LoadCommands::LoadCommand::SerializationContext.context_for(self)
|
context = LoadCommands::LoadCommand::SerializationContext.context_for(self)
|
||||||
cmd_raw = lc.serialize(context)
|
cmd_raw = lc.serialize(context)
|
||||||
@ -196,7 +204,7 @@ module MachO
|
|||||||
# Appends a new load command to the Mach-O.
|
# Appends a new load command to the Mach-O.
|
||||||
# @param lc [LoadCommands::LoadCommand] the load command being added
|
# @param lc [LoadCommands::LoadCommand] the load command being added
|
||||||
# @param options [Hash]
|
# @param options [Hash]
|
||||||
# @option options [Boolean] :repopulate (true) whether or not to repopulate
|
# @option f [Boolean] :repopulate (true) whether or not to repopulate
|
||||||
# the instance fields
|
# the instance fields
|
||||||
# @return [void]
|
# @return [void]
|
||||||
# @see #insert_command
|
# @see #insert_command
|
||||||
@ -368,20 +376,20 @@ module MachO
|
|||||||
# file.change_rpath("/usr/lib", "/usr/local/lib")
|
# file.change_rpath("/usr/lib", "/usr/local/lib")
|
||||||
# @param old_path [String] the old runtime path
|
# @param old_path [String] the old runtime path
|
||||||
# @param new_path [String] the new runtime path
|
# @param new_path [String] the new runtime path
|
||||||
# @param _options [Hash]
|
# @param options [Hash]
|
||||||
|
# @option options [Boolean] :uniq (false) if true, change duplicate
|
||||||
|
# rpaths simultaneously.
|
||||||
# @return [void]
|
# @return [void]
|
||||||
# @raise [RpathUnknownError] if no such old runtime path exists
|
# @raise [RpathUnknownError] if no such old runtime path exists
|
||||||
# @raise [RpathExistsError] if the new runtime path already exists
|
# @raise [RpathExistsError] if the new runtime path already exists
|
||||||
# @note `_options` is currently unused and is provided for signature
|
def change_rpath(old_path, new_path, options = {})
|
||||||
# compatibility with {MachO::FatFile#change_rpath}
|
|
||||||
def change_rpath(old_path, new_path, _options = {})
|
|
||||||
old_lc = command(:LC_RPATH).find { |r| r.path.to_s == old_path }
|
old_lc = command(:LC_RPATH).find { |r| r.path.to_s == old_path }
|
||||||
raise RpathUnknownError, old_path if old_lc.nil?
|
raise RpathUnknownError, old_path if old_lc.nil?
|
||||||
raise RpathExistsError, new_path if rpaths.include?(new_path)
|
raise RpathExistsError, new_path if rpaths.include?(new_path)
|
||||||
|
|
||||||
new_lc = LoadCommands::LoadCommand.create(:LC_RPATH, new_path)
|
new_lc = LoadCommands::LoadCommand.create(:LC_RPATH, new_path)
|
||||||
|
|
||||||
delete_rpath(old_path)
|
delete_rpath(old_path, options)
|
||||||
insert_command(old_lc.view.offset, new_lc)
|
insert_command(old_lc.view.offset, new_lc)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -409,13 +417,18 @@ module MachO
|
|||||||
# file.delete_rpath("/lib")
|
# file.delete_rpath("/lib")
|
||||||
# file.rpaths # => []
|
# file.rpaths # => []
|
||||||
# @param path [String] the runtime path to delete
|
# @param path [String] the runtime path to delete
|
||||||
# @param _options [Hash]
|
# @param options [Hash]
|
||||||
|
# @option options [Boolean] :uniq (false) if true, also delete
|
||||||
|
# duplicates of the requested path. If false, delete the first
|
||||||
|
# instance (by offset) of the requested path.
|
||||||
# @return void
|
# @return void
|
||||||
# @raise [RpathUnknownError] if no such runtime path exists
|
# @raise [RpathUnknownError] if no such runtime path exists
|
||||||
# @note `_options` is currently unused and is provided for signature
|
def delete_rpath(path, options = {})
|
||||||
# compatibility with {MachO::FatFile#delete_rpath}
|
uniq = options.fetch(:uniq, false)
|
||||||
def delete_rpath(path, _options = {})
|
search_method = uniq ? :select : :find
|
||||||
rpath_cmds = command(:LC_RPATH).select { |r| r.path.to_s == path }
|
|
||||||
|
# Cast rpath_cmds into an Array so we can handle the uniq and non-uniq cases the same way
|
||||||
|
rpath_cmds = Array(command(:LC_RPATH).method(search_method).call { |r| r.path.to_s == path })
|
||||||
raise RpathUnknownError, path if rpath_cmds.empty?
|
raise RpathUnknownError, path if rpath_cmds.empty?
|
||||||
|
|
||||||
# delete the commands in reverse order, offset descending.
|
# delete the commands in reverse order, offset descending.
|
||||||
@ -426,7 +439,7 @@ module MachO
|
|||||||
# @param filename [String] the file to write to
|
# @param filename [String] the file to write to
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def write(filename)
|
def write(filename)
|
||||||
File.open(filename, "wb") { |f| f.write(@raw_data) }
|
File.binwrite(filename, @raw_data)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Write all Mach-O data to the file used to initialize the instance.
|
# Write all Mach-O data to the file used to initialize the instance.
|
||||||
@ -436,7 +449,7 @@ module MachO
|
|||||||
def write!
|
def write!
|
||||||
raise MachOError, "no initial file to write to" if @filename.nil?
|
raise MachOError, "no initial file to write to" if @filename.nil?
|
||||||
|
|
||||||
File.open(@filename, "wb") { |f| f.write(@raw_data) }
|
File.binwrite(@filename, @raw_data)
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return [Hash] a hash representation of this {MachOFile}
|
# @return [Hash] a hash representation of this {MachOFile}
|
||||||
@ -458,6 +471,9 @@ module MachO
|
|||||||
# the smallest Mach-O header is 28 bytes
|
# the smallest Mach-O header is 28 bytes
|
||||||
raise TruncatedFileError if @raw_data.size < 28
|
raise TruncatedFileError if @raw_data.size < 28
|
||||||
|
|
||||||
|
magic = @raw_data[0..3].unpack1("N")
|
||||||
|
populate_prelinked_kernel_header if Utils.compressed_magic?(magic)
|
||||||
|
|
||||||
magic = populate_and_check_magic
|
magic = populate_and_check_magic
|
||||||
mh_klass = Utils.magic32?(magic) ? Headers::MachHeader : Headers::MachHeader64
|
mh_klass = Utils.magic32?(magic) ? Headers::MachHeader : Headers::MachHeader64
|
||||||
mh = mh_klass.new_from_bin(endianness, @raw_data[0, mh_klass.bytesize])
|
mh = mh_klass.new_from_bin(endianness, @raw_data[0, mh_klass.bytesize])
|
||||||
@ -469,6 +485,48 @@ module MachO
|
|||||||
mh
|
mh
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Read a compressed Mach-O header and check its validity, as well as whether we're able
|
||||||
|
# to parse it.
|
||||||
|
# @return [void]
|
||||||
|
# @raise [CompressedMachOError] if we weren't asked to perform decompression
|
||||||
|
# @raise [DecompressionError] if decompression is impossible or fails
|
||||||
|
# @api private
|
||||||
|
def populate_prelinked_kernel_header
|
||||||
|
raise CompressedMachOError unless options.fetch(:decompress, false)
|
||||||
|
|
||||||
|
@plh = Headers::PrelinkedKernelHeader.new_from_bin :big, @raw_data[0, Headers::PrelinkedKernelHeader.bytesize]
|
||||||
|
|
||||||
|
raise DecompressionError, "unsupported compression type: LZSS" if @plh.lzss?
|
||||||
|
raise DecompressionError, "unknown compression type: 0x#{plh.compress_type.to_s 16}" unless @plh.lzvn?
|
||||||
|
|
||||||
|
decompress_macho_lzvn
|
||||||
|
end
|
||||||
|
|
||||||
|
# Attempt to decompress a Mach-O file from the data specified in a prelinked kernel header.
|
||||||
|
# @return [void]
|
||||||
|
# @raise [DecompressionError] if decompression is impossible or fails
|
||||||
|
# @api private
|
||||||
|
# @note This method rewrites the internal state of {MachOFile} to pretend as if it was never
|
||||||
|
# compressed to begin with, allowing all other APIs to transparently act on compressed Mach-Os.
|
||||||
|
def decompress_macho_lzvn
|
||||||
|
begin
|
||||||
|
require "lzfse"
|
||||||
|
rescue LoadError
|
||||||
|
raise DecompressionError, "LZVN required but the optional 'lzfse' gem is not installed"
|
||||||
|
end
|
||||||
|
|
||||||
|
# From this point onwards, the internal buffer of this MachOFile refers to the decompressed
|
||||||
|
# contents specified by the prelinked kernel header.
|
||||||
|
begin
|
||||||
|
@raw_data = LZFSE.lzvn_decompress @raw_data.slice(Headers::PrelinkedKernelHeader.bytesize, @plh.compressed_size)
|
||||||
|
# Sanity checks.
|
||||||
|
raise DecompressionError if @raw_data.size != @plh.uncompressed_size
|
||||||
|
# TODO: check the adler32 CRC in @plh
|
||||||
|
rescue LZFSE::DecodeError
|
||||||
|
raise DecompressionError, "LZVN decompression failed"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Read just the file's magic number and check its validity.
|
# Read just the file's magic number and check its validity.
|
||||||
# @return [Integer] the magic
|
# @return [Integer] the magic
|
||||||
# @raise [MagicError] if the magic is not valid Mach-O magic
|
# @raise [MagicError] if the magic is not valid Mach-O magic
|
||||||
@ -553,8 +611,8 @@ module MachO
|
|||||||
segments.each do |seg|
|
segments.each do |seg|
|
||||||
seg.sections.each do |sect|
|
seg.sections.each do |sect|
|
||||||
next if sect.empty?
|
next if sect.empty?
|
||||||
next if sect.flag?(:S_ZEROFILL)
|
next if sect.type?(:S_ZEROFILL)
|
||||||
next if sect.flag?(:S_THREAD_LOCAL_ZEROFILL)
|
next if sect.type?(:S_THREAD_LOCAL_ZEROFILL)
|
||||||
next unless sect.offset < offset
|
next unless sect.offset < offset
|
||||||
|
|
||||||
offset = sect.offset
|
offset = sect.offset
|
@ -4,24 +4,24 @@ module MachO
|
|||||||
# Classes and constants for parsing sections in Mach-O binaries.
|
# Classes and constants for parsing sections in Mach-O binaries.
|
||||||
module Sections
|
module Sections
|
||||||
# type mask
|
# type mask
|
||||||
SECTION_TYPE = 0x000000ff
|
SECTION_TYPE_MASK = 0x000000ff
|
||||||
|
|
||||||
# attributes mask
|
# attributes mask
|
||||||
SECTION_ATTRIBUTES = 0xffffff00
|
SECTION_ATTRIBUTES_MASK = 0xffffff00
|
||||||
|
|
||||||
# user settable attributes mask
|
# user settable attributes mask
|
||||||
SECTION_ATTRIBUTES_USR = 0xff000000
|
SECTION_ATTRIBUTES_USR_MASK = 0xff000000
|
||||||
|
|
||||||
# system settable attributes mask
|
# system settable attributes mask
|
||||||
SECTION_ATTRIBUTES_SYS = 0x00ffff00
|
SECTION_ATTRIBUTES_SYS_MASK = 0x00ffff00
|
||||||
|
|
||||||
# maximum specifiable section alignment, as a power of 2
|
# maximum specifiable section alignment, as a power of 2
|
||||||
# @note see `MAXSECTALIGN` macro in `cctools/misc/lipo.c`
|
# @note see `MAXSECTALIGN` macro in `cctools/misc/lipo.c`
|
||||||
MAX_SECT_ALIGN = 15
|
MAX_SECT_ALIGN = 15
|
||||||
|
|
||||||
# association of section flag symbols to values
|
# association of section type symbols to values
|
||||||
# @api private
|
# @api private
|
||||||
SECTION_FLAGS = {
|
SECTION_TYPES = {
|
||||||
:S_REGULAR => 0x0,
|
:S_REGULAR => 0x0,
|
||||||
:S_ZEROFILL => 0x1,
|
:S_ZEROFILL => 0x1,
|
||||||
:S_CSTRING_LITERALS => 0x2,
|
:S_CSTRING_LITERALS => 0x2,
|
||||||
@ -44,6 +44,12 @@ module MachO
|
|||||||
:S_THREAD_LOCAL_VARIABLES => 0x13,
|
:S_THREAD_LOCAL_VARIABLES => 0x13,
|
||||||
:S_THREAD_LOCAL_VARIABLE_POINTERS => 0x14,
|
:S_THREAD_LOCAL_VARIABLE_POINTERS => 0x14,
|
||||||
:S_THREAD_LOCAL_INIT_FUNCTION_POINTERS => 0x15,
|
:S_THREAD_LOCAL_INIT_FUNCTION_POINTERS => 0x15,
|
||||||
|
:S_INIT_FUNC_OFFSETS => 0x16,
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
# association of section attribute symbols to values
|
||||||
|
# @api private
|
||||||
|
SECTION_ATTRIBUTES = {
|
||||||
:S_ATTR_PURE_INSTRUCTIONS => 0x80000000,
|
:S_ATTR_PURE_INSTRUCTIONS => 0x80000000,
|
||||||
:S_ATTR_NO_TOC => 0x40000000,
|
:S_ATTR_NO_TOC => 0x40000000,
|
||||||
:S_ATTR_STRIP_STATIC_SYMS => 0x20000000,
|
:S_ATTR_STRIP_STATIC_SYMS => 0x20000000,
|
||||||
@ -56,6 +62,13 @@ module MachO
|
|||||||
:S_ATTR_LOC_RELOC => 0x00000100,
|
:S_ATTR_LOC_RELOC => 0x00000100,
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
|
# association of section flag symbols to values
|
||||||
|
# @api private
|
||||||
|
SECTION_FLAGS = {
|
||||||
|
**SECTION_TYPES,
|
||||||
|
**SECTION_ATTRIBUTES,
|
||||||
|
}.freeze
|
||||||
|
|
||||||
# association of section name symbols to names
|
# association of section name symbols to names
|
||||||
# @api private
|
# @api private
|
||||||
SECTION_NAMES = {
|
SECTION_NAMES = {
|
||||||
@ -147,6 +160,33 @@ module MachO
|
|||||||
size.zero?
|
size.zero?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# @return [Integer] the raw numeric type of this section
|
||||||
|
def type
|
||||||
|
flags & SECTION_TYPE_MASK
|
||||||
|
end
|
||||||
|
|
||||||
|
# @example
|
||||||
|
# puts "this section is regular" if sect.type?(:S_REGULAR)
|
||||||
|
# @param type_sym [Symbol] a section type symbol
|
||||||
|
# @return [Boolean] whether this section is of the given type
|
||||||
|
def type?(type_sym)
|
||||||
|
type == SECTION_TYPES[type_sym]
|
||||||
|
end
|
||||||
|
|
||||||
|
# @return [Integer] the raw numeric attributes of this section
|
||||||
|
def attributes
|
||||||
|
flags & SECTION_ATTRIBUTES_MASK
|
||||||
|
end
|
||||||
|
|
||||||
|
# @example
|
||||||
|
# puts "pure instructions" if sect.attribute?(:S_ATTR_PURE_INSTRUCTIONS)
|
||||||
|
# @param attr_sym [Symbol] a section attribute symbol
|
||||||
|
# @return [Boolean] whether this section is of the given type
|
||||||
|
def attribute?(attr_sym)
|
||||||
|
!!(attributes & SECTION_ATTRIBUTES[attr_sym])
|
||||||
|
end
|
||||||
|
|
||||||
|
# @deprecated Use {#type?} or {#attribute?} instead.
|
||||||
# @example
|
# @example
|
||||||
# puts "this section is regular" if sect.flag?(:S_REGULAR)
|
# puts "this section is regular" if sect.flag?(:S_REGULAR)
|
||||||
# @param flag [Symbol] a section flag symbol
|
# @param flag [Symbol] a section flag symbol
|
@ -51,6 +51,8 @@ module MachO
|
|||||||
# @param options [Hash]
|
# @param options [Hash]
|
||||||
# @option options [Boolean] :strict (true) whether or not to fail loudly
|
# @option options [Boolean] :strict (true) whether or not to fail loudly
|
||||||
# with an exception if the change cannot be performed
|
# with an exception if the change cannot be performed
|
||||||
|
# @option options [Boolean] :uniq (false) whether or not to change duplicate
|
||||||
|
# rpaths simultaneously
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def self.change_rpath(filename, old_path, new_path, options = {})
|
def self.change_rpath(filename, old_path, new_path, options = {})
|
||||||
file = MachO.open(filename)
|
file = MachO.open(filename)
|
||||||
@ -80,6 +82,8 @@ module MachO
|
|||||||
# @param options [Hash]
|
# @param options [Hash]
|
||||||
# @option options [Boolean] :strict (true) whether or not to fail loudly
|
# @option options [Boolean] :strict (true) whether or not to fail loudly
|
||||||
# with an exception if the change cannot be performed
|
# with an exception if the change cannot be performed
|
||||||
|
# @option options [Boolean] :uniq (false) whether or not to delete duplicate
|
||||||
|
# rpaths simultaneously
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def self.delete_rpath(filename, old_path, options = {})
|
def self.delete_rpath(filename, old_path, options = {})
|
||||||
file = MachO.open(filename)
|
file = MachO.open(filename)
|
@ -121,5 +121,12 @@ module MachO
|
|||||||
def self.big_magic?(num)
|
def self.big_magic?(num)
|
||||||
[Headers::MH_MAGIC, Headers::MH_MAGIC_64].include? num
|
[Headers::MH_MAGIC, Headers::MH_MAGIC_64].include? num
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Compares the given number to the known magic number for a compressed Mach-O slice.
|
||||||
|
# @param num [Integer] the number being checked
|
||||||
|
# @return [Boolean] whether `num` is a valid compressed header magic number
|
||||||
|
def self.compressed_magic?(num)
|
||||||
|
num == Headers::COMPRESSED_MAGIC
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
Loading…
x
Reference in New Issue
Block a user