metasm/exe_format/pe.rb in metasm-1.0.3 vs metasm/exe_format/pe.rb in metasm-1.0.4

- old
+ new

@@ -9,12 +9,13 @@ require 'metasm/exe_format/coff' module Metasm class PE < COFF MAGIC = "PE\0\0" # 0x50450000 + MAGIC.force_encoding('BINARY') if MAGIC.respond_to?(:force_encoding) - attr_accessor :coff_offset, :signature, :mz + attr_accessor :coff_offset, :signature, :mz, :productid def initialize(*a) super(*a) cpu = a.grep(CPU).first @mz = MZ.new(cpu).share_namespace(self) @@ -24,11 +25,18 @@ # simply sets the offset to the PE pointer before decoding the COFF header # also checks the PE signature def decode_header @cursection ||= self @encoded.ptr = 0x3c - @encoded.ptr = decode_word(@encoded) + lfanew = decode_word(@encoded) + + try_rich_sz = [0x400, lfanew].min + rich_ary = [] + rich_ary << decode_word(@encoded) while @encoded.ptr < try_rich_sz + @productid = decode_productid(rich_ary) + + @encoded.ptr = lfanew @signature = @encoded.read(4) raise InvalidExeFormat, "Invalid PE signature #{@signature.inspect}" if @signature != MAGIC @coff_offset = @encoded.ptr if @mz.encoded.empty? @mz.encoded << @encoded[0, @coff_offset-4] @@ -36,10 +44,24 @@ @mz.decode_header end super() end + RICH_MAGIC = 0x68636952 # "Rich" + def decode_productid(ary) + return unless idx = ary.index(RICH_MAGIC) and xorkey = ary[idx+1] + ary = ary[0, idx-1].map { |dw| dw ^ xorkey } + return unless idx = ary.rindex(0x536E6144) # "DanS" + ary = ary[idx+2..-1] + out = [] + until ary.empty? + ar1 = ary.shift + out << { :id => ar1 >> 16, :ver => ar1 & 0xffff, :count => ary.shift.to_i } + end + out + end + # creates a default MZ file to be used in the PE header # this one is specially crafted to fit in the 0x3c bytes before the signature def encode_default_mz_header # XXX use single-quoted source, to avoid ruby interpretation of \r\n @mz.cpu = Ia32.new(386, 16) @@ -224,10 +246,10 @@ a = dasm.backtrace(sehptr, di.address, :include_start => true, :origin => di.address, :type => :x, :detached => true) puts "backtrace seh from #{di} => #{a.map { |addr| Expression[addr] }.join(', ')}" if $VERBOSE a.each { |aa| next if aa == Expression::Unknown dasm.auto_label_at(aa, 'seh', 'loc', 'sub') - dasm.addrs_todo << [aa] + dasm.addrs_todo << { :addr => aa } } super(dasm, di) else super(dasm, di) end