class Metasm::ZIP

Constants

COMPRESSION_METHOD
MAGIC_CENTRALHEADER
MAGIC_ENDCENTRALDIRECTORY
MAGIC_LOCALHEADER

Attributes

files[RW]
header[RW]

Public Class Methods

autoexe_load(bin) click to toggle source

when called as AutoExe, try to find a meaningful exefmt

# File metasm/exe_format/zip.rb, line 325
def self.autoexe_load(bin)
        z = decode(bin)
        if dex = z.file_data('classes.dex')
                puts "ZIP: APK file, loading 'classes.dex'" if $VERBOSE
                AutoExe.load(dex)
        else
                z
        end
end
new(cpu = nil) click to toggle source
Calls superclass method Metasm::ExeFormat::new
# File metasm/exe_format/zip.rb, line 219
def initialize(cpu = nil)
        @endianness = :little
        @header = EndCentralDirectory.new
        @files = []
        super(cpu)
end

Public Instance Methods

add_file(fname, data, compress=:auto) click to toggle source

add a new file to the zip archive

# File metasm/exe_format/zip.rb, line 266
def add_file(fname, data, compress=:auto)
        f = CentralHeader.new

        case compress
        when 'NONE', false; f.compress_method = 'NONE'
        when 'DEFLATE', true; f.compress_method = 'DEFLATE'
        end

        f.fname = fname
        f.data = data

        @files << f
        f
end
decode() click to toggle source

read the whole central directory file descriptors

# File metasm/exe_format/zip.rb, line 235
def decode
        decode_header
        @encoded.ptr = @header.directory_off
        while @encoded.ptr < @header.directory_off + @header.directory_sz
                @files << CentralHeader.decode(self)
        end
end
decode_half(edata=@encoded) click to toggle source
# File metasm/exe_format/zip.rb, line 210
def decode_half(edata=@encoded) edata.decode_imm(:u16, @endianness) end
decode_header() click to toggle source

scan and decode the 'end of central directory' header

# File metasm/exe_format/zip.rb, line 227
def decode_header
        if not @encoded.ptr = @encoded.data.rindex([MAGIC_ENDCENTRALDIRECTORY].pack('V'))
                raise "ZIP: no end of central directory record"
        end
        @header = EndCentralDirectory.decode(self)
end
decode_word(edata=@encoded) click to toggle source
# File metasm/exe_format/zip.rb, line 211
def decode_word(edata=@encoded) edata.decode_imm(:u32, @endianness) end
encode() click to toggle source

create a new zip file

# File metasm/exe_format/zip.rb, line 282
def encode
        edata = EncodedData.new
        central_dir = EncodedData.new

        @files.each { |f|
                encode_entry(f, edata, central_dir)
        }

        @header.directory_off = edata.length
        @header.directory_sz  = central_dir.length

        edata << central_dir << @header.encode(self)

        @encoded = edata
end
encode_entry(f, edata, central_dir) click to toggle source

add one file to the zip stream

# File metasm/exe_format/zip.rb, line 299
def encode_entry(f, edata, central_dir)
        f.localhdr_off = edata.length

        # may autodetect compression method
        raw = f.encode_data(self)

        zipalign(f, edata)

        central_dir << f.encode(self) # calls f.set_default_values

        l = LocalHeader.from_central(f)
        edata << l.encode(self)

        edata << raw
end
encode_half(w) click to toggle source
# File metasm/exe_format/zip.rb, line 212
def encode_half(w) Expression[w].encode(:u16, @endianness) end
encode_word(w) click to toggle source
# File metasm/exe_format/zip.rb, line 213
def encode_word(w) Expression[w].encode(:u32, @endianness) end
file_data(fname, lcase=true) click to toggle source

returns the uncompressed raw file content from a given name nil if name not found case-insensitive if lcase is false

# File metasm/exe_format/zip.rb, line 259
def file_data(fname, lcase=true)
        if f = has_file(fname, lcase)
                f.file_data(self)
        end
end
has_file(fname, lcase=true) click to toggle source

checks if a given file name exists in the archive returns the CentralHeader or nil case-insensitive if lcase is false

# File metasm/exe_format/zip.rb, line 246
def has_file(fname, lcase=true)
        decode if @files.empty?
        if lcase
                @files.find { |f| f.fname == fname }
        else
                fname = fname.downcase
                @files.find { |f| f.fname.downcase == fname }
        end
end
sizeof_half() click to toggle source
# File metasm/exe_format/zip.rb, line 214
def sizeof_half ; 2 ; end
sizeof_word() click to toggle source
# File metasm/exe_format/zip.rb, line 215
def sizeof_word ; 4 ; end
zipalign(f, edata) click to toggle source

zipalign: ensure uncompressed data starts on a 4-aligned offset

# File metasm/exe_format/zip.rb, line 316
def zipalign(f, edata)
        if f.compress_method == 'NONE' and not f.extra
                o = (edata.length + f.fname.length + 2) & 3
                f.extra = " "*(4-o) if o > 0
        end

end