Skip to content

Commit

Permalink
add test code for macho parsing via ipa interface and add aliases for…
Browse files Browse the repository at this point in the history
… macho parser helpers matching from_* convention used elsewhere
  • Loading branch information
Eric Monti committed Apr 21, 2018
1 parent 3bb786e commit f1c54fe
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 14 deletions.
4 changes: 2 additions & 2 deletions lib/pliney/apple_code_signature.rb
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ def self.parse(data)
end

def self.from_stream(f)
obj = MachO::read_stream(f)
obj = MachO::from_stream(f)
mh = if MachO::is_fat_magic(obj.magic)
obj.machos.first
elsif MachO::is_macho_magic(obj.magic)
Expand All @@ -240,7 +240,7 @@ def self.from_stream(f)
end

def self.from_path(fname)
File.open(fname, 'rb') {|f| return from_stream(f) }
return from_stream(File.open(fname, 'rb'))
end
end
end
Expand Down
44 changes: 39 additions & 5 deletions lib/pliney/ipa.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@

module Pliney
class IPA
class ZipExtractError < StandardError
end

SYSTEM_HAS_UNZIP = system("which unzip")

def self.from_path(path)
ipa = new(Zip::File.open(path))
if block_given?
Expand Down Expand Up @@ -92,6 +97,16 @@ def provisioning_profile
ProvisioningProfile.from_asn1(profile_data)
end

def with_macho_for_entry(file_entry)
with_extracted_tmpfile(file_entry) do |tmpfile|
yield ::Pliney::MachO.from_stream(tmpfile)
end
end

def with_executable_macho(&block)
with_macho_for_entry(self.executable_entry, &block)
end

def codesignature_for_entry(file_entry)
_with_tmpdir do |tmp_path|
tmpf = tmp_path.join("executable")
Expand Down Expand Up @@ -137,11 +152,19 @@ def team_identifier
end

def extract(path)
zipfile.each do |ent|
extract_path = path.join(ent.name)
FileUtils.mkdir_p(extract_path.dirname)
ent.extract(extract_path.to_s)
extract_path.chmod(ent.unix_perms & 0777)
if SYSTEM_HAS_UNZIP
ret = system("unzip", "-qd", path.to_s, self.zipfile.name.to_s)
unless ret
raise(ZipExtractError, "'unzip' command returned non-zero status: #{$?.inspect}")
end
else
path = Pathname(path)
zipfile.each do |ent|
extract_path = path.join(ent.name)
FileUtils.mkdir_p(extract_path.dirname)
ent.extract(extract_path.to_s)
extract_path.chmod(ent.unix_perms & 0777)
end
end
return path
end
Expand All @@ -150,6 +173,17 @@ def with_extracted_tmpdir(&block)
_with_tmpdir {|tmp_path| yield(extract(tmp_path)) }
end

def with_extracted_tmpfile(ent, &block)
tmpf = Tempfile.new("ent")
begin
Zip::IOExtras.copy_stream(tmpf, ent.get_input_stream)
tmpf.rewind
yield(tmpf)
ensure
tmpf.unlink()
end
end

def each_file_entry
zipfile.entries.select do |ent|
not ent.name_is_directory?
Expand Down
7 changes: 1 addition & 6 deletions lib/pliney/macho.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,7 @@ def self.read_stream(fh)
fh.pos -= 4
return reader_for_filemagic(magic).parse(fh)
end

def self.read_file(path)
File.open(path, 'rb') do |fh|
return read_stream(fh)
end
end
singleton_class.send(:alias_method, :from_stream, :read_stream)

module LoadCommandConst
LC_SEGMENT = 0x1
Expand Down
41 changes: 40 additions & 1 deletion spec/ipa_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,45 @@
ents["application-identifier"].should == "UL736KYQR9.computer.versus.pliney-test"
end

it "reads the executable object"
it "gets the team_identifier" do
@ipa.team_identifier == "UL736KYQR9"
end

it "extracts ipa contents" do
Dir.mktmpdir do |tmpd|
@ipa.extract(tmpd)
tmp_path = Pathname(tmpd)
@ipa.each_file_entry do |ent|
tmp_path.join(ent.name).exist?.should == true
end
end
end

it "extracts ipa contents to a temp directory yielded to a block" do
block_was_called = false
@ipa.with_extracted_tmpdir do |tmp_path|
block_was_called = true
@ipa.each_file_entry do |ent|
tmp_path.join(ent.name).exist?.should == true
end
end
block_was_called.should == true
end

it "reads the executable object" do
block_was_called = false
@ipa.with_executable_macho do |exe_obj|
block_was_called = true
exe_obj.should be_a Pliney::MachO::FatHeaderReader
exe_obj.fat_arches.count.should == 2
machos = exe_obj.machos
machos.map{|x| x.magic}.should == [
Pliney::MachO::MACHO_MAGIC32,
Pliney::MachO::MACHO_MAGIC64,
]
end
block_was_called.should == true
end

end

0 comments on commit f1c54fe

Please sign in to comment.